git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 04/10] Make setup_work_tree() return new prefix

From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date
Mar 2, 2008, 10:34 UTC
Message-ID
<20080302103405.GA8942@laptop>
In-Reply-To
<cover.1204453703.git.pclouds@gmail.com>

worktree setup inside setup_git_directory*() is not perfect. It does not take core.worktree into account. So when you do setup_work_tree(), the real work tree may be not the one setup_git_directory*() gives you. You need a new prefix in that case.

This also effectively reverts dd5c8af (Fix setup_git_directory_gently() with relative GIT_DIR & GIT_WORK_TREE). The problem is IMHO that git-diff does not setup worktree when it needs it, so setting up worktree from setup_git_directory_gently() is a fix in a wrong place.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin-blame.c      |    4 +-
 builtin-diff-files.c |    4 ++-
 builtin-diff.c       |    4 ++-
 builtin-ls-files.c   |    8 ++--
 builtin-read-tree.c  |    2 +-
 builtin-rev-parse.c  |    2 +
 builtin-rm.c         |    2 +-
 cache.h              |    2 +-
 git.c                |    2 +-
 setup.c              |   84 ++++++++++++++++----------------------------------
 10 files changed, 45 insertions(+), 69 deletions(-)
diff --git a/builtin-blame.c b/builtin-blame.c
index bfd562d..f5a878b 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c
@@ -2291,6 +2291,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 			/* (3) */
 			if (argc <= i)
 				usage(blame_usage);
+			prefix = setup_work_tree(prefix);
 			path = add_prefix(prefix, argv[i]);
 			if (i + 1 == argc - 1) {
 				final_commit_name = argv[i + 1];
@@ -2306,7 +2307,6 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 			else if (i != argc - 1)
 				usage(blame_usage); /* garbage at end */
 
-			setup_work_tree();
 			if (!has_path_in_work_tree(path))
 				die("cannot stat path %s: %s",
 				    path, strerror(errno));
@@ -2354,7 +2354,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 		 * do not default to HEAD, but use the working tree
 		 * or "--contents".
 		 */
-		setup_work_tree();
+		setup_work_tree(prefix);
 		sb.final = fake_working_tree_commit(path, contents_from);
 		add_pending_object(&revs, &(sb.final->object), ":");
 	}
diff --git a/builtin-diff-files.c b/builtin-diff-files.c
index 4abe3c2..11671a8 100644
--- a/builtin-diff-files.c
+++ b/builtin-diff-files.c
@@ -26,8 +26,10 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
 
 	if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix))
 		argc = 0;
-	else
+	else {
+		rev.prefix = setup_work_tree(prefix);
 		argc = setup_revisions(argc, argv, &rev, NULL);
+	}
 	if (!rev.diffopt.output_format)
 		rev.diffopt.output_format = DIFF_FORMAT_RAW;
 	result = run_diff_files_cmd(&rev, argc, argv);
diff --git a/builtin-diff.c b/builtin-diff.c
index 444ff2f..254e5a0 100644
--- a/builtin-diff.c
+++ b/builtin-diff.c
@@ -244,8 +244,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
 
 	if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix))
 		argc = 0;
-	else
+	else {
+		rev.prefix = setup_work_tree(prefix);
 		argc = setup_revisions(argc, argv, &rev, NULL);
+	}
 	if (!rev.diffopt.output_format) {
 		rev.diffopt.output_format = DIFF_FORMAT_PATCH;
 		if (diff_setup_done(&rev.diffopt) < 0)
diff --git a/builtin-ls-files.c b/builtin-ls-files.c
index 25dbfb4..cf4c492 100644
--- a/builtin-ls-files.c
+++ b/builtin-ls-files.c
@@ -23,7 +23,7 @@ static int show_valid_bit;
 static int line_terminator = '\n';
 
 static int prefix_len;
-static int prefix_offset;
+static int prefix_offset = -1;
 static const char **pathspec;
 static int error_unmatch;
 static char *ps_matched;
@@ -435,8 +435,6 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
 	struct dir_struct dir;
 
 	memset(&dir, 0, sizeof(dir));
-	if (prefix)
-		prefix_offset = strlen(prefix);
 	git_config(git_default_config);
 
 	for (i = 1; i < argc; i++) {
@@ -569,7 +567,9 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
 	}
 
 	if (require_work_tree && !is_inside_work_tree())
-		setup_work_tree();
+		prefix = setup_work_tree(prefix);
+	if (prefix_offset == -1)
+		prefix_offset = prefix ? strlen(prefix) : 0;
 
 	pathspec = get_pathspec(prefix, argv + i);
 
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index a69bac4..851f24d 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -221,7 +221,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
 		die("--exclude-per-directory is meaningless unless -u");
 
 	if (opts.merge && !opts.index_only)
-		setup_work_tree();
+		setup_work_tree(NULL);
 
 	if (opts.prefix) {
 		int pfxlen = strlen(opts.prefix);
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index 13412b4..3d3a309 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -472,6 +472,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 				continue;
 			}
 			if (!strcmp(arg, "--show-prefix")) {
+				if (is_inside_work_tree())
+					prefix = setup_work_tree(prefix);
 				if (prefix)
 					puts(prefix);
 				continue;
diff --git a/builtin-rm.c b/builtin-rm.c
index c0a8bb6..2c15d66 100644
--- a/builtin-rm.c
+++ b/builtin-rm.c
@@ -156,7 +156,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
 		usage_with_options(builtin_rm_usage, builtin_rm_options);
 
 	if (!index_only)
-		setup_work_tree();
+		prefix = setup_work_tree(prefix);
 
 	pathspec = get_pathspec(prefix, argv);
 	seen = NULL;
diff --git a/cache.h b/cache.h
index bdefcc9..b98f7e8 100644
--- a/cache.h
+++ b/cache.h
@@ -315,7 +315,7 @@ extern const char *get_git_work_tree(void);
 #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
 
 extern const char **get_pathspec(const char *prefix, const char **pathspec);
-extern void setup_work_tree(void);
+extern const char *setup_work_tree(const char *prefix);
 extern const char *setup_git_directory_gently(int *);
 extern const char *setup_git_directory(void);
 extern const char *prefix_path(const char *prefix, int len, const char *path);
diff --git a/git.c b/git.c
index 1e3eb10..9e53a2e 100644
--- a/git.c
+++ b/git.c
@@ -241,7 +241,7 @@ static int run_command(struct cmd_struct *p, int argc, const char **argv)
 	if (p->option & USE_PAGER)
 		setup_pager();
 	if (p->option & NEED_WORK_TREE)
-		setup_work_tree();
+		prefix = setup_work_tree(prefix);
 
 	trace_argv_printf(argv, "trace: built-in: git");
 
diff --git a/setup.c b/setup.c
index 89c81e5..6c908a5 100644
--- a/setup.c
+++ b/setup.c
@@ -262,38 +262,23 @@ int is_inside_work_tree(void)
 	return inside_work_tree;
 }
 
-/*
- * set_work_tree() is only ever called if you set GIT_DIR explicitely.
- * The old behaviour (which we retain here) is to set the work tree root
- * to the cwd, unless overridden by the config, the command line, or
- * GIT_WORK_TREE.
- */
-static const char *set_work_tree(const char *dir)
-{
-	char buffer[PATH_MAX + 1];
-
-	if (!getcwd(buffer, sizeof(buffer)))
-		die ("Could not get the current working directory");
-	git_work_tree_cfg = xstrdup(buffer);
-	inside_work_tree = 1;
-
-	return NULL;
-}
-
-void setup_work_tree(void)
+const char *setup_work_tree(const char *prefix)
 {
-	const char *work_tree, *git_dir;
-	static int initialized = 0;
+	const char *work_tree;
+	static char buffer[PATH_MAX + 1];
+	char *rel;
 
-	if (initialized)
-		return;
+	get_git_dir(); /* ensure git_dir has been initialized as cwd will change */
 	work_tree = get_git_work_tree();
-	git_dir = get_git_dir();
-	if (!is_absolute_path(git_dir))
-		set_git_dir(make_absolute_path(git_dir));
-	if (!work_tree || chdir(work_tree))
+	if (!work_tree)
 		die("This operation must be run in a work tree");
-	initialized = 1;
+	if (prefix && chdir(prefix))
+		die ("Could not jump back into original cwd");
+	rel = get_relative_cwd(buffer, PATH_MAX, work_tree);
+	trace_printf("test: worktree = %s\n", rel ? rel : "NULL");
+	if (chdir(work_tree))
+		die("This operation must be run in a work tree");
+	return rel && *rel ? strcat(rel, "/") : NULL;
 }
 
 static int check_repository_format_gently(int *nongit_ok)
@@ -336,24 +321,21 @@ const char *setup_git_directory_gently(int *nongit_ok)
 			static char buffer[1024 + 1];
 			const char *retval;
 
+			/*
+			 * The old behaviour (which we retain here) is to set
+			 * the work tree root to the cwd, unless overridden by
+			 * the config, the command line, or GIT_WORK_TREE.
+			 */
 			if (!work_tree_env) {
-				retval = set_work_tree(gitdirenv);
-				/* config may override worktree */
-				if (check_repository_format_gently(nongit_ok))
-					return NULL;
-				return retval;
+				char buffer[PATH_MAX + 1];
+
+				if (!getcwd(buffer, sizeof(buffer)))
+					die ("Could not get the current working directory");
+				git_work_tree_cfg = xstrdup(buffer);
+				inside_work_tree = 1;
 			}
-			if (check_repository_format_gently(nongit_ok))
-				return NULL;
-			retval = get_relative_cwd(buffer, sizeof(buffer) - 1,
-					get_git_work_tree());
-			if (!retval || !*retval)
-				return NULL;
-			set_git_dir(make_absolute_path(gitdirenv));
-			if (chdir(work_tree_env) < 0)
-				die ("Could not chdir to %s", work_tree_env);
-			strcat(buffer, "/");
-			return retval;
+			check_repository_format_gently(nongit_ok);
+			return NULL;
 		}
 		if (nongit_ok) {
 			*nongit_ok = 1;
@@ -462,17 +444,5 @@ int check_repository_format(void)
 
 const char *setup_git_directory(void)
 {
-	const char *retval = setup_git_directory_gently(NULL);
-
-	/* If the work tree is not the default one, recompute prefix */
-	if (inside_work_tree < 0) {
-		static char buffer[PATH_MAX + 1];
-		char *rel;
-		if (retval && chdir(retval))
-			die ("Could not jump back into original cwd");
-		rel = get_relative_cwd(buffer, PATH_MAX, get_git_work_tree());
-		return rel && *rel ? strcat(rel, "/") : NULL;
-	}
Previous: Johannes SchindelinNext: Johannes Schindelin
Message 13 of 32 in “"git read-tree -m" and the like require worktree”
  1. 01/10 "git read-tree -m" and the like require worktreeNguyễn Thái Ngọc Duy, Mar 2, 2008
  2. Johannes SchindelinMar 11, 2008
  3. Nguyen Thai Ngoc DuyMar 11, 2008
  4. Johannes SchindelinMar 11, 2008
  5. Nguyen Thai Ngoc DuyMar 11, 2008
  6. 02/10 Make sure setup_git_directory is called before accessing repositoryNguyễn Thái Ngọc Duy, Mar 2, 2008
  7. 03/10 Make get_git_dir() and 'git rev-parse --git-dir' absolute pathNguyễn Thái Ngọc Duy, Mar 2, 2008
  8. Johannes SchindelinMar 11, 2008
  9. Nguyen Thai Ngoc DuyMar 11, 2008
  10. Johannes SchindelinMar 11, 2008
  11. Nguyen Thai Ngoc DuyMar 11, 2008
  12. Johannes SchindelinMar 11, 2008
  13. 04/10 Make setup_work_tree() return new prefixNguyễn Thái Ngọc Duy, Mar 2, 2008
  14. Johannes SchindelinMar 11, 2008
  15. Nguyen Thai Ngoc DuyMar 11, 2008
  16. 05/10 http-push: Avoid calling setup_git_directory() twiceNguyễn Thái Ngọc Duy, Mar 2, 2008
  17. Johannes SchindelinMar 11, 2008
  18. Nguyen Thai Ngoc DuyMar 11, 2008
  19. Johannes SchindelinMar 11, 2008
  20. Nguyen Thai Ngoc DuyMar 11, 2008
  21. 06/10 Completely move out worktree setup from setup_git_directory_gently()Nguyễn Thái Ngọc Duy, Mar 2, 2008
  22. Johannes SchindelinMar 11, 2008
  23. Nguyen Thai Ngoc DuyMar 11, 2008
  24. Johannes SchindelinMar 11, 2008
  25. 07/10 builtin-archive: mark unused prefix "unused_prefix"Nguyễn Thái Ngọc Duy, Mar 2, 2008
  26. Johannes SchindelinMar 11, 2008
  27. Nguyen Thai Ngoc DuyMar 11, 2008
  28. Jay SoffianMar 11, 2008
  29. Nguyen Thai Ngoc DuyMar 11, 2008
  30. 08/10 Make setup_git_directory() auto-setup worktree if foundNguyễn Thái Ngọc Duy, Mar 2, 2008
  31. 09/10 Documentation: update api-builtin and api-setupNguyễn Thái Ngọc Duy, Mar 2, 2008
  32. 10/10 Additional tests to capture worktree special casesNguyễn Thái Ngọc Duy, Mar 2, 2008

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.