update-ref: allow creation of multiple transactions

While git-update-ref has recently grown commands which allow interactive control of transactions in e48cf33b61 (update-ref: implement interactive transaction handling, 2020-04-02), it is not yet possible to create multiple transactions in a single session. To do so, one currently still needs to invoke the executable multiple times. This commit addresses this shortcoming by allowing the "start" command to create a new transaction if the current transaction has already been either committed or aborted. Signed-off-by: Patrick Steinhardt <ps@pks.im> Reviewed-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Nov 13, 2020 at 09:12 UTC 262a4d28feb26aff89705b3254cdfc015eaa3ef9
3 files changed +64 -2
Documentation/git-update-ref.txt
+2 -1
@@ -125,7 +125,8 @@ option::
125 start::
126 Start a transaction. In contrast to a non-transactional session, a
127 transaction will automatically abort if the session ends without an
128 - explicit commit.
128 + explicit commit. This command may create a new empty transaction when
129 + the current one has been committed or aborted already.
130
131 prepare::
132 Prepare to commit the transaction. This will create lock files for all
builtin/update-ref.c
+12 -1
@@ -446,7 +446,18 @@ static void update_refs_stdin(void)
446 state = cmd->state;
447 break;
448 case UPDATE_REFS_CLOSED:
449 - die("transaction is closed");
449 + if (cmd->state != UPDATE_REFS_STARTED)
450 + die("transaction is closed");
451 +
452 + /*
453 + * Open a new transaction if we're currently closed and
454 + * get a "start".
455 + */
456 + state = cmd->state;
457 + transaction = ref_transaction_begin(&err);
458 + if (!transaction)
459 + die("%s", err.buf);
460 +
461 break;
462 }
463
t/t1400-update-ref.sh
+50
@@ -1533,4 +1533,54 @@ test_expect_success 'transaction with prepare aborts by default' '
1533 test_must_fail git show-ref --verify -q $b
1534 '
1535
1536 +test_expect_success 'transaction can commit multiple times' '
1537 + cat >stdin <<-EOF &&
1538 + start
1539 + create refs/heads/branch-1 $A
1540 + commit
1541 + start
1542 + create refs/heads/branch-2 $B
1543 + commit
1544 + EOF
1545 + git update-ref --stdin <stdin >actual &&
1546 + printf "%s: ok\n" start commit start commit >expect &&
1547 + test_cmp expect actual &&
1548 + echo "$A" >expect &&
1549 + git rev-parse refs/heads/branch-1 >actual &&
1550 + test_cmp expect actual &&
1551 + echo "$B" >expect &&
1552 + git rev-parse refs/heads/branch-2 >actual &&
1553 + test_cmp expect actual
1554 +'
1555 +
1556 +test_expect_success 'transaction can create and delete' '
1557 + cat >stdin <<-EOF &&
1558 + start
1559 + create refs/heads/create-and-delete $A
1560 + commit
1561 + start
1562 + delete refs/heads/create-and-delete $A
1563 + commit
1564 + EOF
1565 + git update-ref --stdin <stdin >actual &&
1566 + printf "%s: ok\n" start commit start commit >expect &&
1567 + test_must_fail git show-ref --verify refs/heads/create-and-delete
1568 +'
1569 +
1570 +test_expect_success 'transaction can commit after abort' '
1571 + cat >stdin <<-EOF &&
1572 + start
1573 + create refs/heads/abort $A
1574 + abort
1575 + start
1576 + create refs/heads/abort $A
1577 + commit
1578 + EOF
1579 + git update-ref --stdin <stdin >actual &&
1580 + printf "%s: ok\n" start abort start commit >expect &&
1581 + echo "$A" >expect &&
1582 + git rev-parse refs/heads/abort >actual &&
1583 + test_cmp expect actual
1584 +'
1585 +
1586 test_done