Allow multiple updates of a ref in the same transaction as long as
each update has have_old and old_sha1 matches the new_sha1 of the
previous update.

Add a test that verifies that a valid sequence such as
  create ref a
  update ref b a
  update ref c b
works and a test that an invalid sequence such as this still fails:
  update ref a c
  update ref b b
  update ref c c

Signed-off-by: Ronnie Sahlberg <sahlb...@google.com>
---
 refs.c                | 23 +++++++++++++++++------
 t/t1400-update-ref.sh | 23 +++++++++++++++++++++--
 2 files changed, 38 insertions(+), 8 deletions(-)

diff --git a/refs.c b/refs.c
index 76cab6e..87cdd91 100644
--- a/refs.c
+++ b/refs.c
@@ -3455,12 +3455,6 @@ int transaction_update_sha1(struct ref_transaction 
*transaction,
        if (update->lock)
                return 0;
 
-       /* If we could not lock the ref it means we either collided with a
-          different command or that we tried to perform a second update to
-          the same ref from within the same transaction.
-       */
-       transaction->status = REF_TRANSACTION_ERROR;
-
        /* -1 is the update we just added. Start at -2 and find the most recent
           previous update for this ref.
        */
@@ -3472,6 +3466,23 @@ int transaction_update_sha1(struct ref_transaction 
*transaction,
                            update->refname))
                        break;
        }
+       /* If the current update has_old==1 and old_sha1 matches the new_sha1
+        * of the previous update then merge the two updates into one.
+        */
+       if (i >= 0 && update->have_old && !hashcmp(update->old_sha1,
+                          transaction->updates[i]->new_sha1)) {
+               hashcpy(transaction->updates[i]->new_sha1, update->new_sha1);
+               transaction->nr--;
+               free((char *)transaction->updates[transaction->nr]->msg);
+               free(transaction->updates[transaction->nr]);
+               return 0;
+       }
+       /* If we could not lock the ref it means we either collided with a
+          different command or that we tried to perform a second update to
+          the same ref from within the same transaction.
+       */
+       transaction->status = REF_TRANSACTION_ERROR;
+
        if (err)
                if (i >= 0) {
                        const char *str =
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index f9b7bef..078cd4b 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -446,7 +446,7 @@ test_expect_success 'stdin fails option with unknown name' '
        grep "fatal: option unknown: unknown" err
 '
 
-test_expect_success 'stdin fails with duplicate refs' '
+test_expect_success 'stdin fails with duplicate create refs' '
        cat >stdin <<-EOF &&
        create $a $m
        create $b $m
@@ -464,6 +464,25 @@ test_expect_success 'stdin create ref works' '
        test_cmp expect actual
 '
 
+test_expect_success 'stdin succeeds with correctly chained update refs' '
+       cat >stdin <<-EOF &&
+       update $a $A $m
+       update $a $B $A
+       update $a $C $B
+       EOF
+       git update-ref --stdin <stdin
+'
+
+test_expect_success 'stdin fails with incorrectly chained update refs' '
+       cat >stdin <<-EOF &&
+       update $a $A $C
+       update $a $B $B
+       update $a $B $B
+       EOF
+       test_must_fail git update-ref --stdin <stdin &&
+       grep "fatal: Multiple updates for ref '"'"'$a'"'"' not allowed." err
+'
+
 test_expect_success 'stdin succeeds with quoted argument' '
        git update-ref -d $a &&
        echo "create $a \"$m\"" >stdin &&
@@ -786,7 +805,7 @@ test_expect_success 'stdin -z fails option with unknown 
name' '
        grep "fatal: option unknown: unknown" err
 '
 
-test_expect_success 'stdin -z fails with duplicate refs' '
+test_expect_success 'stdin -z fails with duplicate create refs' '
        printf $F "create $a" "$m" "create $b" "$m" "create $a" "$m" >stdin &&
        test_must_fail git update-ref -z --stdin <stdin 2>err &&
        grep "fatal: Multiple updates for ref '"'"'$a'"'"' not allowed." err
-- 
2.0.0.rc3.506.g3739a35

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to