setup: split "extensions found" messages into singular and plural
[git] / t / t7064-wtstatus-pv2.sh
1 #!/bin/sh
2
3 test_description='git status --porcelain=v2
4
5 This test exercises porcelain V2 output for git status.'
6
7
8 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
9 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
10
11 . ./test-lib.sh
12
13
14 test_expect_success setup '
15         git checkout -f --orphan initial-branch &&
16         test_tick &&
17         git config core.autocrlf false &&
18         echo x >file_x &&
19         echo y >file_y &&
20         echo z >file_z &&
21         mkdir dir1 &&
22         echo a >dir1/file_a &&
23         echo b >dir1/file_b
24 '
25
26 test_expect_success 'before initial commit, nothing added, only untracked' '
27         cat >expect <<-EOF &&
28         # branch.oid (initial)
29         # branch.head initial-branch
30         ? actual
31         ? dir1/
32         ? expect
33         ? file_x
34         ? file_y
35         ? file_z
36         EOF
37
38         git status --porcelain=v2 --branch --untracked-files=normal >actual &&
39         test_cmp expect actual
40 '
41
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) &&
49
50         cat >expect <<-EOF &&
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
58         ? actual
59         ? expect
60         EOF
61
62         git status --porcelain=v2 --branch --untracked-files=all >actual &&
63         test_cmp expect actual
64 '
65
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
75         ? actual
76         ? expect
77         EOF
78
79         git status -z --porcelain=v2 --branch --untracked-files=all >actual &&
80         test_cmp expect actual
81 '
82
83 test_expect_success 'make first commit, comfirm HEAD oid and branch' '
84         git commit -m initial &&
85         H0=$(git rev-parse HEAD) &&
86         cat >expect <<-EOF &&
87         # branch.oid $H0
88         # branch.head initial-branch
89         ? actual
90         ? expect
91         EOF
92
93         git status --porcelain=v2 --branch --untracked-files=all >actual &&
94         test_cmp expect actual
95 '
96
97 test_expect_success 'after first commit, create unstaged changes' '
98         echo x >>file_x &&
99         OID_X1=$(git hash-object -t blob -- file_x) &&
100         rm file_z &&
101         H0=$(git rev-parse HEAD) &&
102
103         cat >expect <<-EOF &&
104         # branch.oid $H0
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
108         ? actual
109         ? expect
110         EOF
111
112         git status --porcelain=v2 --branch --untracked-files=all >actual &&
113         test_cmp expect actual
114 '
115
116 test_expect_success 'after first commit but omit untracked files and branch' '
117         cat >expect <<-EOF &&
118         1 .M N... 100644 100644 100644 $OID_X $OID_X file_x
119         1 .D N... 100644 100644 000000 $OID_Z $OID_Z file_z
120         EOF
121
122         git status --porcelain=v2 --untracked-files=no >actual &&
123         test_cmp expect actual
124 '
125
126 test_expect_success 'after first commit, stage existing changes' '
127         git add file_x &&
128         git rm file_z &&
129         H0=$(git rev-parse HEAD) &&
130
131         cat >expect <<-EOF &&
132         # branch.oid $H0
133         # branch.head initial-branch
134         1 M. N... 100644 100644 100644 $OID_X $OID_X1 file_x
135         1 D. N... 100644 000000 000000 $OID_Z $ZERO_OID file_z
136         ? actual
137         ? expect
138         EOF
139
140         git status --porcelain=v2 --branch --untracked-files=all >actual &&
141         test_cmp expect actual
142 '
143
144 test_expect_success 'rename causes 2 path lines' '
145         git mv file_y renamed_y &&
146         H0=$(git rev-parse HEAD) &&
147
148         q_to_tab >expect <<-EOF &&
149         # branch.oid $H0
150         # branch.head initial-branch
151         1 M. N... 100644 100644 100644 $OID_X $OID_X1 file_x
152         1 D. N... 100644 000000 000000 $OID_Z $ZERO_OID file_z
153         2 R. N... 100644 100644 100644 $OID_Y $OID_Y R100 renamed_yQfile_y
154         ? actual
155         ? expect
156         EOF
157
158         git status --porcelain=v2 --branch --untracked-files=all >actual &&
159         test_cmp expect actual
160 '
161
162 test_expect_success 'rename causes 2 path lines (-z)' '
163         H0=$(git rev-parse HEAD) &&
164
165         ## Lines use NUL path separator and line terminator, so double transform here.
166         q_to_nul <<-EOF | lf_to_nul >expect &&
167         # branch.oid $H0
168         # branch.head initial-branch
169         1 M. N... 100644 100644 100644 $OID_X $OID_X1 file_x
170         1 D. N... 100644 000000 000000 $OID_Z $ZERO_OID file_z
171         2 R. N... 100644 100644 100644 $OID_Y $OID_Y R100 renamed_yQfile_y
172         ? actual
173         ? expect
174         EOF
175
176         git status --porcelain=v2 --branch --untracked-files=all -z >actual &&
177         test_cmp expect actual
178 '
179
180 test_expect_success 'make second commit, confirm clean and new HEAD oid' '
181         git commit -m second &&
182         H1=$(git rev-parse HEAD) &&
183
184         cat >expect <<-EOF &&
185         # branch.oid $H1
186         # branch.head initial-branch
187         ? actual
188         ? expect
189         EOF
190
191         git status --porcelain=v2 --branch --untracked-files=all >actual &&
192         test_cmp expect actual
193 '
194
195 test_expect_success 'confirm ignored files are not printed' '
196         test_when_finished "rm -f x.ign .gitignore" &&
197         echo x.ign >.gitignore &&
198         echo "ignore me" >x.ign &&
199
200         cat >expect <<-EOF &&
201         ? .gitignore
202         ? actual
203         ? expect
204         EOF
205
206         git status --porcelain=v2 --untracked-files=all >actual &&
207         test_cmp expect actual
208 '
209
210 test_expect_success 'ignored files are printed with --ignored' '
211         test_when_finished "rm -f x.ign .gitignore" &&
212         echo x.ign >.gitignore &&
213         echo "ignore me" >x.ign &&
214
215         cat >expect <<-EOF &&
216         ? .gitignore
217         ? actual
218         ? expect
219         ! x.ign
220         EOF
221
222         git status --porcelain=v2 --ignored --untracked-files=all >actual &&
223         test_cmp expect actual
224 '
225
226 test_expect_success 'create and commit permanent ignore file' '
227         cat >.gitignore <<-EOF &&
228         actual*
229         expect*
230         EOF
231
232         git add .gitignore &&
233         git commit -m ignore_trash &&
234         H1=$(git rev-parse HEAD) &&
235
236         cat >expect <<-EOF &&
237         # branch.oid $H1
238         # branch.head initial-branch
239         EOF
240
241         git status --porcelain=v2 --branch >actual &&
242         test_cmp expect actual
243 '
244
245 test_expect_success 'verify --intent-to-add output' '
246         test_when_finished "git rm -f intent1.add intent2.add" &&
247         touch intent1.add &&
248         echo test >intent2.add &&
249
250         git add --intent-to-add intent1.add intent2.add &&
251
252         cat >expect <<-EOF &&
253         1 .A N... 000000 000000 100644 $ZERO_OID $ZERO_OID intent1.add
254         1 .A N... 000000 000000 100644 $ZERO_OID $ZERO_OID intent2.add
255         EOF
256
257         git status --porcelain=v2 >actual &&
258         test_cmp expect actual
259 '
260
261 test_expect_success 'verify AA (add-add) conflict' '
262         test_when_finished "git reset --hard" &&
263
264         git branch AA_A initial-branch &&
265         git checkout AA_A &&
266         echo "Branch AA_A" >conflict.txt &&
267         OID_AA_A=$(git hash-object -t blob -- conflict.txt) &&
268         git add conflict.txt &&
269         git commit -m "branch aa_a" &&
270
271         git branch AA_B initial-branch &&
272         git checkout AA_B &&
273         echo "Branch AA_B" >conflict.txt &&
274         OID_AA_B=$(git hash-object -t blob -- conflict.txt) &&
275         git add conflict.txt &&
276         git commit -m "branch aa_b" &&
277
278         git branch AA_M AA_B &&
279         git checkout AA_M &&
280         test_must_fail git merge AA_A &&
281
282         HM=$(git rev-parse HEAD) &&
283
284         cat >expect <<-EOF &&
285         # branch.oid $HM
286         # branch.head AA_M
287         u AA N... 000000 100644 100644 100644 $ZERO_OID $OID_AA_B $OID_AA_A conflict.txt
288         EOF
289
290         git status --porcelain=v2 --branch --untracked-files=all >actual &&
291         test_cmp expect actual
292 '
293
294 test_expect_success 'verify UU (edit-edit) conflict' '
295         test_when_finished "git reset --hard" &&
296
297         git branch UU_ANC initial-branch &&
298         git checkout UU_ANC &&
299         echo "Ancestor" >conflict.txt &&
300         OID_UU_ANC=$(git hash-object -t blob -- conflict.txt) &&
301         git add conflict.txt &&
302         git commit -m "UU_ANC" &&
303
304         git branch UU_A UU_ANC &&
305         git checkout UU_A &&
306         echo "Branch UU_A" >conflict.txt &&
307         OID_UU_A=$(git hash-object -t blob -- conflict.txt) &&
308         git add conflict.txt &&
309         git commit -m "branch uu_a" &&
310
311         git branch UU_B UU_ANC &&
312         git checkout UU_B &&
313         echo "Branch UU_B" >conflict.txt &&
314         OID_UU_B=$(git hash-object -t blob -- conflict.txt) &&
315         git add conflict.txt &&
316         git commit -m "branch uu_b" &&
317
318         git branch UU_M UU_B &&
319         git checkout UU_M &&
320         test_must_fail git merge UU_A &&
321
322         HM=$(git rev-parse HEAD) &&
323
324         cat >expect <<-EOF &&
325         # branch.oid $HM
326         # branch.head UU_M
327         u UU N... 100644 100644 100644 100644 $OID_UU_ANC $OID_UU_B $OID_UU_A conflict.txt
328         EOF
329
330         git status --porcelain=v2 --branch --untracked-files=all >actual &&
331         test_cmp expect actual
332 '
333
334 test_expect_success 'verify upstream fields in branch header' '
335         git checkout initial-branch &&
336         test_when_finished "rm -rf sub_repo" &&
337         git clone . sub_repo &&
338         (
339                 ## Confirm local initial-branch tracks remote initial-branch.
340                 cd sub_repo &&
341                 HUF=$(git rev-parse HEAD) &&
342
343                 cat >expect <<-EOF &&
344                 # branch.oid $HUF
345                 # branch.head initial-branch
346                 # branch.upstream origin/initial-branch
347                 # branch.ab +0 -0
348                 EOF
349
350                 git status --porcelain=v2 --branch --untracked-files=all >actual &&
351                 test_cmp expect actual &&
352
353                 ## Test ahead/behind.
354                 echo xyz >file_xyz &&
355                 git add file_xyz &&
356                 git commit -m xyz &&
357
358                 HUF=$(git rev-parse HEAD) &&
359
360                 cat >expect <<-EOF &&
361                 # branch.oid $HUF
362                 # branch.head initial-branch
363                 # branch.upstream origin/initial-branch
364                 # branch.ab +1 -0
365                 EOF
366
367                 git status --porcelain=v2 --branch --untracked-files=all >actual &&
368                 test_cmp expect actual &&
369
370                 ## Repeat the above but without --branch.
371                 git status --porcelain=v2 --untracked-files=all >actual &&
372                 test_must_be_empty actual &&
373
374                 ## Test upstream-gone case. Fake this by pointing
375                 ## origin/initial-branch at a non-existing commit.
376                 OLD=$(git rev-parse origin/initial-branch) &&
377                 NEW=$ZERO_OID &&
378                 mv .git/packed-refs .git/old-packed-refs &&
379                 sed "s/$OLD/$NEW/g" <.git/old-packed-refs >.git/packed-refs &&
380
381                 HUF=$(git rev-parse HEAD) &&
382
383                 cat >expect <<-EOF &&
384                 # branch.oid $HUF
385                 # branch.head initial-branch
386                 # branch.upstream origin/initial-branch
387                 EOF
388
389                 git status --porcelain=v2 --branch --untracked-files=all >actual &&
390                 test_cmp expect actual
391         )
392 '
393
394 test_expect_success 'verify --[no-]ahead-behind with V2 format' '
395         git checkout initial-branch &&
396         test_when_finished "rm -rf sub_repo" &&
397         git clone . sub_repo &&
398         (
399                 ## Confirm local initial-branch tracks remote initial-branch.
400                 cd sub_repo &&
401                 HUF=$(git rev-parse HEAD) &&
402
403                 # Confirm --no-ahead-behind reports traditional branch.ab with 0/0 for equal branches.
404                 cat >expect <<-EOF &&
405                 # branch.oid $HUF
406                 # branch.head initial-branch
407                 # branch.upstream origin/initial-branch
408                 # branch.ab +0 -0
409                 EOF
410
411                 git status --no-ahead-behind --porcelain=v2 --branch --untracked-files=all >actual &&
412                 test_cmp expect actual &&
413
414                 # Confirm --ahead-behind reports traditional branch.ab with 0/0.
415                 cat >expect <<-EOF &&
416                 # branch.oid $HUF
417                 # branch.head initial-branch
418                 # branch.upstream origin/initial-branch
419                 # branch.ab +0 -0
420                 EOF
421
422                 git status --ahead-behind --porcelain=v2 --branch --untracked-files=all >actual &&
423                 test_cmp expect actual &&
424
425                 ## Test non-equal ahead/behind.
426                 echo xyz >file_xyz &&
427                 git add file_xyz &&
428                 git commit -m xyz &&
429
430                 HUF=$(git rev-parse HEAD) &&
431
432                 # Confirm --no-ahead-behind reports branch.ab with ?/? for non-equal branches.
433                 cat >expect <<-EOF &&
434                 # branch.oid $HUF
435                 # branch.head initial-branch
436                 # branch.upstream origin/initial-branch
437                 # branch.ab +? -?
438                 EOF
439
440                 git status --no-ahead-behind --porcelain=v2 --branch --untracked-files=all >actual &&
441                 test_cmp expect actual &&
442
443                 # Confirm --ahead-behind reports traditional branch.ab with 1/0.
444                 cat >expect <<-EOF &&
445                 # branch.oid $HUF
446                 # branch.head initial-branch
447                 # branch.upstream origin/initial-branch
448                 # branch.ab +1 -0
449                 EOF
450
451                 git status --ahead-behind --porcelain=v2 --branch --untracked-files=all >actual &&
452                 test_cmp expect actual &&
453
454                 # Confirm that "status.aheadbehind" DOES NOT work on V2 format.
455                 git -c status.aheadbehind=false status --porcelain=v2 --branch --untracked-files=all >actual &&
456                 test_cmp expect actual &&
457
458                 # Confirm that "status.aheadbehind" DOES NOT work on V2 format.
459                 git -c status.aheadbehind=true status --porcelain=v2 --branch --untracked-files=all >actual &&
460                 test_cmp expect actual
461         )
462 '
463
464 test_expect_success 'create and add submodule, submodule appears clean (A. S...)' '
465         git checkout initial-branch &&
466         git clone . sub_repo &&
467         git clone . super_repo &&
468         (       cd super_repo &&
469                 git submodule add ../sub_repo sub1 &&
470
471                 ## Confirm stage/add of clean submodule.
472                 HMOD=$(git hash-object -t blob -- .gitmodules) &&
473                 HSUP=$(git rev-parse HEAD) &&
474                 HSUB=$HSUP &&
475
476                 cat >expect <<-EOF &&
477                 # branch.oid $HSUP
478                 # branch.head initial-branch
479                 # branch.upstream origin/initial-branch
480                 # branch.ab +0 -0
481                 1 A. N... 000000 100644 100644 $ZERO_OID $HMOD .gitmodules
482                 1 A. S... 000000 160000 160000 $ZERO_OID $HSUB sub1
483                 EOF
484
485                 git status --porcelain=v2 --branch --untracked-files=all >actual &&
486                 test_cmp expect actual
487         )
488 '
489
490 test_expect_success 'untracked changes in added submodule (AM S..U)' '
491         (       cd super_repo &&
492                 ## create untracked file in the submodule.
493                 (       cd sub1 &&
494                         echo "xxxx" >file_in_sub
495                 ) &&
496
497                 HMOD=$(git hash-object -t blob -- .gitmodules) &&
498                 HSUP=$(git rev-parse HEAD) &&
499                 HSUB=$HSUP &&
500
501                 cat >expect <<-EOF &&
502                 # branch.oid $HSUP
503                 # branch.head initial-branch
504                 # branch.upstream origin/initial-branch
505                 # branch.ab +0 -0
506                 1 A. N... 000000 100644 100644 $ZERO_OID $HMOD .gitmodules
507                 1 AM S..U 000000 160000 160000 $ZERO_OID $HSUB sub1
508                 EOF
509
510                 git status --porcelain=v2 --branch --untracked-files=all >actual &&
511                 test_cmp expect actual
512         )
513 '
514
515 test_expect_success 'staged changes in added submodule (AM S.M.)' '
516         (       cd super_repo &&
517                 ## stage the changes in the submodule.
518                 (       cd sub1 &&
519                         git add file_in_sub
520                 ) &&
521
522                 HMOD=$(git hash-object -t blob -- .gitmodules) &&
523                 HSUP=$(git rev-parse HEAD) &&
524                 HSUB=$HSUP &&
525
526                 cat >expect <<-EOF &&
527                 # branch.oid $HSUP
528                 # branch.head initial-branch
529                 # branch.upstream origin/initial-branch
530                 # branch.ab +0 -0
531                 1 A. N... 000000 100644 100644 $ZERO_OID $HMOD .gitmodules
532                 1 AM S.M. 000000 160000 160000 $ZERO_OID $HSUB sub1
533                 EOF
534
535                 git status --porcelain=v2 --branch --untracked-files=all >actual &&
536                 test_cmp expect actual
537         )
538 '
539
540 test_expect_success 'staged and unstaged changes in added (AM S.M.)' '
541         (       cd super_repo &&
542                 (       cd sub1 &&
543                         ## make additional unstaged changes (on the same file) in the submodule.
544                         ## This does not cause us to get S.MU (because the submodule does not report
545                         ## a "?" line for the unstaged changes).
546                         echo "more changes" >>file_in_sub
547                 ) &&
548
549                 HMOD=$(git hash-object -t blob -- .gitmodules) &&
550                 HSUP=$(git rev-parse HEAD) &&
551                 HSUB=$HSUP &&
552
553                 cat >expect <<-EOF &&
554                 # branch.oid $HSUP
555                 # branch.head initial-branch
556                 # branch.upstream origin/initial-branch
557                 # branch.ab +0 -0
558                 1 A. N... 000000 100644 100644 $ZERO_OID $HMOD .gitmodules
559                 1 AM S.M. 000000 160000 160000 $ZERO_OID $HSUB sub1
560                 EOF
561
562                 git status --porcelain=v2 --branch --untracked-files=all >actual &&
563                 test_cmp expect actual
564         )
565 '
566
567 test_expect_success 'staged and untracked changes in added submodule (AM S.MU)' '
568         (       cd super_repo &&
569                 (       cd sub1 &&
570                         ## stage new changes in tracked file.
571                         git add file_in_sub &&
572                         ## create new untracked file.
573                         echo "yyyy" >>another_file_in_sub
574                 ) &&
575
576                 HMOD=$(git hash-object -t blob -- .gitmodules) &&
577                 HSUP=$(git rev-parse HEAD) &&
578                 HSUB=$HSUP &&
579
580                 cat >expect <<-EOF &&
581                 # branch.oid $HSUP
582                 # branch.head initial-branch
583                 # branch.upstream origin/initial-branch
584                 # branch.ab +0 -0
585                 1 A. N... 000000 100644 100644 $ZERO_OID $HMOD .gitmodules
586                 1 AM S.MU 000000 160000 160000 $ZERO_OID $HSUB sub1
587                 EOF
588
589                 git status --porcelain=v2 --branch --untracked-files=all >actual &&
590                 test_cmp expect actual
591         )
592 '
593
594 test_expect_success 'commit within the submodule appears as new commit in super (AM SC..)' '
595         (       cd super_repo &&
596                 (       cd sub1 &&
597                         ## Make a new commit in the submodule.
598                         git add file_in_sub &&
599                         rm -f another_file_in_sub &&
600                         git commit -m "new commit"
601                 ) &&
602
603                 HMOD=$(git hash-object -t blob -- .gitmodules) &&
604                 HSUP=$(git rev-parse HEAD) &&
605                 HSUB=$HSUP &&
606
607                 cat >expect <<-EOF &&
608                 # branch.oid $HSUP
609                 # branch.head initial-branch
610                 # branch.upstream origin/initial-branch
611                 # branch.ab +0 -0
612                 1 A. N... 000000 100644 100644 $ZERO_OID $HMOD .gitmodules
613                 1 AM SC.. 000000 160000 160000 $ZERO_OID $HSUB sub1
614                 EOF
615
616                 git status --porcelain=v2 --branch --untracked-files=all >actual &&
617                 test_cmp expect actual
618         )
619 '
620
621 test_expect_success 'stage submodule in super and commit' '
622         (       cd super_repo &&
623                 ## Stage the new submodule commit in the super.
624                 git add sub1 &&
625                 ## Commit the super so that the sub no longer appears as added.
626                 git commit -m "super commit" &&
627
628                 HSUP=$(git rev-parse HEAD) &&
629
630                 cat >expect <<-EOF &&
631                 # branch.oid $HSUP
632                 # branch.head initial-branch
633                 # branch.upstream origin/initial-branch
634                 # branch.ab +1 -0
635                 EOF
636
637                 git status --porcelain=v2 --branch --untracked-files=all >actual &&
638                 test_cmp expect actual
639         )
640 '
641
642 test_expect_success 'make unstaged changes in existing submodule (.M S.M.)' '
643         (       cd super_repo &&
644                 (       cd sub1 &&
645                         echo "zzzz" >>file_in_sub
646                 ) &&
647
648                 HSUP=$(git rev-parse HEAD) &&
649                 HSUB=$(cd sub1 && git rev-parse HEAD) &&
650
651                 cat >expect <<-EOF &&
652                 # branch.oid $HSUP
653                 # branch.head initial-branch
654                 # branch.upstream origin/initial-branch
655                 # branch.ab +1 -0
656                 1 .M S.M. 160000 160000 160000 $HSUB $HSUB sub1
657                 EOF
658
659                 git status --porcelain=v2 --branch --untracked-files=all >actual &&
660                 test_cmp expect actual
661         )
662 '
663
664 test_done