Volume XXII, number 279Tuesday, October 6, 2026Latest message 43 minutes ago

The Git List

News and archive of git@vger.kernel.org, since April 2005

patchcopy: drop dependency on `the_repository`

6 messages between Jul 16, 2026 and Jul 17, 2026, from Patrick Steinhardt, Phillip Wood, Junio C Hamano.

Plain Markdown or JSON for tools and agents. Diffs are folded; open one to read it.

Patrick SteinhardtJul 16, 2026, 09:56 UTC on lore

When copying a file we need to potentially adapt permissions of the new file based on whether or not "core.shared" is enabled. Parsing this configuration makes us implicitly depend on `the_repository`.

Refactor the code to instead require the caller to pass in a repository so that we can remove `USE_THE_REPOSITORY_VARIABLE`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
Hi,

I guess the title says it all: this small patch removes the dependency on `the_repository` in "copy.c". Thanks!

Patrick
---
 builtin/clone.c      |  2 +-
 builtin/difftool.c   |  4 ++--
 builtin/worktree.c   |  4 ++--
 bundle-uri.c         |  2 +-
 copy.c               | 12 ++++++------
 copy.h               |  8 ++++++--
 refs/files-backend.c |  2 +-
 rerere.c             |  2 +-
 sequencer.c          |  6 +++---
 setup.c              |  2 +-
 10 files changed, 24 insertions(+), 20 deletions(-)
Show changes to 10 files +24 −20

builtin/clone.c, builtin/difftool.c, builtin/worktree.c, bundle-uri.c, copy.c, copy.h, refs/files-backend.c, rerere.c, sequencer.c, setup.c

diff --git a/builtin/clone.c b/builtin/clone.c
index d60d1b60bc..18603dd4ce 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -335,7 +335,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
 				die_errno(_("failed to create link '%s'"), dest->buf);
 			option_no_hardlinks = 1;
 		}
-		if (copy_file_with_time(dest->buf, src->buf, 0666))
+		if (copy_file_with_time(the_repository, dest->buf, src->buf, 0666))
 			die_errno(_("failed to copy file to '%s'"), dest->buf);
 	}
 
diff --git a/builtin/difftool.c b/builtin/difftool.c
index 26778f8515..5e7777fbe4 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -552,7 +552,7 @@ static int run_dir_diff(struct repository *repo,
 					struct stat st;
 					if (stat(wtdir.buf, &st))
 						st.st_mode = 0644;
-					if (copy_file(rdir.buf, wtdir.buf,
+					if (copy_file(repo, rdir.buf, wtdir.buf,
 						      st.st_mode)) {
 						ret = error("could not copy '%s' to '%s'", wtdir.buf, rdir.buf);
 						goto finish;
@@ -658,7 +658,7 @@ static int run_dir_diff(struct repository *repo,
 				warning("%s", "");
 				err = 1;
 			} else if (unlink(wtdir.buf) ||
-				   copy_file(wtdir.buf, rdir.buf, st.st_mode))
+				   copy_file(repo, wtdir.buf, rdir.buf, st.st_mode))
 				warning_errno(_("could not copy '%s' to '%s'"),
 					      rdir.buf, wtdir.buf);
 		}
diff --git a/builtin/worktree.c b/builtin/worktree.c
index d21c43fde3..84b01960fb 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -349,7 +349,7 @@ static void copy_sparse_checkout(const char *worktree_git_dir)
 
 	if (file_exists(from_file)) {
 		if (safe_create_leading_directories(the_repository, to_file) ||
-			copy_file(to_file, from_file, 0666))
+			copy_file(the_repository, to_file, from_file, 0666))
 			error(_("failed to copy '%s' to '%s'; sparse-checkout may not work correctly"),
 				from_file, to_file);
 	}
@@ -368,7 +368,7 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir)
 		int bare;
 
 		if (safe_create_leading_directories(the_repository, to_file) ||
-			copy_file(to_file, from_file, 0666)) {
+			copy_file(the_repository, to_file, from_file, 0666)) {
 			error(_("failed to copy worktree config from '%s' to '%s'"),
 				from_file, to_file);
 			goto worktree_copy_cleanup;
diff --git a/bundle-uri.c b/bundle-uri.c
index 3b2e347288..ef37aebf30 100644
--- a/bundle-uri.c
+++ b/bundle-uri.c
@@ -396,7 +396,7 @@ static int copy_uri_to_file(const char *filename, const char *uri)
 		uri = out;
 
 	/* Copy as a file */
-	return copy_file(filename, uri, 0);
+	return copy_file(the_repository, filename, uri, 0);
 }
 
 static int unbundle_from_file(struct repository *r, const char *file)
diff --git a/copy.c b/copy.c
index b668209b6c..6074132050 100644
--- a/copy.c
+++ b/copy.c
@@ -1,5 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
 #include "git-compat-util.h"
 #include "copy.h"
 #include "path.h"
@@ -35,7 +33,8 @@ static int copy_times(const char *dst, const char *src)
 	return 0;
 }
 
-int copy_file(const char *dst, const char *src, int mode)
+int copy_file(struct repository *repo,
+	      const char *dst, const char *src, int mode)
 {
 	int fdi, fdo, status;
 
@@ -59,15 +58,16 @@ int copy_file(const char *dst, const char *src, int mode)
 	if (close(fdo) != 0)
 		return error_errno("%s: close error", dst);
 
-	if (!status && adjust_shared_perm(the_repository, dst))
+	if (!status && adjust_shared_perm(repo, dst))
 		return -1;
 
 	return status;
 }
 
-int copy_file_with_time(const char *dst, const char *src, int mode)
+int copy_file_with_time(struct repository *repo,
+			const char *dst, const char *src, int mode)
 {
-	int status = copy_file(dst, src, mode);
+	int status = copy_file(repo, dst, src, mode);
 	if (!status)
 		return copy_times(dst, src);
 	return status;
diff --git a/copy.h b/copy.h
index 2af77cba86..1059b118d6 100644
--- a/copy.h
+++ b/copy.h
@@ -1,10 +1,14 @@
 #ifndef COPY_H
 #define COPY_H
 
+struct repository;
+
 #define COPY_READ_ERROR (-2)
 #define COPY_WRITE_ERROR (-3)
 int copy_fd(int ifd, int ofd);
-int copy_file(const char *dst, const char *src, int mode);
-int copy_file_with_time(const char *dst, const char *src, int mode);
+int copy_file(struct repository *repo,
+	      const char *dst, const char *src, int mode);
+int copy_file_with_time(struct repository *repo,
+			const char *dst, const char *src, int mode);
 
 #endif /* COPY_H */
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 3df56c25c8..442c98414e 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1736,7 +1736,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
 		goto out;
 	}
 
-	if (copy && log && copy_file(tmp_renamed_log.buf, sb_oldref.buf, 0644)) {
+	if (copy && log && copy_file(refs->base.repo, tmp_renamed_log.buf, sb_oldref.buf, 0644)) {
 		ret = error("unable to copy logfile logs/%s to logs/"TMP_RENAMED_LOG": %s",
 			    oldrefname, strerror(errno));
 		goto out;
diff --git a/rerere.c b/rerere.c
index 8232542585..bf5cfc6e51 100644
--- a/rerere.c
+++ b/rerere.c
@@ -756,7 +756,7 @@ static void do_rerere_one_path(struct index_state *istate,
 	/* Has the user resolved it already? */
 	if (variant >= 0) {
 		if (!handle_file(istate, path, NULL, NULL)) {
-			copy_file(rerere_path(&buf, id, "postimage"), path, 0666);
+			copy_file(the_repository, rerere_path(&buf, id, "postimage"), path, 0666);
 			id->collection->status[variant] |= RR_HAS_POSTIMAGE;
 			fprintf_ln(stderr, _("Recorded resolution for '%s'."), path);
 			free_rerere_id(rr_item);
diff --git a/sequencer.c b/sequencer.c
index 1355a99a09..c9ede9c02d 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2419,7 +2419,7 @@ static int do_pick_commit(struct repository *r,
 		} else {
 			const char *dest = git_path_squash_msg(r);
 			unlink(dest);
-			if (copy_file(dest, rebase_path_squash_msg(), 0666)) {
+			if (copy_file(the_repository, dest, rebase_path_squash_msg(), 0666)) {
 				res = error(_("could not copy '%s' to '%s'"),
 					    rebase_path_squash_msg(), dest);
 				goto leave;
@@ -3864,11 +3864,11 @@ static int error_failed_squash(struct repository *r,
 			       int subject_len,
 			       const char *subject)
 {
-	if (copy_file(rebase_path_message(), rebase_path_squash_msg(), 0666))
+	if (copy_file(the_repository, rebase_path_message(), rebase_path_squash_msg(), 0666))
 		return error(_("could not copy '%s' to '%s'"),
 			rebase_path_squash_msg(), rebase_path_message());
 	unlink(git_path_merge_msg(r));
-	if (copy_file(git_path_merge_msg(r), rebase_path_message(), 0666))
+	if (copy_file(the_repository, git_path_merge_msg(r), rebase_path_message(), 0666))
 		return error(_("could not copy '%s' to '%s'"),
 			     rebase_path_message(),
 			     git_path_merge_msg(r));
diff --git a/setup.c b/setup.c
index 0de56a074f..91d61a5939 100644
--- a/setup.c
+++ b/setup.c
@@ -2331,7 +2331,7 @@ static void copy_templates_1(struct repository *repo,
 			strbuf_release(&lnk);
 		}
 		else if (S_ISREG(st_template.st_mode)) {
-			if (copy_file(path->buf, template_path->buf, st_template.st_mode))
+			if (copy_file(repo, path->buf, template_path->buf, st_template.st_mode))
 				die_errno(_("cannot copy '%s' to '%s'"),
 					  template_path->buf, path->buf);
 		}

---
base-commit: d35c5399e3e54ac277bb391fc2f6be3e816d312b
change-id: 20260716-pks-copy-wo-the-repository-aa01ccdbed76
Phillip WoodJul 16, 2026, 13:41 UTC in reply to Patrick Steinhardt on lore

Re: [PATCH] copy: drop dependency on `the_repository`

Hi Patrick
On 16/07/2026 10:56, Patrick Steinhardt wrote:
Show 6 quoted lines
> When copying a file we need to potentially adapt permissions of the new
> file based on whether or not "core.shared" is enabled. Parsing this
> configuration makes us implicitly depend on `the_repository`.
> 
> Refactor the code to instead require the caller to pass in a repository
> so that we can remove `USE_THE_REPOSITORY_VARIABLE`.
Sounds sensible
Show 10 quoted lines
> diff --git a/sequencer.c b/sequencer.c
> index 1355a99a09..c9ede9c02d 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -2419,7 +2419,7 @@ static int do_pick_commit(struct repository *r,
>   		} else {
>   			const char *dest = git_path_squash_msg(r);
>   			unlink(dest);
> -			if (copy_file(dest, rebase_path_squash_msg(), 0666)) {
> +			if (copy_file(the_repository, dest, rebase_path_squash_msg(), 0666)) {

The path for "dest" is obtained using a local repository instance "r", but we're using "the_repository" to set the permissions on that path. While that matches the current behavior it is clearly better to use the same repository instance to obtain both the path and and permissions for that path. In the hunk below we even have "the_repository" and "r" on the same line which seems confusing. This patch uses a local repository instance in refs/files-backend.c and setup.c, lets do the same here.

Thanks
Phillip
Show 36 quoted lines
>   				res = error(_("could not copy '%s' to '%s'"),
>   					    rebase_path_squash_msg(), dest);
>   				goto leave;
> @@ -3864,11 +3864,11 @@ static int error_failed_squash(struct repository *r,
>   			       int subject_len,
>   			       const char *subject)
>   {
> -	if (copy_file(rebase_path_message(), rebase_path_squash_msg(), 0666))
> +	if (copy_file(the_repository, rebase_path_message(), rebase_path_squash_msg(), 0666))
>   		return error(_("could not copy '%s' to '%s'"),
>   			rebase_path_squash_msg(), rebase_path_message());
>   	unlink(git_path_merge_msg(r));
> -	if (copy_file(git_path_merge_msg(r), rebase_path_message(), 0666))
> +	if (copy_file(the_repository, git_path_merge_msg(r), rebase_path_message(), 0666))
>   		return error(_("could not copy '%s' to '%s'"),
>   			     rebase_path_message(),
>   			     git_path_merge_msg(r));
> diff --git a/setup.c b/setup.c
> index 0de56a074f..91d61a5939 100644
> --- a/setup.c
> +++ b/setup.c
> @@ -2331,7 +2331,7 @@ static void copy_templates_1(struct repository *repo,
>   			strbuf_release(&lnk);
>   		}
>   		else if (S_ISREG(st_template.st_mode)) {
> -			if (copy_file(path->buf, template_path->buf, st_template.st_mode))
> +			if (copy_file(repo, path->buf, template_path->buf, st_template.st_mode))
>   				die_errno(_("cannot copy '%s' to '%s'"),
>   					  template_path->buf, path->buf);
>   		}
> 
> ---
> base-commit: d35c5399e3e54ac277bb391fc2f6be3e816d312b
> change-id: 20260716-pks-copy-wo-the-repository-aa01ccdbed76
> 
> 
Patrick SteinhardtJul 16, 2026, 15:06 UTC in reply to Phillip Wood on lore

Re: [PATCH] copy: drop dependency on `the_repository`

On Thu, Jul 16, 2026 at 02:41:44PM +0100, Phillip Wood wrote:
Show 18 quoted lines
> > diff --git a/sequencer.c b/sequencer.c
> > index 1355a99a09..c9ede9c02d 100644
> > --- a/sequencer.c
> > +++ b/sequencer.c
> > @@ -2419,7 +2419,7 @@ static int do_pick_commit(struct repository *r,
> >   		} else {
> >   			const char *dest = git_path_squash_msg(r);
> >   			unlink(dest);
> > -			if (copy_file(dest, rebase_path_squash_msg(), 0666)) {
> > +			if (copy_file(the_repository, dest, rebase_path_squash_msg(), 0666)) {
> 
> The path for "dest" is obtained using a local repository instance "r", but
> we're using "the_repository" to set the permissions on that path. While that
> matches the current behavior it is clearly better to use the same repository
> instance to obtain both the path and and permissions for that path. In the
> hunk below we even have "the_repository" and "r" on the same line which
> seems confusing. This patch uses a local repository instance in
> refs/files-backend.c and setup.c, lets do the same here.

Makes sense. In that case though I'll also adapt the two uses of `the_repository` below. Thanks!

Patrick
Show 14 quoted lines
> > @@ -3864,11 +3864,11 @@ static int error_failed_squash(struct repository *r,
> >   			       int subject_len,
> >   			       const char *subject)
> >   {
> > -	if (copy_file(rebase_path_message(), rebase_path_squash_msg(), 0666))
> > +	if (copy_file(the_repository, rebase_path_message(), rebase_path_squash_msg(), 0666))
> >   		return error(_("could not copy '%s' to '%s'"),
> >   			rebase_path_squash_msg(), rebase_path_message());
> >   	unlink(git_path_merge_msg(r));
> > -	if (copy_file(git_path_merge_msg(r), rebase_path_message(), 0666))
> > +	if (copy_file(the_repository, git_path_merge_msg(r), rebase_path_message(), 0666))
> >   		return error(_("could not copy '%s' to '%s'"),
> >   			     rebase_path_message(),
> >   			     git_path_merge_msg(r));
Patrick SteinhardtJul 16, 2026, 15:28 UTC in reply to Patrick Steinhardt on lore

[PATCH v2] copy: drop dependency on `the_repository`

When copying a file we need to potentially adapt permissions of the new file based on whether or not "core.shared" is enabled. Parsing this configuration makes us implicitly depend on `the_repository`.

Refactor the code to instead require the caller to pass in a repository so that we can remove `USE_THE_REPOSITORY_VARIABLE`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
Hi,

I guess the title says it all: this small patch removes the dependency on `the_repository` in "copy.c". Thanks!

Changes in v2:
  - Adapt a couple more sites to use a repository from the context.
  - Link to v1: https://patch.msgid.link/20260716-pks-copy-wo-the-repository-v1-1-8f1e078bb82f@pks.im
Patrick
---
 builtin/clone.c      |  2 +-
 builtin/difftool.c   |  4 ++--
 builtin/worktree.c   |  4 ++--
 bundle-uri.c         |  2 +-
 copy.c               | 12 ++++++------
 copy.h               |  8 ++++++--
 refs/files-backend.c |  2 +-
 rerere.c             |  2 +-
 sequencer.c          |  6 +++---
 setup.c              |  2 +-
 10 files changed, 24 insertions(+), 20 deletions(-)
Show changes to 10 files +24 −20

builtin/clone.c, builtin/difftool.c, builtin/worktree.c, bundle-uri.c, copy.c, copy.h, refs/files-backend.c, rerere.c, sequencer.c, setup.c

diff --git a/builtin/clone.c b/builtin/clone.c
index d60d1b60bc..18603dd4ce 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -335,7 +335,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
 				die_errno(_("failed to create link '%s'"), dest->buf);
 			option_no_hardlinks = 1;
 		}
-		if (copy_file_with_time(dest->buf, src->buf, 0666))
+		if (copy_file_with_time(the_repository, dest->buf, src->buf, 0666))
 			die_errno(_("failed to copy file to '%s'"), dest->buf);
 	}
 
diff --git a/builtin/difftool.c b/builtin/difftool.c
index 26778f8515..5e7777fbe4 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -552,7 +552,7 @@ static int run_dir_diff(struct repository *repo,
 					struct stat st;
 					if (stat(wtdir.buf, &st))
 						st.st_mode = 0644;
-					if (copy_file(rdir.buf, wtdir.buf,
+					if (copy_file(repo, rdir.buf, wtdir.buf,
 						      st.st_mode)) {
 						ret = error("could not copy '%s' to '%s'", wtdir.buf, rdir.buf);
 						goto finish;
@@ -658,7 +658,7 @@ static int run_dir_diff(struct repository *repo,
 				warning("%s", "");
 				err = 1;
 			} else if (unlink(wtdir.buf) ||
-				   copy_file(wtdir.buf, rdir.buf, st.st_mode))
+				   copy_file(repo, wtdir.buf, rdir.buf, st.st_mode))
 				warning_errno(_("could not copy '%s' to '%s'"),
 					      rdir.buf, wtdir.buf);
 		}
diff --git a/builtin/worktree.c b/builtin/worktree.c
index d21c43fde3..84b01960fb 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -349,7 +349,7 @@ static void copy_sparse_checkout(const char *worktree_git_dir)
 
 	if (file_exists(from_file)) {
 		if (safe_create_leading_directories(the_repository, to_file) ||
-			copy_file(to_file, from_file, 0666))
+			copy_file(the_repository, to_file, from_file, 0666))
 			error(_("failed to copy '%s' to '%s'; sparse-checkout may not work correctly"),
 				from_file, to_file);
 	}
@@ -368,7 +368,7 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir)
 		int bare;
 
 		if (safe_create_leading_directories(the_repository, to_file) ||
-			copy_file(to_file, from_file, 0666)) {
+			copy_file(the_repository, to_file, from_file, 0666)) {
 			error(_("failed to copy worktree config from '%s' to '%s'"),
 				from_file, to_file);
 			goto worktree_copy_cleanup;
diff --git a/bundle-uri.c b/bundle-uri.c
index 3b2e347288..ef37aebf30 100644
--- a/bundle-uri.c
+++ b/bundle-uri.c
@@ -396,7 +396,7 @@ static int copy_uri_to_file(const char *filename, const char *uri)
 		uri = out;
 
 	/* Copy as a file */
-	return copy_file(filename, uri, 0);
+	return copy_file(the_repository, filename, uri, 0);
 }
 
 static int unbundle_from_file(struct repository *r, const char *file)
diff --git a/copy.c b/copy.c
index b668209b6c..6074132050 100644
--- a/copy.c
+++ b/copy.c
@@ -1,5 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
 #include "git-compat-util.h"
 #include "copy.h"
 #include "path.h"
@@ -35,7 +33,8 @@ static int copy_times(const char *dst, const char *src)
 	return 0;
 }
 
-int copy_file(const char *dst, const char *src, int mode)
+int copy_file(struct repository *repo,
+	      const char *dst, const char *src, int mode)
 {
 	int fdi, fdo, status;
 
@@ -59,15 +58,16 @@ int copy_file(const char *dst, const char *src, int mode)
 	if (close(fdo) != 0)
 		return error_errno("%s: close error", dst);
 
-	if (!status && adjust_shared_perm(the_repository, dst))
+	if (!status && adjust_shared_perm(repo, dst))
 		return -1;
 
 	return status;
 }
 
-int copy_file_with_time(const char *dst, const char *src, int mode)
+int copy_file_with_time(struct repository *repo,
+			const char *dst, const char *src, int mode)
 {
-	int status = copy_file(dst, src, mode);
+	int status = copy_file(repo, dst, src, mode);
 	if (!status)
 		return copy_times(dst, src);
 	return status;
diff --git a/copy.h b/copy.h
index 2af77cba86..1059b118d6 100644
--- a/copy.h
+++ b/copy.h
@@ -1,10 +1,14 @@
 #ifndef COPY_H
 #define COPY_H
 
+struct repository;
+
 #define COPY_READ_ERROR (-2)
 #define COPY_WRITE_ERROR (-3)
 int copy_fd(int ifd, int ofd);
-int copy_file(const char *dst, const char *src, int mode);
-int copy_file_with_time(const char *dst, const char *src, int mode);
+int copy_file(struct repository *repo,
+	      const char *dst, const char *src, int mode);
+int copy_file_with_time(struct repository *repo,
+			const char *dst, const char *src, int mode);
 
 #endif /* COPY_H */
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 3df56c25c8..442c98414e 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1736,7 +1736,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
 		goto out;
 	}
 
-	if (copy && log && copy_file(tmp_renamed_log.buf, sb_oldref.buf, 0644)) {
+	if (copy && log && copy_file(refs->base.repo, tmp_renamed_log.buf, sb_oldref.buf, 0644)) {
 		ret = error("unable to copy logfile logs/%s to logs/"TMP_RENAMED_LOG": %s",
 			    oldrefname, strerror(errno));
 		goto out;
diff --git a/rerere.c b/rerere.c
index 8232542585..bf5cfc6e51 100644
--- a/rerere.c
+++ b/rerere.c
@@ -756,7 +756,7 @@ static void do_rerere_one_path(struct index_state *istate,
 	/* Has the user resolved it already? */
 	if (variant >= 0) {
 		if (!handle_file(istate, path, NULL, NULL)) {
-			copy_file(rerere_path(&buf, id, "postimage"), path, 0666);
+			copy_file(the_repository, rerere_path(&buf, id, "postimage"), path, 0666);
 			id->collection->status[variant] |= RR_HAS_POSTIMAGE;
 			fprintf_ln(stderr, _("Recorded resolution for '%s'."), path);
 			free_rerere_id(rr_item);
diff --git a/sequencer.c b/sequencer.c
index 1355a99a09..63bc1ef215 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2419,7 +2419,7 @@ static int do_pick_commit(struct repository *r,
 		} else {
 			const char *dest = git_path_squash_msg(r);
 			unlink(dest);
-			if (copy_file(dest, rebase_path_squash_msg(), 0666)) {
+			if (copy_file(r, dest, rebase_path_squash_msg(), 0666)) {
 				res = error(_("could not copy '%s' to '%s'"),
 					    rebase_path_squash_msg(), dest);
 				goto leave;
@@ -3864,11 +3864,11 @@ static int error_failed_squash(struct repository *r,
 			       int subject_len,
 			       const char *subject)
 {
-	if (copy_file(rebase_path_message(), rebase_path_squash_msg(), 0666))
+	if (copy_file(r, rebase_path_message(), rebase_path_squash_msg(), 0666))
 		return error(_("could not copy '%s' to '%s'"),
 			rebase_path_squash_msg(), rebase_path_message());
 	unlink(git_path_merge_msg(r));
-	if (copy_file(git_path_merge_msg(r), rebase_path_message(), 0666))
+	if (copy_file(r, git_path_merge_msg(r), rebase_path_message(), 0666))
 		return error(_("could not copy '%s' to '%s'"),
 			     rebase_path_message(),
 			     git_path_merge_msg(r));
diff --git a/setup.c b/setup.c
index 0de56a074f..91d61a5939 100644
--- a/setup.c
+++ b/setup.c
@@ -2331,7 +2331,7 @@ static void copy_templates_1(struct repository *repo,
 			strbuf_release(&lnk);
 		}
 		else if (S_ISREG(st_template.st_mode)) {
-			if (copy_file(path->buf, template_path->buf, st_template.st_mode))
+			if (copy_file(repo, path->buf, template_path->buf, st_template.st_mode))
 				die_errno(_("cannot copy '%s' to '%s'"),
 					  template_path->buf, path->buf);
 		}

---
base-commit: d35c5399e3e54ac277bb391fc2f6be3e816d312b
change-id: 20260716-pks-copy-wo-the-repository-aa01ccdbed76
Phillip WoodJul 17, 2026, 15:00 UTC in reply to Patrick Steinhardt on lore

Re: [PATCH v2] copy: drop dependency on `the_repository`

Hi Patrick
This version looks good to me
Thanks
Phillip
On 16/07/2026 16:28, Patrick Steinhardt wrote:
Show 235 quoted lines
> When copying a file we need to potentially adapt permissions of the new
> file based on whether or not "core.shared" is enabled. Parsing this
> configuration makes us implicitly depend on `the_repository`.
> 
> Refactor the code to instead require the caller to pass in a repository
> so that we can remove `USE_THE_REPOSITORY_VARIABLE`.
> 
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
> Hi,
> 
> I guess the title says it all: this small patch removes the dependency
> on `the_repository` in "copy.c". Thanks!
> 
> Changes in v2:
>    - Adapt a couple more sites to use a repository from the context.
>    - Link to v1: https://patch.msgid.link/20260716-pks-copy-wo-the-repository-v1-1-8f1e078bb82f@pks.im
> 
> Patrick
> ---
>   builtin/clone.c      |  2 +-
>   builtin/difftool.c   |  4 ++--
>   builtin/worktree.c   |  4 ++--
>   bundle-uri.c         |  2 +-
>   copy.c               | 12 ++++++------
>   copy.h               |  8 ++++++--
>   refs/files-backend.c |  2 +-
>   rerere.c             |  2 +-
>   sequencer.c          |  6 +++---
>   setup.c              |  2 +-
>   10 files changed, 24 insertions(+), 20 deletions(-)
> 
> diff --git a/builtin/clone.c b/builtin/clone.c
> index d60d1b60bc..18603dd4ce 100644
> --- a/builtin/clone.c
> +++ b/builtin/clone.c
> @@ -335,7 +335,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
>   				die_errno(_("failed to create link '%s'"), dest->buf);
>   			option_no_hardlinks = 1;
>   		}
> -		if (copy_file_with_time(dest->buf, src->buf, 0666))
> +		if (copy_file_with_time(the_repository, dest->buf, src->buf, 0666))
>   			die_errno(_("failed to copy file to '%s'"), dest->buf);
>   	}
>   
> diff --git a/builtin/difftool.c b/builtin/difftool.c
> index 26778f8515..5e7777fbe4 100644
> --- a/builtin/difftool.c
> +++ b/builtin/difftool.c
> @@ -552,7 +552,7 @@ static int run_dir_diff(struct repository *repo,
>   					struct stat st;
>   					if (stat(wtdir.buf, &st))
>   						st.st_mode = 0644;
> -					if (copy_file(rdir.buf, wtdir.buf,
> +					if (copy_file(repo, rdir.buf, wtdir.buf,
>   						      st.st_mode)) {
>   						ret = error("could not copy '%s' to '%s'", wtdir.buf, rdir.buf);
>   						goto finish;
> @@ -658,7 +658,7 @@ static int run_dir_diff(struct repository *repo,
>   				warning("%s", "");
>   				err = 1;
>   			} else if (unlink(wtdir.buf) ||
> -				   copy_file(wtdir.buf, rdir.buf, st.st_mode))
> +				   copy_file(repo, wtdir.buf, rdir.buf, st.st_mode))
>   				warning_errno(_("could not copy '%s' to '%s'"),
>   					      rdir.buf, wtdir.buf);
>   		}
> diff --git a/builtin/worktree.c b/builtin/worktree.c
> index d21c43fde3..84b01960fb 100644
> --- a/builtin/worktree.c
> +++ b/builtin/worktree.c
> @@ -349,7 +349,7 @@ static void copy_sparse_checkout(const char *worktree_git_dir)
>   
>   	if (file_exists(from_file)) {
>   		if (safe_create_leading_directories(the_repository, to_file) ||
> -			copy_file(to_file, from_file, 0666))
> +			copy_file(the_repository, to_file, from_file, 0666))
>   			error(_("failed to copy '%s' to '%s'; sparse-checkout may not work correctly"),
>   				from_file, to_file);
>   	}
> @@ -368,7 +368,7 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir)
>   		int bare;
>   
>   		if (safe_create_leading_directories(the_repository, to_file) ||
> -			copy_file(to_file, from_file, 0666)) {
> +			copy_file(the_repository, to_file, from_file, 0666)) {
>   			error(_("failed to copy worktree config from '%s' to '%s'"),
>   				from_file, to_file);
>   			goto worktree_copy_cleanup;
> diff --git a/bundle-uri.c b/bundle-uri.c
> index 3b2e347288..ef37aebf30 100644
> --- a/bundle-uri.c
> +++ b/bundle-uri.c
> @@ -396,7 +396,7 @@ static int copy_uri_to_file(const char *filename, const char *uri)
>   		uri = out;
>   
>   	/* Copy as a file */
> -	return copy_file(filename, uri, 0);
> +	return copy_file(the_repository, filename, uri, 0);
>   }
>   
>   static int unbundle_from_file(struct repository *r, const char *file)
> diff --git a/copy.c b/copy.c
> index b668209b6c..6074132050 100644
> --- a/copy.c
> +++ b/copy.c
> @@ -1,5 +1,3 @@
> -#define USE_THE_REPOSITORY_VARIABLE
> -
>   #include "git-compat-util.h"
>   #include "copy.h"
>   #include "path.h"
> @@ -35,7 +33,8 @@ static int copy_times(const char *dst, const char *src)
>   	return 0;
>   }
>   
> -int copy_file(const char *dst, const char *src, int mode)
> +int copy_file(struct repository *repo,
> +	      const char *dst, const char *src, int mode)
>   {
>   	int fdi, fdo, status;
>   
> @@ -59,15 +58,16 @@ int copy_file(const char *dst, const char *src, int mode)
>   	if (close(fdo) != 0)
>   		return error_errno("%s: close error", dst);
>   
> -	if (!status && adjust_shared_perm(the_repository, dst))
> +	if (!status && adjust_shared_perm(repo, dst))
>   		return -1;
>   
>   	return status;
>   }
>   
> -int copy_file_with_time(const char *dst, const char *src, int mode)
> +int copy_file_with_time(struct repository *repo,
> +			const char *dst, const char *src, int mode)
>   {
> -	int status = copy_file(dst, src, mode);
> +	int status = copy_file(repo, dst, src, mode);
>   	if (!status)
>   		return copy_times(dst, src);
>   	return status;
> diff --git a/copy.h b/copy.h
> index 2af77cba86..1059b118d6 100644
> --- a/copy.h
> +++ b/copy.h
> @@ -1,10 +1,14 @@
>   #ifndef COPY_H
>   #define COPY_H
>   
> +struct repository;
> +
>   #define COPY_READ_ERROR (-2)
>   #define COPY_WRITE_ERROR (-3)
>   int copy_fd(int ifd, int ofd);
> -int copy_file(const char *dst, const char *src, int mode);
> -int copy_file_with_time(const char *dst, const char *src, int mode);
> +int copy_file(struct repository *repo,
> +	      const char *dst, const char *src, int mode);
> +int copy_file_with_time(struct repository *repo,
> +			const char *dst, const char *src, int mode);
>   
>   #endif /* COPY_H */
> diff --git a/refs/files-backend.c b/refs/files-backend.c
> index 3df56c25c8..442c98414e 100644
> --- a/refs/files-backend.c
> +++ b/refs/files-backend.c
> @@ -1736,7 +1736,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
>   		goto out;
>   	}
>   
> -	if (copy && log && copy_file(tmp_renamed_log.buf, sb_oldref.buf, 0644)) {
> +	if (copy && log && copy_file(refs->base.repo, tmp_renamed_log.buf, sb_oldref.buf, 0644)) {
>   		ret = error("unable to copy logfile logs/%s to logs/"TMP_RENAMED_LOG": %s",
>   			    oldrefname, strerror(errno));
>   		goto out;
> diff --git a/rerere.c b/rerere.c
> index 8232542585..bf5cfc6e51 100644
> --- a/rerere.c
> +++ b/rerere.c
> @@ -756,7 +756,7 @@ static void do_rerere_one_path(struct index_state *istate,
>   	/* Has the user resolved it already? */
>   	if (variant >= 0) {
>   		if (!handle_file(istate, path, NULL, NULL)) {
> -			copy_file(rerere_path(&buf, id, "postimage"), path, 0666);
> +			copy_file(the_repository, rerere_path(&buf, id, "postimage"), path, 0666);
>   			id->collection->status[variant] |= RR_HAS_POSTIMAGE;
>   			fprintf_ln(stderr, _("Recorded resolution for '%s'."), path);
>   			free_rerere_id(rr_item);
> diff --git a/sequencer.c b/sequencer.c
> index 1355a99a09..63bc1ef215 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -2419,7 +2419,7 @@ static int do_pick_commit(struct repository *r,
>   		} else {
>   			const char *dest = git_path_squash_msg(r);
>   			unlink(dest);
> -			if (copy_file(dest, rebase_path_squash_msg(), 0666)) {
> +			if (copy_file(r, dest, rebase_path_squash_msg(), 0666)) {
>   				res = error(_("could not copy '%s' to '%s'"),
>   					    rebase_path_squash_msg(), dest);
>   				goto leave;
> @@ -3864,11 +3864,11 @@ static int error_failed_squash(struct repository *r,
>   			       int subject_len,
>   			       const char *subject)
>   {
> -	if (copy_file(rebase_path_message(), rebase_path_squash_msg(), 0666))
> +	if (copy_file(r, rebase_path_message(), rebase_path_squash_msg(), 0666))
>   		return error(_("could not copy '%s' to '%s'"),
>   			rebase_path_squash_msg(), rebase_path_message());
>   	unlink(git_path_merge_msg(r));
> -	if (copy_file(git_path_merge_msg(r), rebase_path_message(), 0666))
> +	if (copy_file(r, git_path_merge_msg(r), rebase_path_message(), 0666))
>   		return error(_("could not copy '%s' to '%s'"),
>   			     rebase_path_message(),
>   			     git_path_merge_msg(r));
> diff --git a/setup.c b/setup.c
> index 0de56a074f..91d61a5939 100644
> --- a/setup.c
> +++ b/setup.c
> @@ -2331,7 +2331,7 @@ static void copy_templates_1(struct repository *repo,
>   			strbuf_release(&lnk);
>   		}
>   		else if (S_ISREG(st_template.st_mode)) {
> -			if (copy_file(path->buf, template_path->buf, st_template.st_mode))
> +			if (copy_file(repo, path->buf, template_path->buf, st_template.st_mode))
>   				die_errno(_("cannot copy '%s' to '%s'"),
>   					  template_path->buf, path->buf);
>   		}
> 
> ---
> base-commit: d35c5399e3e54ac277bb391fc2f6be3e816d312b
> change-id: 20260716-pks-copy-wo-the-repository-aa01ccdbed76
> 
> 
Junio C HamanoJul 17, 2026, 17:09 UTC in reply to Phillip Wood on lore

Re: [PATCH v2] copy: drop dependency on `the_repository`

Phillip Wood <phillip.wood123@gmail.com> writes:
Show 7 quoted lines
> Hi Patrick
>
> This version looks good to me
>
> Thanks
>
> Phillip

The changes to 'copy.c' are fairly straightforward and trivially correct. The resulting updates to the callers are also minor, as requiring them to pass 'the_repository' introduces no change in behavior by definition.

Thanks.  Let's mark the topic for 'next'.

Back to recent threads