diff options
author | Johannes Schindelin <Johannes.Schindelin@gmx.de> | 2007-11-29 01:02:53 +0000 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2007-11-30 14:59:43 -0800 |
commit | 28391a80a94d2b59d1d21f8264fe5dab91d77249 (patch) | |
tree | ecad6b60280162cff18197f5b069c6df6801a025 | |
parent | Add config_int() method to the Git perl module (diff) | |
download | tgif-28391a80a94d2b59d1d21f8264fe5dab91d77249.tar.xz |
receive-pack: allow deletion of corrupt refs
Occasionally, in some setups (*cough* forks on repo.or.cz *cough*) some
refs go stale, e.g. when the forkee rebased and lost some objects needed
by the fork. The quick & dirty way to deal with those refs is to delete
them and push them again.
However, git-push first would first fetch the current commit name for the
ref, would receive a null sha1 since the ref does not point to a valid
object, then tell receive-pack that it should delete the ref with this
commit name. delete_ref() would be subsequently be called, and check that
resolve_ref() (which does _not_ check for validity of the object) returns
the same commit name. Which would fail.
The proper fix is to avoid corrupting repositories, but in the meantime
this is a good fix in any case.
Incidentally, some instances of "cd .." in the test cases were fixed, so
that subsequent test cases run in t/trash/ irrespective of the outcome of
the previous test cases.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r-- | receive-pack.c | 4 | ||||
-rwxr-xr-x | t/t5516-fetch-push.sh | 45 |
2 files changed, 46 insertions, 3 deletions
diff --git a/receive-pack.c b/receive-pack.c index ed44b897f6..fba4cf8235 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -200,6 +200,10 @@ static const char *update(struct command *cmd) } if (is_null_sha1(new_sha1)) { + if (!parse_object(old_sha1)) { + warning ("Allowing deletion of corrupt ref."); + old_sha1 = NULL; + } if (delete_ref(name, old_sha1)) { error("failed to delete %s", name); return "failed to delete"; diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 4fbd5b1f47..987c9d21ca 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -247,11 +247,50 @@ test_expect_success 'push with colon-less refspec (4)' ' test_expect_success 'push with dry-run' ' mk_test heads/master && - cd testrepo && - old_commit=$(git show-ref -s --verify refs/heads/master) && - cd .. && + (cd testrepo && + old_commit=$(git show-ref -s --verify refs/heads/master)) && git push --dry-run testrepo && check_push_result $old_commit heads/master ' +test_expect_success 'push updates local refs' ' + + rm -rf parent child && + mkdir parent && + (cd parent && git init && + echo one >foo && git add foo && git commit -m one) && + git clone parent child && + (cd child && + echo two >foo && git commit -a -m two && + git push && + test $(git rev-parse master) = $(git rev-parse remotes/origin/master)) + +' + +test_expect_success 'push does not update local refs on failure' ' + + rm -rf parent child && + mkdir parent && + (cd parent && git init && + echo one >foo && git add foo && git commit -m one && + echo exit 1 >.git/hooks/pre-receive && + chmod +x .git/hooks/pre-receive) && + git clone parent child && + (cd child && + echo two >foo && git commit -a -m two && + ! git push && + test $(git rev-parse master) != \ + $(git rev-parse remotes/origin/master)) + +' + +test_expect_success 'allow deleting an invalid remote ref' ' + + pwd && + rm -f testrepo/.git/objects/??/* && + git push testrepo :refs/heads/master && + (cd testrepo && ! git rev-parse --verify refs/heads/master) + +' + test_done |