From: Tao Klerks <tao@xxxxxxxxxx> 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 qualified replace ref paths. Signed-off-by: Tao Klerks <tao@xxxxxxxxxx> --- replace-refs: fix support of qualified replace ref paths Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1903%2FTaoK%2Fstructured-replace-ref-decoration-fix-v1 Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1903/TaoK/structured-replace-ref-decoration-fix-v1 Pull-Request: https://github.com/gitgitgadget/git/pull/1903 log-tree.c | 5 +++-- t/t4207-log-decoration-colors.sh | 17 +++++++++++++++++ t/t6050-replace.sh | 10 ++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/log-tree.c b/log-tree.c index a4d4ab59ca0..6a87724527b 100644 --- a/log-tree.c +++ b/log-tree.c @@ -163,10 +163,11 @@ static int add_ref_decoration(const char *refname, const char *referent UNUSED, if (starts_with(refname, git_replace_ref_base)) { struct object_id original_oid; + const char *slash = strrchr(refname, '/'); + const char *hash = slash ? slash + 1 : refname; if (!replace_refs_enabled(the_repository)) return 0; - if (get_oid_hex(refname + strlen(git_replace_ref_base), - &original_oid)) { + if (get_oid_hex(hash, &original_oid)) { warning("invalid replace ref %s", refname); return 0; } diff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh index 2e83cc820a1..f80684efcff 100755 --- a/t/t4207-log-decoration-colors.sh +++ b/t/t4207-log-decoration-colors.sh @@ -131,4 +131,21 @@ ${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A cmp_filtered_decorations ' +test_expect_success 'test replace decoration for nested replace path' ' + test_when_finished remove_replace_refs && + + CURRENT_HASH=$(git rev-parse --verify HEAD) && + git replace --graft HEAD HEAD~2 && + git update-ref refs/tmp/tmpref refs/replace/$CURRENT_HASH && + git update-ref -d refs/replace/$CURRENT_HASH && + git update-ref refs/replace/nested-path/abc/$CURRENT_HASH refs/tmp/tmpref && + + git log --decorate -1 HEAD >actual && + test_grep "replaced" actual && + + git --no-replace-objects log --decorate -1 HEAD >actual && + test_grep ! "replaced" actual + +' + test_done diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh index aa1b5351873..9b06baa1439 100755 --- a/t/t6050-replace.sh +++ b/t/t6050-replace.sh @@ -546,4 +546,14 @@ test_expect_success '--convert-graft-file' ' test_grep "$EMPTY_BLOB $EMPTY_TREE" .git/info/grafts ' +test_expect_success 'replace ref in a nested path' ' + git cat-file commit $HASH2 >actual && + R=$(sed -e "s/A U/O/" actual | git hash-object -t commit --stdin -w) && + git update-ref refs/replace/abc1/$HASH2 $R && + git show $HASH2 >actual && + test_grep "O Thor" actual && + git --no-replace-objects show $HASH2 >actual && + test_grep "A U Thor" actual +' + test_done base-commit: f65182a99e545d2f2bc22e6c1c2da192133b16a3 -- gitgitgadget