3 test_description
='git status --porcelain=v2
5 This test exercises porcelain V2 output for git status.'
8 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
=master
9 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
14 test_expect_success setup
'
15 git checkout -f --orphan initial-branch &&
17 git config core.autocrlf false &&
22 echo a >dir1/file_a &&
26 test_expect_success
'before initial commit, nothing added, only untracked' '
28 # branch.oid (initial)
29 # branch.head initial-branch
38 git status --porcelain=v2 --branch --untracked-files=normal >actual &&
39 test_cmp expect actual
42 test_expect_success
'before initial commit, things added' '
43 git add file_x file_y file_z dir1 &&
44 OID_A=$(git hash-object -t blob -- dir1/file_a) &&
45 OID_B=$(git hash-object -t blob -- dir1/file_b) &&
46 OID_X=$(git hash-object -t blob -- file_x) &&
47 OID_Y=$(git hash-object -t blob -- file_y) &&
48 OID_Z=$(git hash-object -t blob -- file_z) &&
51 # branch.oid (initial)
52 # branch.head initial-branch
53 1 A. N... 000000 100644 100644 $ZERO_OID $OID_A dir1/file_a
54 1 A. N... 000000 100644 100644 $ZERO_OID $OID_B dir1/file_b
55 1 A. N... 000000 100644 100644 $ZERO_OID $OID_X file_x
56 1 A. N... 000000 100644 100644 $ZERO_OID $OID_Y file_y
57 1 A. N... 000000 100644 100644 $ZERO_OID $OID_Z file_z
62 git status --porcelain=v2 --branch --untracked-files=all >actual &&
63 test_cmp expect actual
66 test_expect_success
'before initial commit, things added (-z)' '
67 lf_to_nul >expect <<-EOF &&
68 # branch.oid (initial)
69 # branch.head initial-branch
70 1 A. N... 000000 100644 100644 $ZERO_OID $OID_A dir1/file_a
71 1 A. N... 000000 100644 100644 $ZERO_OID $OID_B dir1/file_b
72 1 A. N... 000000 100644 100644 $ZERO_OID $OID_X file_x
73 1 A. N... 000000 100644 100644 $ZERO_OID $OID_Y file_y
74 1 A. N... 000000 100644 100644 $ZERO_OID $OID_Z file_z
79 git status -z --porcelain=v2 --branch --untracked-files=all >actual &&
80 test_cmp expect actual
83 test_expect_success
'make first commit, comfirm HEAD oid and branch' '
84 git commit -m initial &&
85 H0=$(git rev-parse HEAD) &&
88 # branch.head initial-branch
93 git status --porcelain=v2 --branch --untracked-files=all >actual &&
94 test_cmp expect actual
97 test_expect_success
'after first commit, create unstaged changes' '
99 OID_X1=$(git hash-object -t blob -- file_x) &&
101 H0=$(git rev-parse HEAD) &&
103 cat >expect <<-EOF &&
105 # branch.head initial-branch
106 1 .M N... 100644 100644 100644 $OID_X $OID_X file_x
107 1 .D N... 100644 100644 000000 $OID_Z $OID_Z file_z
112 git status --porcelain=v2 --branch --untracked-files=all >actual &&
113 test_cmp expect actual
116 test_expect_success
'after first commit, stash existing changes' '
117 cat >expect <<-EOF &&
119 # branch.head initial-branch
123 test_when_finished "git stash pop && git stash pop" &&
125 git stash -- file_x &&
127 git status --porcelain=v2 --branch --show-stash --untracked-files=no >actual &&
128 test_cmp expect actual
131 test_expect_success
'after first commit but omit untracked files and branch' '
132 cat >expect <<-EOF &&
133 1 .M N... 100644 100644 100644 $OID_X $OID_X file_x
134 1 .D N... 100644 100644 000000 $OID_Z $OID_Z file_z
137 git status --porcelain=v2 --untracked-files=no >actual &&
138 test_cmp expect actual
141 test_expect_success
'after first commit, stage existing changes' '
144 H0=$(git rev-parse HEAD) &&
146 cat >expect <<-EOF &&
148 # branch.head initial-branch
149 1 M. N... 100644 100644 100644 $OID_X $OID_X1 file_x
150 1 D. N... 100644 000000 000000 $OID_Z $ZERO_OID file_z
155 git status --porcelain=v2 --branch --untracked-files=all >actual &&
156 test_cmp expect actual
159 test_expect_success
'rename causes 2 path lines' '
160 git mv file_y renamed_y &&
161 H0=$(git rev-parse HEAD) &&
163 q_to_tab >expect <<-EOF &&
165 # branch.head initial-branch
166 1 M. N... 100644 100644 100644 $OID_X $OID_X1 file_x
167 1 D. N... 100644 000000 000000 $OID_Z $ZERO_OID file_z
168 2 R. N... 100644 100644 100644 $OID_Y $OID_Y R100 renamed_yQfile_y
173 git status --porcelain=v2 --branch --untracked-files=all >actual &&
174 test_cmp expect actual
177 test_expect_success
'rename causes 2 path lines (-z)' '
178 H0=$(git rev-parse HEAD) &&
180 ## Lines use NUL path separator and line terminator, so double transform here.
181 q_to_nul <<-EOF | lf_to_nul >expect &&
183 # branch.head initial-branch
184 1 M. N... 100644 100644 100644 $OID_X $OID_X1 file_x
185 1 D. N... 100644 000000 000000 $OID_Z $ZERO_OID file_z
186 2 R. N... 100644 100644 100644 $OID_Y $OID_Y R100 renamed_yQfile_y
191 git status --porcelain=v2 --branch --untracked-files=all -z >actual &&
192 test_cmp expect actual
195 test_expect_success
'make second commit, confirm clean and new HEAD oid' '
196 git commit -m second &&
197 H1=$(git rev-parse HEAD) &&
199 cat >expect <<-EOF &&
201 # branch.head initial-branch
206 git status --porcelain=v2 --branch --untracked-files=all >actual &&
207 test_cmp expect actual
210 test_expect_success
'confirm ignored files are not printed' '
211 test_when_finished "rm -f x.ign .gitignore" &&
212 echo x.ign >.gitignore &&
213 echo "ignore me" >x.ign &&
215 cat >expect <<-EOF &&
221 git status --porcelain=v2 --untracked-files=all >actual &&
222 test_cmp expect actual
225 test_expect_success
'ignored files are printed with --ignored' '
226 test_when_finished "rm -f x.ign .gitignore" &&
227 echo x.ign >.gitignore &&
228 echo "ignore me" >x.ign &&
230 cat >expect <<-EOF &&
237 git status --porcelain=v2 --ignored --untracked-files=all >actual &&
238 test_cmp expect actual
241 test_expect_success
'create and commit permanent ignore file' '
242 cat >.gitignore <<-EOF &&
247 git add .gitignore &&
248 git commit -m ignore_trash &&
249 H1=$(git rev-parse HEAD) &&
251 cat >expect <<-EOF &&
253 # branch.head initial-branch
256 git status --porcelain=v2 --branch >actual &&
257 test_cmp expect actual
260 test_expect_success
'verify --intent-to-add output' '
261 test_when_finished "git rm -f intent1.add intent2.add" &&
263 echo test >intent2.add &&
265 git add --intent-to-add intent1.add intent2.add &&
267 cat >expect <<-EOF &&
268 1 .A N... 000000 000000 100644 $ZERO_OID $ZERO_OID intent1.add
269 1 .A N... 000000 000000 100644 $ZERO_OID $ZERO_OID intent2.add
272 git status --porcelain=v2 >actual &&
273 test_cmp expect actual
276 test_expect_success
'verify AA (add-add) conflict' '
277 test_when_finished "git reset --hard" &&
279 git branch AA_A initial-branch &&
281 echo "Branch AA_A" >conflict.txt &&
282 OID_AA_A=$(git hash-object -t blob -- conflict.txt) &&
283 git add conflict.txt &&
284 git commit -m "branch aa_a" &&
286 git branch AA_B initial-branch &&
288 echo "Branch AA_B" >conflict.txt &&
289 OID_AA_B=$(git hash-object -t blob -- conflict.txt) &&
290 git add conflict.txt &&
291 git commit -m "branch aa_b" &&
293 git branch AA_M AA_B &&
295 test_must_fail git merge AA_A &&
297 HM=$(git rev-parse HEAD) &&
299 cat >expect <<-EOF &&
302 u AA N... 000000 100644 100644 100644 $ZERO_OID $OID_AA_B $OID_AA_A conflict.txt
305 git status --porcelain=v2 --branch --untracked-files=all >actual &&
306 test_cmp expect actual
309 test_expect_success
'verify UU (edit-edit) conflict' '
310 test_when_finished "git reset --hard" &&
312 git branch UU_ANC initial-branch &&
313 git checkout UU_ANC &&
314 echo "Ancestor" >conflict.txt &&
315 OID_UU_ANC=$(git hash-object -t blob -- conflict.txt) &&
316 git add conflict.txt &&
317 git commit -m "UU_ANC" &&
319 git branch UU_A UU_ANC &&
321 echo "Branch UU_A" >conflict.txt &&
322 OID_UU_A=$(git hash-object -t blob -- conflict.txt) &&
323 git add conflict.txt &&
324 git commit -m "branch uu_a" &&
326 git branch UU_B UU_ANC &&
328 echo "Branch UU_B" >conflict.txt &&
329 OID_UU_B=$(git hash-object -t blob -- conflict.txt) &&
330 git add conflict.txt &&
331 git commit -m "branch uu_b" &&
333 git branch UU_M UU_B &&
335 test_must_fail git merge UU_A &&
337 HM=$(git rev-parse HEAD) &&
339 cat >expect <<-EOF &&
342 u UU N... 100644 100644 100644 100644 $OID_UU_ANC $OID_UU_B $OID_UU_A conflict.txt
345 git status --porcelain=v2 --branch --untracked-files=all >actual &&
346 test_cmp expect actual
349 test_expect_success
'verify upstream fields in branch header' '
350 git checkout initial-branch &&
351 test_when_finished "rm -rf sub_repo" &&
352 git clone . sub_repo &&
354 ## Confirm local initial-branch tracks remote initial-branch.
356 HUF=$(git rev-parse HEAD) &&
358 cat >expect <<-EOF &&
360 # branch.head initial-branch
361 # branch.upstream origin/initial-branch
365 git status --porcelain=v2 --branch --untracked-files=all >actual &&
366 test_cmp expect actual &&
368 ## Test ahead/behind.
369 echo xyz >file_xyz &&
373 HUF=$(git rev-parse HEAD) &&
375 cat >expect <<-EOF &&
377 # branch.head initial-branch
378 # branch.upstream origin/initial-branch
382 git status --porcelain=v2 --branch --untracked-files=all >actual &&
383 test_cmp expect actual &&
385 ## Repeat the above but without --branch.
386 git status --porcelain=v2 --untracked-files=all >actual &&
387 test_must_be_empty actual &&
389 ## Test upstream-gone case. Fake this by pointing
390 ## origin/initial-branch at a non-existing commit.
391 git update-ref -d refs/remotes/origin/initial-branch &&
393 HUF=$(git rev-parse HEAD) &&
395 cat >expect <<-EOF &&
397 # branch.head initial-branch
398 # branch.upstream origin/initial-branch
401 git status --porcelain=v2 --branch --untracked-files=all >actual &&
402 test_cmp expect actual
406 test_expect_success
'verify --[no-]ahead-behind with V2 format' '
407 git checkout initial-branch &&
408 test_when_finished "rm -rf sub_repo" &&
409 git clone . sub_repo &&
411 ## Confirm local initial-branch tracks remote initial-branch.
413 HUF=$(git rev-parse HEAD) &&
415 # Confirm --no-ahead-behind reports traditional branch.ab with 0/0 for equal branches.
416 cat >expect <<-EOF &&
418 # branch.head initial-branch
419 # branch.upstream origin/initial-branch
423 git status --no-ahead-behind --porcelain=v2 --branch --untracked-files=all >actual &&
424 test_cmp expect actual &&
426 # Confirm --ahead-behind reports traditional branch.ab with 0/0.
427 cat >expect <<-EOF &&
429 # branch.head initial-branch
430 # branch.upstream origin/initial-branch
434 git status --ahead-behind --porcelain=v2 --branch --untracked-files=all >actual &&
435 test_cmp expect actual &&
437 ## Test non-equal ahead/behind.
438 echo xyz >file_xyz &&
442 HUF=$(git rev-parse HEAD) &&
444 # Confirm --no-ahead-behind reports branch.ab with ?/? for non-equal branches.
445 cat >expect <<-EOF &&
447 # branch.head initial-branch
448 # branch.upstream origin/initial-branch
452 git status --no-ahead-behind --porcelain=v2 --branch --untracked-files=all >actual &&
453 test_cmp expect actual &&
455 # Confirm --ahead-behind reports traditional branch.ab with 1/0.
456 cat >expect <<-EOF &&
458 # branch.head initial-branch
459 # branch.upstream origin/initial-branch
463 git status --ahead-behind --porcelain=v2 --branch --untracked-files=all >actual &&
464 test_cmp expect actual &&
466 # Confirm that "status.aheadbehind" DOES NOT work on V2 format.
467 git -c status.aheadbehind=false status --porcelain=v2 --branch --untracked-files=all >actual &&
468 test_cmp expect actual &&
470 # Confirm that "status.aheadbehind" DOES NOT work on V2 format.
471 git -c status.aheadbehind=true status --porcelain=v2 --branch --untracked-files=all >actual &&
472 test_cmp expect actual
476 test_expect_success
'create and add submodule, submodule appears clean (A. S...)' '
477 git checkout initial-branch &&
478 git clone . sub_repo &&
479 git clone . super_repo &&
481 git submodule add ../sub_repo sub1 &&
483 ## Confirm stage/add of clean submodule.
484 HMOD=$(git hash-object -t blob -- .gitmodules) &&
485 HSUP=$(git rev-parse HEAD) &&
488 cat >expect <<-EOF &&
490 # branch.head initial-branch
491 # branch.upstream origin/initial-branch
493 1 A. N... 000000 100644 100644 $ZERO_OID $HMOD .gitmodules
494 1 A. S... 000000 160000 160000 $ZERO_OID $HSUB sub1
497 git status --porcelain=v2 --branch --untracked-files=all >actual &&
498 test_cmp expect actual
502 test_expect_success
'untracked changes in added submodule (AM S..U)' '
504 ## create untracked file in the submodule.
506 echo "xxxx" >file_in_sub
509 HMOD=$(git hash-object -t blob -- .gitmodules) &&
510 HSUP=$(git rev-parse HEAD) &&
513 cat >expect <<-EOF &&
515 # branch.head initial-branch
516 # branch.upstream origin/initial-branch
518 1 A. N... 000000 100644 100644 $ZERO_OID $HMOD .gitmodules
519 1 AM S..U 000000 160000 160000 $ZERO_OID $HSUB sub1
522 git status --porcelain=v2 --branch --untracked-files=all >actual &&
523 test_cmp expect actual
527 test_expect_success
'staged changes in added submodule (AM S.M.)' '
529 ## stage the changes in the submodule.
534 HMOD=$(git hash-object -t blob -- .gitmodules) &&
535 HSUP=$(git rev-parse HEAD) &&
538 cat >expect <<-EOF &&
540 # branch.head initial-branch
541 # branch.upstream origin/initial-branch
543 1 A. N... 000000 100644 100644 $ZERO_OID $HMOD .gitmodules
544 1 AM S.M. 000000 160000 160000 $ZERO_OID $HSUB sub1
547 git status --porcelain=v2 --branch --untracked-files=all >actual &&
548 test_cmp expect actual
552 test_expect_success
'staged and unstaged changes in added (AM S.M.)' '
555 ## make additional unstaged changes (on the same file) in the submodule.
556 ## This does not cause us to get S.MU (because the submodule does not report
557 ## a "?" line for the unstaged changes).
558 echo "more changes" >>file_in_sub
561 HMOD=$(git hash-object -t blob -- .gitmodules) &&
562 HSUP=$(git rev-parse HEAD) &&
565 cat >expect <<-EOF &&
567 # branch.head initial-branch
568 # branch.upstream origin/initial-branch
570 1 A. N... 000000 100644 100644 $ZERO_OID $HMOD .gitmodules
571 1 AM S.M. 000000 160000 160000 $ZERO_OID $HSUB sub1
574 git status --porcelain=v2 --branch --untracked-files=all >actual &&
575 test_cmp expect actual
579 test_expect_success
'staged and untracked changes in added submodule (AM S.MU)' '
582 ## stage new changes in tracked file.
583 git add file_in_sub &&
584 ## create new untracked file.
585 echo "yyyy" >>another_file_in_sub
588 HMOD=$(git hash-object -t blob -- .gitmodules) &&
589 HSUP=$(git rev-parse HEAD) &&
592 cat >expect <<-EOF &&
594 # branch.head initial-branch
595 # branch.upstream origin/initial-branch
597 1 A. N... 000000 100644 100644 $ZERO_OID $HMOD .gitmodules
598 1 AM S.MU 000000 160000 160000 $ZERO_OID $HSUB sub1
601 git status --porcelain=v2 --branch --untracked-files=all >actual &&
602 test_cmp expect actual
606 test_expect_success
'commit within the submodule appears as new commit in super (AM SC..)' '
609 ## Make a new commit in the submodule.
610 git add file_in_sub &&
611 rm -f another_file_in_sub &&
612 git commit -m "new commit"
615 HMOD=$(git hash-object -t blob -- .gitmodules) &&
616 HSUP=$(git rev-parse HEAD) &&
619 cat >expect <<-EOF &&
621 # branch.head initial-branch
622 # branch.upstream origin/initial-branch
624 1 A. N... 000000 100644 100644 $ZERO_OID $HMOD .gitmodules
625 1 AM SC.. 000000 160000 160000 $ZERO_OID $HSUB sub1
628 git status --porcelain=v2 --branch --untracked-files=all >actual &&
629 test_cmp expect actual
633 test_expect_success
'stage submodule in super and commit' '
635 ## Stage the new submodule commit in the super.
637 ## Commit the super so that the sub no longer appears as added.
638 git commit -m "super commit" &&
640 HSUP=$(git rev-parse HEAD) &&
642 cat >expect <<-EOF &&
644 # branch.head initial-branch
645 # branch.upstream origin/initial-branch
649 git status --porcelain=v2 --branch --untracked-files=all >actual &&
650 test_cmp expect actual
654 test_expect_success
'make unstaged changes in existing submodule (.M S.M.)' '
657 echo "zzzz" >>file_in_sub
660 HSUP=$(git rev-parse HEAD) &&
661 HSUB=$(cd sub1 && git rev-parse HEAD) &&
663 cat >expect <<-EOF &&
665 # branch.head initial-branch
666 # branch.upstream origin/initial-branch
668 1 .M S.M. 160000 160000 160000 $HSUB $HSUB sub1
671 git status --porcelain=v2 --branch --untracked-files=all >actual &&
672 test_cmp expect actual