push-to-deploy: allow pushing into an unborn branch and updating it
Setting receive.denycurrentbranch to updateinstead and pushing into the current branch, when the working tree and the index is truly clean, is supposed to reset the working tree and the index to match the tree of the pushed commit. This did not work when pushing into an unborn branch. The code that drives push-to-checkout hook needs no change, as the interface is defined so that hook can decide what to do when the push is coming to an unborn branch and take an appropriate action since the beginning. Acked-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
Mar 31, 2015 at 23:15 UTC
1a51b52422e055e433dec9a496621341d70d38ff
2 files changed
+74
-2
builtin/receive-pack.c
+20
-1
@@ -733,6 +733,22 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
733
return 0;
734
}
735
736
+/*
737
+ * NEEDSWORK: we should consolidate various implementions of "are we
738
+ * on an unborn branch?" test into one, and make the unified one more
739
+ * robust. !get_sha1() based check used here and elsewhere would not
740
+ * allow us to tell an unborn branch from corrupt ref, for example.
741
+ * For the purpose of fixing "deploy-to-update does not work when
742
+ * pushing into an empty repository" issue, this should suffice for
743
+ * now.
744
+ */
745
+static int head_has_history(void)
746
+{
747
+ unsigned char sha1[20];
748
+
749
+ return !get_sha1("HEAD", sha1);
750
+}
751
+
752
static const char *push_to_deploy(unsigned char *sha1,
753
struct argv_array *env,
754
const char *work_tree)
@@ -745,7 +761,7 @@ static const char *push_to_deploy(unsigned char *sha1,
761
};
762
const char *diff_index[] = {
763
"diff-index", "--quiet", "--cached", "--ignore-submodules",
748
- "HEAD", "--", NULL
764
+ NULL, "--", NULL
765
};
766
const char *read_tree[] = {
767
"read-tree", "-u", "-m", NULL, NULL
@@ -772,6 +788,9 @@ static const char *push_to_deploy(unsigned char *sha1,
788
if (run_command(&child))
789
return "Working directory has unstaged changes";
790
791
+ /* diff-index with either HEAD or an empty tree */
792
+ diff_index[4] = head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX;
793
+
794
child_process_init(&child);
795
child.argv = diff_index;
796
child.env = env->argv;
t/t5516-fetch-push.sh
+54
-1
@@ -1430,8 +1430,22 @@ test_expect_success 'receive.denyCurrentBranch = updateInstead' '
1430
test $(git -C .. rev-parse HEAD^^) = $(git rev-parse HEAD) &&
1431
git diff --quiet &&
1432
test fifth = "$(cat path3)"
1433
- )
1433
+ ) &&
1434
1435
+ # (5) push into void
1436
+ rm -fr void &&
1437
+ git init void &&
1438
+ (
1439
+ cd void &&
1440
+ git config receive.denyCurrentBranch updateInstead
1441
+ ) &&
1442
+ git push void master &&
1443
+ (
1444
+ cd void &&
1445
+ test $(git -C .. rev-parse master) = $(git rev-parse HEAD) &&
1446
+ git diff --quiet &&
1447
+ git diff --cached --quiet
1448
+ )
1449
'
1450
1451
test_expect_success 'updateInstead with push-to-checkout hook' '
@@ -1494,6 +1508,45 @@ test_expect_success 'updateInstead with push-to-checkout hook' '
1508
test "$(cat path5)" = irrelevant &&
1509
test "$(git diff --name-only --cached HEAD)" = path5 &&
1510
test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
1511
+ ) &&
1512
+
1513
+ # push into void
1514
+ rm -fr void &&
1515
+ git init void &&
1516
+ (
1517
+ cd void &&
1518
+ git config receive.denyCurrentBranch updateInstead &&
1519
+ write_script .git/hooks/push-to-checkout <<-\EOF
1520
+ if git rev-parse --quiet --verify HEAD
1521
+ then
1522
+ has_head=yes
1523
+ echo >&2 updating from $(git rev-parse HEAD)
1524
+ else
1525
+ has_head=no
1526
+ echo >&2 pushing into void
1527
+ fi
1528
+ echo >&2 updating to "$1"
1529
+
1530
+ git update-index -q --refresh &&
1531
+ case "$has_head" in
1532
+ yes)
1533
+ git read-tree -u -m HEAD "$1" ;;
1534
+ no)
1535
+ git read-tree -u -m "$1" ;;
1536
+ esac || {
1537
+ status=$?
1538
+ echo >&2 read-tree failed
1539
+ exit $status
1540
+ }
1541
+ EOF
1542
+ ) &&
1543
+
1544
+ git push void master &&
1545
+ (
1546
+ cd void &&
1547
+ git diff --quiet &&
1548
+ git diff --cached --quiet &&
1549
+ test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
1550
)
1551
'
1552