Skip to content

Commit 557bd83

Browse files
pcloudsgitster
authored andcommitted
git_path(): be aware of file relocation in $GIT_DIR
We allow the user to relocate certain paths out of $GIT_DIR via environment variables, e.g. GIT_OBJECT_DIRECTORY, GIT_INDEX_FILE and GIT_GRAFT_FILE. Callers are not supposed to use git_path() or git_pathdup() to get those paths. Instead they must use get_object_directory(), get_index_file() and get_graft_file() respectively. This is inconvenient and could be missed in review (for example, there's git_path("objects/info/alternates") somewhere in sha1_file.c). This patch makes git_path() and git_pathdup() understand those environment variables. So if you set GIT_OBJECT_DIRECTORY to /foo/bar, git_path("objects/abc") should return /foo/bar/abc. The same is done for the two remaining env variables. "git rev-parse --git-path" is the wrapper for script use. This patch kinda reverts a0279e1 (setup_git_env: use git_pathdup instead of xmalloc + sprintf - 2014-06-19) because using git_pathdup here would result in infinite recursion: setup_git_env() -> git_pathdup("objects") -> .. -> adjust_git_path() -> get_object_directory() -> oops, git_object_directory is NOT set yet -> setup_git_env() I wanted to make git_pathdup_literal() that skips adjust_git_path(). But that won't work because later on when $GIT_COMMON_DIR is introduced, git_pathdup_literal("objects") needs adjust_git_path() to replace $GIT_DIR with $GIT_COMMON_DIR. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 57a23b7 commit 557bd83

File tree

6 files changed

+95
-7
lines changed

6 files changed

+95
-7
lines changed

Documentation/git-rev-parse.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,13 @@ print a message to stderr and exit with nonzero status.
233233
repository. If <path> is a gitfile then the resolved path
234234
to the real repository is printed.
235235

236+
--git-path <path>::
237+
Resolve "$GIT_DIR/<path>" and takes other path relocation
238+
variables such as $GIT_OBJECT_DIRECTORY,
239+
$GIT_INDEX_FILE... into account. For example, if
240+
$GIT_OBJECT_DIRECTORY is set to /foo/bar then "git rev-parse
241+
--git-path objects/abc" returns /foo/bar/abc.
242+
236243
--show-cdup::
237244
When the command is invoked from a subdirectory, show the
238245
path of the top-level directory relative to the current

builtin/rev-parse.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,13 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
533533
for (i = 1; i < argc; i++) {
534534
const char *arg = argv[i];
535535

536+
if (!strcmp(arg, "--git-path")) {
537+
if (!argv[i + 1])
538+
die("--git-path requires an argument");
539+
puts(git_path("%s", argv[i + 1]));
540+
i++;
541+
continue;
542+
}
536543
if (as_is) {
537544
if (show_file(arg, output_prefix) && as_is < 2)
538545
verify_filename(prefix, arg, 0);

cache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,7 @@ extern int fsync_object_files;
617617
extern int core_preload_index;
618618
extern int core_apply_sparse_checkout;
619619
extern int precomposed_unicode;
620+
extern int git_db_env, git_index_env, git_graft_env;
620621

621622
/*
622623
* The character that begins a commented line in user-editable file

environment.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ static size_t namespace_len;
8383

8484
static const char *git_dir;
8585
static char *git_object_dir, *git_index_file, *git_graft_file;
86+
int git_db_env, git_index_env, git_graft_env;
8687

8788
/*
8889
* Repository-local GIT_* environment variables; see cache.h for details.
@@ -124,10 +125,18 @@ static char *expand_namespace(const char *raw_namespace)
124125
return strbuf_detach(&buf, NULL);
125126
}
126127

127-
static char *git_path_from_env(const char *envvar, const char *path)
128+
static char *git_path_from_env(const char *envvar, const char *path,
129+
int *fromenv)
128130
{
129131
const char *value = getenv(envvar);
130-
return value ? xstrdup(value) : git_pathdup("%s", path);
132+
if (!value) {
133+
char *buf = xmalloc(strlen(git_dir) + strlen(path) + 2);
134+
sprintf(buf, "%s/%s", git_dir, path);
135+
return buf;
136+
}
137+
if (fromenv)
138+
*fromenv = 1;
139+
return xstrdup(value);
131140
}
132141

133142
static void setup_git_env(void)
@@ -140,9 +149,9 @@ static void setup_git_env(void)
140149
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
141150
gitfile = read_gitfile(git_dir);
142151
git_dir = xstrdup(gitfile ? gitfile : git_dir);
143-
git_object_dir = git_path_from_env(DB_ENVIRONMENT, "objects");
144-
git_index_file = git_path_from_env(INDEX_ENVIRONMENT, "index");
145-
git_graft_file = git_path_from_env(GRAFT_ENVIRONMENT, "info/grafts");
152+
git_object_dir = git_path_from_env(DB_ENVIRONMENT, "objects", &git_db_env);
153+
git_index_file = git_path_from_env(INDEX_ENVIRONMENT, "index", &git_index_env);
154+
git_graft_file = git_path_from_env(GRAFT_ENVIRONMENT, "info/grafts", &git_graft_env);
146155
if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
147156
check_replace_refs = 0;
148157
namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));

path.c

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,58 @@ char *mksnpath(char *buf, size_t n, const char *fmt, ...)
6060
return cleanup_path(buf);
6161
}
6262

63+
static int dir_prefix(const char *buf, const char *dir)
64+
{
65+
int len = strlen(dir);
66+
return !strncmp(buf, dir, len) &&
67+
(is_dir_sep(buf[len]) || buf[len] == '\0');
68+
}
69+
70+
/* $buf =~ m|$dir/+$file| but without regex */
71+
static int is_dir_file(const char *buf, const char *dir, const char *file)
72+
{
73+
int len = strlen(dir);
74+
if (strncmp(buf, dir, len) || !is_dir_sep(buf[len]))
75+
return 0;
76+
while (is_dir_sep(buf[len]))
77+
len++;
78+
return !strcmp(buf + len, file);
79+
}
80+
81+
static void replace_dir(struct strbuf *buf, int len, const char *newdir)
82+
{
83+
int newlen = strlen(newdir);
84+
int need_sep = (buf->buf[len] && !is_dir_sep(buf->buf[len])) &&
85+
!is_dir_sep(newdir[newlen - 1]);
86+
if (need_sep)
87+
len--; /* keep one char, to be replaced with '/' */
88+
strbuf_splice(buf, 0, len, newdir, newlen);
89+
if (need_sep)
90+
buf->buf[newlen] = '/';
91+
}
92+
93+
static void adjust_git_path(struct strbuf *buf, int git_dir_len)
94+
{
95+
const char *base = buf->buf + git_dir_len;
96+
if (git_graft_env && is_dir_file(base, "info", "grafts"))
97+
strbuf_splice(buf, 0, buf->len,
98+
get_graft_file(), strlen(get_graft_file()));
99+
else if (git_index_env && !strcmp(base, "index"))
100+
strbuf_splice(buf, 0, buf->len,
101+
get_index_file(), strlen(get_index_file()));
102+
else if (git_db_env && dir_prefix(base, "objects"))
103+
replace_dir(buf, git_dir_len + 7, get_object_directory());
104+
}
105+
63106
static void do_git_path(struct strbuf *buf, const char *fmt, va_list args)
64107
{
65-
const char *git_dir = get_git_dir();
66-
strbuf_addstr(buf, git_dir);
108+
int gitdir_len;
109+
strbuf_addstr(buf, get_git_dir());
67110
if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
68111
strbuf_addch(buf, '/');
112+
gitdir_len = buf->len;
69113
strbuf_vaddf(buf, fmt, args);
114+
adjust_git_path(buf, gitdir_len);
70115
strbuf_cleanup_path(buf);
71116
}
72117

t/t0060-path-utils.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ relative_path() {
1919
"test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'"
2020
}
2121

22+
test_git_path() {
23+
test_expect_success "git-path $1 $2 => $3" "
24+
$1 git rev-parse --git-path $2 >actual &&
25+
echo $3 >expect &&
26+
test_cmp expect actual
27+
"
28+
}
29+
2230
# On Windows, we are using MSYS's bash, which mangles the paths.
2331
# Absolute paths are anchored at the MSYS installation directory,
2432
# which means that the path / accounts for this many characters:
@@ -244,4 +252,15 @@ relative_path "<null>" "<empty>" ./
244252
relative_path "<null>" "<null>" ./
245253
relative_path "<null>" /foo/a/b ./
246254

255+
test_git_path A=B info/grafts .git/info/grafts
256+
test_git_path GIT_GRAFT_FILE=foo info/grafts foo
257+
test_git_path GIT_GRAFT_FILE=foo info/////grafts foo
258+
test_git_path GIT_INDEX_FILE=foo index foo
259+
test_git_path GIT_INDEX_FILE=foo index/foo .git/index/foo
260+
test_git_path GIT_INDEX_FILE=foo index2 .git/index2
261+
test_expect_success 'setup fake objects directory foo' 'mkdir foo'
262+
test_git_path GIT_OBJECT_DIRECTORY=foo objects foo
263+
test_git_path GIT_OBJECT_DIRECTORY=foo objects/foo foo/foo
264+
test_git_path GIT_OBJECT_DIRECTORY=foo objects2 .git/objects2
265+
247266
test_done

0 commit comments

Comments
 (0)