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

[PATCH v2 07/21] Add new environment variable $GIT_SUPER_DIR

From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date
Dec 14, 2013, 10:54 UTC
Message-ID
<1387018507-21999-8-git-send-email-pclouds@gmail.com>
In-Reply-To
<1387018507-21999-1-git-send-email-pclouds@gmail.com>

If $GIT_SUPER_DIR is defined, the repository is splitted into two places:

 - HEAD, logs/HEAD, index, other top-level refs and unrecognized files
   are from $GIT_DIR
 - the rest like objects, refs, info, hooks, packed-refs, shallow...
   are from $GIT_SUPER_DIR
The redirection is done by git_path(), git_pathdup() and git_snpath()
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git.txt |  8 ++++++
 cache.h               |  2 ++
 environment.c         | 11 +++++--
 path.c                | 28 ++++++++++++++++++
 t/t0060-path-utils.sh | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 126 insertions(+), 2 deletions(-)
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 4448ce2..9f4e9f8 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -764,6 +764,14 @@ Git so take care if using Cogito etc.
 	an explicit repository directory set via 'GIT_DIR' or on the
 	command line.
 
+'GIT_SUPER_DIR'::
+	If this variable is set to a path, non-worktree files that are
+	normally in $GIT_DIR will be taken from this path
+	instead. Worktree-specific files such as HEAD or index are
+	taken from $GIT_DIR. This variable has lower precedence than
+	other path variables such as GIT_INDEX_FILE,
+	GIT_OBJECT_DIRECTORY...
+
 Git Commits
 ~~~~~~~~~~~
 'GIT_AUTHOR_NAME'::
diff --git a/cache.h b/cache.h
index cdafbd7..823582f 100644
--- a/cache.h
+++ b/cache.h
@@ -347,6 +347,7 @@ static inline enum object_type object_type(unsigned int mode)
 
 /* Double-check local_repo_env below if you add to this list. */
 #define GIT_DIR_ENVIRONMENT "GIT_DIR"
+#define GIT_SUPER_DIR_ENVIRONMENT "GIT_SUPER_DIR"
 #define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
 #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
 #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
@@ -399,6 +400,7 @@ extern int is_inside_git_dir(void);
 extern char *git_work_tree_cfg;
 extern int is_inside_work_tree(void);
 extern const char *get_git_dir(void);
+extern const char *get_git_super_dir(void);
 extern int is_git_directory(const char *path);
 extern char *get_object_directory(void);
 extern char *get_index_file(void);
diff --git a/environment.c b/environment.c
index 1d74dde..d5ae7a3 100644
--- a/environment.c
+++ b/environment.c
@@ -79,7 +79,7 @@ static char *work_tree;
 static const char *namespace;
 static size_t namespace_len;
 
-static const char *git_dir;
+static const char *git_dir, *git_super_dir;
 static char *git_object_dir, *git_index_file, *git_graft_file;
 int git_db_env, git_index_env, git_graft_env;
 
@@ -131,10 +131,12 @@ static void setup_git_env(void)
 		git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
 	gitfile = read_gitfile(git_dir);
 	git_dir = xstrdup(gitfile ? gitfile : git_dir);
+	git_super_dir = getenv(GIT_SUPER_DIR_ENVIRONMENT);
 	git_object_dir = getenv(DB_ENVIRONMENT);
 	if (!git_object_dir) {
 		git_object_dir = xmalloc(strlen(git_dir) + 9);
-		sprintf(git_object_dir, "%s/objects", git_dir);
+		sprintf(git_object_dir, "%s/objects",
+			git_super_dir ? git_super_dir : git_dir);
 	} else
 		git_db_env = 1;
 	git_index_file = getenv(INDEX_ENVIRONMENT);
@@ -167,6 +169,11 @@ const char *get_git_dir(void)
 	return git_dir;
 }
 
+const char *get_git_super_dir(void)
+{
+	return git_super_dir;
+}
+
 const char *get_git_namespace(void)
 {
 	if (!namespace)
diff --git a/path.c b/path.c
index 93e3ecc..e51fc35 100644
--- a/path.c
+++ b/path.c
@@ -89,8 +89,34 @@ static void replace_dir(char *buf, size_t n, int len, const char *newdir)
 	buf[newlen] = '/';
 }
 
+static void update_super_dir(char *buf, size_t n, int git_dir_len)
+{
+	const char *super_dir_list[] = {
+		"branches", "hooks", "info", "logs", "modules",
+		"objects", "refs", "remotes", "rr-cache", "svn", NULL
+	};
+	const char *super_top_file_list[] = {
+		"config", "packed-refs", "shallow", NULL
+	};
+	char *base = buf + git_dir_len;
+	const char **p;
+	if (is_dir_file(base, "logs", "HEAD"))
+		return;	/* keep this in $GIT_DIR */
+	for (p = super_dir_list; *p; p++)
+		if (dir_prefix(base, *p)) {
+			replace_dir(buf, n, git_dir_len, get_git_super_dir());
+			return;
+		}
+	for (p = super_top_file_list; *p; p++)
+		if (!strcmp(base, *p)) {
+			replace_dir(buf, n, git_dir_len, get_git_super_dir());
+			return;
+		}
+}
+
 static void adjust_git_path(char *buf, size_t n, int git_dir_len)
 {
+
 	char *base = buf + git_dir_len;
 	if (git_graft_env && is_dir_file(base, "info", "grafts"))
 		copy_path(buf, n, get_graft_file());
@@ -98,6 +124,8 @@ static void adjust_git_path(char *buf, size_t n, int git_dir_len)
 		copy_path(buf, n, get_index_file());
 	else if (git_db_env && dir_prefix(base, "objects"))
 		replace_dir(buf, n, git_dir_len + 7, get_object_directory());
+	else if (get_git_super_dir())
+		update_super_dir(buf, n, git_dir_len);
 }
 
 static char *git_vsnpath(char *buf, size_t n, const char *fmt, va_list args)
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index bce16f5..5e798c4 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -277,4 +277,83 @@ test_expect_success 'git_path objects2' '
 	test_cmp expect actual
 '
 
+test_expect_success 'git_path super index' '
+	GIT_SUPER_DIR=foo test-path-utils git_path index >actual &&
+	echo .git/index >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git_path super HEAD' '
+	GIT_SUPER_DIR=foo test-path-utils git_path HEAD >actual &&
+	echo .git/HEAD >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git_path super objects/*' '
+	GIT_SUPER_DIR=foo test-path-utils git_path objects/foo >actual &&
+	echo foo/objects/foo >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git_path super info/*' '
+	GIT_SUPER_DIR=foo test-path-utils git_path info/exclude >actual &&
+	echo foo/info/exclude >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git_path super remotes/*' '
+	GIT_SUPER_DIR=foo test-path-utils git_path remotes/foo >actual &&
+	echo foo/remotes/foo >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git_path super branches/*' '
+	GIT_SUPER_DIR=foo test-path-utils git_path branches/foo >actual &&
+	echo foo/branches/foo >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git_path super logs/refs/heads/master' '
+	GIT_SUPER_DIR=foo test-path-utils git_path logs/refs/heads/master >actual &&
+	echo foo/logs/refs/heads/master >expect &&
+	test_cmp expect actual
+'
+
+
+test_expect_success 'git_path super refs/heads/master' '
+	GIT_SUPER_DIR=foo test-path-utils git_path refs/heads/master >actual &&
+	echo foo/refs/heads/master >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git_path super logs/HEAD' '
+	GIT_SUPER_DIR=foo test-path-utils git_path logs/HEAD >actual &&
+	echo .git/logs/HEAD >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git_path super hooks/me' '
+	GIT_SUPER_DIR=foo test-path-utils git_path hooks/me >actual &&
+	echo foo/hooks/me >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git_path super config' '
+	GIT_SUPER_DIR=foo test-path-utils git_path config >actual &&
+	echo foo/config >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git_path super packed-refs' '
+	GIT_SUPER_DIR=foo test-path-utils git_path packed-refs >actual &&
+	echo foo/packed-refs >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git_path super shallow' '
+	GIT_SUPER_DIR=foo test-path-utils git_path shallow >actual &&
+	echo foo/shallow >expect &&
+	test_cmp expect actual
+'
+
 test_done
-- 
1.8.5.1.77.g42c48fa
Previous: Nguyễn Thái Ngọc DuyNext: Nguyễn Thái Ngọc Duy
Message 34 of 49 in “Support multiple worktrees”
  1. 0/7 Support multiple worktreesNguyễn Thái Ngọc Duy, Dec 11, 2013
  2. 1/7 Make git_path() beware of file relocation in $GIT_DIRNguyễn Thái Ngọc Duy, Dec 11, 2013
  3. Junio C HamanoDec 13, 2013
  4. 2/7 Add new environment variable $GIT_SUPER_DIRNguyễn Thái Ngọc Duy, Dec 11, 2013
  5. Junio C HamanoDec 13, 2013
  6. Duy NguyenDec 14, 2013
  7. Junio C HamanoDec 14, 2013
  8. 3/7 setup.c: add split-repo support to .git filesNguyễn Thái Ngọc Duy, Dec 11, 2013
  9. Junio C HamanoDec 13, 2013
  10. Jonathan NiederDec 13, 2013
  11. Duy NguyenDec 14, 2013
  12. Duy NguyenDec 23, 2013
  13. 4/7 setup.c: add split-repo support to is_git_directory()Nguyễn Thái Ngọc Duy, Dec 11, 2013
  14. 5/7 setup.c: reduce cleanup sites in setup_explicit_git_dir()Nguyễn Thái Ngọc Duy, Dec 11, 2013
  15. 6/7 setup.c: add split-repo support to setup_git_directory*Nguyễn Thái Ngọc Duy, Dec 11, 2013
  16. 7/7 init: add --split-repo with the same functionality as git-new-workdirNguyễn Thái Ngọc Duy, Dec 11, 2013
  17. 00/21 Support multiple worktreesNguyễn Thái Ngọc Duy, Dec 14, 2013
  18. 01/21 path.c: avoid PATH_MAX as buffer size from get_pathname()Nguyễn Thái Ngọc Duy, Dec 14, 2013
  19. Torsten BögershausenDec 15, 2013
  20. Duy NguyenDec 15, 2013
  21. Antoine PelisseDec 15, 2013
  22. 02/21 path.c: rename vsnpath() to git_vsnpath()Nguyễn Thái Ngọc Duy, Dec 14, 2013
  23. Ramsay JonesDec 14, 2013
  24. Duy NguyenDec 15, 2013
  25. Ramsay JonesDec 15, 2013
  26. Duy NguyenDec 16, 2013
  27. Jonathan NiederDec 16, 2013
  28. Junio C HamanoDec 16, 2013
  29. Ramsay JonesDec 16, 2013
  30. 03/21 path.c: move git_path() closer to similar functions git_pathdup()Nguyễn Thái Ngọc Duy, Dec 14, 2013
  31. 04/21 Make git_path() aware of file relocation in $GIT_DIRNguyễn Thái Ngọc Duy, Dec 14, 2013
  32. 05/21 reflog: use avoid constructing .lock path with git_pathNguyễn Thái Ngọc Duy, Dec 14, 2013
  33. 06/21 fast-import: use git_path() for accessing .git dir instead of get_git_dir()Nguyễn Thái Ngọc Duy, Dec 14, 2013
  34. 07/21 Add new environment variable $GIT_SUPER_DIRNguyễn Thái Ngọc Duy, Dec 14, 2013
  35. 08/21 setup.c: refactor path manipulation out of read_gitfile()Nguyễn Thái Ngọc Duy, Dec 14, 2013
  36. 09/21 setup.c: add split-repo support to .git filesNguyễn Thái Ngọc Duy, Dec 14, 2013
  37. 10/21 setup.c: add split-repo support to is_git_directory()Nguyễn Thái Ngọc Duy, Dec 14, 2013
  38. 11/21 setup.c: reduce cleanup sites in setup_explicit_git_dir()Nguyễn Thái Ngọc Duy, Dec 14, 2013
  39. 12/21 environment.c: support super .git file specified by $GIT_DIRNguyễn Thái Ngọc Duy, Dec 14, 2013
  40. 13/21 setup: support $GIT_SUPER_DIR as well as super .git filesNguyễn Thái Ngọc Duy, Dec 14, 2013
  41. 14/21 checkout: support checking out into a new working directoryNguyễn Thái Ngọc Duy, Dec 14, 2013
  42. 15/21 checkout: clean up half-prepared directories in --to modeNguyễn Thái Ngọc Duy, Dec 14, 2013
  43. 16/21 setup.c: keep track of the .git file location if readNguyễn Thái Ngọc Duy, Dec 14, 2013
  44. 17/21 prune: strategies for split repositoriesNguyễn Thái Ngọc Duy, Dec 14, 2013
  45. 18/21 refs: adjust reflog path for repos/<id>/HEADNguyễn Thái Ngọc Duy, Dec 14, 2013
  46. 19/21 refs: detach split repos' HEAD when the linked ref is updated/deletedNguyễn Thái Ngọc Duy, Dec 14, 2013
  47. 20/21 refs.c: refactor do_head_ref(... to do_one_head_ref("HEAD", ...Nguyễn Thái Ngọc Duy, Dec 14, 2013
  48. 21/21 revision: include repos/../HEAD in --allNguyễn Thái Ngọc Duy, Dec 14, 2013
  49. Duy NguyenDec 15, 2013

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.