summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff King <peff@peff.net>2014-09-12 03:38:30 (GMT)
committerJunio C Hamano <gitster@pobox.com>2014-09-12 17:45:49 (GMT)
commit30d1038d1bd538bf2f8abfb5f5dccf80327a26c9 (patch)
treebcac4b82fce1c7ba24cf71bea861e98c110ab41c
parent2e770fe47ef9c0b20bc687e37f3eb50f1bf919d0 (diff)
downloadgit-30d1038d1bd538bf2f8abfb5f5dccf80327a26c9.zip
git-30d1038d1bd538bf2f8abfb5f5dccf80327a26c9.tar.gz
git-30d1038d1bd538bf2f8abfb5f5dccf80327a26c9.tar.bz2
fsck: return non-zero status on missing ref tips
Fsck tries hard to detect missing objects, and will complain (and exit non-zero) about any inter-object links that are missing. However, it will not exit non-zero for any missing ref tips, meaning that a severely broken repository may still pass "git fsck && echo ok". The problem is that we use for_each_ref to iterate over the ref tips, which hides broken tips. It does at least print an error from the refs.c code, but fsck does not ever see the ref and cannot note the problem in its exit code. We can solve this by using for_each_rawref and noting the error ourselves. In addition to adding tests for this case, we add tests for all types of missing-object links (all of which worked, but which we were not testing). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--builtin/fsck.c3
-rwxr-xr-xt/t1450-fsck.sh56
2 files changed, 58 insertions, 1 deletions
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 8abe644..ca3018c 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -495,6 +495,7 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int f
obj = parse_object(sha1);
if (!obj) {
error("%s: invalid sha1 pointer %s", refname, sha1_to_hex(sha1));
+ errors_found |= ERROR_REACHABLE;
/* We'll continue with the rest despite the error.. */
return 0;
}
@@ -511,7 +512,7 @@ static void get_default_heads(void)
{
if (head_points_at && !is_null_sha1(head_sha1))
fsck_handle_ref("HEAD", head_sha1, 0, NULL);
- for_each_ref(fsck_handle_ref, NULL);
+ for_each_rawref(fsck_handle_ref, NULL);
if (include_reflogs)
for_each_reflog(fsck_handle_reflog, NULL);
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 0de755c..b52397a 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -302,4 +302,60 @@ test_expect_success 'fsck notices ".git" in trees' '
)
'
+# create a static test repo which is broken by omitting
+# one particular object ($1, which is looked up via rev-parse
+# in the new repository).
+create_repo_missing () {
+ rm -rf missing &&
+ git init missing &&
+ (
+ cd missing &&
+ git commit -m one --allow-empty &&
+ mkdir subdir &&
+ echo content >subdir/file &&
+ git add subdir/file &&
+ git commit -m two &&
+ unrelated=$(echo unrelated | git hash-object --stdin -w) &&
+ git tag -m foo tag $unrelated &&
+ sha1=$(git rev-parse --verify "$1") &&
+ path=$(echo $sha1 | sed 's|..|&/|') &&
+ rm .git/objects/$path
+ )
+}
+
+test_expect_success 'fsck notices missing blob' '
+ create_repo_missing HEAD:subdir/file &&
+ test_must_fail git -C missing fsck
+'
+
+test_expect_success 'fsck notices missing subtree' '
+ create_repo_missing HEAD:subdir &&
+ test_must_fail git -C missing fsck
+'
+
+test_expect_success 'fsck notices missing root tree' '
+ create_repo_missing HEAD^{tree} &&
+ test_must_fail git -C missing fsck
+'
+
+test_expect_success 'fsck notices missing parent' '
+ create_repo_missing HEAD^ &&
+ test_must_fail git -C missing fsck
+'
+
+test_expect_success 'fsck notices missing tagged object' '
+ create_repo_missing tag^{blob} &&
+ test_must_fail git -C missing fsck
+'
+
+test_expect_success 'fsck notices ref pointing to missing commit' '
+ create_repo_missing HEAD &&
+ test_must_fail git -C missing fsck
+'
+
+test_expect_success 'fsck notices ref pointing to missing tag' '
+ create_repo_missing tag &&
+ test_must_fail git -C missing fsck
+'
+
test_done