Skip to content

Commit 37a9586

Browse files
committed
alternates: re-allow relative paths from environment
Commit 670c359 (link_alt_odb_entry: handle normalize_path errors, 2016-10-03) regressed the handling of relative paths in the GIT_ALTERNATE_OBJECT_DIRECTORIES variable. It's not entirely clear this was ever meant to work, but it _has_ worked for several years, so this commit restores the original behavior. When we get a path in GIT_ALTERNATE_OBJECT_DIRECTORIES, we add it the path to the list of alternate object directories as if it were found in objects/info/alternates, but with one difference: we do not provide the link_alt_odb_entry() function with a base for relative paths. That function doesn't turn it into an absolute path, and we end up feeding the relative path to the strbuf_normalize_path() function. Most relative paths break out of the top-level directory (e.g., "../foo.git/objects"), and thus normalizing fails. Prior to 670c359, we simply ignored the error, and due to the way normalize_path_copy() was implemented it happened to return the original path in this case. We then accessed the alternate objects using this relative path. By storing the relative path in the alt_odb list, the path is relative to wherever we happen to be at the time we do an object lookup. That means we look from $GIT_DIR in a bare repository, and from the top of the worktree in a non-bare repository. If this were being designed from scratch, it would make sense to pick a stable location (probably $GIT_DIR, or even the object directory) and use that as the relative base, turning the result into an absolute path. However, given the history, at this point the minimal fix is to match the pre-670c359da behavior. We can do this simply by ignoring the error when we have no relative base and using the original value (which we now reliably have, thanks to strbuf_normalize_path()). That still leaves us with a relative path that foils our duplicate detection, and may act strangely if we ever chdir() later in the process. We could solve that by storing an absolute path based on getcwd(). That may be a good future direction; for now we'll do just the minimum to fix the regression. The new t5615 script demonstrates the fix in its final three tests. Since we didn't have any tests of the alternates environment variable at all, it also adds some tests of absolute paths. Reported-by: Bryan Turner <[email protected]> Signed-off-by: Jeff King <[email protected]>
1 parent ea0fc3b commit 37a9586

File tree

2 files changed

+72
-1
lines changed

2 files changed

+72
-1
lines changed

sha1_file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ static int link_alt_odb_entry(const char *entry, const char *relative_base,
296296
}
297297
strbuf_addstr(&pathbuf, entry);
298298

299-
if (strbuf_normalize_path(&pathbuf) < 0) {
299+
if (strbuf_normalize_path(&pathbuf) < 0 && relative_base) {
300300
error("unable to normalize alternate object path: %s",
301301
pathbuf.buf);
302302
strbuf_release(&pathbuf);

t/t5615-alternate-env.sh

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#!/bin/sh
2+
3+
test_description='handling of alternates in environment variables'
4+
. ./test-lib.sh
5+
6+
check_obj () {
7+
alt=$1; shift
8+
while read obj expect
9+
do
10+
echo "$obj" >&3 &&
11+
echo "$obj $expect" >&4
12+
done 3>input 4>expect &&
13+
GIT_ALTERNATE_OBJECT_DIRECTORIES=$alt \
14+
git "$@" cat-file --batch-check='%(objectname) %(objecttype)' \
15+
<input >actual &&
16+
test_cmp expect actual
17+
}
18+
19+
test_expect_success 'create alternate repositories' '
20+
git init --bare one.git &&
21+
one=$(echo one | git -C one.git hash-object -w --stdin) &&
22+
git init --bare two.git &&
23+
two=$(echo two | git -C two.git hash-object -w --stdin)
24+
'
25+
26+
test_expect_success 'objects inaccessible without alternates' '
27+
check_obj "" <<-EOF
28+
$one missing
29+
$two missing
30+
EOF
31+
'
32+
33+
test_expect_success 'access alternate via absolute path' '
34+
check_obj "$(pwd)/one.git/objects" <<-EOF
35+
$one blob
36+
$two missing
37+
EOF
38+
'
39+
40+
test_expect_success 'access multiple alternates' '
41+
check_obj "$(pwd)/one.git/objects:$(pwd)/two.git/objects" <<-EOF
42+
$one blob
43+
$two blob
44+
EOF
45+
'
46+
47+
# bare paths are relative from $GIT_DIR
48+
test_expect_success 'access alternate via relative path (bare)' '
49+
git init --bare bare.git &&
50+
check_obj "../one.git/objects" -C bare.git <<-EOF
51+
$one blob
52+
EOF
53+
'
54+
55+
# non-bare paths are relative to top of worktree
56+
test_expect_success 'access alternate via relative path (worktree)' '
57+
git init worktree &&
58+
check_obj "../one.git/objects" -C worktree <<-EOF
59+
$one blob
60+
EOF
61+
'
62+
63+
# path is computed after moving to top-level of worktree
64+
test_expect_success 'access alternate via relative path (subdir)' '
65+
mkdir subdir &&
66+
check_obj "one.git/objects" -C subdir <<-EOF
67+
$one blob
68+
EOF
69+
'
70+
71+
test_done

0 commit comments

Comments
 (0)