| 1 | #!/bin/sh |
| 2 | |
| 3 | test_description='handling of missing objects in rev-list' |
| 4 | |
| 5 | . ./test-lib.sh |
| 6 | |
| 7 | # We setup the repository with two commits, this way HEAD is always |
| 8 | # available and we can hide commit 1. |
| 9 | test_expect_success 'create repository and alternate directory' ' |
| 10 | test_commit 1 && |
| 11 | test_commit 2 && |
| 12 | test_commit 3 && |
| 13 | git tag -m "tag message" annot_tag HEAD~1 && |
| 14 | git tag regul_tag HEAD~1 && |
| 15 | git branch a_branch HEAD~1 |
| 16 | ' |
| 17 | |
| 18 | # We manually corrupt the repository, which means that the commit-graph may |
| 19 | # contain references to already-deleted objects. We thus need to enable |
| 20 | # commit-graph paranoia to not returned these deleted commits from the graph. |
| 21 | GIT_COMMIT_GRAPH_PARANOIA=true |
| 22 | export GIT_COMMIT_GRAPH_PARANOIA |
| 23 | |
| 24 | for obj in "HEAD~1" "HEAD~1^{tree}" "HEAD:1.t" |
| 25 | do |
| 26 | test_expect_success "rev-list --missing=error fails with missing object $obj" ' |
| 27 | oid="$(git rev-parse $obj)" && |
| 28 | path=".git/objects/$(test_oid_to_path $oid)" && |
| 29 | |
| 30 | mv "$path" "$path.hidden" && |
| 31 | test_when_finished "mv $path.hidden $path" && |
| 32 | |
| 33 | test_must_fail git rev-list --missing=error --objects \ |
| 34 | --no-object-names HEAD |
| 35 | ' |
| 36 | done |
| 37 | |
| 38 | for obj in "HEAD~1" "HEAD~1^{tree}" "HEAD:1.t" |
| 39 | do |
| 40 | for action in "allow-any" "print" |
| 41 | do |
| 42 | test_expect_success "rev-list --missing=$action with missing $obj" ' |
| 43 | oid="$(git rev-parse $obj)" && |
| 44 | path=".git/objects/$(test_oid_to_path $oid)" && |
| 45 | |
| 46 | # Before the object is made missing, we use rev-list to |
| 47 | # get the expected oids. |
| 48 | git rev-list --objects --no-object-names \ |
| 49 | HEAD ^$obj >expect.raw && |
| 50 | |
| 51 | # Blobs are shared by all commits, so even though a commit/tree |
| 52 | # might be skipped, its blob must be accounted for. |
| 53 | if test $obj != "HEAD:1.t" |
| 54 | then |
| 55 | echo $(git rev-parse HEAD:1.t) >>expect.raw && |
| 56 | echo $(git rev-parse HEAD:2.t) >>expect.raw |
| 57 | fi && |
| 58 | |
| 59 | mv "$path" "$path.hidden" && |
| 60 | test_when_finished "mv $path.hidden $path" && |
| 61 | |
| 62 | git rev-list --missing=$action --objects --no-object-names \ |
| 63 | HEAD >actual.raw && |
| 64 | |
| 65 | # When the action is to print, we should also add the missing |
| 66 | # oid to the expect list. |
| 67 | case $action in |
| 68 | allow-any) |
| 69 | ;; |
| 70 | print) |
| 71 | test_grep ?$oid actual.raw && |
| 72 | echo ?$oid >>expect.raw |
| 73 | ;; |
| 74 | esac && |
| 75 | |
| 76 | sort actual.raw >actual && |
| 77 | sort expect.raw >expect && |
| 78 | test_cmp expect actual |
| 79 | ' |
| 80 | done |
| 81 | done |
| 82 | |
| 83 | for missing_tip in "annot_tag" "regul_tag" "a_branch" "HEAD~1" "HEAD~1^{tree}" "HEAD:1.t" |
| 84 | do |
| 85 | # We want to check that things work when both |
| 86 | # - all the tips passed are missing (case existing_tip = ""), and |
| 87 | # - there is one missing tip and one existing tip (case existing_tip = "HEAD") |
| 88 | for existing_tip in "" "HEAD" |
| 89 | do |
| 90 | for action in "allow-any" "print" |
| 91 | do |
| 92 | test_expect_success "--missing=$action with tip '$missing_tip' missing and tip '$existing_tip'" ' |
| 93 | # Before the object is made missing, we use rev-list to |
| 94 | # get the expected oids. |
| 95 | if test "$existing_tip" = "HEAD" |
| 96 | then |
| 97 | git rev-list --objects --no-object-names \ |
| 98 | HEAD ^$missing_tip >expect.raw |
| 99 | else |
| 100 | >expect.raw |
| 101 | fi && |
| 102 | |
| 103 | # Blobs are shared by all commits, so even though a commit/tree |
| 104 | # might be skipped, its blob must be accounted for. |
| 105 | if test "$existing_tip" = "HEAD" && test $missing_tip != "HEAD:1.t" |
| 106 | then |
| 107 | echo $(git rev-parse HEAD:1.t) >>expect.raw && |
| 108 | echo $(git rev-parse HEAD:2.t) >>expect.raw |
| 109 | fi && |
| 110 | |
| 111 | missing_oid="$(git rev-parse $missing_tip)" && |
| 112 | |
| 113 | if test "$missing_tip" = "annot_tag" |
| 114 | then |
| 115 | oid="$(git rev-parse $missing_tip^{commit})" && |
| 116 | echo "$missing_oid" >>expect.raw |
| 117 | else |
| 118 | oid="$missing_oid" |
| 119 | fi && |
| 120 | |
| 121 | path=".git/objects/$(test_oid_to_path $oid)" && |
| 122 | |
| 123 | mv "$path" "$path.hidden" && |
| 124 | test_when_finished "mv $path.hidden $path" && |
| 125 | |
| 126 | git rev-list --missing=$action --objects --no-object-names \ |
| 127 | $missing_oid $existing_tip >actual.raw && |
| 128 | |
| 129 | # When the action is to print, we should also add the missing |
| 130 | # oid to the expect list. |
| 131 | case $action in |
| 132 | allow-any) |
| 133 | ;; |
| 134 | print) |
| 135 | test_grep ?$oid actual.raw && |
| 136 | echo ?$oid >>expect.raw |
| 137 | ;; |
| 138 | esac && |
| 139 | |
| 140 | sort actual.raw >actual && |
| 141 | sort expect.raw >expect && |
| 142 | test_cmp expect actual |
| 143 | ' |
| 144 | done |
| 145 | done |
| 146 | done |
| 147 | |
| 148 | for obj in "HEAD~1" "HEAD^{tree}" "HEAD:foo" "HEAD:foo/bar" "HEAD:baz baz" |
| 149 | do |
| 150 | test_expect_success "--missing=print-info with missing '$obj'" ' |
| 151 | test_when_finished rm -rf missing-info && |
| 152 | |
| 153 | git init missing-info && |
| 154 | ( |
| 155 | cd missing-info && |
| 156 | git commit --allow-empty -m first && |
| 157 | |
| 158 | mkdir foo && |
| 159 | echo bar >foo/bar && |
| 160 | echo baz >"baz baz" && |
| 161 | echo bat >bat\" && |
| 162 | git add -A && |
| 163 | git commit -m second && |
| 164 | |
| 165 | oid="$(git rev-parse "$obj")" && |
| 166 | path=".git/objects/$(test_oid_to_path $oid)" && |
| 167 | type_info=" type=$(git cat-file -t $oid)" && |
| 168 | |
| 169 | case $obj in |
| 170 | HEAD:foo) |
| 171 | path_info=" path=foo" |
| 172 | ;; |
| 173 | HEAD:foo/bar) |
| 174 | path_info=" path=foo/bar" |
| 175 | ;; |
| 176 | "HEAD:baz baz") |
| 177 | path_info=" path=\"baz baz\"" |
| 178 | ;; |
| 179 | "HEAD:bat\"") |
| 180 | path_info=" path=\"bat\\\"\"" |
| 181 | ;; |
| 182 | esac && |
| 183 | |
| 184 | # Before the object is made missing, we use rev-list to |
| 185 | # get the expected oids. |
| 186 | git rev-list --objects --no-object-names \ |
| 187 | HEAD ^"$obj" >expect.raw && |
| 188 | echo "?$oid$path_info$type_info" >>expect.raw && |
| 189 | |
| 190 | mv "$path" "$path.hidden" && |
| 191 | git rev-list --objects --no-object-names \ |
| 192 | --missing=print-info HEAD >actual.raw && |
| 193 | |
| 194 | sort actual.raw >actual && |
| 195 | sort expect.raw >expect && |
| 196 | test_cmp expect actual |
| 197 | ) |
| 198 | ' |
| 199 | done |
| 200 | |
| 201 | test_expect_success "-z nul-delimited --missing" ' |
| 202 | test_when_finished rm -rf repo && |
| 203 | |
| 204 | git init repo && |
| 205 | ( |
| 206 | cd repo && |
| 207 | git commit --allow-empty -m first && |
| 208 | |
| 209 | path="foo bar" && |
| 210 | echo foobar >"$path" && |
| 211 | git add -A && |
| 212 | git commit -m second && |
| 213 | |
| 214 | oid=$(git rev-parse "HEAD:$path") && |
| 215 | type="$(git cat-file -t $oid)" && |
| 216 | |
| 217 | obj_path=".git/objects/$(test_oid_to_path $oid)" && |
| 218 | |
| 219 | git rev-list -z --objects --no-object-names \ |
| 220 | HEAD ^"$oid" >expect && |
| 221 | printf "%s\0missing=yes\0path=%s\0type=%s\0" "$oid" "$path" \ |
| 222 | "$type" >>expect && |
| 223 | |
| 224 | mv "$obj_path" "$obj_path.hidden" && |
| 225 | git rev-list -z --objects --no-object-names \ |
| 226 | --missing=print-info HEAD >actual && |
| 227 | |
| 228 | test_cmp expect actual |
| 229 | ) |
| 230 | ' |
| 231 | |
| 232 | test_done |