Files
git-mirror/t/t1421-reflog-write.sh
Patrick Steinhardt 465eff81de refs: fix invalid old object IDs when migrating reflogs
When migrating reflog entries between different storage formats we end
up with invalid old object IDs for the migrated entries: instead of
writing the old object ID of the to-be-migrated entry, we end up with
the all-zeroes object ID.

The root cause of this issue is that we don't know to use the old object
ID provided by the caller. Instead, we manually resolve the old object
ID by resolving the current value of its matching reference. But as that
reference does not yet exist in the target ref storage we always end up
resolving it to all-zeroes.

This issue got unnoticed as there is no user-facing command that would
even show the old object ID. While `git log -g` knows to show the new
object ID, we don't have any formatting directive to show the old object
ID.

Fix the bug by introducing a new flag `REF_LOG_USE_PROVIDED_OIDS`. If
set, backends are instructed to use the old and new object IDs provided
by the caller, without doing any manual resolving. Set this flag in
`ref_transaction_update_reflog()`.

Amend our tests in t1460-refs-migrate to use our test tool to read
reflog entries. This test tool prints out both old and new object ID of
each reflog entry, which fixes the test gap. Furthermore it also prints
the full identity used to write the reflog, which provides test coverage
for the previous commit in this patch series that fixed the identity for
migrated reflogs.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-08-06 07:36:31 -07:00

127 lines
3.3 KiB
Bash
Executable File

#!/bin/sh
test_description='Manually write reflog entries'
. ./test-lib.sh
SIGNATURE="C O Mitter <committer@example.com> 1112911993 -0700"
test_reflog_matches () {
repo="$1" &&
refname="$2" &&
cat >actual &&
test-tool -C "$repo" ref-store main for-each-reflog-ent "$refname" >expected &&
test_cmp expected actual
}
test_expect_success 'invalid number of arguments' '
test_when_finished "rm -rf repo" &&
git init repo &&
(
cd repo &&
for args in "" "1" "1 2" "1 2 3" "1 2 3 4 5"
do
test_must_fail git reflog write $args 2>err &&
test_grep "usage: git reflog write" err || return 1
done
)
'
test_expect_success 'invalid refname' '
test_when_finished "rm -rf repo" &&
git init repo &&
(
cd repo &&
test_must_fail git reflog write "refs/heads/ invalid" $ZERO_OID $ZERO_OID first 2>err &&
test_grep "invalid reference name: " err
)
'
test_expect_success 'unqualified refname is rejected' '
test_when_finished "rm -rf repo" &&
git init repo &&
(
cd repo &&
test_must_fail git reflog write unqualified $ZERO_OID $ZERO_OID first 2>err &&
test_grep "invalid reference name: " err
)
'
test_expect_success 'nonexistent object IDs' '
test_when_finished "rm -rf repo" &&
git init repo &&
(
cd repo &&
test_must_fail git reflog write refs/heads/something $(test_oid deadbeef) $ZERO_OID old-object-id 2>err &&
test_grep "old object .* does not exist" err &&
test_must_fail git reflog write refs/heads/something $ZERO_OID $(test_oid deadbeef) new-object-id 2>err &&
test_grep "new object .* does not exist" err
)
'
test_expect_success 'abbreviated object IDs' '
test_when_finished "rm -rf repo" &&
git init repo &&
(
cd repo &&
test_commit initial &&
abbreviated_oid=$(git rev-parse HEAD | test_copy_bytes 8) &&
test_must_fail git reflog write refs/heads/something $abbreviated_oid $ZERO_OID old-object-id 2>err &&
test_grep "invalid old object ID" err &&
test_must_fail git reflog write refs/heads/something $ZERO_OID $abbreviated_oid new-object-id 2>err &&
test_grep "invalid new object ID" err
)
'
test_expect_success 'reflog message gets normalized' '
test_when_finished "rm -rf repo" &&
git init repo &&
(
cd repo &&
test_commit initial &&
COMMIT_OID=$(git rev-parse HEAD) &&
git reflog write HEAD $COMMIT_OID $COMMIT_OID "$(printf "message\nwith\nnewlines")" &&
git reflog show -1 --format=%gs HEAD >actual &&
echo "message with newlines" >expected &&
test_cmp expected actual
)
'
test_expect_success 'simple writes' '
test_when_finished "rm -rf repo" &&
git init repo &&
(
cd repo &&
test_commit initial &&
COMMIT_OID=$(git rev-parse HEAD) &&
git reflog write refs/heads/something $ZERO_OID $COMMIT_OID first &&
test_reflog_matches . refs/heads/something <<-EOF &&
$ZERO_OID $COMMIT_OID $SIGNATURE first
EOF
git reflog write refs/heads/something $COMMIT_OID $COMMIT_OID second &&
test_reflog_matches . refs/heads/something <<-EOF
$ZERO_OID $COMMIT_OID $SIGNATURE first
$COMMIT_OID $COMMIT_OID $SIGNATURE second
EOF
)
'
test_expect_success 'can write to root ref' '
test_when_finished "rm -rf repo" &&
git init repo &&
(
cd repo &&
test_commit initial &&
COMMIT_OID=$(git rev-parse HEAD) &&
git reflog write ROOT_REF_HEAD $ZERO_OID $COMMIT_OID first &&
test_reflog_matches . ROOT_REF_HEAD <<-EOF
$ZERO_OID $COMMIT_OID $SIGNATURE first
EOF
)
'
test_done