Skip to content

Commit a666d75

Browse files
committed
replace-refs: Fix "invalid replace ref" warning during decoration
The enactment of replace refs in replace-object.c#register_replace_ref() explicitly uses the last portion of the ref "path", the substring after the last slash, as the object ID to be replaced. This means that replace refs can be organized into different paths; you can separate replace refs created for different purposes, like "refs/replace/2012-migration/*". This in turn makes it practical to store prepared replace refs in different ref paths on a git server, and have users "map" them, via specific refspecs, into their local repos; different types of replacements can be mapped into different sub-paths of refs/replace/. The only way this didn't "work" is in the commit decoration process, in log-tree.c#add_ref_decoration(), where different logic was used to obtain the replaced object ID, removing the "refs/replace/" prefix only. This inconsistent logic meant that more structured replace ref paths caused a warning to be printed, and the "replaced" decoration to be omitted. Fix this decoration logic to use the same "last part of ref path" logic, fixing spurious warnings (and missing decorations) for users of more structured replace ref paths. Also add tests for nested replace ref paths.
1 parent 4bbb303 commit a666d75

File tree

3 files changed

+30
-2
lines changed

3 files changed

+30
-2
lines changed

log-tree.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,11 @@ static int add_ref_decoration(const char *refname, const char *referent UNUSED,
163163

164164
if (starts_with(refname, git_replace_ref_base)) {
165165
struct object_id original_oid;
166+
const char *slash = strrchr(refname, '/');
167+
const char *hash = slash ? slash + 1 : refname;
166168
if (!replace_refs_enabled(the_repository))
167169
return 0;
168-
if (get_oid_hex(refname + strlen(git_replace_ref_base),
169-
&original_oid)) {
170+
if (get_oid_hex(hash, &original_oid)) {
170171
warning("invalid replace ref %s", refname);
171172
return 0;
172173
}

t/t4207-log-decoration-colors.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,21 @@ ${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A
131131
cmp_filtered_decorations
132132
'
133133

134+
test_expect_success 'test replace decoration for nested replace path' '
135+
test_when_finished remove_replace_refs &&
136+
137+
CURRENT_HASH=$(git rev-parse --verify HEAD) &&
138+
git replace --graft HEAD HEAD~2 &&
139+
git update-ref refs/tmp/tmpref refs/replace/$CURRENT_HASH &&
140+
git update-ref -d refs/replace/$CURRENT_HASH &&
141+
git update-ref refs/replace/nested-path/abc/$CURRENT_HASH refs/tmp/tmpref &&
142+
143+
git log --decorate -1 HEAD >actual &&
144+
test_grep "replaced" actual &&
145+
146+
git --no-replace-objects log --decorate -1 HEAD >actual &&
147+
test_grep ! "replaced" actual
148+
149+
'
150+
134151
test_done

t/t6050-replace.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,4 +546,14 @@ test_expect_success '--convert-graft-file' '
546546
test_grep "$EMPTY_BLOB $EMPTY_TREE" .git/info/grafts
547547
'
548548

549+
test_expect_success 'replace ref in a nested path' '
550+
git cat-file commit $HASH2 >actual &&
551+
R=$(sed -e "s/A U/O/" actual | git hash-object -t commit --stdin -w) &&
552+
git update-ref refs/replace/abc1/$HASH2 $R &&
553+
git show $HASH2 >actual &&
554+
test_grep "O Thor" actual &&
555+
git --no-replace-objects show $HASH2 >actual &&
556+
test_grep "A U Thor" actual
557+
'
558+
549559
test_done

0 commit comments

Comments
 (0)