aboutsummaryrefslogtreecommitdiffstats
path: root/t/t1400-update-ref.sh
diff options
context:
space:
mode:
authorKarthik Nayak <karthik.188@gmail.com>2025-04-08 10:51:12 +0200
committerJunio C Hamano <gitster@pobox.com>2025-04-08 07:59:49 -0700
commit221e8fcb7f543f056246a901bcb1269a13145fa9 (patch)
treeb41af0e7c0ea7578e05c3d222a0da5cac88fa917 /t/t1400-update-ref.sh
parent31726bb90d70236f7afaa345bf45195e2ef62d22 (diff)
downloadgit-221e8fcb7f543f056246a901bcb1269a13145fa9.tar.gz
update-ref: add --batch-updates flag for stdin mode
When updating multiple references through stdin, Git's update-ref command normally aborts the entire transaction if any single update fails. This atomic behavior prevents partial updates. Introduce a new batch update system, where the updates the performed together similar but individual updates are allowed to fail. Add a new `--batch-updates` flag that allows the transaction to continue even when individual reference updates fail. This flag can only be used in `--stdin` mode and builds upon the batch update support added to the refs subsystem in the previous commits. When enabled, failed updates are reported in the following format: rejected SP (<old-oid> | <old-target>) SP (<new-oid> | <new-target>) SP <rejection-reason> LF Update the documentation to reflect this change and also tests to cover different scenarios where an update could be rejected. Signed-off-by: Karthik Nayak <karthik.188@gmail.com> Acked-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 't/t1400-update-ref.sh')
-rwxr-xr-xt/t1400-update-ref.sh233
1 files changed, 233 insertions, 0 deletions
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 29045aad43..d29d23cb89 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -2066,6 +2066,239 @@ do
grep "$(git rev-parse $a) $(git rev-parse $a)" actual
'
+ test_expect_success "stdin $type batch-updates" '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+ test_commit commit &&
+ head=$(git rev-parse HEAD) &&
+
+ format_command $type "update refs/heads/ref1" "$head" "$Z" >stdin &&
+ format_command $type "update refs/heads/ref2" "$head" "$Z" >>stdin &&
+ git update-ref $type --stdin --batch-updates <stdin &&
+ echo $head >expect &&
+ git rev-parse refs/heads/ref1 >actual &&
+ test_cmp expect actual &&
+ git rev-parse refs/heads/ref2 >actual &&
+ test_cmp expect actual
+ )
+ '
+
+ test_expect_success "stdin $type batch-updates with invalid new_oid" '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+ test_commit one &&
+ old_head=$(git rev-parse HEAD) &&
+ test_commit two &&
+ head=$(git rev-parse HEAD) &&
+ git update-ref refs/heads/ref1 $head &&
+ git update-ref refs/heads/ref2 $head &&
+
+ format_command $type "update refs/heads/ref1" "$old_head" "$head" >stdin &&
+ format_command $type "update refs/heads/ref2" "$(test_oid 001)" "$head" >>stdin &&
+ git update-ref $type --stdin --batch-updates <stdin >stdout &&
+ echo $old_head >expect &&
+ git rev-parse refs/heads/ref1 >actual &&
+ test_cmp expect actual &&
+ echo $head >expect &&
+ git rev-parse refs/heads/ref2 >actual &&
+ test_cmp expect actual &&
+ test_grep -q "invalid new value provided" stdout
+ )
+ '
+
+ test_expect_success "stdin $type batch-updates with non-commit new_oid" '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+ test_commit one &&
+ old_head=$(git rev-parse HEAD) &&
+ test_commit two &&
+ head=$(git rev-parse HEAD) &&
+ head_tree=$(git rev-parse HEAD^{tree}) &&
+ git update-ref refs/heads/ref1 $head &&
+ git update-ref refs/heads/ref2 $head &&
+
+ format_command $type "update refs/heads/ref1" "$old_head" "$head" >stdin &&
+ format_command $type "update refs/heads/ref2" "$head_tree" "$head" >>stdin &&
+ git update-ref $type --stdin --batch-updates <stdin >stdout &&
+ echo $old_head >expect &&
+ git rev-parse refs/heads/ref1 >actual &&
+ test_cmp expect actual &&
+ echo $head >expect &&
+ git rev-parse refs/heads/ref2 >actual &&
+ test_cmp expect actual &&
+ test_grep -q "invalid new value provided" stdout
+ )
+ '
+
+ test_expect_success "stdin $type batch-updates with non-existent ref" '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+ test_commit one &&
+ old_head=$(git rev-parse HEAD) &&
+ test_commit two &&
+ head=$(git rev-parse HEAD) &&
+ git update-ref refs/heads/ref1 $head &&
+
+ format_command $type "update refs/heads/ref1" "$old_head" "$head" >stdin &&
+ format_command $type "update refs/heads/ref2" "$old_head" "$head" >>stdin &&
+ git update-ref $type --stdin --batch-updates <stdin >stdout &&
+ echo $old_head >expect &&
+ git rev-parse refs/heads/ref1 >actual &&
+ test_cmp expect actual &&
+ test_must_fail git rev-parse refs/heads/ref2 &&
+ test_grep -q "reference does not exist" stdout
+ )
+ '
+
+ test_expect_success "stdin $type batch-updates with dangling symref" '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+ test_commit one &&
+ old_head=$(git rev-parse HEAD) &&
+ test_commit two &&
+ head=$(git rev-parse HEAD) &&
+ git update-ref refs/heads/ref1 $head &&
+ git symbolic-ref refs/heads/ref2 refs/heads/nonexistent &&
+
+ format_command $type "update refs/heads/ref1" "$old_head" "$head" >stdin &&
+ format_command $type "update refs/heads/ref2" "$old_head" "$head" >>stdin &&
+ git update-ref $type --no-deref --stdin --batch-updates <stdin >stdout &&
+ echo $old_head >expect &&
+ git rev-parse refs/heads/ref1 >actual &&
+ test_cmp expect actual &&
+ echo $head >expect &&
+ test_must_fail git rev-parse refs/heads/ref2 &&
+ test_grep -q "reference does not exist" stdout
+ )
+ '
+
+ test_expect_success "stdin $type batch-updates with regular ref as symref" '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+ test_commit one &&
+ old_head=$(git rev-parse HEAD) &&
+ test_commit two &&
+ head=$(git rev-parse HEAD) &&
+ git update-ref refs/heads/ref1 $head &&
+ git update-ref refs/heads/ref2 $head &&
+
+ format_command $type "update refs/heads/ref1" "$old_head" "$head" >stdin &&
+ format_command $type "symref-update refs/heads/ref2" "$old_head" "ref" "refs/heads/nonexistent" >>stdin &&
+ git update-ref $type --no-deref --stdin --batch-updates <stdin >stdout &&
+ echo $old_head >expect &&
+ git rev-parse refs/heads/ref1 >actual &&
+ test_cmp expect actual &&
+ echo $head >expect &&
+ echo $head >expect &&
+ git rev-parse refs/heads/ref2 >actual &&
+ test_cmp expect actual &&
+ test_grep -q "expected symref but found regular ref" stdout
+ )
+ '
+
+ test_expect_success "stdin $type batch-updates with invalid old_oid" '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+ test_commit one &&
+ old_head=$(git rev-parse HEAD) &&
+ test_commit two &&
+ head=$(git rev-parse HEAD) &&
+ git update-ref refs/heads/ref1 $head &&
+ git update-ref refs/heads/ref2 $head &&
+
+ format_command $type "update refs/heads/ref1" "$old_head" "$head" >stdin &&
+ format_command $type "update refs/heads/ref2" "$old_head" "$Z" >>stdin &&
+ git update-ref $type --stdin --batch-updates <stdin >stdout &&
+ echo $old_head >expect &&
+ git rev-parse refs/heads/ref1 >actual &&
+ test_cmp expect actual &&
+ echo $head >expect &&
+ git rev-parse refs/heads/ref2 >actual &&
+ test_cmp expect actual &&
+ test_grep -q "reference already exists" stdout
+ )
+ '
+
+ test_expect_success "stdin $type batch-updates with incorrect old oid" '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+ test_commit one &&
+ old_head=$(git rev-parse HEAD) &&
+ test_commit two &&
+ head=$(git rev-parse HEAD) &&
+ git update-ref refs/heads/ref1 $head &&
+ git update-ref refs/heads/ref2 $head &&
+
+ format_command $type "update refs/heads/ref1" "$old_head" "$head" >stdin &&
+ format_command $type "update refs/heads/ref2" "$head" "$old_head" >>stdin &&
+ git update-ref $type --stdin --batch-updates <stdin >stdout &&
+ echo $old_head >expect &&
+ git rev-parse refs/heads/ref1 >actual &&
+ test_cmp expect actual &&
+ echo $head >expect &&
+ git rev-parse refs/heads/ref2 >actual &&
+ test_cmp expect actual &&
+ test_grep -q "incorrect old value provided" stdout
+ )
+ '
+
+ test_expect_success "stdin $type batch-updates refname conflict" '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+ test_commit one &&
+ old_head=$(git rev-parse HEAD) &&
+ test_commit two &&
+ head=$(git rev-parse HEAD) &&
+ git update-ref refs/heads/ref/foo $head &&
+
+ format_command $type "update refs/heads/ref/foo" "$old_head" "$head" >stdin &&
+ format_command $type "update refs/heads/ref" "$old_head" "" >>stdin &&
+ git update-ref $type --stdin --batch-updates <stdin >stdout &&
+ echo $old_head >expect &&
+ git rev-parse refs/heads/ref/foo >actual &&
+ test_cmp expect actual &&
+ test_grep -q "refname conflict" stdout
+ )
+ '
+
+ test_expect_success "stdin $type batch-updates refname conflict new ref" '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+ test_commit one &&
+ old_head=$(git rev-parse HEAD) &&
+ test_commit two &&
+ head=$(git rev-parse HEAD) &&
+ git update-ref refs/heads/ref/foo $head &&
+
+ format_command $type "update refs/heads/foo" "$old_head" "" >stdin &&
+ format_command $type "update refs/heads/ref" "$old_head" "" >>stdin &&
+ git update-ref $type --stdin --batch-updates <stdin >stdout &&
+ echo $old_head >expect &&
+ git rev-parse refs/heads/foo >actual &&
+ test_cmp expect actual &&
+ test_grep -q "refname conflict" stdout
+ )
+ '
done
test_expect_success 'update-ref should also create reflog for HEAD' '