summaryrefslogtreecommitdiff
path: root/t
diff options
context:
space:
mode:
Diffstat (limited to 't')
-rw-r--r--t/Makefile2
-rw-r--r--t/README44
-rwxr-xr-xt/aggregate-results.sh14
-rw-r--r--t/annotate-tests.sh13
-rw-r--r--t/gitweb-lib.sh13
-rw-r--r--t/lib-diff-alternative.sh165
-rw-r--r--t/lib-git-p4.sh74
-rwxr-xr-xt/lib-gpg.sh34
-rw-r--r--t/lib-gpg/pubring.gpg (renamed from t/t7004/pubring.gpg)bin1164 -> 1164 bytes
-rw-r--r--t/lib-gpg/random_seed (renamed from t/t7004/random_seed)bin600 -> 600 bytes
-rw-r--r--t/lib-gpg/secring.gpg (renamed from t/t7004/secring.gpg)bin1237 -> 1237 bytes
-rw-r--r--t/lib-gpg/trustdb.gpg (renamed from t/t7004/trustdb.gpg)bin1280 -> 1280 bytes
-rw-r--r--t/lib-httpd.sh13
-rw-r--r--t/lib-read-tree.sh43
-rw-r--r--t/lib-terminal.sh22
-rwxr-xr-xt/t0000-basic.sh10
-rwxr-xr-xt/t0001-init.sh59
-rwxr-xr-xt/t0003-attributes.sh172
-rwxr-xr-xt/t0006-date.sh7
-rwxr-xr-xt/t0021-conversion.sh51
-rwxr-xr-xt/t0040-parse-options.sh21
-rwxr-xr-xt/t0061-run-command.sh23
-rwxr-xr-xt/t0070-fundamental.sh13
-rwxr-xr-xt/t0080-vcs-svn.sh54
-rwxr-xr-xt/t0081-line-buffer.sh90
-rwxr-xr-xt/t0201-gettext-fallbacks.sh51
-rwxr-xr-xt/t1000-read-tree-m-3way.sh81
-rwxr-xr-xt/t1001-read-tree-m-2way.sh45
-rwxr-xr-xt/t1002-read-tree-m-u-2way.sh81
-rwxr-xr-xt/t1004-read-tree-m-u-wf.sh23
-rwxr-xr-xt/t1005-read-tree-reset.sh13
-rwxr-xr-xt/t1007-hash-object.sh13
-rwxr-xr-xt/t1008-read-tree-overlay.sh3
-rwxr-xr-xt/t1011-read-tree-sparse-checkout.sh96
-rwxr-xr-xt/t1012-read-tree-df.sh9
-rwxr-xr-xt/t1013-loose-object-format.sh66
-rw-r--r--t/t1013/objects/14/9cedb5c46929d18e0f118e9fa31927487af3b6bin0 -> 117 bytes
-rw-r--r--t/t1013/objects/16/56f9233d999f61ef23ef390b9c71d75399f435bin0 -> 17 bytes
-rw-r--r--t/t1013/objects/1e/72a6b2c4a577ab0338860fa9fe87f761fc9bbdbin0 -> 18 bytes
-rw-r--r--t/t1013/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99bin0 -> 19 bytes
-rw-r--r--t/t1013/objects/2e/65efe2a145dda7ee51d1741299f848e5bf752ebin0 -> 10 bytes
-rw-r--r--t/t1013/objects/6b/aee0540ea990d9761a3eb9ab183003a71c3696bin0 -> 181 bytes
-rw-r--r--t/t1013/objects/70/e6a83d8dcb26fc8bc0cf702e2ddeb6adca18fdbin0 -> 26 bytes
-rw-r--r--t/t1013/objects/76/e7fa9941f4d5f97f64fea65a2cba436bc79cbb2
-rw-r--r--t/t1013/objects/78/75c6237d3fcdd0ac2f0decc7d3fa6a50b66c09bin0 -> 139 bytes
-rw-r--r--t/t1013/objects/7a/37b887a73791d12d26c0d3e39568a8fb0fa6e8bin0 -> 54 bytes
-rw-r--r--t/t1013/objects/85/df50785d62d3b05ab03d9cbf7e4a0b49449730bin0 -> 13 bytes
-rw-r--r--t/t1013/objects/8d/4e360d6c70fbd72411991c02a09c442cf7a9fabin0 -> 156 bytes
-rw-r--r--t/t1013/objects/95/b1625de3ba8b2214d1e0d0591138aea733f64fbin0 -> 252 bytes
-rw-r--r--t/t1013/objects/9a/e9e86b7bd6cb1472d9373702d8249973da0832bin0 -> 11 bytes
-rw-r--r--t/t1013/objects/bd/15045f6ce8ff75747562173640456a394412c8bin0 -> 34 bytes
-rw-r--r--t/t1013/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391bin0 -> 9 bytes
-rw-r--r--t/t1013/objects/f8/16d5255855ac160652ee5253b06cd8ee14165a1
-rwxr-xr-xt/t1020-subdirectory.sh44
-rwxr-xr-xt/t1021-rerere-in-workdir.sh55
-rwxr-xr-xt/t1050-large.sh27
-rwxr-xr-xt/t1200-tutorial.sh7
-rwxr-xr-xt/t1300-repo-config.sh273
-rwxr-xr-xt/t1303-wacky-config.sh2
-rwxr-xr-xt/t1304-default-acl.sh5
-rwxr-xr-xt/t1400-update-ref.sh2
-rwxr-xr-xt/t1402-check-ref-format.sh143
-rwxr-xr-xt/t1411-reflog-show.sh18
-rwxr-xr-xt/t1412-reflog-loop.sh8
-rwxr-xr-xt/t1450-fsck.sh36
-rwxr-xr-xt/t1501-worktree.sh7
-rwxr-xr-xt/t1506-rev-parse-diagnosis.sh20
-rwxr-xr-xt/t1510-repo-setup.sh2
-rwxr-xr-xt/t2011-checkout-invalid-head.sh2
-rwxr-xr-xt/t2018-checkout-branch.sh28
-rwxr-xr-xt/t2019-checkout-ambiguous-ref.sh59
-rwxr-xr-xt/t2020-checkout-detach.sh154
-rwxr-xr-xt/t2021-checkout-overwrite.sh50
-rwxr-xr-xt/t2022-checkout-paths.sh42
-rwxr-xr-xt/t2200-add-update.sh26
-rwxr-xr-xt/t2201-add-update-typechange.sh2
-rwxr-xr-xt/t2204-add-ignored.sh37
-rwxr-xr-xt/t3000-ls-files-others.sh19
-rwxr-xr-xt/t3005-ls-files-relative.sh72
-rwxr-xr-xt/t3030-merge-recursive.sh13
-rwxr-xr-xt/t3032-merge-recursive-options.sh14
-rwxr-xr-xt/t3102-ls-tree-wildcards.sh22
-rwxr-xr-xt/t3103-ls-tree-misc.sh24
-rwxr-xr-xt/t3200-branch.sh111
-rwxr-xr-xt/t3203-branch-output.sh30
-rwxr-xr-xt/t3301-notes.sh142
-rwxr-xr-xt/t3306-notes-prune.sh3
-rwxr-xr-xt/t3307-notes-man.sh6
-rwxr-xr-xt/t3400-rebase.sh27
-rwxr-xr-xt/t3403-rebase-skip.sh5
-rwxr-xr-xt/t3404-rebase-interactive.sh18
-rwxr-xr-xt/t3407-rebase-abort.sh10
-rwxr-xr-xt/t3409-rebase-preserve-merges.sh58
-rwxr-xr-xt/t3411-rebase-preserve-around-merges.sh2
-rwxr-xr-xt/t3418-rebase-continue.sh55
-rwxr-xr-xt/t3501-revert-cherry-pick.sh2
-rwxr-xr-xt/t3503-cherry-pick-root.sh54
-rwxr-xr-xt/t3507-cherry-pick-conflict.sh167
-rwxr-xr-xt/t3509-cherry-pick-merge-df.sh6
-rwxr-xr-xt/t3510-cherry-pick-sequence.sh214
-rwxr-xr-xt/t3600-rm.sh3
-rwxr-xr-xt/t3700-add.sh17
-rwxr-xr-xt/t3701-add-interactive.sh41
-rwxr-xr-xt/t3703-add-magic-pathspec.sh58
-rwxr-xr-xt/t3900-i18n-commit.sh4
-rwxr-xr-xt/t3902-quoted.sh2
-rwxr-xr-xt/t3903-stash.sh67
-rwxr-xr-xt/t3904-stash-patch.sh12
-rwxr-xr-xt/t3905-stash-include-untracked.sh175
-rwxr-xr-xt/t4001-diff-rename.sh31
-rwxr-xr-xt/t4002-diff-basic.sh5
-rwxr-xr-xt/t4003-diff-rename-1.sh2
-rwxr-xr-xt/t4004-diff-rename-symlink.sh2
-rwxr-xr-xt/t4005-diff-rename-2.sh2
-rwxr-xr-xt/t4008-diff-break-rewrite.sh4
-rwxr-xr-xt/t4009-diff-rename-4.sh2
-rwxr-xr-xt/t4010-diff-pathspec.sh32
-rwxr-xr-xt/t4012-diff-binary.sh2
-rwxr-xr-xt/t4013-diff-various.sh41
-rw-r--r--t/t4013/diff.diff_--cached38
-rw-r--r--t/t4013/diff.diff_--cached_--_file015
-rw-r--r--t/t4013/diff.diff_--dirstat-by-file_initial_rearrange3
-rw-r--r--t/t4013/diff.diff_--dirstat_initial_rearrange3
-rw-r--r--t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^2
-rw-r--r--t/t4013/diff.log_--decorate=full_--all6
-rw-r--r--t/t4013/diff.log_--decorate_--all6
-rw-r--r--t/t4013/diff.log_-SF_master_--max-count=02
-rw-r--r--t/t4013/diff.log_-SF_master_--max-count=17
-rw-r--r--t/t4013/diff.log_-SF_master_--max-count=27
-rwxr-xr-xt/t4014-format-patch.sh205
-rwxr-xr-xt/t4018-diff-funcname.sh161
-rwxr-xr-xt/t4020-diff-external.sh2
-rwxr-xr-xt/t4022-diff-rewrite.sh43
-rwxr-xr-xt/t4027-diff-submodule.sh1
-rwxr-xr-xt/t4031-diff-rewrite-binary.sh7
-rwxr-xr-xt/t4033-diff-patience.sh162
-rwxr-xr-xt/t4034-diff-words.sh462
-rw-r--r--t/t4034/bibtex/expect15
-rw-r--r--t/t4034/bibtex/post10
-rw-r--r--t/t4034/bibtex/pre9
-rw-r--r--t/t4034/cpp/expect36
-rw-r--r--t/t4034/cpp/post19
-rw-r--r--t/t4034/cpp/pre19
-rw-r--r--t/t4034/csharp/expect35
-rw-r--r--t/t4034/csharp/post18
-rw-r--r--t/t4034/csharp/pre18
-rw-r--r--t/t4034/fortran/expect10
-rw-r--r--t/t4034/fortran/post5
-rw-r--r--t/t4034/fortran/pre5
-rw-r--r--t/t4034/html/expect8
-rw-r--r--t/t4034/html/post3
-rw-r--r--t/t4034/html/pre3
-rw-r--r--t/t4034/java/expect36
-rw-r--r--t/t4034/java/post19
-rw-r--r--t/t4034/java/pre19
-rw-r--r--t/t4034/objc/expect35
-rw-r--r--t/t4034/objc/post18
-rw-r--r--t/t4034/objc/pre18
-rw-r--r--t/t4034/pascal/expect35
-rw-r--r--t/t4034/pascal/post18
-rw-r--r--t/t4034/pascal/pre18
-rw-r--r--t/t4034/perl/expect13
-rw-r--r--t/t4034/perl/post22
-rw-r--r--t/t4034/perl/pre22
-rw-r--r--t/t4034/php/expect35
-rw-r--r--t/t4034/php/post18
-rw-r--r--t/t4034/php/pre18
-rw-r--r--t/t4034/python/expect34
-rw-r--r--t/t4034/python/post17
-rw-r--r--t/t4034/python/pre17
-rw-r--r--t/t4034/ruby/expect34
-rw-r--r--t/t4034/ruby/post17
-rw-r--r--t/t4034/ruby/pre17
-rw-r--r--t/t4034/tex/expect9
-rw-r--r--t/t4034/tex/post4
-rw-r--r--t/t4034/tex/pre4
-rwxr-xr-xt/t4040-whitespace-status.sh12
-rwxr-xr-xt/t4046-diff-unmerged.sh87
-rwxr-xr-xt/t4047-diff-dirstat.sh979
-rwxr-xr-xt/t4048-diff-combined-binary.sh212
-rwxr-xr-xt/t4049-diff-stat-count.sh25
-rwxr-xr-xt/t4050-diff-histogram.sh12
-rwxr-xr-xt/t4051-diff-function-context.sh92
-rwxr-xr-xt/t4120-apply-popt.sh9
-rwxr-xr-xt/t4150-am.sh20
-rwxr-xr-xt/t4151-am-abort.sh5
-rwxr-xr-xt/t4152-am-subjects.sh77
-rwxr-xr-xt/t4202-log.sh53
-rwxr-xr-xt/t4203-mailmap.sh2
-rwxr-xr-xt/t4204-patch-id.sh36
-rwxr-xr-xt/t4205-log-pretty-formats.sh2
-rwxr-xr-xt/t4208-log-magic-pathspec.sh36
-rwxr-xr-xt/t4254-am-corrupt.sh43
-rwxr-xr-xt/t5000-tar-tree.sh100
-rwxr-xr-xt/t5001-archive-attr.sh9
-rwxr-xr-xt/t5302-pack-index.sh23
-rwxr-xr-xt/t5304-prune.sh3
-rwxr-xr-xt/t5400-send-pack.sh4
-rwxr-xr-xt/t5403-post-checkout-hook.sh46
-rwxr-xr-xt/t5501-fetch-push-alternates.sh66
-rwxr-xr-xt/t5504-fetch-receive-strict.sh104
-rwxr-xr-xt/t5505-remote.sh131
-rwxr-xr-xt/t5506-remote-groups.sh6
-rwxr-xr-xt/t5509-fetch-push-namespaces.sh85
-rwxr-xr-xt/t5510-fetch.sh50
-rwxr-xr-xt/t5512-ls-remote.sh24
-rwxr-xr-xt/t5516-fetch-push.sh207
-rwxr-xr-xt/t5520-pull.sh11
-rwxr-xr-xt/t5526-fetch-submodules.sh292
-rwxr-xr-xt/t5531-deep-submodule-push.sh87
-rwxr-xr-xt/t5532-fetch-proxy.sh43
-rwxr-xr-xt/t5540-http-push.sh8
-rwxr-xr-xt/t5541-http-push.sh27
-rwxr-xr-xt/t5550-http-fetch.sh53
-rwxr-xr-xt/t5601-clone.sh60
-rwxr-xr-xt/t5701-clone-local.sh13
-rwxr-xr-xt/t5707-clone-detached.sh76
-rwxr-xr-xt/t5708-clone-config.sh40
-rwxr-xr-xt/t5800-remote-helpers.sh93
-rwxr-xr-xt/t6000-rev-list-misc.sh51
-rwxr-xr-xt/t6004-rev-list-path-optim.sh69
-rwxr-xr-xt/t6007-rev-list-cherry-pick-file.sh140
-rwxr-xr-xt/t6009-rev-list-parent.sh118
-rwxr-xr-xt/t6010-merge-base.sh50
-rwxr-xr-xt/t6017-rev-list-stdin.sh17
-rwxr-xr-xt/t6018-rev-list-glob.sh50
-rwxr-xr-xt/t6019-rev-list-ancestry-path.sh38
-rwxr-xr-xt/t6020-merge-df.sh26
-rwxr-xr-xt/t6022-merge-rename.sh291
-rwxr-xr-xt/t6023-merge-file.sh2
-rwxr-xr-xt/t6027-merge-binary.sh2
-rwxr-xr-xt/t6030-bisect-porcelain.sh175
-rwxr-xr-xt/t6035-merge-dir-to-symlink.sh14
-rwxr-xr-xt/t6036-recursive-corner-cases.sh598
-rwxr-xr-xt/t6040-tracking-info.sh48
-rwxr-xr-xt/t6042-merge-rename-corner-cases.sh578
-rwxr-xr-xt/t6050-replace.sh18
-rwxr-xr-xt/t6060-merge-index.sh100
-rwxr-xr-xt/t6110-rev-list-sparse.sh20
-rwxr-xr-xt/t6120-describe.sh2
-rwxr-xr-xt/t6300-for-each-ref.sh101
-rwxr-xr-xt/t7004-tag.sh39
-rwxr-xr-xt/t7006-pager.sh102
-rwxr-xr-xt/t7008-grep-binary.sh4
-rwxr-xr-xt/t7011-skip-worktree-reading.sh4
-rwxr-xr-xt/t7012-skip-worktree-writing.sh6
-rwxr-xr-xt/t7060-wtstatus.sh66
-rwxr-xr-xt/t7102-reset.sh17
-rwxr-xr-xt/t7106-reset-sequence.sh44
-rwxr-xr-xt/t7110-reset-merge.sh6
-rwxr-xr-xt/t7201-co.sh20
-rwxr-xr-xt/t7300-clean.sh13
-rwxr-xr-xt/t7400-submodule-basic.sh30
-rwxr-xr-xt/t7401-submodule-summary.sh12
-rwxr-xr-xt/t7403-submodule-sync.sh22
-rwxr-xr-xt/t7405-submodule-merge.sh109
-rwxr-xr-xt/t7406-submodule-update.sh408
-rwxr-xr-xt/t7407-submodule-foreach.sh129
-rwxr-xr-xt/t7408-submodule-reference.sh4
-rwxr-xr-xt/t7500-commit.sh35
-rwxr-xr-xt/t7500/add-whitespaced-content8
-rwxr-xr-xt/t7501-commit.sh29
-rwxr-xr-xt/t7502-commit.sh56
-rwxr-xr-xt/t7503-pre-commit-hook.sh33
-rwxr-xr-xt/t7505-prepare-commit-msg-hook.sh12
-rwxr-xr-xt/t7506-status-submodule.sh120
-rwxr-xr-xt/t7508-status.sh297
-rwxr-xr-xt/t7509-commit.sh29
-rwxr-xr-xt/t7511-status-index.sh50
-rwxr-xr-xt/t7600-merge.sh260
-rwxr-xr-xt/t7602-merge-octopus-many.sh6
-rwxr-xr-xt/t7607-merge-overwrite.sh29
-rwxr-xr-xt/t7609-merge-co-error-msgs.sh5
-rwxr-xr-xt/t7610-mergetool.sh352
-rwxr-xr-xt/t7611-merge-abort.sh10
-rwxr-xr-xt/t7800-difftool.sh46
-rwxr-xr-xt/t7810-grep.sh307
-rwxr-xr-xt/t7811-grep-open.sh2
-rwxr-xr-xt/t8001-annotate.sh11
-rwxr-xr-xt/t8002-blame.sh2
-rwxr-xr-xt/t8006-blame-textconv.sh3
-rwxr-xr-xt/t8008-blame-formats.sh90
-rwxr-xr-xt/t9001-send-email.sh29
-rwxr-xr-xt/t9010-svn-fe.sh811
-rwxr-xr-xt/t9116-git-svn-log.sh15
-rwxr-xr-xt/t9130-git-svn-authors-file.sh1
-rwxr-xr-xt/t9146-git-svn-empty-dirs.sh17
-rwxr-xr-xt/t9158-git-svn-mergeinfo.sh13
-rwxr-xr-xt/t9159-git-svn-no-parent-mergeinfo.sh41
-rwxr-xr-xt/t9160-git-svn-preserve-empty-dirs.sh153
-rwxr-xr-xt/t9161-git-svn-mergeinfo-push.sh104
-rw-r--r--t/t9161/branches.dump374
-rwxr-xr-xt/t9162-git-svn-dcommit-interactive.sh64
-rwxr-xr-xt/t9200-git-cvsexportcommit.sh14
-rwxr-xr-xt/t9300-fast-import.sh484
-rwxr-xr-xt/t9301-fast-import-notes.sh1
-rwxr-xr-xt/t9350-fast-export.sh28
-rwxr-xr-xt/t9500-gitweb-standalone-no-errors.sh157
-rwxr-xr-xt/t9501-gitweb-standalone-http-status.sh1
-rwxr-xr-xt/t9502-gitweb-standalone-parse-output.sh74
-rwxr-xr-xt/t9700-perl-git.sh6
-rwxr-xr-xt/t9700/test.pl14
-rwxr-xr-xt/t9800-git-p4.sh404
-rwxr-xr-xt/t9801-git-p4-branch.sh233
-rwxr-xr-xt/t9802-git-p4-filetype.sh108
-rwxr-xr-xt/t9803-git-shell-metachars.sh64
-rwxr-xr-xt/t9901-git-web--browse.sh63
-rw-r--r--t/test-binary-1.png (renamed from t/test4012.png)bin5660 -> 5660 bytes
-rw-r--r--t/test-binary-2.png (renamed from t/test9200b.png)bin275 -> 275 bytes
-rw-r--r--t/test-lib.sh170
-rw-r--r--t/test9200a.pngbin5660 -> 0 bytes
-rw-r--r--t/valgrind/default.supp6
312 files changed, 16211 insertions, 1824 deletions
diff --git a/t/Makefile b/t/Makefile
index 47cbeb6e68..9046ec9816 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -71,7 +71,7 @@ gitweb-test:
$(MAKE) $(TGITWEB)
valgrind:
- GIT_TEST_OPTS=--valgrind $(MAKE)
+ $(MAKE) GIT_TEST_OPTS="$(GIT_TEST_OPTS) --valgrind"
# Smoke testing targets
-include ../GIT-VERSION-FILE
diff --git a/t/README b/t/README
index 25f7d2d2e3..c85abaffb3 100644
--- a/t/README
+++ b/t/README
@@ -79,6 +79,10 @@ appropriately before running "make".
--debug::
This may help the person who is developing a new test.
It causes the command defined with test_debug to run.
+ The "trash" directory (used to store all temporary data
+ during testing) is not deleted even if there are no
+ failed tests so that you can inspect its contents after
+ the test finished.
--immediate::
This causes the test to immediately exit upon the first
@@ -98,6 +102,13 @@ appropriately before running "make".
not see any output, this option implies --verbose. For
convenience, it also implies --tee.
+ Note that valgrind is run with the option --leak-check=no,
+ as the git process is short-lived and some errors are not
+ interesting. In order to run a single command under the same
+ conditions manually, you should set GIT_VALGRIND to point to
+ the 't/valgrind/' directory and use the commands under
+ 't/valgrind/bin/'.
+
--tee::
In addition to printing the test output to the terminal,
write it to files named 't/test-results/$TEST_NAME.out'.
@@ -190,7 +201,7 @@ we are testing.
If you create files under t/ directory (i.e. here) that is not
the top-level test script, never name the file to match the above
pattern. The Makefile here considers all such files as the
-top-level test script and tries to run all of them. A care is
+top-level test script and tries to run all of them. Care is
especially needed if you are creating a common test library
file, similar to test-lib.sh, because such a library file may
not be suitable for standalone execution.
@@ -274,9 +285,8 @@ Do:
- Check the test coverage for your tests. See the "Test coverage"
below.
- Don't blindly follow test coverage metrics, they're a good way to
- spot if you've missed something. If a new function you added
- doesn't have any coverage you're probably doing something wrong,
+ Don't blindly follow test coverage metrics; if a new function you added
+ doesn't have any coverage, then you're probably doing something wrong,
but having 100% coverage doesn't necessarily mean that you tested
everything.
@@ -328,7 +338,7 @@ Keep in mind:
Skipping tests
--------------
-If you need to skip tests you should do so be using the three-arg form
+If you need to skip tests you should do so by using the three-arg form
of the test_* functions (see the "Test harness library" section
below), e.g.:
@@ -369,7 +379,7 @@ library for your script to use.
- test_expect_success [<prereq>] <message> <script>
- Usually takes two strings as parameter, and evaluates the
+ Usually takes two strings as parameters, and evaluates the
<script>. If it yields success, test is considered
successful. <message> should state what it is testing.
@@ -380,7 +390,7 @@ library for your script to use.
'tree=$(git-write-tree)'
If you supply three parameters the first will be taken to be a
- prerequisite, see the test_set_prereq and test_have_prereq
+ prerequisite; see the test_set_prereq and test_have_prereq
documentation below:
test_expect_success TTY 'git --paginate rev-list uses a pager' \
@@ -420,7 +430,7 @@ library for your script to use.
- test_tick
Make commit and tag names consistent by setting the author and
- committer times to defined stated. Subsequent calls will
+ committer times to defined state. Subsequent calls will
advance the times by a fixed amount.
- test_commit <message> [<filename> [<contents>]]
@@ -436,7 +446,7 @@ library for your script to use.
Merges the given rev using the given message. Like test_commit,
creates a tag and calls test_tick before committing.
- - test_set_prereq SOME_PREREQ
+ - test_set_prereq <prereq>
Set a test prerequisite to be used later with test_have_prereq. The
test-lib will set some prerequisites for you, see the
@@ -446,7 +456,7 @@ library for your script to use.
test_have_prereq directly, or the three argument invocation of
test_expect_success and test_expect_failure.
- - test_have_prereq SOME PREREQ
+ - test_have_prereq <prereq>
Check if we have a prerequisite previously set with
test_set_prereq. The most common use of this directly is to skip
@@ -516,12 +526,13 @@ library for your script to use.
Check whether a file has the length it is expected to.
- - test_path_is_file <file> [<diagnosis>]
- test_path_is_dir <dir> [<diagnosis>]
+ - test_path_is_file <path> [<diagnosis>]
+ test_path_is_dir <path> [<diagnosis>]
test_path_is_missing <path> [<diagnosis>]
- Check whether a file/directory exists or doesn't. <diagnosis> will
- be displayed if the test fails.
+ Check if the named path is a file, if the named path is a
+ directory, or if the named path does not exist, respectively,
+ and fail otherwise, showing the <diagnosis> text.
- test_when_finished <script>
@@ -577,6 +588,11 @@ use these, and "test_set_prereq" for how to define your own.
Test is not run by root user, and an attempt to write to an
unwritable file is expected to fail correctly.
+ - LIBPCRE
+
+ Git was compiled with USE_LIBPCRE=YesPlease. Wrap any tests
+ that use git-grep --perl-regexp or git-grep -P in these.
+
Tips for Writing Tests
----------------------
diff --git a/t/aggregate-results.sh b/t/aggregate-results.sh
index d206b7c4cf..7913e206ed 100755
--- a/t/aggregate-results.sh
+++ b/t/aggregate-results.sh
@@ -1,5 +1,6 @@
#!/bin/sh
+failed_tests=
fixed=0
success=0
failed=0
@@ -18,7 +19,13 @@ do
success)
success=$(($success + $value)) ;;
failed)
- failed=$(($failed + $value)) ;;
+ failed=$(($failed + $value))
+ if test $value != 0
+ then
+ testnum=$(expr "$file" : 'test-results/\(t[0-9]*\)-')
+ failed_tests="$failed_tests $testnum"
+ fi
+ ;;
broken)
broken=$(($broken + $value)) ;;
total)
@@ -27,6 +34,11 @@ do
done <"$file"
done
+if test -n "$failed_tests"
+then
+ printf "\nfailed test(s):$failed_tests\n\n"
+fi
+
printf "%-8s%d\n" fixed $fixed
printf "%-8s%d\n" success $success
printf "%-8s%d\n" failed $failed
diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh
index d34208cc27..c56a77d237 100644
--- a/t/annotate-tests.sh
+++ b/t/annotate-tests.sh
@@ -1,5 +1,5 @@
# This file isn't used as a test script directly, instead it is
-# sourced from t8001-annotate.sh and t8001-blame.sh.
+# sourced from t8001-annotate.sh and t8002-blame.sh.
check_count () {
head=
@@ -124,3 +124,14 @@ test_expect_success \
test_expect_success \
'some edit' \
'check_count A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1'
+
+test_expect_success \
+ 'an obfuscated email added' \
+ 'echo "No robots allowed" > file.new &&
+ cat file >> file.new &&
+ mv file.new file &&
+ GIT_AUTHOR_NAME="E" GIT_AUTHOR_EMAIL="E at test dot git" git commit -a -m "norobots"'
+
+test_expect_success \
+ 'obfuscated email parsed' \
+ 'check_count A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1'
diff --git a/t/gitweb-lib.sh b/t/gitweb-lib.sh
index b9bb95feaa..21d11d6c2d 100644
--- a/t/gitweb-lib.sh
+++ b/t/gitweb-lib.sh
@@ -16,6 +16,7 @@ our \$projectroot = "$safe_pwd";
our \$project_maxdepth = 8;
our \$home_link_str = 'projects';
our \$site_name = '[localhost]';
+our \$site_html_head_string = '';
our \$site_header = '';
our \$site_footer = '';
our \$home_text = 'indextext.html';
@@ -82,7 +83,12 @@ gitweb_run () {
}
close O;
' gitweb.output &&
- if grep '^[[]' gitweb.log >/dev/null 2>&1; then false; else true; fi
+ if grep '^[[]' gitweb.log >/dev/null 2>&1; then
+ test_debug 'cat gitweb.log >&2' &&
+ false
+ else
+ true
+ fi
# gitweb.log is left for debugging
# gitweb.output is used to parse HTTP output
@@ -102,4 +108,9 @@ perl -MEncode -e '$e="";decode_utf8($e, Encode::FB_CROAK)' >/dev/null 2>&1 || {
test_done
}
+perl -MCGI -MCGI::Util -MCGI::Carp -e 0 >/dev/null 2>&1 || {
+ skip_all='skipping gitweb tests, CGI module unusable'
+ test_done
+}
+
gitweb_init
diff --git a/t/lib-diff-alternative.sh b/t/lib-diff-alternative.sh
new file mode 100644
index 0000000000..75ffd9174f
--- /dev/null
+++ b/t/lib-diff-alternative.sh
@@ -0,0 +1,165 @@
+#!/bin/sh
+
+test_diff_frobnitz() {
+ cat >file1 <<\EOF
+#include <stdio.h>
+
+// Frobs foo heartily
+int frobnitz(int foo)
+{
+ int i;
+ for(i = 0; i < 10; i++)
+ {
+ printf("Your answer is: ");
+ printf("%d\n", foo);
+ }
+}
+
+int fact(int n)
+{
+ if(n > 1)
+ {
+ return fact(n-1) * n;
+ }
+ return 1;
+}
+
+int main(int argc, char **argv)
+{
+ frobnitz(fact(10));
+}
+EOF
+
+ cat >file2 <<\EOF
+#include <stdio.h>
+
+int fib(int n)
+{
+ if(n > 2)
+ {
+ return fib(n-1) + fib(n-2);
+ }
+ return 1;
+}
+
+// Frobs foo heartily
+int frobnitz(int foo)
+{
+ int i;
+ for(i = 0; i < 10; i++)
+ {
+ printf("%d\n", foo);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ frobnitz(fib(10));
+}
+EOF
+
+ cat >expect <<\EOF
+diff --git a/file1 b/file2
+index 6faa5a3..e3af329 100644
+--- a/file1
++++ b/file2
+@@ -1,26 +1,25 @@
+ #include <stdio.h>
+
++int fib(int n)
++{
++ if(n > 2)
++ {
++ return fib(n-1) + fib(n-2);
++ }
++ return 1;
++}
++
+ // Frobs foo heartily
+ int frobnitz(int foo)
+ {
+ int i;
+ for(i = 0; i < 10; i++)
+ {
+- printf("Your answer is: ");
+ printf("%d\n", foo);
+ }
+ }
+
+-int fact(int n)
+-{
+- if(n > 1)
+- {
+- return fact(n-1) * n;
+- }
+- return 1;
+-}
+-
+ int main(int argc, char **argv)
+ {
+- frobnitz(fact(10));
++ frobnitz(fib(10));
+ }
+EOF
+
+ STRATEGY=$1
+
+ test_expect_success "$STRATEGY diff" '
+ test_must_fail git diff --no-index "--$STRATEGY" file1 file2 > output &&
+ test_cmp expect output
+ '
+
+ test_expect_success "$STRATEGY diff output is valid" '
+ mv file2 expect &&
+ git apply < output &&
+ test_cmp expect file2
+ '
+}
+
+test_diff_unique() {
+ cat >uniq1 <<\EOF
+1
+2
+3
+4
+5
+6
+EOF
+
+ cat >uniq2 <<\EOF
+a
+b
+c
+d
+e
+f
+EOF
+
+ cat >expect <<\EOF
+diff --git a/uniq1 b/uniq2
+index b414108..0fdf397 100644
+--- a/uniq1
++++ b/uniq2
+@@ -1,6 +1,6 @@
+-1
+-2
+-3
+-4
+-5
+-6
++a
++b
++c
++d
++e
++f
+EOF
+
+ STRATEGY=$1
+
+ test_expect_success 'completely different files' '
+ test_must_fail git diff --no-index "--$STRATEGY" uniq1 uniq2 > output &&
+ test_cmp expect output
+ '
+}
+
diff --git a/t/lib-git-p4.sh b/t/lib-git-p4.sh
new file mode 100644
index 0000000000..a870f9a5d2
--- /dev/null
+++ b/t/lib-git-p4.sh
@@ -0,0 +1,74 @@
+#
+# Library code for git-p4 tests
+#
+
+. ./test-lib.sh
+
+if ! test_have_prereq PYTHON; then
+ skip_all='skipping git-p4 tests; python not available'
+ test_done
+fi
+( p4 -h && p4d -h ) >/dev/null 2>&1 || {
+ skip_all='skipping git-p4 tests; no p4 or p4d'
+ test_done
+}
+
+GITP4="$GIT_BUILD_DIR/contrib/fast-import/git-p4"
+
+# Try to pick a unique port: guess a large number, then hope
+# no more than one of each test is running.
+#
+# This does not handle the case where somebody else is running the
+# same tests and has chosen the same ports.
+testid=${this_test#t}
+git_p4_test_start=9800
+P4DPORT=$((10669 + ($testid - $git_p4_test_start)))
+
+export P4PORT=localhost:$P4DPORT
+export P4CLIENT=client
+
+db="$TRASH_DIRECTORY/db"
+cli="$TRASH_DIRECTORY/cli"
+git="$TRASH_DIRECTORY/git"
+pidfile="$TRASH_DIRECTORY/p4d.pid"
+
+start_p4d() {
+ mkdir -p "$db" "$cli" "$git" &&
+ (
+ p4d -q -r "$db" -p $P4DPORT &
+ echo $! >"$pidfile"
+ ) &&
+ for i in 1 2 3 4 5 ; do
+ p4 info >/dev/null 2>&1 && break || true &&
+ echo waiting for p4d to start &&
+ sleep 1
+ done &&
+ # complain if it never started
+ p4 info >/dev/null &&
+ (
+ cd "$cli" &&
+ p4 client -i <<-EOF
+ Client: client
+ Description: client
+ Root: $cli
+ View: //depot/... //client/...
+ EOF
+ )
+}
+
+kill_p4d() {
+ pid=$(cat "$pidfile")
+ # it had better exist for the first kill
+ kill $pid &&
+ for i in 1 2 3 4 5 ; do
+ kill $pid >/dev/null 2>&1 || break
+ sleep 1
+ done &&
+ # complain if it would not die
+ test_must_fail kill $pid >/dev/null 2>&1 &&
+ rm -rf "$db" "$cli" "$pidfile"
+}
+
+cleanup_git() {
+ rm -rf "$git"
+}
diff --git a/t/lib-gpg.sh b/t/lib-gpg.sh
new file mode 100755
index 0000000000..05824fa8e4
--- /dev/null
+++ b/t/lib-gpg.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+gpg_version=`gpg --version 2>&1`
+if test $? = 127; then
+ say "You do not seem to have gpg installed"
+else
+ # As said here: http://www.gnupg.org/documentation/faqs.html#q6.19
+ # the gpg version 1.0.6 didn't parse trust packets correctly, so for
+ # that version, creation of signed tags using the generated key fails.
+ case "$gpg_version" in
+ 'gpg (GnuPG) 1.0.6'*)
+ say "Your version of gpg (1.0.6) is too buggy for testing"
+ ;;
+ *)
+ # key generation info: gpg --homedir t/lib-gpg --gen-key
+ # Type DSA and Elgamal, size 2048 bits, no expiration date.
+ # Name and email: C O Mitter <committer@example.com>
+ # No password given, to enable non-interactive operation.
+ cp -R "$TEST_DIRECTORY"/lib-gpg ./gpghome
+ chmod 0700 gpghome
+ GNUPGHOME="$(pwd)/gpghome"
+ export GNUPGHOME
+ test_set_prereq GPG
+ ;;
+ esac
+fi
+
+sanitize_pgp() {
+ perl -ne '
+ /^-----END PGP/ and $in_pgp = 0;
+ print unless $in_pgp;
+ /^-----BEGIN PGP/ and $in_pgp = 1;
+ '
+}
diff --git a/t/t7004/pubring.gpg b/t/lib-gpg/pubring.gpg
index 83855fa4e1..83855fa4e1 100644
--- a/t/t7004/pubring.gpg
+++ b/t/lib-gpg/pubring.gpg
Binary files differ
diff --git a/t/t7004/random_seed b/t/lib-gpg/random_seed
index 8fed1339ed..8fed1339ed 100644
--- a/t/t7004/random_seed
+++ b/t/lib-gpg/random_seed
Binary files differ
diff --git a/t/t7004/secring.gpg b/t/lib-gpg/secring.gpg
index d831cd9eb3..d831cd9eb3 100644
--- a/t/t7004/secring.gpg
+++ b/t/lib-gpg/secring.gpg
Binary files differ
diff --git a/t/t7004/trustdb.gpg b/t/lib-gpg/trustdb.gpg
index abace962b8..abace962b8 100644
--- a/t/t7004/trustdb.gpg
+++ b/t/lib-gpg/trustdb.gpg
Binary files differ
diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
index 3f24384371..f7dc0781d5 100644
--- a/t/lib-httpd.sh
+++ b/t/lib-httpd.sh
@@ -81,8 +81,7 @@ prepare_httpd() {
if test -n "$LIB_HTTPD_SSL"
then
- HTTPD_URL=https://127.0.0.1:$LIB_HTTPD_PORT
- AUTH_HTTPD_URL=https://user%40host:user%40host@127.0.0.1:$LIB_HTTPD_PORT
+ HTTPD_PROTO=https
RANDFILE_PATH="$HTTPD_ROOT_PATH"/.rnd openssl req \
-config "$TEST_PATH/ssl.cnf" \
@@ -93,9 +92,12 @@ prepare_httpd() {
export GIT_SSL_NO_VERIFY
HTTPD_PARA="$HTTPD_PARA -DSSL"
else
- HTTPD_URL=http://127.0.0.1:$LIB_HTTPD_PORT
- AUTH_HTTPD_URL=http://user%40host:user%40host@127.0.0.1:$LIB_HTTPD_PORT
+ HTTPD_PROTO=http
fi
+ HTTPD_DEST=127.0.0.1:$LIB_HTTPD_PORT
+ HTTPD_URL=$HTTPD_PROTO://$HTTPD_DEST
+ HTTPD_URL_USER=$HTTPD_PROTO://user%40host@$HTTPD_DEST
+ HTTPD_URL_USER_PASS=$HTTPD_PROTO://user%40host:user%40host@$HTTPD_DEST
if test -n "$LIB_HTTPD_DAV" -o -n "$LIB_HTTPD_SVN"
then
@@ -158,7 +160,6 @@ test_http_push_nonff() {
'
test_expect_success 'non-fast-forward push shows help message' '
- grep "To prevent you from losing history, non-fast-forward updates were rejected" \
- output
+ test_i18ngrep "To prevent you from losing history, non-fast-forward updates were rejected" output
'
}
diff --git a/t/lib-read-tree.sh b/t/lib-read-tree.sh
new file mode 100644
index 0000000000..abc2c6f57f
--- /dev/null
+++ b/t/lib-read-tree.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+#
+# Helper functions to check if read-tree would succeed/fail as expected with
+# and without the dry-run option. They also test that the dry-run does not
+# write the index and that together with -u it doesn't touch the work tree.
+#
+read_tree_must_succeed () {
+ git ls-files -s >pre-dry-run &&
+ git read-tree -n "$@" &&
+ git ls-files -s >post-dry-run &&
+ test_cmp pre-dry-run post-dry-run &&
+ git read-tree "$@"
+}
+
+read_tree_must_fail () {
+ git ls-files -s >pre-dry-run &&
+ test_must_fail git read-tree -n "$@" &&
+ git ls-files -s >post-dry-run &&
+ test_cmp pre-dry-run post-dry-run &&
+ test_must_fail git read-tree "$@"
+}
+
+read_tree_u_must_succeed () {
+ git ls-files -s >pre-dry-run &&
+ git diff-files -p >pre-dry-run-wt &&
+ git read-tree -n "$@" &&
+ git ls-files -s >post-dry-run &&
+ git diff-files -p >post-dry-run-wt &&
+ test_cmp pre-dry-run post-dry-run &&
+ test_cmp pre-dry-run-wt post-dry-run-wt &&
+ git read-tree "$@"
+}
+
+read_tree_u_must_fail () {
+ git ls-files -s >pre-dry-run &&
+ git diff-files -p >pre-dry-run-wt &&
+ test_must_fail git read-tree -n "$@" &&
+ git ls-files -s >post-dry-run &&
+ git diff-files -p >post-dry-run-wt &&
+ test_cmp pre-dry-run post-dry-run &&
+ test_cmp pre-dry-run-wt post-dry-run-wt &&
+ test_must_fail git read-tree "$@"
+}
diff --git a/t/lib-terminal.sh b/t/lib-terminal.sh
index c383b57ed9..58d911d21b 100644
--- a/t/lib-terminal.sh
+++ b/t/lib-terminal.sh
@@ -1,8 +1,24 @@
#!/bin/sh
-test_expect_success 'set up terminal for tests' '
- if
- test_have_prereq PERL &&
+test_expect_success PERL 'set up terminal for tests' '
+ # Reading from the pty master seems to get stuck _sometimes_
+ # on Mac OS X 10.5.0, using Perl 5.10.0 or 5.8.9.
+ #
+ # Reproduction recipe: run
+ #
+ # i=0
+ # while ./test-terminal.perl echo hi $i
+ # do
+ # : $((i = $i + 1))
+ # done
+ #
+ # After 2000 iterations or so it hangs.
+ # https://rt.cpan.org/Ticket/Display.html?id=65692
+ #
+ if test "$(uname -s)" = Darwin
+ then
+ :
+ elif
"$PERL_PATH" "$TEST_DIRECTORY"/test-terminal.perl \
sh -c "test -t 1 && test -t 2"
then
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 8deec75c3a..f4e8f43bae 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -435,7 +435,7 @@ test_expect_success 'update-index D/F conflict' '
test $numpath0 = 1
'
-test_expect_success SYMLINKS 'absolute path works as expected' '
+test_expect_success SYMLINKS 'real path works as expected' '
mkdir first &&
ln -s ../.git first/.git &&
mkdir second &&
@@ -443,14 +443,14 @@ test_expect_success SYMLINKS 'absolute path works as expected' '
mkdir third &&
dir="$(cd .git; pwd -P)" &&
dir2=third/../second/other/.git &&
- test "$dir" = "$(test-path-utils make_absolute_path $dir2)" &&
+ test "$dir" = "$(test-path-utils real_path $dir2)" &&
file="$dir"/index &&
- test "$file" = "$(test-path-utils make_absolute_path $dir2/index)" &&
+ test "$file" = "$(test-path-utils real_path $dir2/index)" &&
basename=blub &&
- test "$dir/$basename" = "$(cd .git && test-path-utils make_absolute_path "$basename")" &&
+ test "$dir/$basename" = "$(cd .git && test-path-utils real_path "$basename")" &&
ln -s ../first/file .git/syml &&
sym="$(cd first; pwd -P)"/file &&
- test "$sym" = "$(test-path-utils make_absolute_path "$dir2/syml")"
+ test "$sym" = "$(test-path-utils real_path "$dir2/syml")"
'
test_expect_success 'very long name in the index handled sanely' '
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index f684993211..ad66410564 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -47,7 +47,7 @@ test_expect_success 'plain nested in bare' '
test_expect_success 'plain through aliased command, outside any git repo' '
(
- sane_unset GIT_DIR GIT_WORK_TREE GIT_CONFIG_NOGLOBAL &&
+ sane_unset GIT_DIR GIT_WORK_TREE &&
HOME=$(pwd)/alias-config &&
export HOME &&
mkdir alias-config &&
@@ -190,11 +190,11 @@ test_expect_success 'reinit' '
git init >out1 2>err1 &&
git init >out2 2>err2
) &&
- grep "Initialized empty" again/out1 &&
- grep "Reinitialized existing" again/out2 &&
+ test_i18ngrep "Initialized empty" again/out1 &&
+ test_i18ngrep "Reinitialized existing" again/out2 &&
>again/empty &&
- test_cmp again/empty again/err1 &&
- test_cmp again/empty again/err2
+ test_i18ncmp again/empty again/err1 &&
+ test_i18ncmp again/empty again/err2
'
test_expect_success 'init with --template' '
@@ -231,7 +231,6 @@ test_expect_success 'init with init.templatedir set' '
git config -f "$test_config" init.templatedir "${HOME}/templatedir-source" &&
mkdir templatedir-set &&
cd templatedir-set &&
- sane_unset GIT_CONFIG_NOGLOBAL &&
sane_unset GIT_TEMPLATE_DIR &&
NO_SET_GIT_TEMPLATE_DIR=t &&
export NO_SET_GIT_TEMPLATE_DIR &&
@@ -243,7 +242,6 @@ test_expect_success 'init with init.templatedir set' '
test_expect_success 'init --bare/--shared overrides system/global config' '
(
test_config="$HOME"/.gitconfig &&
- sane_unset GIT_CONFIG_NOGLOBAL &&
git config -f "$test_config" core.bare false &&
git config -f "$test_config" core.sharedRepository 0640 &&
mkdir init-bare-shared-override &&
@@ -258,7 +256,6 @@ test_expect_success 'init --bare/--shared overrides system/global config' '
test_expect_success 'init honors global core.sharedRepository' '
(
test_config="$HOME"/.gitconfig &&
- sane_unset GIT_CONFIG_NOGLOBAL &&
git config -f "$test_config" core.sharedRepository 0666 &&
mkdir shared-honor-global &&
cd shared-honor-global &&
@@ -374,4 +371,50 @@ test_expect_success 'init prefers command line to GIT_DIR' '
! test -d otherdir/refs
'
+test_expect_success 'init with separate gitdir' '
+ rm -rf newdir &&
+ git init --separate-git-dir realgitdir newdir &&
+ echo "gitdir: `pwd`/realgitdir" >expected &&
+ test_cmp expected newdir/.git &&
+ test -d realgitdir/refs
+'
+
+test_expect_success 're-init to update git link' '
+ (
+ cd newdir &&
+ git init --separate-git-dir ../surrealgitdir
+ ) &&
+ echo "gitdir: `pwd`/surrealgitdir" >expected &&
+ test_cmp expected newdir/.git &&
+ test -d surrealgitdir/refs &&
+ ! test -d realgitdir/refs
+'
+
+test_expect_success 're-init to move gitdir' '
+ rm -rf newdir realgitdir surrealgitdir &&
+ git init newdir &&
+ (
+ cd newdir &&
+ git init --separate-git-dir ../realgitdir
+ ) &&
+ echo "gitdir: `pwd`/realgitdir" >expected &&
+ test_cmp expected newdir/.git &&
+ test -d realgitdir/refs
+'
+
+test_expect_success SYMLINKS 're-init to move gitdir symlink' '
+ rm -rf newdir realgitdir &&
+ git init newdir &&
+ (
+ cd newdir &&
+ mv .git here &&
+ ln -s here .git &&
+ git init --separate-git-dir ../realgitdir
+ ) &&
+ echo "gitdir: `pwd`/realgitdir" >expected &&
+ test_cmp expected newdir/.git &&
+ test -d realgitdir/refs &&
+ ! test -d newdir/here
+'
+
test_done
diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
index ebbc7554a7..dbb2623d93 100755
--- a/t/t0003-attributes.sh
+++ b/t/t0003-attributes.sh
@@ -5,20 +5,17 @@ test_description=gitattributes
. ./test-lib.sh
attr_check () {
+ path="$1" expect="$2"
- path="$1"
- expect="$2"
-
- git check-attr test -- "$path" >actual &&
+ git $3 check-attr test -- "$path" >actual 2>err &&
echo "$path: test: $2" >expect &&
- test_cmp expect actual
-
+ test_cmp expect actual &&
+ test_line_count = 0 err
}
test_expect_success 'setup' '
-
- mkdir -p a/b/d a/c &&
+ mkdir -p a/b/d a/c b &&
(
echo "[attr]notest !test"
echo "f test=f"
@@ -26,6 +23,7 @@ test_expect_success 'setup' '
echo "onoff test -test"
echo "offon -test test"
echo "no notest"
+ echo "A/e/F test=A/e/F"
) >.gitattributes &&
(
echo "g test=a/g" &&
@@ -35,15 +33,43 @@ test_expect_success 'setup' '
echo "h test=a/b/h" &&
echo "d/* test=a/b/d/*"
echo "d/yes notest"
- ) >a/b/.gitattributes
+ ) >a/b/.gitattributes &&
(
echo "global test=global"
- ) >"$HOME"/global-gitattributes
+ ) >"$HOME"/global-gitattributes &&
+ cat <<-EOF >expect-all
+ f: test: f
+ a/f: test: f
+ a/c/f: test: f
+ a/g: test: a/g
+ a/b/g: test: a/b/g
+ b/g: test: unspecified
+ a/b/h: test: a/b/h
+ a/b/d/g: test: a/b/d/*
+ onoff: test: unset
+ offon: test: set
+ no: notest: set
+ no: test: unspecified
+ a/b/d/no: notest: set
+ a/b/d/no: test: a/b/d/*
+ a/b/d/yes: notest: set
+ a/b/d/yes: test: unspecified
+ EOF
+'
+test_expect_success 'command line checks' '
+ test_must_fail git check-attr &&
+ test_must_fail git check-attr -- &&
+ test_must_fail git check-attr test &&
+ test_must_fail git check-attr test -- &&
+ test_must_fail git check-attr -- f &&
+ echo "f" | test_must_fail git check-attr --stdin &&
+ echo "f" | test_must_fail git check-attr --stdin -- f &&
+ echo "f" | test_must_fail git check-attr --stdin test -- f &&
+ test_must_fail git check-attr "" -- f
'
test_expect_success 'attribute test' '
-
attr_check f f &&
attr_check a/f f &&
attr_check a/c/f f &&
@@ -57,7 +83,80 @@ test_expect_success 'attribute test' '
attr_check no unspecified &&
attr_check a/b/d/no "a/b/d/*" &&
attr_check a/b/d/yes unspecified
+'
+
+test_expect_success 'attribute matching is case sensitive when core.ignorecase=0' '
+
+ test_must_fail attr_check F f "-c core.ignorecase=0" &&
+ test_must_fail attr_check a/F f "-c core.ignorecase=0" &&
+ test_must_fail attr_check a/c/F f "-c core.ignorecase=0" &&
+ test_must_fail attr_check a/G a/g "-c core.ignorecase=0" &&
+ test_must_fail attr_check a/B/g a/b/g "-c core.ignorecase=0" &&
+ test_must_fail attr_check a/b/G a/b/g "-c core.ignorecase=0" &&
+ test_must_fail attr_check a/b/H a/b/h "-c core.ignorecase=0" &&
+ test_must_fail attr_check a/b/D/g "a/b/d/*" "-c core.ignorecase=0" &&
+ test_must_fail attr_check oNoFf unset "-c core.ignorecase=0" &&
+ test_must_fail attr_check oFfOn set "-c core.ignorecase=0" &&
+ attr_check NO unspecified "-c core.ignorecase=0" &&
+ test_must_fail attr_check a/b/D/NO "a/b/d/*" "-c core.ignorecase=0" &&
+ attr_check a/b/d/YES a/b/d/* "-c core.ignorecase=0" &&
+ test_must_fail attr_check a/E/f "A/e/F" "-c core.ignorecase=0"
+
+'
+
+test_expect_success 'attribute matching is case insensitive when core.ignorecase=1' '
+
+ attr_check F f "-c core.ignorecase=1" &&
+ attr_check a/F f "-c core.ignorecase=1" &&
+ attr_check a/c/F f "-c core.ignorecase=1" &&
+ attr_check a/G a/g "-c core.ignorecase=1" &&
+ attr_check a/B/g a/b/g "-c core.ignorecase=1" &&
+ attr_check a/b/G a/b/g "-c core.ignorecase=1" &&
+ attr_check a/b/H a/b/h "-c core.ignorecase=1" &&
+ attr_check a/b/D/g "a/b/d/*" "-c core.ignorecase=1" &&
+ attr_check oNoFf unset "-c core.ignorecase=1" &&
+ attr_check oFfOn set "-c core.ignorecase=1" &&
+ attr_check NO unspecified "-c core.ignorecase=1" &&
+ attr_check a/b/D/NO "a/b/d/*" "-c core.ignorecase=1" &&
+ attr_check a/b/d/YES unspecified "-c core.ignorecase=1" &&
+ attr_check a/E/f "A/e/F" "-c core.ignorecase=1"
+
+'
+
+test_expect_success 'check whether FS is case-insensitive' '
+ mkdir junk &&
+ echo good >junk/CamelCase &&
+ echo bad >junk/camelcase &&
+ if test "$(cat junk/CamelCase)" != good
+ then
+ test_set_prereq CASE_INSENSITIVE_FS
+ fi
+'
+
+test_expect_success CASE_INSENSITIVE_FS 'additional case insensitivity tests' '
+ test_must_fail attr_check a/B/D/g "a/b/d/*" "-c core.ignorecase=0" &&
+ test_must_fail attr_check A/B/D/NO "a/b/d/*" "-c core.ignorecase=0" &&
+ attr_check A/b/h a/b/h "-c core.ignorecase=1" &&
+ attr_check a/B/D/g "a/b/d/*" "-c core.ignorecase=1" &&
+ attr_check A/B/D/NO "a/b/d/*" "-c core.ignorecase=1"
+'
+
+test_expect_success 'unnormalized paths' '
+ attr_check ./f f &&
+ attr_check ./a/g a/g &&
+ attr_check a/./g a/g &&
+ attr_check a/c/../b/g a/b/g
+'
+test_expect_success 'relative paths' '
+ (cd a && attr_check ../f f) &&
+ (cd a && attr_check f f) &&
+ (cd a && attr_check i a/i) &&
+ (cd a && attr_check g a/g) &&
+ (cd a && attr_check b/g a/b/g) &&
+ (cd b && attr_check ../a/f f) &&
+ (cd b && attr_check ../a/g a/g) &&
+ (cd b && attr_check ../a/b/g a/b/g)
'
test_expect_success 'core.attributesfile' '
@@ -66,48 +165,43 @@ test_expect_success 'core.attributesfile' '
attr_check global global &&
git config core.attributesfile "~/global-gitattributes" &&
attr_check global global &&
- echo "global test=precedence" >> .gitattributes &&
+ echo "global test=precedence" >>.gitattributes &&
attr_check global precedence
'
test_expect_success 'attribute test: read paths from stdin' '
-
- cat <<EOF > expect &&
-f: test: f
-a/f: test: f
-a/c/f: test: f
-a/g: test: a/g
-a/b/g: test: a/b/g
-b/g: test: unspecified
-a/b/h: test: a/b/h
-a/b/d/g: test: a/b/d/*
-onoff: test: unset
-offon: test: set
-no: test: unspecified
-a/b/d/no: test: a/b/d/*
-a/b/d/yes: test: unspecified
-EOF
-
- sed -e "s/:.*//" < expect | git check-attr --stdin test > actual &&
+ grep -v notest <expect-all >expect &&
+ sed -e "s/:.*//" <expect | git check-attr --stdin test >actual &&
test_cmp expect actual
'
-test_expect_success 'root subdir attribute test' '
+test_expect_success 'attribute test: --all option' '
+ grep -v unspecified <expect-all | sort >specified-all &&
+ sed -e "s/:.*//" <expect-all | uniq >stdin-all &&
+ git check-attr --stdin --all <stdin-all | sort >actual &&
+ test_cmp specified-all actual
+'
+
+test_expect_success 'attribute test: --cached option' '
+ : >empty &&
+ git check-attr --cached --stdin --all <stdin-all | sort >actual &&
+ test_cmp empty actual &&
+ git add .gitattributes a/.gitattributes a/b/.gitattributes &&
+ git check-attr --cached --stdin --all <stdin-all | sort >actual &&
+ test_cmp specified-all actual
+'
+test_expect_success 'root subdir attribute test' '
attr_check a/i a/i &&
attr_check subdir/a/i unspecified
-
'
test_expect_success 'setup bare' '
-
git clone --bare . bare.git &&
cd bare.git
-
'
test_expect_success 'bare repository: check that .gitattribute is ignored' '
-
(
echo "f test=f"
echo "a/i test=a/i"
@@ -117,11 +211,16 @@ test_expect_success 'bare repository: check that .gitattribute is ignored' '
attr_check a/c/f unspecified &&
attr_check a/i unspecified &&
attr_check subdir/a/i unspecified
+'
+test_expect_success 'bare repository: check that --cached honors index' '
+ GIT_INDEX_FILE=../.git/index \
+ git check-attr --cached --stdin --all <../stdin-all |
+ sort >actual &&
+ test_cmp ../specified-all actual
'
test_expect_success 'bare repository: test info/attributes' '
-
(
echo "f test=f"
echo "a/i test=a/i"
@@ -131,7 +230,6 @@ test_expect_success 'bare repository: test info/attributes' '
attr_check a/c/f f &&
attr_check a/i a/i &&
attr_check subdir/a/i unspecified
-
'
test_done
diff --git a/t/t0006-date.sh b/t/t0006-date.sh
index 1d4d0a5c7d..1d29810a7a 100755
--- a/t/t0006-date.sh
+++ b/t/t0006-date.sh
@@ -25,6 +25,7 @@ check_show 37500000 '1 year, 2 months ago'
check_show 55188000 '1 year, 9 months ago'
check_show 630000000 '20 years ago'
check_show 31449600 '12 months ago'
+check_show 62985600 '2 years ago'
check_parse() {
echo "$1 -> $2" >expect
@@ -39,6 +40,12 @@ check_parse 2008-02 bad
check_parse 2008-02-14 bad
check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 +0000'
check_parse '2008-02-14 20:30:45 -0500' '2008-02-14 20:30:45 -0500'
+check_parse '2008-02-14 20:30:45 -0015' '2008-02-14 20:30:45 -0015'
+check_parse '2008-02-14 20:30:45 -5' '2008-02-14 20:30:45 +0000'
+check_parse '2008-02-14 20:30:45 -5:' '2008-02-14 20:30:45 +0000'
+check_parse '2008-02-14 20:30:45 -05' '2008-02-14 20:30:45 -0500'
+check_parse '2008-02-14 20:30:45 -:30' '2008-02-14 20:30:45 +0000'
+check_parse '2008-02-14 20:30:45 -05:00' '2008-02-14 20:30:45 -0500'
check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 -0500' EST5
check_approxidate() {
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 9078b84ae6..f19e6510d0 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -66,31 +66,48 @@ test_expect_success expanded_in_repo '
echo "\$Id:NoSpaceAtEitherEnd\$"
echo "\$Id: NoTerminatingSymbol"
echo "\$Id: Foreign Commit With Spaces \$"
- echo "\$Id: NoTerminatingSymbolAtEOF"
- } > expanded-keywords &&
+ } >expanded-keywords.0 &&
+
+ {
+ cat expanded-keywords.0 &&
+ printf "\$Id: NoTerminatingSymbolAtEOF"
+ } >expanded-keywords &&
+ cat expanded-keywords >expanded-keywords-crlf &&
+ git add expanded-keywords expanded-keywords-crlf &&
+ git commit -m "File with keywords expanded" &&
+ id=$(git rev-parse --verify :expanded-keywords) &&
{
echo "File with expanded keywords"
- echo "\$Id: fd0478f5f1486f3d5177d4c3f6eb2765e8fc56b9 \$"
- echo "\$Id: fd0478f5f1486f3d5177d4c3f6eb2765e8fc56b9 \$"
- echo "\$Id: fd0478f5f1486f3d5177d4c3f6eb2765e8fc56b9 \$"
- echo "\$Id: fd0478f5f1486f3d5177d4c3f6eb2765e8fc56b9 \$"
- echo "\$Id: fd0478f5f1486f3d5177d4c3f6eb2765e8fc56b9 \$"
- echo "\$Id: fd0478f5f1486f3d5177d4c3f6eb2765e8fc56b9 \$"
+ echo "\$Id: $id \$"
+ echo "\$Id: $id \$"
+ echo "\$Id: $id \$"
+ echo "\$Id: $id \$"
+ echo "\$Id: $id \$"
+ echo "\$Id: $id \$"
echo "\$Id: NoTerminatingSymbol"
echo "\$Id: Foreign Commit With Spaces \$"
- echo "\$Id: NoTerminatingSymbolAtEOF"
- } > expected-output &&
-
- git add expanded-keywords &&
- git commit -m "File with keywords expanded" &&
+ } >expected-output.0 &&
+ {
+ cat expected-output.0 &&
+ printf "\$Id: NoTerminatingSymbolAtEOF"
+ } >expected-output &&
+ {
+ append_cr <expected-output.0 &&
+ printf "\$Id: NoTerminatingSymbolAtEOF"
+ } >expected-output-crlf &&
+ {
+ echo "expanded-keywords ident"
+ echo "expanded-keywords-crlf ident text eol=crlf"
+ } >>.gitattributes &&
- echo "expanded-keywords ident" >> .gitattributes &&
+ rm -f expanded-keywords expanded-keywords-crlf &&
- rm -f expanded-keywords &&
git checkout -- expanded-keywords &&
- cat expanded-keywords &&
- cmp expanded-keywords expected-output
+ test_cmp expanded-keywords expected-output &&
+
+ git checkout -- expanded-keywords-crlf &&
+ test_cmp expanded-keywords-crlf expected-output-crlf
'
# The use of %f in a filter definition is expanded to the path to
diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index 20924506af..a1e4616feb 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -19,7 +19,7 @@ usage: test-parse-options <options>
--set23 set integer to 23
-t <time> get timestamp of <time>
-L, --length <str> get length of <str>
- -F, --file <FILE> set file to <FILE>
+ -F, --file <file> set file to <file>
String options
-s, --string <string>
@@ -28,6 +28,7 @@ String options
--st <st> get another string (pervert ordering)
-o <str> get another string
--default-string set string to default
+ --list <str> add str to list
Magic arguments
--quux means --quux
@@ -86,7 +87,7 @@ EOF
test_expect_success 'long options' '
test-parse-options --boolean --integer 1729 --boolean --string2=321 \
--verbose --verbose --no-dry-run --abbrev=10 --file fi.le\
- > output 2> output.err &&
+ --obsolete > output 2> output.err &&
test ! -s output.err &&
test_cmp expect output
'
@@ -337,4 +338,20 @@ test_expect_success 'negation of OPT_NONEG flags is not ambiguous' '
test_cmp expect output
'
+cat >>expect <<'EOF'
+list: foo
+list: bar
+list: baz
+EOF
+test_expect_success '--list keeps list of strings' '
+ test-parse-options --list foo --list=bar --list=baz >output &&
+ test_cmp expect output
+'
+
+test_expect_success '--no-list resets list' '
+ test-parse-options --list=other --list=irrelevant --list=options \
+ --no-list --list=foo --list=bar --list=baz >output &&
+ test_cmp expect output
+'
+
test_done
diff --git a/t/t0061-run-command.sh b/t/t0061-run-command.sh
index 10b26e4d8e..8d4938f019 100755
--- a/t/t0061-run-command.sh
+++ b/t/t0061-run-command.sh
@@ -7,8 +7,31 @@ test_description='Test run command'
. ./test-lib.sh
+cat >hello-script <<-EOF
+ #!$SHELL_PATH
+ cat hello-script
+EOF
+>empty
+
test_expect_success 'start_command reports ENOENT' '
test-run-command start-command-ENOENT ./does-not-exist
'
+test_expect_success 'run_command can run a command' '
+ cat hello-script >hello.sh &&
+ chmod +x hello.sh &&
+ test-run-command run-command ./hello.sh >actual 2>err &&
+
+ test_cmp hello-script actual &&
+ test_cmp empty err
+'
+
+test_expect_success POSIXPERM 'run_command reports EACCES' '
+ cat hello-script >hello.sh &&
+ chmod -x hello.sh &&
+ test_must_fail test-run-command run-command ./hello.sh 2>err &&
+
+ grep "fatal: cannot exec.*hello.sh" err
+'
+
test_done
diff --git a/t/t0070-fundamental.sh b/t/t0070-fundamental.sh
index 680d7d6861..9bee8bfd2e 100755
--- a/t/t0070-fundamental.sh
+++ b/t/t0070-fundamental.sh
@@ -12,4 +12,17 @@ test_expect_success 'character classes (isspace, isalpha etc.)' '
test-ctype
'
+test_expect_success 'mktemp to nonexistent directory prints filename' '
+ test_must_fail test-mktemp doesnotexist/testXXXXXX 2>err &&
+ grep "doesnotexist/test" err
+'
+
+test_expect_success POSIXPERM 'mktemp to unwritable directory prints filename' '
+ mkdir cannotwrite &&
+ chmod -w cannotwrite &&
+ test_when_finished "chmod +w cannotwrite" &&
+ test_must_fail test-mktemp cannotwrite/testXXXXXX 2>err &&
+ grep "cannotwrite/test" err
+'
+
test_done
diff --git a/t/t0080-vcs-svn.sh b/t/t0080-vcs-svn.sh
index d3225ada68..99a314b080 100755
--- a/t/t0080-vcs-svn.sh
+++ b/t/t0080-vcs-svn.sh
@@ -76,60 +76,6 @@ test_expect_success 'obj pool: high-water mark' '
test_cmp expected actual
'
-test_expect_success 'line buffer' '
- echo HELLO >expected1 &&
- printf "%s\n" "" HELLO >expected2 &&
- echo >expected3 &&
- printf "%s\n" "" Q | q_to_nul >expected4 &&
- printf "%s\n" foo "" >expected5 &&
- printf "%s\n" "" foo >expected6 &&
-
- test-line-buffer <<-\EOF >actual1 &&
- 5
- HELLO
- EOF
-
- test-line-buffer <<-\EOF >actual2 &&
- 0
-
- 5
- HELLO
- EOF
-
- q_to_nul <<-\EOF |
- 1
- Q
- EOF
- test-line-buffer >actual3 &&
-
- q_to_nul <<-\EOF |
- 0
-
- 1
- Q
- EOF
- test-line-buffer >actual4 &&
-
- test-line-buffer <<-\EOF >actual5 &&
- 5
- foo
- EOF
-
- test-line-buffer <<-\EOF >actual6 &&
- 0
-
- 5
- foo
- EOF
-
- test_cmp expected1 actual1 &&
- test_cmp expected2 actual2 &&
- test_cmp expected3 actual3 &&
- test_cmp expected4 actual4 &&
- test_cmp expected5 actual5 &&
- test_cmp expected6 actual6
-'
-
test_expect_success 'string pool' '
echo a does not equal b >expected.differ &&
echo a equals a >expected.match &&
diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
new file mode 100755
index 0000000000..bd83ed371a
--- /dev/null
+++ b/t/t0081-line-buffer.sh
@@ -0,0 +1,90 @@
+#!/bin/sh
+
+test_description="Test the svn importer's input handling routines.
+
+These tests provide some simple checks that the line_buffer API
+behaves as advertised.
+
+While at it, check that input of newlines and null bytes are handled
+correctly.
+"
+. ./test-lib.sh
+
+test_expect_success 'hello world' '
+ echo ">HELLO" >expect &&
+ test-line-buffer <<-\EOF >actual &&
+ binary 6
+ HELLO
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success '0-length read, send along greeting' '
+ echo ">HELLO" >expect &&
+ test-line-buffer <<-\EOF >actual &&
+ binary 0
+ copy 6
+ HELLO
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'read from file descriptor' '
+ rm -f input &&
+ echo hello >expect &&
+ echo hello >input &&
+ echo copy 6 |
+ test-line-buffer "&4" 4<input >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'skip, copy null byte' '
+ echo Q | q_to_nul >expect &&
+ q_to_nul <<-\EOF | test-line-buffer >actual &&
+ skip 2
+ Q
+ copy 2
+ Q
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'read null byte' '
+ echo ">QhelloQ" | q_to_nul >expect &&
+ q_to_nul <<-\EOF | test-line-buffer >actual &&
+ binary 8
+ QhelloQ
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'long reads are truncated' '
+ echo ">foo" >expect &&
+ test-line-buffer <<-\EOF >actual &&
+ binary 5
+ foo
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'long copies are truncated' '
+ printf "%s\n" ">" foo >expect &&
+ test-line-buffer <<-\EOF >actual &&
+ binary 1
+
+ copy 5
+ foo
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'long binary reads are truncated' '
+ echo ">foo" >expect &&
+ test-line-buffer <<-\EOF >actual &&
+ binary 5
+ foo
+ EOF
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t0201-gettext-fallbacks.sh b/t/t0201-gettext-fallbacks.sh
new file mode 100755
index 0000000000..54d98b9b10
--- /dev/null
+++ b/t/t0201-gettext-fallbacks.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 Ævar Arnfjörð Bjarmason
+#
+
+test_description='Gettext Shell fallbacks'
+
+. ./test-lib.sh
+. "$GIT_BUILD_DIR"/git-sh-i18n
+
+test_expect_success 'gettext: our gettext() fallback has pass-through semantics' '
+ printf "test" >expect &&
+ gettext "test" >actual &&
+ test_i18ncmp expect actual &&
+ printf "test more words" >expect &&
+ gettext "test more words" >actual &&
+ test_i18ncmp expect actual
+'
+
+test_expect_success 'eval_gettext: our eval_gettext() fallback has pass-through semantics' '
+ printf "test" >expect &&
+ eval_gettext "test" >actual &&
+ test_i18ncmp expect actual &&
+ printf "test more words" >expect &&
+ eval_gettext "test more words" >actual &&
+ test_i18ncmp expect actual
+'
+
+test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables' '
+ printf "test YesPlease" >expect &&
+ GIT_INTERNAL_GETTEXT_TEST_FALLBACKS=YesPlease eval_gettext "test \$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS" >actual &&
+ test_i18ncmp expect actual
+'
+
+test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces' '
+ cmdline="git am" &&
+ export cmdline;
+ printf "When you have resolved this problem run git am --resolved." >expect &&
+ eval_gettext "When you have resolved this problem run \$cmdline --resolved." >actual
+ test_i18ncmp expect actual
+'
+
+test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces and quotes' '
+ cmdline="git am" &&
+ export cmdline;
+ printf "When you have resolved this problem run \"git am --resolved\"." >expect &&
+ eval_gettext "When you have resolved this problem run \"\$cmdline --resolved\"." >actual
+ test_i18ncmp expect actual
+'
+
+test_done
diff --git a/t/t1000-read-tree-m-3way.sh b/t/t1000-read-tree-m-3way.sh
index ca8a4098fa..babcdd2343 100755
--- a/t/t1000-read-tree-m-3way.sh
+++ b/t/t1000-read-tree-m-3way.sh
@@ -72,6 +72,7 @@ In addition:
'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-read-tree.sh
. "$TEST_DIRECTORY"/lib-read-tree-m-3way.sh
################################################################
@@ -137,7 +138,7 @@ test_expect_success \
'3-way merge with git read-tree -m, empty cache' \
"rm -fr [NDMALTS][NDMALTSF] Z &&
rm .git/index &&
- git read-tree -m $tree_O $tree_A $tree_B &&
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B &&
check_result"
# This starts out with the first head, which is the normal
@@ -146,9 +147,9 @@ test_expect_success \
'3-way merge with git read-tree -m, match H' \
"rm -fr [NDMALTS][NDMALTSF] Z &&
rm .git/index &&
- git read-tree $tree_A &&
+ read_tree_must_succeed $tree_A &&
git checkout-index -f -u -a &&
- git read-tree -m $tree_O $tree_A $tree_B &&
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B &&
check_result"
: <<\END_OF_CASE_TABLE
@@ -211,7 +212,7 @@ test_expect_success '1 - must not have an entry not in A.' "
rm -f .git/index XX &&
echo XX >XX &&
git update-index --add XX &&
- test_must_fail git read-tree -m $tree_O $tree_A $tree_B
+ read_tree_must_fail -m $tree_O $tree_A $tree_B
"
test_expect_success \
@@ -219,7 +220,7 @@ test_expect_success \
"rm -f .git/index NA &&
cp .orig-B/NA NA &&
git update-index --add NA &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B"
test_expect_success \
'2 - matching B alone is OK in !O && !A && B case.' \
@@ -227,14 +228,14 @@ test_expect_success \
cp .orig-B/NA NA &&
git update-index --add NA &&
echo extra >>NA &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B"
test_expect_success \
'3 - must match A in !O && A && !B case.' \
"rm -f .git/index AN &&
cp .orig-A/AN AN &&
git update-index --add AN &&
- git read-tree -m $tree_O $tree_A $tree_B &&
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
@@ -243,7 +244,7 @@ test_expect_success \
cp .orig-A/AN AN &&
git update-index --add AN &&
echo extra >>AN &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B"
test_expect_success \
'3 (fail) - must match A in !O && A && !B case.' "
@@ -251,7 +252,7 @@ test_expect_success \
cp .orig-A/AN AN &&
echo extra >>AN &&
git update-index --add AN &&
- test_must_fail git read-tree -m $tree_O $tree_A $tree_B
+ read_tree_must_fail -m $tree_O $tree_A $tree_B
"
test_expect_success \
@@ -259,7 +260,7 @@ test_expect_success \
"rm -f .git/index AA &&
cp .orig-A/AA AA &&
git update-index --add AA &&
- git read-tree -m $tree_O $tree_A $tree_B &&
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
@@ -268,7 +269,7 @@ test_expect_success \
cp .orig-A/AA AA &&
git update-index --add AA &&
echo extra >>AA &&
- test_must_fail git read-tree -m $tree_O $tree_A $tree_B
+ read_tree_must_fail -m $tree_O $tree_A $tree_B
"
test_expect_success \
@@ -277,7 +278,7 @@ test_expect_success \
cp .orig-A/AA AA &&
echo extra >>AA &&
git update-index --add AA &&
- test_must_fail git read-tree -m $tree_O $tree_A $tree_B
+ read_tree_must_fail -m $tree_O $tree_A $tree_B
"
test_expect_success \
@@ -285,7 +286,7 @@ test_expect_success \
"rm -f .git/index LL &&
cp .orig-A/LL LL &&
git update-index --add LL &&
- git read-tree -m $tree_O $tree_A $tree_B &&
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
@@ -294,7 +295,7 @@ test_expect_success \
cp .orig-A/LL LL &&
git update-index --add LL &&
echo extra >>LL &&
- git read-tree -m $tree_O $tree_A $tree_B &&
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
@@ -303,7 +304,7 @@ test_expect_success \
cp .orig-A/LL LL &&
echo extra >>LL &&
git update-index --add LL &&
- test_must_fail git read-tree -m $tree_O $tree_A $tree_B
+ read_tree_must_fail -m $tree_O $tree_A $tree_B
"
test_expect_success \
@@ -311,7 +312,7 @@ test_expect_success \
rm -f .git/index DD &&
echo DD >DD &&
git update-index --add DD &&
- test_must_fail git read-tree -m $tree_O $tree_A $tree_B
+ read_tree_must_fail -m $tree_O $tree_A $tree_B
"
test_expect_success \
@@ -319,7 +320,7 @@ test_expect_success \
rm -f .git/index DM &&
cp .orig-B/DM DM &&
git update-index --add DM &&
- test_must_fail git read-tree -m $tree_O $tree_A $tree_B
+ read_tree_must_fail -m $tree_O $tree_A $tree_B
"
test_expect_success \
@@ -327,7 +328,7 @@ test_expect_success \
rm -f .git/index DN &&
cp .orig-B/DN DN &&
git update-index --add DN &&
- test_must_fail git read-tree -m $tree_O $tree_A $tree_B
+ read_tree_must_fail -m $tree_O $tree_A $tree_B
"
test_expect_success \
@@ -335,7 +336,7 @@ test_expect_success \
"rm -f .git/index MD &&
cp .orig-A/MD MD &&
git update-index --add MD &&
- git read-tree -m $tree_O $tree_A $tree_B &&
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
@@ -344,7 +345,7 @@ test_expect_success \
cp .orig-A/MD MD &&
git update-index --add MD &&
echo extra >>MD &&
- test_must_fail git read-tree -m $tree_O $tree_A $tree_B
+ read_tree_must_fail -m $tree_O $tree_A $tree_B
"
test_expect_success \
@@ -353,7 +354,7 @@ test_expect_success \
cp .orig-A/MD MD &&
echo extra >>MD &&
git update-index --add MD &&
- test_must_fail git read-tree -m $tree_O $tree_A $tree_B
+ read_tree_must_fail -m $tree_O $tree_A $tree_B
"
test_expect_success \
@@ -361,7 +362,7 @@ test_expect_success \
"rm -f .git/index ND &&
cp .orig-A/ND ND &&
git update-index --add ND &&
- git read-tree -m $tree_O $tree_A $tree_B &&
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
@@ -370,7 +371,7 @@ test_expect_success \
cp .orig-A/ND ND &&
git update-index --add ND &&
echo extra >>ND &&
- test_must_fail git read-tree -m $tree_O $tree_A $tree_B
+ read_tree_must_fail -m $tree_O $tree_A $tree_B
"
test_expect_success \
@@ -379,7 +380,7 @@ test_expect_success \
cp .orig-A/ND ND &&
echo extra >>ND &&
git update-index --add ND &&
- test_must_fail git read-tree -m $tree_O $tree_A $tree_B
+ read_tree_must_fail -m $tree_O $tree_A $tree_B
"
test_expect_success \
@@ -387,7 +388,7 @@ test_expect_success \
"rm -f .git/index MM &&
cp .orig-A/MM MM &&
git update-index --add MM &&
- git read-tree -m $tree_O $tree_A $tree_B &&
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
@@ -396,7 +397,7 @@ test_expect_success \
cp .orig-A/MM MM &&
git update-index --add MM &&
echo extra >>MM &&
- test_must_fail git read-tree -m $tree_O $tree_A $tree_B
+ read_tree_must_fail -m $tree_O $tree_A $tree_B
"
test_expect_success \
@@ -405,7 +406,7 @@ test_expect_success \
cp .orig-A/MM MM &&
echo extra >>MM &&
git update-index --add MM &&
- test_must_fail git read-tree -m $tree_O $tree_A $tree_B
+ read_tree_must_fail -m $tree_O $tree_A $tree_B
"
test_expect_success \
@@ -413,7 +414,7 @@ test_expect_success \
"rm -f .git/index SS &&
cp .orig-A/SS SS &&
git update-index --add SS &&
- git read-tree -m $tree_O $tree_A $tree_B &&
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
@@ -422,7 +423,7 @@ test_expect_success \
cp .orig-A/SS SS &&
git update-index --add SS &&
echo extra >>SS &&
- git read-tree -m $tree_O $tree_A $tree_B &&
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
@@ -431,7 +432,7 @@ test_expect_success \
cp .orig-A/SS SS &&
echo extra >>SS &&
git update-index --add SS &&
- test_must_fail git read-tree -m $tree_O $tree_A $tree_B
+ read_tree_must_fail -m $tree_O $tree_A $tree_B
"
test_expect_success \
@@ -439,7 +440,7 @@ test_expect_success \
"rm -f .git/index MN &&
cp .orig-A/MN MN &&
git update-index --add MN &&
- git read-tree -m $tree_O $tree_A $tree_B &&
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
@@ -448,7 +449,7 @@ test_expect_success \
cp .orig-A/MN MN &&
git update-index --add MN &&
echo extra >>MN &&
- git read-tree -m $tree_O $tree_A $tree_B &&
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
@@ -456,7 +457,7 @@ test_expect_success \
"rm -f .git/index NM &&
cp .orig-A/NM NM &&
git update-index --add NM &&
- git read-tree -m $tree_O $tree_A $tree_B &&
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
@@ -465,7 +466,7 @@ test_expect_success \
cp .orig-B/NM NM &&
git update-index --add NM &&
echo extra >>NM &&
- git read-tree -m $tree_O $tree_A $tree_B &&
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
@@ -474,7 +475,7 @@ test_expect_success \
cp .orig-A/NM NM &&
git update-index --add NM &&
echo extra >>NM &&
- test_must_fail git read-tree -m $tree_O $tree_A $tree_B
+ read_tree_must_fail -m $tree_O $tree_A $tree_B
"
test_expect_success \
@@ -483,7 +484,7 @@ test_expect_success \
cp .orig-A/NM NM &&
echo extra >>NM &&
git update-index --add NM &&
- test_must_fail git read-tree -m $tree_O $tree_A $tree_B
+ read_tree_must_fail -m $tree_O $tree_A $tree_B
"
test_expect_success \
@@ -491,7 +492,7 @@ test_expect_success \
"rm -f .git/index NN &&
cp .orig-A/NN NN &&
git update-index --add NN &&
- git read-tree -m $tree_O $tree_A $tree_B &&
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
@@ -500,7 +501,7 @@ test_expect_success \
cp .orig-A/NN NN &&
git update-index --add NN &&
echo extra >>NN &&
- git read-tree -m $tree_O $tree_A $tree_B &&
+ read_tree_must_succeed -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
@@ -509,7 +510,7 @@ test_expect_success \
cp .orig-A/NN NN &&
echo extra >>NN &&
git update-index --add NN &&
- test_must_fail git read-tree -m $tree_O $tree_A $tree_B
+ read_tree_must_fail -m $tree_O $tree_A $tree_B
"
# #16
@@ -522,7 +523,7 @@ test_expect_success \
echo E16 >F16 &&
git update-index F16 &&
tree1=`git write-tree` &&
- git read-tree -m $tree0 $tree1 $tree1 $tree0 &&
+ read_tree_must_succeed -m $tree0 $tree1 $tree1 $tree0 &&
git ls-files --stage'
test_done
diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh
index 680d992f22..acaab07fac 100755
--- a/t/t1001-read-tree-m-2way.sh
+++ b/t/t1001-read-tree-m-2way.sh
@@ -21,6 +21,7 @@ In the test, these paths are used:
yomin - not in H nor M
'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-read-tree.sh
read_tree_twoway () {
git read-tree -m "$1" "$2" && git ls-files --stage
@@ -94,7 +95,7 @@ echo '+100644 X 0 yomin' >expected
test_expect_success \
'4 - carry forward local addition.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
git update-index --add yomin &&
read_tree_twoway $treeH $treeM &&
@@ -106,7 +107,7 @@ test_expect_success \
test_expect_success \
'5 - carry forward local addition.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
echo yomin >yomin &&
git update-index --add yomin &&
@@ -120,7 +121,7 @@ test_expect_success \
test_expect_success \
'6 - local addition already has the same.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
git update-index --add frotz &&
read_tree_twoway $treeH $treeM &&
@@ -131,7 +132,7 @@ test_expect_success \
test_expect_success \
'7 - local addition already has the same.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
echo frotz >frotz &&
git update-index --add frotz &&
@@ -144,7 +145,7 @@ test_expect_success \
test_expect_success \
'8 - conflicting addition.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
echo frotz frotz >frotz &&
git update-index --add frotz &&
@@ -153,7 +154,7 @@ test_expect_success \
test_expect_success \
'9 - conflicting addition.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
echo frotz frotz >frotz &&
git update-index --add frotz &&
@@ -163,7 +164,7 @@ test_expect_success \
test_expect_success \
'10 - path removed.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
echo rezrov >rezrov &&
git update-index --add rezrov &&
@@ -174,7 +175,7 @@ test_expect_success \
test_expect_success \
'11 - dirty path removed.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
echo rezrov >rezrov &&
git update-index --add rezrov &&
@@ -184,7 +185,7 @@ test_expect_success \
test_expect_success \
'12 - unmatching local changes being removed.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
echo rezrov rezrov >rezrov &&
git update-index --add rezrov &&
@@ -193,7 +194,7 @@ test_expect_success \
test_expect_success \
'13 - unmatching local changes being removed.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
echo rezrov rezrov >rezrov &&
git update-index --add rezrov &&
@@ -208,7 +209,7 @@ EOF
test_expect_success \
'14 - unchanged in two heads.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
echo nitfol nitfol >nitfol &&
git update-index --add nitfol &&
@@ -221,7 +222,7 @@ test_expect_success \
test_expect_success \
'15 - unchanged in two heads.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
echo nitfol nitfol >nitfol &&
git update-index --add nitfol &&
@@ -235,7 +236,7 @@ test_expect_success \
test_expect_success \
'16 - conflicting local change.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
echo bozbar bozbar >bozbar &&
git update-index --add bozbar &&
@@ -244,7 +245,7 @@ test_expect_success \
test_expect_success \
'17 - conflicting local change.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
echo bozbar bozbar >bozbar &&
git update-index --add bozbar &&
@@ -254,7 +255,7 @@ test_expect_success \
test_expect_success \
'18 - local change already having a good result.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
cat bozbar-new >bozbar &&
git update-index --add bozbar &&
@@ -266,7 +267,7 @@ test_expect_success \
test_expect_success \
'19 - local change already having a good result, further modified.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
cat bozbar-new >bozbar &&
git update-index --add bozbar &&
@@ -279,7 +280,7 @@ test_expect_success \
test_expect_success \
'20 - no local change, use new tree.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
cat bozbar-old >bozbar &&
git update-index --add bozbar &&
@@ -291,7 +292,7 @@ test_expect_success \
test_expect_success \
'21 - no local change, dirty cache.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
cat bozbar-old >bozbar &&
git update-index --add bozbar &&
@@ -302,7 +303,7 @@ test_expect_success \
test_expect_success \
'22 - local change cache updated.' \
'rm -f .git/index &&
- git read-tree $treeH &&
+ read_tree_must_succeed $treeH &&
git checkout-index -u -f -q -a &&
sed -e "s/such as/SUCH AS/" bozbar-old >bozbar &&
git update-index --add bozbar &&
@@ -359,7 +360,7 @@ test_expect_success \
test_expect_success \
'a/b (untracked) vs a, plus c/d case test.' \
- 'test_must_fail git read-tree -u -m "$treeH" "$treeM" &&
+ 'read_tree_u_must_fail -u -m "$treeH" "$treeM" &&
git ls-files --stage &&
test -f a/b'
@@ -386,7 +387,7 @@ test_expect_success \
test_expect_success \
'a/b vs a, plus c/d case test.' \
- 'git read-tree -u -m "$treeH" "$treeM" &&
+ 'read_tree_u_must_succeed -u -m "$treeH" "$treeM" &&
git ls-files --stage | tee >treeMcheck.out &&
test_cmp treeM.out treeMcheck.out'
@@ -401,7 +402,7 @@ test_expect_success '-m references the correct modified tree' '
echo a >file-a &&
git add file-a &&
git ls-tree $(git write-tree) file-a >expect &&
- git read-tree -m HEAD initial-mod &&
+ read_tree_must_succeed -m HEAD initial-mod &&
git ls-tree $(git write-tree) file-a >actual &&
test_cmp expect actual
'
diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh
index a4a17e0017..a847709a13 100755
--- a/t/t1002-read-tree-m-u-2way.sh
+++ b/t/t1002-read-tree-m-u-2way.sh
@@ -9,6 +9,7 @@ This is identical to t1001, but uses -u to update the work tree as well.
'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-read-tree.sh
compare_change () {
sed >current \
@@ -56,8 +57,8 @@ test_expect_success \
test_expect_success \
'1, 2, 3 - no carry forward' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
- git read-tree -m -u $treeH $treeM &&
+ read_tree_u_must_succeed --reset -u $treeH &&
+ read_tree_u_must_succeed -m -u $treeH $treeM &&
git ls-files --stage >1-3.out &&
cmp M.out 1-3.out &&
sum bozbar frotz nitfol >actual3.sum &&
@@ -69,11 +70,11 @@ test_expect_success \
test_expect_success \
'4 - carry forward local addition.' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
+ read_tree_u_must_succeed --reset -u $treeH &&
echo "+100644 X 0 yomin" >expected &&
echo yomin >yomin &&
git update-index --add yomin &&
- git read-tree -m -u $treeH $treeM &&
+ read_tree_u_must_succeed -m -u $treeH $treeM &&
git ls-files --stage >4.out || return 1
git diff -U0 --no-index M.out 4.out >4diff.out
compare_change 4diff.out expected &&
@@ -87,12 +88,12 @@ test_expect_success \
test_expect_success \
'5 - carry forward local addition.' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
- git read-tree -m -u $treeH &&
+ read_tree_u_must_succeed --reset -u $treeH &&
+ read_tree_u_must_succeed -m -u $treeH &&
echo yomin >yomin &&
git update-index --add yomin &&
echo yomin yomin >yomin &&
- git read-tree -m -u $treeH $treeM &&
+ read_tree_u_must_succeed -m -u $treeH $treeM &&
git ls-files --stage >5.out || return 1
git diff -U0 --no-index M.out 5.out >5diff.out
compare_change 5diff.out expected &&
@@ -107,10 +108,10 @@ test_expect_success \
test_expect_success \
'6 - local addition already has the same.' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
+ read_tree_u_must_succeed --reset -u $treeH &&
echo frotz >frotz &&
git update-index --add frotz &&
- git read-tree -m -u $treeH $treeM &&
+ read_tree_u_must_succeed -m -u $treeH $treeM &&
git ls-files --stage >6.out &&
test_cmp M.out 6.out &&
check_cache_at frotz clean &&
@@ -123,11 +124,11 @@ test_expect_success \
test_expect_success \
'7 - local addition already has the same.' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
+ read_tree_u_must_succeed --reset -u $treeH &&
echo frotz >frotz &&
git update-index --add frotz &&
echo frotz frotz >frotz &&
- git read-tree -m -u $treeH $treeM &&
+ read_tree_u_must_succeed -m -u $treeH $treeM &&
git ls-files --stage >7.out &&
test_cmp M.out 7.out &&
check_cache_at frotz dirty &&
@@ -141,27 +142,27 @@ test_expect_success \
test_expect_success \
'8 - conflicting addition.' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
+ read_tree_u_must_succeed --reset -u $treeH &&
echo frotz frotz >frotz &&
git update-index --add frotz &&
- if git read-tree -m -u $treeH $treeM; then false; else :; fi'
+ if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi'
test_expect_success \
'9 - conflicting addition.' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
+ read_tree_u_must_succeed --reset -u $treeH &&
echo frotz frotz >frotz &&
git update-index --add frotz &&
echo frotz >frotz &&
- if git read-tree -m -u $treeH $treeM; then false; else :; fi'
+ if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi'
test_expect_success \
'10 - path removed.' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
+ read_tree_u_must_succeed --reset -u $treeH &&
echo rezrov >rezrov &&
git update-index --add rezrov &&
- git read-tree -m -u $treeH $treeM &&
+ read_tree_u_must_succeed -m -u $treeH $treeM &&
git ls-files --stage >10.out &&
cmp M.out 10.out &&
sum bozbar frotz nitfol >actual10.sum &&
@@ -170,28 +171,28 @@ test_expect_success \
test_expect_success \
'11 - dirty path removed.' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
+ read_tree_u_must_succeed --reset -u $treeH &&
echo rezrov >rezrov &&
git update-index --add rezrov &&
echo rezrov rezrov >rezrov &&
- if git read-tree -m -u $treeH $treeM; then false; else :; fi'
+ if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi'
test_expect_success \
'12 - unmatching local changes being removed.' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
+ read_tree_u_must_succeed --reset -u $treeH &&
echo rezrov rezrov >rezrov &&
git update-index --add rezrov &&
- if git read-tree -m -u $treeH $treeM; then false; else :; fi'
+ if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi'
test_expect_success \
'13 - unmatching local changes being removed.' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
+ read_tree_u_must_succeed --reset -u $treeH &&
echo rezrov rezrov >rezrov &&
git update-index --add rezrov &&
echo rezrov >rezrov &&
- if git read-tree -m -u $treeH $treeM; then false; else :; fi'
+ if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi'
cat >expected <<EOF
-100644 X 0 nitfol
@@ -201,10 +202,10 @@ EOF
test_expect_success \
'14 - unchanged in two heads.' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
+ read_tree_u_must_succeed --reset -u $treeH &&
echo nitfol nitfol >nitfol &&
git update-index --add nitfol &&
- git read-tree -m -u $treeH $treeM &&
+ read_tree_u_must_succeed -m -u $treeH $treeM &&
git ls-files --stage >14.out &&
test_must_fail git diff -U0 --no-index M.out 14.out >14diff.out &&
compare_change 14diff.out expected &&
@@ -221,11 +222,11 @@ test_expect_success \
test_expect_success \
'15 - unchanged in two heads.' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
+ read_tree_u_must_succeed --reset -u $treeH &&
echo nitfol nitfol >nitfol &&
git update-index --add nitfol &&
echo nitfol nitfol nitfol >nitfol &&
- git read-tree -m -u $treeH $treeM &&
+ read_tree_u_must_succeed -m -u $treeH $treeM &&
git ls-files --stage >15.out &&
test_must_fail git diff -U0 --no-index M.out 15.out >15diff.out &&
compare_change 15diff.out expected &&
@@ -242,27 +243,27 @@ test_expect_success \
test_expect_success \
'16 - conflicting local change.' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
+ read_tree_u_must_succeed --reset -u $treeH &&
echo bozbar bozbar >bozbar &&
git update-index --add bozbar &&
- if git read-tree -m -u $treeH $treeM; then false; else :; fi'
+ if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi'
test_expect_success \
'17 - conflicting local change.' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
+ read_tree_u_must_succeed --reset -u $treeH &&
echo bozbar bozbar >bozbar &&
git update-index --add bozbar &&
echo bozbar bozbar bozbar >bozbar &&
- if git read-tree -m -u $treeH $treeM; then false; else :; fi'
+ if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi'
test_expect_success \
'18 - local change already having a good result.' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
+ read_tree_u_must_succeed --reset -u $treeH &&
echo gnusto >bozbar &&
git update-index --add bozbar &&
- git read-tree -m -u $treeH $treeM &&
+ read_tree_u_must_succeed -m -u $treeH $treeM &&
git ls-files --stage >18.out &&
test_cmp M.out 18.out &&
check_cache_at bozbar clean &&
@@ -272,11 +273,11 @@ test_expect_success \
test_expect_success \
'19 - local change already having a good result, further modified.' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
+ read_tree_u_must_succeed --reset -u $treeH &&
echo gnusto >bozbar &&
git update-index --add bozbar &&
echo gnusto gnusto >bozbar &&
- git read-tree -m -u $treeH $treeM &&
+ read_tree_u_must_succeed -m -u $treeH $treeM &&
git ls-files --stage >19.out &&
test_cmp M.out 19.out &&
check_cache_at bozbar dirty &&
@@ -292,10 +293,10 @@ test_expect_success \
test_expect_success \
'20 - no local change, use new tree.' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
+ read_tree_u_must_succeed --reset -u $treeH &&
echo bozbar >bozbar &&
git update-index --add bozbar &&
- git read-tree -m -u $treeH $treeM &&
+ read_tree_u_must_succeed -m -u $treeH $treeM &&
git ls-files --stage >20.out &&
test_cmp M.out 20.out &&
check_cache_at bozbar clean &&
@@ -305,11 +306,11 @@ test_expect_success \
test_expect_success \
'21 - no local change, dirty cache.' \
'rm -f .git/index nitfol bozbar rezrov frotz &&
- git read-tree --reset -u $treeH &&
+ read_tree_u_must_succeed --reset -u $treeH &&
echo bozbar >bozbar &&
git update-index --add bozbar &&
echo gnusto gnusto >bozbar &&
- if git read-tree -m -u $treeH $treeM; then false; else :; fi'
+ if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi'
# Also make sure we did not break DF vs DF/DF case.
test_expect_success \
@@ -336,7 +337,7 @@ test_expect_success \
rm -fr DF &&
echo DF >DF &&
git update-index --add DF &&
- git read-tree -m -u $treeDF $treeDFDF &&
+ read_tree_u_must_succeed -m -u $treeDF $treeDFDF &&
git ls-files --stage >DFDFcheck.out &&
test_cmp DFDF.out DFDFcheck.out &&
check_cache_at DF/DF clean'
diff --git a/t/t1004-read-tree-m-u-wf.sh b/t/t1004-read-tree-m-u-wf.sh
index eb8e3d4476..b3ae7d52c6 100755
--- a/t/t1004-read-tree-m-u-wf.sh
+++ b/t/t1004-read-tree-m-u-wf.sh
@@ -3,6 +3,7 @@
test_description='read-tree -m -u checks working tree files'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-read-tree.sh
# two-tree test
@@ -29,7 +30,7 @@ test_expect_success 'two-way not clobbering' '
echo >file2 master creates untracked file2 &&
echo >subdir/file2 master creates untracked subdir/file2 &&
- if err=`git read-tree -m -u master side 2>&1`
+ if err=`read_tree_u_must_succeed -m -u master side 2>&1`
then
echo should have complained
false
@@ -42,7 +43,7 @@ echo file2 >.gitignore
test_expect_success 'two-way with incorrect --exclude-per-directory (1)' '
- if err=`git read-tree -m --exclude-per-directory=.gitignore master side 2>&1`
+ if err=`read_tree_u_must_succeed -m --exclude-per-directory=.gitignore master side 2>&1`
then
echo should have complained
false
@@ -53,7 +54,7 @@ test_expect_success 'two-way with incorrect --exclude-per-directory (1)' '
test_expect_success 'two-way with incorrect --exclude-per-directory (2)' '
- if err=`git read-tree -m -u --exclude-per-directory=foo --exclude-per-directory=.gitignore master side 2>&1`
+ if err=`read_tree_u_must_succeed -m -u --exclude-per-directory=foo --exclude-per-directory=.gitignore master side 2>&1`
then
echo should have complained
false
@@ -64,7 +65,7 @@ test_expect_success 'two-way with incorrect --exclude-per-directory (2)' '
test_expect_success 'two-way clobbering a ignored file' '
- git read-tree -m -u --exclude-per-directory=.gitignore master side
+ read_tree_u_must_succeed -m -u --exclude-per-directory=.gitignore master side
'
rm -f .gitignore
@@ -84,7 +85,7 @@ test_expect_success 'three-way not complaining on an untracked path in both' '
echo >file2 file two is untracked on the master side &&
echo >subdir/file2 file two is untracked on the master side &&
- git read-tree -m -u branch-point master side
+ read_tree_u_must_succeed -m -u branch-point master side
'
test_expect_success 'three-way not clobbering a working tree file' '
@@ -94,7 +95,7 @@ test_expect_success 'three-way not clobbering a working tree file' '
git checkout master &&
echo >file3 file three created in master, untracked &&
echo >subdir/file3 file three created in master, untracked &&
- if err=`git read-tree -m -u branch-point master side 2>&1`
+ if err=`read_tree_u_must_succeed -m -u branch-point master side 2>&1`
then
echo should have complained
false
@@ -113,7 +114,7 @@ test_expect_success 'three-way not complaining on an untracked file' '
echo >file3 file three created in master, untracked &&
echo >subdir/file3 file three created in master, untracked &&
- git read-tree -m -u --exclude-per-directory=.gitignore branch-point master side
+ read_tree_u_must_succeed -m -u --exclude-per-directory=.gitignore branch-point master side
'
test_expect_success '3-way not overwriting local changes (setup)' '
@@ -137,7 +138,7 @@ test_expect_success '3-way not overwriting local changes (our side)' '
git reset --hard &&
echo >>file1 "local changes" &&
- git read-tree -m -u branch-point side-a side-b &&
+ read_tree_u_must_succeed -m -u branch-point side-a side-b &&
grep "new line to be kept" file1 &&
grep "local changes" file1
@@ -151,7 +152,7 @@ test_expect_success '3-way not overwriting local changes (their side)' '
git reset --hard &&
echo >>file2 "local changes" &&
- test_must_fail git read-tree -m -u branch-point side-a side-b &&
+ read_tree_u_must_fail -m -u branch-point side-a side-b &&
! grep "new line to be kept" file2 &&
grep "local changes" file2
@@ -173,7 +174,7 @@ test_expect_success SYMLINKS 'funny symlink in work tree' '
git add a/b &&
git commit -m "we add a/b" &&
- git read-tree -m -u sym-a sym-a sym-b
+ read_tree_u_must_succeed -m -u sym-a sym-a sym-b
'
@@ -209,7 +210,7 @@ test_expect_success 'D/F setup' '
test_expect_success 'D/F' '
git checkout side-b &&
- git read-tree -m -u branch-point side-b side-a &&
+ read_tree_u_must_succeed -m -u branch-point side-b side-a &&
git ls-files -u >actual &&
(
a=$(git rev-parse branch-point:subdir/file2)
diff --git a/t/t1005-read-tree-reset.sh b/t/t1005-read-tree-reset.sh
index 849911683a..f53de79e56 100755
--- a/t/t1005-read-tree-reset.sh
+++ b/t/t1005-read-tree-reset.sh
@@ -3,6 +3,7 @@
test_description='read-tree -u --reset'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-read-tree.sh
# two-tree test
@@ -22,13 +23,13 @@ test_expect_success 'setup' '
'
test_expect_success 'reset should work' '
- git read-tree -u --reset HEAD^ &&
+ read_tree_u_must_succeed -u --reset HEAD^ &&
git ls-files >actual &&
test_cmp expect actual
'
test_expect_success 'reset should remove remnants from a failed merge' '
- git read-tree --reset -u HEAD &&
+ read_tree_u_must_succeed --reset -u HEAD &&
git ls-files -s >expect &&
sha1=$(git rev-parse :new) &&
(
@@ -37,13 +38,13 @@ test_expect_success 'reset should remove remnants from a failed merge' '
) | git update-index --index-info &&
>old &&
git ls-files -s &&
- git read-tree --reset -u HEAD &&
+ read_tree_u_must_succeed --reset -u HEAD &&
git ls-files -s >actual &&
! test -f old
'
test_expect_success 'Porcelain reset should remove remnants too' '
- git read-tree --reset -u HEAD &&
+ read_tree_u_must_succeed --reset -u HEAD &&
git ls-files -s >expect &&
sha1=$(git rev-parse :new) &&
(
@@ -58,7 +59,7 @@ test_expect_success 'Porcelain reset should remove remnants too' '
'
test_expect_success 'Porcelain checkout -f should remove remnants too' '
- git read-tree --reset -u HEAD &&
+ read_tree_u_must_succeed --reset -u HEAD &&
git ls-files -s >expect &&
sha1=$(git rev-parse :new) &&
(
@@ -73,7 +74,7 @@ test_expect_success 'Porcelain checkout -f should remove remnants too' '
'
test_expect_success 'Porcelain checkout -f HEAD should remove remnants too' '
- git read-tree --reset -u HEAD &&
+ read_tree_u_must_succeed --reset -u HEAD &&
git ls-files -s >expect &&
sha1=$(git rev-parse :new) &&
(
diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh
index dd32432d62..6d52b824b1 100755
--- a/t/t1007-hash-object.sh
+++ b/t/t1007-hash-object.sh
@@ -188,4 +188,17 @@ for args in "-w --stdin-paths" "--stdin-paths -w"; do
pop_repo
done
+test_expect_success 'corrupt tree' '
+ echo abc >malformed-tree
+ test_must_fail git hash-object -t tree malformed-tree
+'
+
+test_expect_success 'corrupt commit' '
+ test_must_fail git hash-object -t commit --stdin </dev/null
+'
+
+test_expect_success 'corrupt tag' '
+ test_must_fail git hash-object -t tag --stdin </dev/null
+'
+
test_done
diff --git a/t/t1008-read-tree-overlay.sh b/t/t1008-read-tree-overlay.sh
index f9e00285db..4c50ed955e 100755
--- a/t/t1008-read-tree-overlay.sh
+++ b/t/t1008-read-tree-overlay.sh
@@ -3,6 +3,7 @@
test_description='test multi-tree read-tree without merging'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-read-tree.sh
test_expect_success setup '
echo one >a &&
@@ -21,7 +22,7 @@ test_expect_success setup '
'
test_expect_success 'multi-read' '
- git read-tree initial master side &&
+ read_tree_must_succeed initial master side &&
(echo a; echo b/c) >expect &&
git ls-files >actual &&
test_cmp expect actual
diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh
index de84e35c43..5c0053a20b 100755
--- a/t/t1011-read-tree-sparse-checkout.sh
+++ b/t/t1011-read-tree-sparse-checkout.sh
@@ -12,24 +12,27 @@ test_description='sparse checkout tests
'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-read-tree.sh
test_expect_success 'setup' '
cat >expected <<-\EOF &&
100644 77f0ba1734ed79d12881f81b36ee134de6a3327b 0 init.t
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 sub/added
+ 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 sub/addedtoo
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 subsub/added
EOF
cat >expected.swt <<-\EOF &&
H init.t
H sub/added
+ H sub/addedtoo
H subsub/added
EOF
test_commit init &&
echo modified >>init.t &&
mkdir sub subsub &&
- touch sub/added subsub/added &&
- git add init.t sub/added subsub/added &&
+ touch sub/added sub/addedtoo subsub/added &&
+ git add init.t sub/added sub/addedtoo subsub/added &&
git commit -m "modified and added" &&
git tag top &&
git rm sub/added &&
@@ -41,7 +44,7 @@ test_expect_success 'setup' '
'
test_expect_success 'read-tree without .git/info/sparse-checkout' '
- git read-tree -m -u HEAD &&
+ read_tree_u_must_succeed -m -u HEAD &&
git ls-files --stage >result &&
test_cmp expected result &&
git ls-files -t >result &&
@@ -50,7 +53,7 @@ test_expect_success 'read-tree without .git/info/sparse-checkout' '
test_expect_success 'read-tree with .git/info/sparse-checkout but disabled' '
echo >.git/info/sparse-checkout &&
- git read-tree -m -u HEAD &&
+ read_tree_u_must_succeed -m -u HEAD &&
git ls-files -t >result &&
test_cmp expected.swt result &&
test -f init.t &&
@@ -60,7 +63,7 @@ test_expect_success 'read-tree with .git/info/sparse-checkout but disabled' '
test_expect_success 'read-tree --no-sparse-checkout with empty .git/info/sparse-checkout and enabled' '
git config core.sparsecheckout true &&
echo >.git/info/sparse-checkout &&
- git read-tree --no-sparse-checkout -m -u HEAD &&
+ read_tree_u_must_succeed --no-sparse-checkout -m -u HEAD &&
git ls-files -t >result &&
test_cmp expected.swt result &&
test -f init.t &&
@@ -70,7 +73,7 @@ test_expect_success 'read-tree --no-sparse-checkout with empty .git/info/sparse-
test_expect_success 'read-tree with empty .git/info/sparse-checkout' '
git config core.sparsecheckout true &&
echo >.git/info/sparse-checkout &&
- test_must_fail git read-tree -m -u HEAD &&
+ read_tree_u_must_fail -m -u HEAD &&
git ls-files --stage >result &&
test_cmp expected result &&
git ls-files -t >result &&
@@ -83,11 +86,12 @@ test_expect_success 'match directories with trailing slash' '
cat >expected.swt-noinit <<-\EOF &&
S init.t
H sub/added
+ H sub/addedtoo
S subsub/added
EOF
echo sub/ > .git/info/sparse-checkout &&
- git read-tree -m -u HEAD &&
+ read_tree_u_must_succeed -m -u HEAD &&
git ls-files -t > result &&
test_cmp expected.swt-noinit result &&
test ! -f init.t &&
@@ -95,18 +99,59 @@ test_expect_success 'match directories with trailing slash' '
'
test_expect_success 'match directories without trailing slash' '
- echo sub >>.git/info/sparse-checkout &&
- git read-tree -m -u HEAD &&
+ echo sub >.git/info/sparse-checkout &&
+ read_tree_u_must_succeed -m -u HEAD &&
git ls-files -t >result &&
test_cmp expected.swt-noinit result &&
test ! -f init.t &&
test -f sub/added
'
-test_expect_success 'match directory pattern' '
- echo "s?b" >>.git/info/sparse-checkout &&
+test_expect_success 'match directories with negated patterns' '
+ cat >expected.swt-negation <<\EOF &&
+S init.t
+S sub/added
+H sub/addedtoo
+S subsub/added
+EOF
+
+ cat >.git/info/sparse-checkout <<\EOF &&
+sub
+!sub/added
+EOF
+ git read-tree -m -u HEAD &&
+ git ls-files -t >result &&
+ test_cmp expected.swt-negation result &&
+ test ! -f init.t &&
+ test ! -f sub/added &&
+ test -f sub/addedtoo
+'
+
+test_expect_success 'match directories with negated patterns (2)' '
+ cat >expected.swt-negation2 <<\EOF &&
+H init.t
+H sub/added
+S sub/addedtoo
+H subsub/added
+EOF
+
+ cat >.git/info/sparse-checkout <<\EOF &&
+/*
+!sub
+sub/added
+EOF
git read-tree -m -u HEAD &&
git ls-files -t >result &&
+ test_cmp expected.swt-negation2 result &&
+ test -f init.t &&
+ test -f sub/added &&
+ test ! -f sub/addedtoo
+'
+
+test_expect_success 'match directory pattern' '
+ echo "s?b" >.git/info/sparse-checkout &&
+ read_tree_u_must_succeed -m -u HEAD &&
+ git ls-files -t >result &&
test_cmp expected.swt-noinit result &&
test ! -f init.t &&
test -f sub/added
@@ -116,11 +161,12 @@ test_expect_success 'checkout area changes' '
cat >expected.swt-nosub <<-\EOF &&
H init.t
S sub/added
+ S sub/addedtoo
S subsub/added
EOF
echo init.t >.git/info/sparse-checkout &&
- git read-tree -m -u HEAD &&
+ read_tree_u_must_succeed -m -u HEAD &&
git ls-files -t >result &&
test_cmp expected.swt-nosub result &&
test -f init.t &&
@@ -130,7 +176,7 @@ test_expect_success 'checkout area changes' '
test_expect_success 'read-tree updates worktree, absent case' '
echo sub/added >.git/info/sparse-checkout &&
git checkout -f top &&
- git read-tree -m -u HEAD^ &&
+ read_tree_u_must_succeed -m -u HEAD^ &&
test ! -f init.t
'
@@ -138,7 +184,7 @@ test_expect_success 'read-tree updates worktree, dirty case' '
echo sub/added >.git/info/sparse-checkout &&
git checkout -f top &&
echo dirty >init.t &&
- git read-tree -m -u HEAD^ &&
+ read_tree_u_must_succeed -m -u HEAD^ &&
grep -q dirty init.t &&
rm init.t
'
@@ -147,14 +193,14 @@ test_expect_success 'read-tree removes worktree, dirty case' '
echo init.t >.git/info/sparse-checkout &&
git checkout -f top &&
echo dirty >added &&
- git read-tree -m -u HEAD^ &&
+ read_tree_u_must_succeed -m -u HEAD^ &&
grep -q dirty added
'
test_expect_success 'read-tree adds to worktree, absent case' '
echo init.t >.git/info/sparse-checkout &&
git checkout -f removed &&
- git read-tree -u -m HEAD^ &&
+ read_tree_u_must_succeed -u -m HEAD^ &&
test ! -f sub/added
'
@@ -163,7 +209,7 @@ test_expect_success 'read-tree adds to worktree, dirty case' '
git checkout -f removed &&
mkdir sub &&
echo dirty >sub/added &&
- git read-tree -u -m HEAD^ &&
+ read_tree_u_must_succeed -u -m HEAD^ &&
grep -q dirty sub/added
'
@@ -188,4 +234,20 @@ test_expect_success 'read-tree --reset removes outside worktree' '
test_cmp empty result
'
+test_expect_success 'print errors when failed to update worktree' '
+ echo sub >.git/info/sparse-checkout &&
+ git checkout -f init &&
+ mkdir sub &&
+ touch sub/added sub/addedtoo &&
+ test_must_fail git checkout top 2>actual &&
+ cat >expected <<\EOF &&
+error: The following untracked working tree files would be overwritten by checkout:
+ sub/added
+ sub/addedtoo
+Please move or remove them before you can switch branches.
+Aborting
+EOF
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t1012-read-tree-df.sh b/t/t1012-read-tree-df.sh
index 9811d467da..a6a04b6b90 100755
--- a/t/t1012-read-tree-df.sh
+++ b/t/t1012-read-tree-df.sh
@@ -3,6 +3,7 @@
test_description='read-tree D/F conflict corner cases'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-read-tree.sh
maketree () {
(
@@ -53,7 +54,7 @@ test_expect_success setup '
test_expect_success '3-way (1)' '
settree A-000 &&
- git read-tree -m -u O-000 A-000 B-000 &&
+ read_tree_u_must_succeed -m -u O-000 A-000 B-000 &&
checkindex <<-EOF
3 a/b
0 a/b-2/c/d
@@ -65,7 +66,7 @@ test_expect_success '3-way (1)' '
test_expect_success '3-way (2)' '
settree A-001 &&
- git read-tree -m -u O-000 A-001 B-000 &&
+ read_tree_u_must_succeed -m -u O-000 A-001 B-000 &&
checkindex <<-EOF
3 a/b
0 a/b-2/c/d
@@ -78,7 +79,7 @@ test_expect_success '3-way (2)' '
test_expect_success '3-way (3)' '
settree A-010 &&
- git read-tree -m -u O-010 A-010 B-010 &&
+ read_tree_u_must_succeed -m -u O-010 A-010 B-010 &&
checkindex <<-EOF
2 t
1 t-0
@@ -92,7 +93,7 @@ test_expect_success '3-way (3)' '
test_expect_success '2-way (1)' '
settree O-020 &&
- git read-tree -m -u O-020 A-020 &&
+ read_tree_u_must_succeed -m -u O-020 A-020 &&
checkindex <<-EOF
0 ds/dma/ioat/Makefile
0 ds/dma/ioat/registers.h
diff --git a/t/t1013-loose-object-format.sh b/t/t1013-loose-object-format.sh
new file mode 100755
index 0000000000..0a9cedd374
--- /dev/null
+++ b/t/t1013-loose-object-format.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+#
+# Copyright (c) 2011 Roberto Tyley
+#
+
+test_description='Correctly identify and parse loose object headers
+
+There are two file formats for loose objects - the original standard
+format, and the experimental format introduced with Git v1.4.3, later
+deprecated with v1.5.3. Although Git no longer writes the
+experimental format, objects in both formats must be read, with the
+format for a given file being determined by the header.
+
+Detecting file format based on header is not entirely trivial, not
+least because the first byte of a zlib-deflated stream will vary
+depending on how much memory was allocated for the deflation window
+buffer when the object was written out (for example 4KB on Android,
+rather that 32KB on a normal PC).
+
+The loose objects used as test vectors have been generated with the
+following Git versions:
+
+standard format: Git v1.7.4.1
+experimental format: Git v1.4.3 (legacyheaders=false)
+standard format, deflated with 4KB window size: Agit/JGit on Android
+'
+
+. ./test-lib.sh
+
+assert_blob_equals() {
+ printf "%s" "$2" >expected &&
+ git cat-file -p "$1" >actual &&
+ test_cmp expected actual
+}
+
+test_expect_success setup '
+ cp -R "$TEST_DIRECTORY/t1013/objects" .git/
+ git --version
+'
+
+test_expect_success 'read standard-format loose objects' '
+ git cat-file tag 8d4e360d6c70fbd72411991c02a09c442cf7a9fa &&
+ git cat-file commit 6baee0540ea990d9761a3eb9ab183003a71c3696 &&
+ git ls-tree 7a37b887a73791d12d26c0d3e39568a8fb0fa6e8 &&
+ assert_blob_equals "257cc5642cb1a054f08cc83f2d943e56fd3ebe99" "foo$LF"
+'
+
+test_expect_success 'read experimental-format loose objects' '
+ git cat-file tag 76e7fa9941f4d5f97f64fea65a2cba436bc79cbb &&
+ git cat-file commit 7875c6237d3fcdd0ac2f0decc7d3fa6a50b66c09 &&
+ git ls-tree 95b1625de3ba8b2214d1e0d0591138aea733f64f &&
+ assert_blob_equals "2e65efe2a145dda7ee51d1741299f848e5bf752e" "a" &&
+ assert_blob_equals "9ae9e86b7bd6cb1472d9373702d8249973da0832" "ab" &&
+ assert_blob_equals "85df50785d62d3b05ab03d9cbf7e4a0b49449730" "abcd" &&
+ assert_blob_equals "1656f9233d999f61ef23ef390b9c71d75399f435" "abcdefgh" &&
+ assert_blob_equals "1e72a6b2c4a577ab0338860fa9fe87f761fc9bbd" "abcdefghi" &&
+ assert_blob_equals "70e6a83d8dcb26fc8bc0cf702e2ddeb6adca18fd" "abcdefghijklmnop" &&
+ assert_blob_equals "bd15045f6ce8ff75747562173640456a394412c8" "abcdefghijklmnopqrstuvwx"
+'
+
+test_expect_success 'read standard-format objects deflated with smaller window buffer' '
+ git cat-file tag f816d5255855ac160652ee5253b06cd8ee14165a &&
+ git cat-file tag 149cedb5c46929d18e0f118e9fa31927487af3b6
+'
+
+test_done
diff --git a/t/t1013/objects/14/9cedb5c46929d18e0f118e9fa31927487af3b6 b/t/t1013/objects/14/9cedb5c46929d18e0f118e9fa31927487af3b6
new file mode 100644
index 0000000000..472fd1458e
--- /dev/null
+++ b/t/t1013/objects/14/9cedb5c46929d18e0f118e9fa31927487af3b6
Binary files differ
diff --git a/t/t1013/objects/16/56f9233d999f61ef23ef390b9c71d75399f435 b/t/t1013/objects/16/56f9233d999f61ef23ef390b9c71d75399f435
new file mode 100644
index 0000000000..c379d74ae2
--- /dev/null
+++ b/t/t1013/objects/16/56f9233d999f61ef23ef390b9c71d75399f435
Binary files differ
diff --git a/t/t1013/objects/1e/72a6b2c4a577ab0338860fa9fe87f761fc9bbd b/t/t1013/objects/1e/72a6b2c4a577ab0338860fa9fe87f761fc9bbd
new file mode 100644
index 0000000000..93706305bc
--- /dev/null
+++ b/t/t1013/objects/1e/72a6b2c4a577ab0338860fa9fe87f761fc9bbd
Binary files differ
diff --git a/t/t1013/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99 b/t/t1013/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99
new file mode 100644
index 0000000000..bdcf704c9e
--- /dev/null
+++ b/t/t1013/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99
Binary files differ
diff --git a/t/t1013/objects/2e/65efe2a145dda7ee51d1741299f848e5bf752e b/t/t1013/objects/2e/65efe2a145dda7ee51d1741299f848e5bf752e
new file mode 100644
index 0000000000..ad62c43e41
--- /dev/null
+++ b/t/t1013/objects/2e/65efe2a145dda7ee51d1741299f848e5bf752e
Binary files differ
diff --git a/t/t1013/objects/6b/aee0540ea990d9761a3eb9ab183003a71c3696 b/t/t1013/objects/6b/aee0540ea990d9761a3eb9ab183003a71c3696
new file mode 100644
index 0000000000..3d2f0337db
--- /dev/null
+++ b/t/t1013/objects/6b/aee0540ea990d9761a3eb9ab183003a71c3696
Binary files differ
diff --git a/t/t1013/objects/70/e6a83d8dcb26fc8bc0cf702e2ddeb6adca18fd b/t/t1013/objects/70/e6a83d8dcb26fc8bc0cf702e2ddeb6adca18fd
new file mode 100644
index 0000000000..b3f71a6ee5
--- /dev/null
+++ b/t/t1013/objects/70/e6a83d8dcb26fc8bc0cf702e2ddeb6adca18fd
Binary files differ
diff --git a/t/t1013/objects/76/e7fa9941f4d5f97f64fea65a2cba436bc79cbb b/t/t1013/objects/76/e7fa9941f4d5f97f64fea65a2cba436bc79cbb
new file mode 100644
index 0000000000..af4e9a7b0c
--- /dev/null
+++ b/t/t1013/objects/76/e7fa9941f4d5f97f64fea65a2cba436bc79cbb
@@ -0,0 +1,2 @@
+ xœ%ÌA‚0@Ñ}O1{cSZ(˜ãνáÃthª”’ZŒÜÞ Ëÿ? ¦m×6dµiÉ9…¤Gå˜h´Ø¨ÁZR'Q¶…RŒ¡ˆ‚ø³p‘ç‚ÓqL9âÏ=g¸§sIÐoopÎÿ”eÏ«_1»€³¤$×ç*Si«ëNwpP•RBôûÅÁú
+³‡[(ð®d-øÁL9á \ No newline at end of file
diff --git a/t/t1013/objects/78/75c6237d3fcdd0ac2f0decc7d3fa6a50b66c09 b/t/t1013/objects/78/75c6237d3fcdd0ac2f0decc7d3fa6a50b66c09
new file mode 100644
index 0000000000..3dd28be5c6
--- /dev/null
+++ b/t/t1013/objects/78/75c6237d3fcdd0ac2f0decc7d3fa6a50b66c09
Binary files differ
diff --git a/t/t1013/objects/7a/37b887a73791d12d26c0d3e39568a8fb0fa6e8 b/t/t1013/objects/7a/37b887a73791d12d26c0d3e39568a8fb0fa6e8
new file mode 100644
index 0000000000..2b97b264c3
--- /dev/null
+++ b/t/t1013/objects/7a/37b887a73791d12d26c0d3e39568a8fb0fa6e8
Binary files differ
diff --git a/t/t1013/objects/85/df50785d62d3b05ab03d9cbf7e4a0b49449730 b/t/t1013/objects/85/df50785d62d3b05ab03d9cbf7e4a0b49449730
new file mode 100644
index 0000000000..6dff746876
--- /dev/null
+++ b/t/t1013/objects/85/df50785d62d3b05ab03d9cbf7e4a0b49449730
Binary files differ
diff --git a/t/t1013/objects/8d/4e360d6c70fbd72411991c02a09c442cf7a9fa b/t/t1013/objects/8d/4e360d6c70fbd72411991c02a09c442cf7a9fa
new file mode 100644
index 0000000000..cb41e92d07
--- /dev/null
+++ b/t/t1013/objects/8d/4e360d6c70fbd72411991c02a09c442cf7a9fa
Binary files differ
diff --git a/t/t1013/objects/95/b1625de3ba8b2214d1e0d0591138aea733f64f b/t/t1013/objects/95/b1625de3ba8b2214d1e0d0591138aea733f64f
new file mode 100644
index 0000000000..7ac46b4f70
--- /dev/null
+++ b/t/t1013/objects/95/b1625de3ba8b2214d1e0d0591138aea733f64f
Binary files differ
diff --git a/t/t1013/objects/9a/e9e86b7bd6cb1472d9373702d8249973da0832 b/t/t1013/objects/9a/e9e86b7bd6cb1472d9373702d8249973da0832
new file mode 100644
index 0000000000..9d8316d4e5
--- /dev/null
+++ b/t/t1013/objects/9a/e9e86b7bd6cb1472d9373702d8249973da0832
Binary files differ
diff --git a/t/t1013/objects/bd/15045f6ce8ff75747562173640456a394412c8 b/t/t1013/objects/bd/15045f6ce8ff75747562173640456a394412c8
new file mode 100644
index 0000000000..eebf23956e
--- /dev/null
+++ b/t/t1013/objects/bd/15045f6ce8ff75747562173640456a394412c8
Binary files differ
diff --git a/t/t1013/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 b/t/t1013/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
new file mode 100644
index 0000000000..134cf19379
--- /dev/null
+++ b/t/t1013/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
Binary files differ
diff --git a/t/t1013/objects/f8/16d5255855ac160652ee5253b06cd8ee14165a b/t/t1013/objects/f8/16d5255855ac160652ee5253b06cd8ee14165a
new file mode 100644
index 0000000000..26b75aec56
--- /dev/null
+++ b/t/t1013/objects/f8/16d5255855ac160652ee5253b06cd8ee14165a
@@ -0,0 +1 @@
+H‰ÌÁ‚0 €aÏ{ŠÞ I»e&Æø*¥ˆG°ß^¸ýù¿ËDåÒ†wU‡Ò—¬S±4ªŠÆ­ªž ,fÅ[ðßVAÛºÎüxÈÇö6[wtG§Lu¸?—¦²¼Ú×@‰"gì{†+by¾%M \ No newline at end of file
diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh
index 1fd187c5eb..e23ac0e69d 100755
--- a/t/t1020-subdirectory.sh
+++ b/t/t1020-subdirectory.sh
@@ -7,6 +7,7 @@ test_description='Try various core-level commands in subdirectory.
'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-read-tree.sh
test_expect_success setup '
long="a b c d e f g h i j k l m n o p q r s t u v w x y z" &&
@@ -16,8 +17,6 @@ test_expect_success setup '
cp one original.one &&
cp dir/two original.two
'
-LF='
-'
test_expect_success 'update-index and ls-files' '
git update-index --add one &&
@@ -98,13 +97,13 @@ test_expect_success 'checkout-index' '
test_expect_success 'read-tree' '
rm -f one dir/two &&
tree=`git write-tree` &&
- git read-tree --reset -u "$tree" &&
+ read_tree_u_must_succeed --reset -u "$tree" &&
cmp one original.one &&
cmp dir/two original.two &&
(
cd dir &&
rm -f two &&
- git read-tree --reset -u "$tree" &&
+ read_tree_u_must_succeed --reset -u "$tree" &&
cmp two ../original.two &&
cmp ../one ../original.one
)
@@ -118,6 +117,43 @@ test_expect_success 'alias expansion' '
git ss
)
'
+
+test_expect_success NOT_MINGW '!alias expansion' '
+ pwd >expect &&
+ (
+ git config alias.test !pwd &&
+ cd dir &&
+ git test >../actual
+ ) &&
+ test_cmp expect actual
+'
+
+test_expect_success 'GIT_PREFIX for !alias' '
+ printf "dir/" >expect &&
+ (
+ git config alias.test "!sh -c \"printf \$GIT_PREFIX\"" &&
+ cd dir &&
+ git test >../actual
+ ) &&
+ test_cmp expect actual
+'
+
+test_expect_success 'GIT_PREFIX for built-ins' '
+ # Use GIT_EXTERNAL_DIFF to test that the "diff" built-in
+ # receives the GIT_PREFIX variable.
+ printf "dir/" >expect &&
+ printf "#!/bin/sh\n" >diff &&
+ printf "printf \"\$GIT_PREFIX\"" >>diff &&
+ chmod +x diff &&
+ (
+ cd dir &&
+ printf "change" >two &&
+ env GIT_EXTERNAL_DIFF=./diff git diff >../actual
+ git checkout -- two
+ ) &&
+ test_cmp expect actual
+'
+
test_expect_success 'no file/rev ambiguity check inside .git' '
git commit -a -m 1 &&
(
diff --git a/t/t1021-rerere-in-workdir.sh b/t/t1021-rerere-in-workdir.sh
new file mode 100755
index 0000000000..301e071ff7
--- /dev/null
+++ b/t/t1021-rerere-in-workdir.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+test_description='rerere run in a workdir'
+. ./test-lib.sh
+
+test_expect_success SYMLINKS setup '
+ git config rerere.enabled true &&
+ >world &&
+ git add world &&
+ test_tick &&
+ git commit -m initial &&
+
+ echo hello >world &&
+ test_tick &&
+ git commit -a -m hello &&
+
+ git checkout -b side HEAD^ &&
+ echo goodbye >world &&
+ test_tick &&
+ git commit -a -m goodbye &&
+
+ git checkout master
+'
+
+test_expect_success SYMLINKS 'rerere in workdir' '
+ rm -rf .git/rr-cache &&
+ "$SHELL_PATH" "$TEST_DIRECTORY/../contrib/workdir/git-new-workdir" . work &&
+ (
+ cd work &&
+ test_must_fail git merge side &&
+ git rerere status >actual &&
+ echo world >expect &&
+ test_cmp expect actual
+ )
+'
+
+# This fails because we don't resolve relative symlink in mkdir_in_gitdir()
+# For the purpose of helping contrib/workdir/git-new-workdir users, we do not
+# have to support relative symlinks, but it might be nicer to make this work
+# with a relative symbolic link someday.
+test_expect_failure SYMLINKS 'rerere in workdir (relative)' '
+ rm -rf .git/rr-cache &&
+ "$SHELL_PATH" "$TEST_DIRECTORY/../contrib/workdir/git-new-workdir" . krow &&
+ (
+ cd krow &&
+ rm -f .git/rr-cache &&
+ ln -s ../.git/rr-cache .git/rr-cache &&
+ test_must_fail git merge side &&
+ git rerere status >actual &&
+ echo world >expect &&
+ test_cmp expect actual
+ )
+'
+
+test_done
diff --git a/t/t1050-large.sh b/t/t1050-large.sh
new file mode 100755
index 0000000000..deba111bd7
--- /dev/null
+++ b/t/t1050-large.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+# Copyright (c) 2011, Google Inc.
+
+test_description='adding and checking out large blobs'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+ git config core.bigfilethreshold 200k &&
+ echo X | dd of=large bs=1k seek=2000
+'
+
+test_expect_success 'add a large file' '
+ git add large &&
+ # make sure we got a packfile and no loose objects
+ test -f .git/objects/pack/pack-*.pack &&
+ test ! -f .git/objects/??/??????????????????????????????????????
+'
+
+test_expect_success 'checkout a large file' '
+ large=$(git rev-parse :large) &&
+ git update-index --add --cacheinfo 100644 $large another &&
+ git checkout another &&
+ cmp large another ;# this must not be test_cmp
+'
+
+test_done
diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh
index bfa2c2190d..5e29e13782 100755
--- a/t/t1200-tutorial.sh
+++ b/t/t1200-tutorial.sh
@@ -163,8 +163,11 @@ test_expect_success 'git resolve' '
git checkout mybranch &&
git merge -m "Merge upstream changes." master |
sed -e "1s/[0-9a-f]\{7\}/VARIABLE/g" \
- -e "s/^Fast[- ]forward /FASTFORWARD /" >resolve.output &&
- test_cmp resolve.expect resolve.output
+ -e "s/^Fast[- ]forward /FASTFORWARD /" >resolve.output
+'
+
+test_expect_success 'git resolve output' '
+ test_i18ncmp resolve.expect resolve.output
'
cat > show-branch2.expect << EOF
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index d0e55465ff..51caff047b 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -7,28 +7,28 @@ test_description='Test git config in different settings'
. ./test-lib.sh
-test -f .git/config && rm .git/config
-
-git config core.penguin "little blue"
+test_expect_success 'clear default config' '
+ rm -f .git/config
+'
cat > expect << EOF
[core]
penguin = little blue
EOF
-
-test_expect_success 'initial' 'cmp .git/config expect'
-
-git config Core.Movie BadPhysics
+test_expect_success 'initial' '
+ git config core.penguin "little blue" &&
+ test_cmp expect .git/config
+'
cat > expect << EOF
[core]
penguin = little blue
Movie = BadPhysics
EOF
-
-test_expect_success 'mixed case' 'cmp .git/config expect'
-
-git config Cores.WhatEver Second
+test_expect_success 'mixed case' '
+ git config Core.Movie BadPhysics &&
+ test_cmp expect .git/config
+'
cat > expect << EOF
[core]
@@ -37,10 +37,10 @@ cat > expect << EOF
[Cores]
WhatEver = Second
EOF
-
-test_expect_success 'similar section' 'cmp .git/config expect'
-
-git config CORE.UPPERCASE true
+test_expect_success 'similar section' '
+ git config Cores.WhatEver Second
+ test_cmp expect .git/config
+'
cat > expect << EOF
[core]
@@ -50,8 +50,10 @@ cat > expect << EOF
[Cores]
WhatEver = Second
EOF
-
-test_expect_success 'similar section' 'cmp .git/config expect'
+test_expect_success 'uppercase section' '
+ git config CORE.UPPERCASE true &&
+ test_cmp expect .git/config
+'
test_expect_success 'replace with non-match' \
'git config core.penguin kingpin !blue'
@@ -69,7 +71,34 @@ cat > expect << EOF
WhatEver = Second
EOF
-test_expect_success 'non-match result' 'cmp .git/config expect'
+test_expect_success 'non-match result' 'test_cmp expect .git/config'
+
+test_expect_success 'find mixed-case key by canonical name' '
+ echo Second >expect &&
+ git config cores.whatever >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'find mixed-case key by non-canonical name' '
+ echo Second >expect &&
+ git config CoReS.WhAtEvEr >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'subsections are not canonicalized by git-config' '
+ cat >>.git/config <<-\EOF &&
+ [section.SubSection]
+ key = one
+ [section "SubSection"]
+ key = two
+ EOF
+ echo one >expect &&
+ git config section.subsection.key >actual &&
+ test_cmp expect actual &&
+ echo two >expect &&
+ git config section.SubSection.key >actual &&
+ test_cmp expect actual
+'
cat > .git/config <<\EOF
[alpha]
@@ -88,7 +117,7 @@ bar = foo
[beta]
EOF
-test_expect_success 'unset with cont. lines is correct' 'cmp .git/config expect'
+test_expect_success 'unset with cont. lines is correct' 'test_cmp expect .git/config'
cat > .git/config << EOF
[beta] ; silly comment # another comment
@@ -116,7 +145,7 @@ noIndent= sillyValue ; 'nother silly comment
[nextSection] noNewline = ouch
EOF
-test_expect_success 'multiple unset is correct' 'cmp .git/config expect'
+test_expect_success 'multiple unset is correct' 'test_cmp expect .git/config'
cp .git/config2 .git/config
@@ -140,9 +169,7 @@ noIndent= sillyValue ; 'nother silly comment
[nextSection] noNewline = ouch
EOF
-test_expect_success 'all replaced' 'cmp .git/config expect'
-
-git config beta.haha alpha
+test_expect_success 'all replaced' 'test_cmp expect .git/config'
cat > expect << EOF
[beta] ; silly comment # another comment
@@ -153,10 +180,10 @@ noIndent= sillyValue ; 'nother silly comment
haha = alpha
[nextSection] noNewline = ouch
EOF
-
-test_expect_success 'really mean test' 'cmp .git/config expect'
-
-git config nextsection.nonewline wow
+test_expect_success 'really mean test' '
+ git config beta.haha alpha &&
+ test_cmp expect .git/config
+'
cat > expect << EOF
[beta] ; silly comment # another comment
@@ -168,11 +195,12 @@ noIndent= sillyValue ; 'nother silly comment
[nextSection]
nonewline = wow
EOF
-
-test_expect_success 'really really mean test' 'cmp .git/config expect'
+test_expect_success 'really really mean test' '
+ git config nextsection.nonewline wow &&
+ test_cmp expect .git/config
+'
test_expect_success 'get value' 'test alpha = $(git config beta.haha)'
-git config --unset beta.haha
cat > expect << EOF
[beta] ; silly comment # another comment
@@ -183,10 +211,10 @@ noIndent= sillyValue ; 'nother silly comment
[nextSection]
nonewline = wow
EOF
-
-test_expect_success 'unset' 'cmp .git/config expect'
-
-git config nextsection.NoNewLine "wow2 for me" "for me$"
+test_expect_success 'unset' '
+ git config --unset beta.haha &&
+ test_cmp expect .git/config
+'
cat > expect << EOF
[beta] ; silly comment # another comment
@@ -198,8 +226,10 @@ noIndent= sillyValue ; 'nother silly comment
nonewline = wow
NoNewLine = wow2 for me
EOF
-
-test_expect_success 'multivar' 'cmp .git/config expect'
+test_expect_success 'multivar' '
+ git config nextsection.NoNewLine "wow2 for me" "for me$" &&
+ test_cmp expect .git/config
+'
test_expect_success 'non-match' \
'git config --get nextsection.nonewline !for'
@@ -214,8 +244,6 @@ test_expect_success 'ambiguous get' '
test_expect_success 'get multivar' \
'git config --get-all nextsection.nonewline'
-git config nextsection.nonewline "wow3" "wow$"
-
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
@@ -226,8 +254,10 @@ noIndent= sillyValue ; 'nother silly comment
nonewline = wow3
NoNewLine = wow2 for me
EOF
-
-test_expect_success 'multivar replace' 'cmp .git/config expect'
+test_expect_success 'multivar replace' '
+ git config nextsection.nonewline "wow3" "wow$" &&
+ test_cmp expect .git/config
+'
test_expect_success 'ambiguous value' '
test_must_fail git config nextsection.nonewline
@@ -241,8 +271,6 @@ test_expect_success 'invalid unset' '
test_must_fail git config --unset somesection.nonewline
'
-git config --unset nextsection.nonewline "wow3$"
-
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
@@ -253,7 +281,10 @@ noIndent= sillyValue ; 'nother silly comment
NoNewLine = wow2 for me
EOF
-test_expect_success 'multivar unset' 'cmp .git/config expect'
+test_expect_success 'multivar unset' '
+ git config --unset nextsection.nonewline "wow3$" &&
+ test_cmp expect .git/config
+'
test_expect_success 'invalid key' 'test_must_fail git config inval.2key blabla'
@@ -276,7 +307,7 @@ noIndent= sillyValue ; 'nother silly comment
Alpha = beta
EOF
-test_expect_success 'hierarchical section value' 'cmp .git/config expect'
+test_expect_success 'hierarchical section value' 'test_cmp expect .git/config'
cat > expect << EOF
beta.noindent=sillyValue
@@ -304,15 +335,16 @@ EOF
test_expect_success '--get-regexp' \
'git config --get-regexp in > output && cmp output expect'
-git config --add nextsection.nonewline "wow4 for you"
-
cat > expect << EOF
wow2 for me
wow4 for you
EOF
-test_expect_success '--add' \
- 'git config --get-all nextsection.nonewline > output && cmp output expect'
+test_expect_success '--add' '
+ git config --add nextsection.nonewline "wow4 for you" &&
+ git config --get-all nextsection.nonewline > output &&
+ test_cmp expect output
+'
cat > .git/config << EOF
[novalue]
@@ -333,6 +365,12 @@ test_expect_success 'get-regexp variable with no value' \
'git config --get-regexp novalue > output &&
cmp output expect'
+echo 'novalue.variable true' > expect
+
+test_expect_success 'get-regexp --bool variable with no value' \
+ 'git config --bool --get-regexp novalue > output &&
+ cmp output expect'
+
echo 'emptyvalue.variable ' > expect
test_expect_success 'get-regexp variable with empty value' \
@@ -361,8 +399,6 @@ cat > .git/config << EOF
c = d
EOF
-git config a.x y
-
cat > expect << EOF
[a.b]
c = d
@@ -370,10 +406,10 @@ cat > expect << EOF
x = y
EOF
-test_expect_success 'new section is partial match of another' 'cmp .git/config expect'
-
-git config b.x y
-git config a.b c
+test_expect_success 'new section is partial match of another' '
+ git config a.x y &&
+ test_cmp expect .git/config
+'
cat > expect << EOF
[a.b]
@@ -385,7 +421,11 @@ cat > expect << EOF
x = y
EOF
-test_expect_success 'new variable inserts into proper section' 'cmp .git/config expect'
+test_expect_success 'new variable inserts into proper section' '
+ git config b.x y &&
+ git config a.b c &&
+ test_cmp expect .git/config
+'
test_expect_success 'alternative GIT_CONFIG (non-existing file should fail)' \
'test_must_fail git config --file non-existing-config -l'
@@ -399,9 +439,10 @@ cat > expect << EOF
ein.bahn=strasse
EOF
-GIT_CONFIG=other-config git config -l > output
-
-test_expect_success 'alternative GIT_CONFIG' 'cmp output expect'
+test_expect_success 'alternative GIT_CONFIG' '
+ GIT_CONFIG=other-config git config -l >output &&
+ test_cmp expect output
+'
test_expect_success 'alternative GIT_CONFIG (--file)' \
'git config --file other-config -l > output && cmp output expect'
@@ -417,8 +458,6 @@ test_expect_success 'refer config from subdirectory' '
'
-GIT_CONFIG=other-config git config anwohner.park ausweis
-
cat > expect << EOF
[ein]
bahn = strasse
@@ -426,7 +465,10 @@ cat > expect << EOF
park = ausweis
EOF
-test_expect_success '--set in alternative GIT_CONFIG' 'cmp other-config expect'
+test_expect_success '--set in alternative GIT_CONFIG' '
+ GIT_CONFIG=other-config git config anwohner.park ausweis &&
+ test_cmp expect other-config
+'
cat > .git/config << EOF
# Hallo
@@ -516,8 +558,6 @@ EOF
test_expect_success "section was removed properly" \
"test_cmp expect .git/config"
-rm .git/config
-
cat > expect << EOF
[gitcvs]
enabled = true
@@ -528,10 +568,11 @@ EOF
test_expect_success 'section ending' '
+ rm -f .git/config &&
git config gitcvs.enabled true &&
git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite &&
git config gitcvs.dbname %Ggitcvs2.%a.%m.sqlite &&
- cmp .git/config expect
+ test_cmp expect .git/config
'
@@ -600,8 +641,6 @@ test_expect_success 'invalid bool (set)' '
test_must_fail git config --bool bool.nobool foobar'
-rm .git/config
-
cat > expect <<\EOF
[bool]
true1 = true
@@ -616,6 +655,7 @@ EOF
test_expect_success 'set --bool' '
+ rm -f .git/config &&
git config --bool bool.true1 01 &&
git config --bool bool.true2 -1 &&
git config --bool bool.true3 YeS &&
@@ -626,8 +666,6 @@ test_expect_success 'set --bool' '
git config --bool bool.false4 FALSE &&
cmp expect .git/config'
-rm .git/config
-
cat > expect <<\EOF
[int]
val1 = 1
@@ -637,13 +675,12 @@ EOF
test_expect_success 'set --int' '
+ rm -f .git/config &&
git config --int int.val1 01 &&
git config --int int.val2 -1 &&
git config --int int.val3 5m &&
cmp expect .git/config'
-rm .git/config
-
cat >expect <<\EOF
[bool]
true1 = true
@@ -657,6 +694,7 @@ cat >expect <<\EOF
EOF
test_expect_success 'get --bool-or-int' '
+ rm -f .git/config &&
(
echo "[bool]"
echo true1
@@ -676,7 +714,6 @@ test_expect_success 'get --bool-or-int' '
'
-rm .git/config
cat >expect <<\EOF
[bool]
true1 = true
@@ -690,6 +727,7 @@ cat >expect <<\EOF
EOF
test_expect_success 'set --bool-or-int' '
+ rm -f .git/config &&
git config --bool-or-int bool.true1 true &&
git config --bool-or-int bool.false1 false &&
git config --bool-or-int bool.true2 yes &&
@@ -700,8 +738,6 @@ test_expect_success 'set --bool-or-int' '
test_cmp expect .git/config
'
-rm .git/config
-
cat >expect <<\EOF
[path]
home = ~/
@@ -710,6 +746,7 @@ cat >expect <<\EOF
EOF
test_expect_success NOT_MINGW 'set --path' '
+ rm -f .git/config &&
git config --path path.home "~/" &&
git config --path path.normal "/dev/null" &&
git config --path path.trailingtilde "foo~" &&
@@ -750,13 +787,6 @@ test_expect_success NOT_MINGW 'get --path copes with unset $HOME' '
test_cmp expect result
'
-rm .git/config
-
-git config quote.leading " test"
-git config quote.ending "test "
-git config quote.semicolon "test;test"
-git config quote.hash "test#test"
-
cat > expect << EOF
[quote]
leading = " test"
@@ -764,8 +794,14 @@ cat > expect << EOF
semicolon = "test;test"
hash = "test#test"
EOF
-
-test_expect_success 'quoting' 'cmp .git/config expect'
+test_expect_success 'quoting' '
+ rm -f .git/config &&
+ git config quote.leading " test" &&
+ git config quote.ending "test " &&
+ git config quote.semicolon "test;test" &&
+ git config quote.hash "test#test" &&
+ test_cmp expect .git/config
+'
test_expect_success 'key with newline' '
test_must_fail git config "key.with
@@ -790,9 +826,10 @@ section.noncont=not continued
section.quotecont=cont;inued
EOF
-git config --list > result
-
-test_expect_success 'value continued on next line' 'cmp result expect'
+test_expect_success 'value continued on next line' '
+ git config --list > result &&
+ cmp result expect
+'
cat > .git/config <<\EOF
[section "sub=section"]
@@ -813,16 +850,17 @@ barQsection.sub=section.val3
Qsection.sub=section.val4
Qsection.sub=section.val5Q
EOF
+test_expect_success '--null --list' '
+ git config --null --list | nul_to_q >result &&
+ echo >>result &&
+ test_cmp expect result
+'
-git config --null --list | perl -pe 'y/\000/Q/' > result
-echo >>result
-
-test_expect_success '--null --list' 'cmp result expect'
-
-git config --null --get-regexp 'val[0-9]' | perl -pe 'y/\000/Q/' > result
-echo >>result
-
-test_expect_success '--null --get-regexp' 'cmp result expect'
+test_expect_success '--null --get-regexp' '
+ git config --null --get-regexp "val[0-9]" | nul_to_q >result &&
+ echo >>result &&
+ test_cmp expect result
+'
test_expect_success 'inner whitespace kept verbatim' '
git config section.val "foo bar" &&
@@ -876,11 +914,50 @@ test_expect_success 'check split_cmdline return' "
"
test_expect_success 'git -c "key=value" support' '
- test "z$(git -c name=value config name)" = zvalue &&
test "z$(git -c core.name=value config core.name)" = zvalue &&
- test "z$(git -c CamelCase=value config camelcase)" = zvalue &&
- test "z$(git -c flag config --bool flag)" = ztrue &&
- test_must_fail git -c core.name=value config name
+ test "z$(git -c foo.CamelCase=value config foo.camelcase)" = zvalue &&
+ test "z$(git -c foo.flag config --bool foo.flag)" = ztrue &&
+ test_must_fail git -c name=value config core.name
+'
+
+test_expect_success 'key sanity-checking' '
+ test_must_fail git config foo=bar &&
+ test_must_fail git config foo=.bar &&
+ test_must_fail git config foo.ba=r &&
+ test_must_fail git config foo.1bar &&
+ test_must_fail git config foo."ba
+ z".bar &&
+ test_must_fail git config . false &&
+ test_must_fail git config .foo false &&
+ test_must_fail git config foo. false &&
+ test_must_fail git config .foo. false &&
+ git config foo.bar true &&
+ git config foo."ba =z".bar false
+'
+
+test_expect_success 'git -c works with aliases of builtins' '
+ git config alias.checkconfig "-c foo.check=bar config foo.check" &&
+ echo bar >expect &&
+ git checkconfig >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git -c does not split values on equals' '
+ echo "value with = in it" >expect &&
+ git -c core.foo="value with = in it" config core.foo >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git -c dies on bogus config' '
+ test_must_fail git -c core.bare=foo rev-parse
+'
+
+test_expect_success 'git -c complains about empty key' '
+ test_must_fail git -c "=foo" rev-parse
+'
+
+test_expect_success 'git -c complains about empty key and value' '
+ test_must_fail git -c "" rev-parse
'
test_done
diff --git a/t/t1303-wacky-config.sh b/t/t1303-wacky-config.sh
index 080117c6bc..46103a1591 100755
--- a/t/t1303-wacky-config.sh
+++ b/t/t1303-wacky-config.sh
@@ -44,7 +44,7 @@ LONG_VALUE=$(printf "x%01021dx a" 7)
test_expect_success 'do not crash on special long config line' '
setup &&
git config section.key "$LONG_VALUE" &&
- check section.key "fatal: bad config file line 2 in .git/config"
+ check section.key "$LONG_VALUE"
'
test_done
diff --git a/t/t1304-default-acl.sh b/t/t1304-default-acl.sh
index b5d89a2250..2b962cfda7 100755
--- a/t/t1304-default-acl.sh
+++ b/t/t1304-default-acl.sh
@@ -25,6 +25,11 @@ else
test_set_prereq SETFACL
fi
+if test -z "$LOGNAME"
+then
+ LOGNAME=$USER
+fi
+
check_perms_and_acl () {
test -r "$1" &&
getfacl "$1" > actual &&
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index ff747f8229..4fd83a667a 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -6,7 +6,7 @@
test_description='Test git update-ref and basic ref logging'
. ./test-lib.sh
-Z=0000000000000000000000000000000000000000
+Z=$_z40
test_expect_success setup '
diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh
index 1b0f82fa4c..1ae4d87c92 100755
--- a/t/t1402-check-ref-format.sh
+++ b/t/t1402-check-ref-format.sh
@@ -5,28 +5,126 @@ test_description='Test git check-ref-format'
. ./test-lib.sh
valid_ref() {
- test_expect_success "ref name '$1' is valid" \
- "git check-ref-format '$1'"
+ prereq=
+ case $1 in
+ [A-Z]*)
+ prereq=$1
+ shift
+ esac
+ test_expect_success $prereq "ref name '$1' is valid${2:+ with options $2}" "
+ git check-ref-format $2 '$1'
+ "
}
invalid_ref() {
- test_expect_success "ref name '$1' is not valid" \
- "test_must_fail git check-ref-format '$1'"
+ prereq=
+ case $1 in
+ [A-Z]*)
+ prereq=$1
+ shift
+ esac
+ test_expect_success $prereq "ref name '$1' is invalid${2:+ with options $2}" "
+ test_must_fail git check-ref-format $2 '$1'
+ "
}
-valid_ref 'heads/foo'
-invalid_ref 'foo'
+invalid_ref ''
+invalid_ref NOT_MINGW '/'
+invalid_ref NOT_MINGW '/' --allow-onelevel
+invalid_ref NOT_MINGW '/' --normalize
+invalid_ref NOT_MINGW '/' '--allow-onelevel --normalize'
valid_ref 'foo/bar/baz'
-valid_ref 'refs///heads/foo'
+valid_ref 'foo/bar/baz' --normalize
+invalid_ref 'refs///heads/foo'
+valid_ref 'refs///heads/foo' --normalize
invalid_ref 'heads/foo/'
+invalid_ref NOT_MINGW '/heads/foo'
+valid_ref NOT_MINGW '/heads/foo' --normalize
+invalid_ref '///heads/foo'
+valid_ref '///heads/foo' --normalize
invalid_ref './foo'
+invalid_ref './foo/bar'
+invalid_ref 'foo/./bar'
+invalid_ref 'foo/bar/.'
invalid_ref '.refs/foo'
invalid_ref 'heads/foo..bar'
invalid_ref 'heads/foo?bar'
valid_ref 'foo./bar'
invalid_ref 'heads/foo.lock'
+invalid_ref 'heads///foo.lock'
+invalid_ref 'foo.lock/bar'
+invalid_ref 'foo.lock///bar'
valid_ref 'heads/foo@bar'
invalid_ref 'heads/v@{ation'
invalid_ref 'heads/foo\bar'
+invalid_ref "$(printf 'heads/foo\t')"
+invalid_ref "$(printf 'heads/foo\177')"
+valid_ref "$(printf 'heads/fu\303\237')"
+invalid_ref 'heads/*foo/bar' --refspec-pattern
+invalid_ref 'heads/foo*/bar' --refspec-pattern
+invalid_ref 'heads/f*o/bar' --refspec-pattern
+
+ref='foo'
+invalid_ref "$ref"
+valid_ref "$ref" --allow-onelevel
+invalid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+invalid_ref "$ref" --normalize
+valid_ref "$ref" '--allow-onelevel --normalize'
+
+ref='foo/bar'
+valid_ref "$ref"
+valid_ref "$ref" --allow-onelevel
+valid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+valid_ref "$ref" --normalize
+
+ref='foo/*'
+invalid_ref "$ref"
+invalid_ref "$ref" --allow-onelevel
+valid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='*/foo'
+invalid_ref "$ref"
+invalid_ref "$ref" --allow-onelevel
+valid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+invalid_ref "$ref" --normalize
+valid_ref "$ref" '--refspec-pattern --normalize'
+
+ref='foo/*/bar'
+invalid_ref "$ref"
+invalid_ref "$ref" --allow-onelevel
+valid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='*'
+invalid_ref "$ref"
+invalid_ref "$ref" --allow-onelevel
+invalid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='foo/*/*'
+invalid_ref "$ref" --refspec-pattern
+invalid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='*/foo/*'
+invalid_ref "$ref" --refspec-pattern
+invalid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='*/*/foo'
+invalid_ref "$ref" --refspec-pattern
+invalid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='/foo'
+invalid_ref NOT_MINGW "$ref"
+invalid_ref NOT_MINGW "$ref" --allow-onelevel
+invalid_ref NOT_MINGW "$ref" --refspec-pattern
+invalid_ref NOT_MINGW "$ref" '--refspec-pattern --allow-onelevel'
+invalid_ref NOT_MINGW "$ref" --normalize
+valid_ref NOT_MINGW "$ref" '--allow-onelevel --normalize'
+invalid_ref NOT_MINGW "$ref" '--refspec-pattern --normalize'
+valid_ref NOT_MINGW "$ref" '--refspec-pattern --allow-onelevel --normalize'
test_expect_success "check-ref-format --branch @{-1}" '
T=$(git write-tree) &&
@@ -59,20 +157,41 @@ test_expect_success 'check-ref-format --branch from subdir' '
'
valid_ref_normalized() {
- test_expect_success "ref name '$1' simplifies to '$2'" "
- refname=\$(git check-ref-format --print '$1') &&
- test \"\$refname\" = '$2'"
+ prereq=
+ case $1 in
+ [A-Z]*)
+ prereq=$1
+ shift
+ esac
+ test_expect_success $prereq "ref name '$1' simplifies to '$2'" "
+ refname=\$(git check-ref-format --normalize '$1') &&
+ test \"\$refname\" = '$2'
+ "
}
invalid_ref_normalized() {
- test_expect_success "check-ref-format --print rejects '$1'" "
- test_must_fail git check-ref-format --print '$1'"
+ prereq=
+ case $1 in
+ [A-Z]*)
+ prereq=$1
+ shift
+ esac
+ test_expect_success $prereq "check-ref-format --normalize rejects '$1'" "
+ test_must_fail git check-ref-format --normalize '$1'
+ "
}
valid_ref_normalized 'heads/foo' 'heads/foo'
valid_ref_normalized 'refs///heads/foo' 'refs/heads/foo'
+valid_ref_normalized NOT_MINGW '/heads/foo' 'heads/foo'
+valid_ref_normalized '///heads/foo' 'heads/foo'
invalid_ref_normalized 'foo'
+invalid_ref_normalized NOT_MINGW '/foo'
invalid_ref_normalized 'heads/foo/../bar'
invalid_ref_normalized 'heads/./foo'
invalid_ref_normalized 'heads\foo'
+invalid_ref_normalized 'heads/foo.lock'
+invalid_ref_normalized 'heads///foo.lock'
+invalid_ref_normalized 'foo.lock/bar'
+invalid_ref_normalized 'foo.lock///bar'
test_done
diff --git a/t/t1411-reflog-show.sh b/t/t1411-reflog-show.sh
index ba25ff354d..caa687b5b4 100755
--- a/t/t1411-reflog-show.sh
+++ b/t/t1411-reflog-show.sh
@@ -28,6 +28,24 @@ test_expect_success 'oneline reflog format' '
test_cmp expect actual
'
+test_expect_success 'reflog default format' '
+ git reflog -1 >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+commit e46513e
+Reflog: HEAD@{0} (C O Mitter <committer@example.com>)
+Reflog message: commit (initial): one
+Author: A U Thor <author@example.com>
+
+ one
+EOF
+test_expect_success 'override reflog default format' '
+ git reflog --format=short -1 >actual &&
+ test_cmp expect actual
+'
+
cat >expect <<'EOF'
Reflog: HEAD@{Thu Apr 7 15:13:13 2005 -0700} (C O Mitter <committer@example.com>)
Reflog message: commit (initial): one
diff --git a/t/t1412-reflog-loop.sh b/t/t1412-reflog-loop.sh
index 7f519e5ebe..647d888507 100755
--- a/t/t1412-reflog-loop.sh
+++ b/t/t1412-reflog-loop.sh
@@ -21,10 +21,10 @@ test_expect_success 'setup reflog with alternating commits' '
test_expect_success 'reflog shows all entries' '
cat >expect <<-\EOF
- topic@{0} two: updating HEAD
- topic@{1} one: updating HEAD
- topic@{2} two: updating HEAD
- topic@{3} one: updating HEAD
+ topic@{0} reset: moving to two
+ topic@{1} reset: moving to one
+ topic@{2} reset: moving to two
+ topic@{3} reset: moving to one
topic@{4} branch: Created from HEAD
EOF
git log -g --format="%gd %gs" topic >actual &&
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index bb01d5ab8f..523ce9c45b 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -110,6 +110,42 @@ test_expect_success 'email with embedded > is not okay' '
grep "error in commit $new" out
'
+test_expect_success 'missing < email delimiter is reported nicely' '
+ git cat-file commit HEAD >basis &&
+ sed "s/<//" basis >bad-email-2 &&
+ new=$(git hash-object -t commit -w --stdin <bad-email-2) &&
+ test_when_finished "remove_object $new" &&
+ git update-ref refs/heads/bogus "$new" &&
+ test_when_finished "git update-ref -d refs/heads/bogus" &&
+ git fsck 2>out &&
+ cat out &&
+ grep "error in commit $new.* - bad name" out
+'
+
+test_expect_success 'missing email is reported nicely' '
+ git cat-file commit HEAD >basis &&
+ sed "s/[a-z]* <[^>]*>//" basis >bad-email-3 &&
+ new=$(git hash-object -t commit -w --stdin <bad-email-3) &&
+ test_when_finished "remove_object $new" &&
+ git update-ref refs/heads/bogus "$new" &&
+ test_when_finished "git update-ref -d refs/heads/bogus" &&
+ git fsck 2>out &&
+ cat out &&
+ grep "error in commit $new.* - missing email" out
+'
+
+test_expect_success '> in name is reported' '
+ git cat-file commit HEAD >basis &&
+ sed "s/ </> </" basis >bad-email-4 &&
+ new=$(git hash-object -t commit -w --stdin <bad-email-4) &&
+ test_when_finished "remove_object $new" &&
+ git update-ref refs/heads/bogus "$new" &&
+ test_when_finished "git update-ref -d refs/heads/bogus" &&
+ git fsck 2>out &&
+ cat out &&
+ grep "error in commit $new" out
+'
+
test_expect_success 'tag pointing to nonexistent' '
cat >invalid-tag <<-\EOF &&
object ffffffffffffffffffffffffffffffffffffffff
diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index da6252b117..63849836c8 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -7,7 +7,6 @@ test_expect_success 'setup' '
EMPTY_TREE=$(git write-tree) &&
EMPTY_BLOB=$(git hash-object -t blob --stdin </dev/null) &&
CHANGED_BLOB=$(echo changed | git hash-object -t blob --stdin) &&
- ZEROES=0000000000000000000000000000000000000000 &&
EMPTY_BLOB7=$(echo $EMPTY_BLOB | sed "s/\(.......\).*/\1/") &&
CHANGED_BLOB7=$(echo $CHANGED_BLOB | sed "s/\(.......\).*/\1/") &&
@@ -239,10 +238,10 @@ test_expect_success '_gently() groks relative GIT_DIR & GIT_WORK_TREE' '
test_expect_success 'diff-index respects work tree under .git dir' '
cat >diff-index-cached.expected <<-EOF &&
- :000000 100644 $ZEROES $EMPTY_BLOB A sub/dir/tracked
+ :000000 100644 $_z40 $EMPTY_BLOB A sub/dir/tracked
EOF
cat >diff-index.expected <<-EOF &&
- :000000 100644 $ZEROES $ZEROES A sub/dir/tracked
+ :000000 100644 $_z40 $_z40 A sub/dir/tracked
EOF
(
@@ -258,7 +257,7 @@ test_expect_success 'diff-index respects work tree under .git dir' '
test_expect_success 'diff-files respects work tree under .git dir' '
cat >diff-files.expected <<-EOF &&
- :100644 100644 $EMPTY_BLOB $ZEROES M sub/dir/tracked
+ :100644 100644 $EMPTY_BLOB $_z40 M sub/dir/tracked
EOF
(
diff --git a/t/t1506-rev-parse-diagnosis.sh b/t/t1506-rev-parse-diagnosis.sh
index 9f8adb1f82..0843a1c13b 100755
--- a/t/t1506-rev-parse-diagnosis.sh
+++ b/t/t1506-rev-parse-diagnosis.sh
@@ -6,6 +6,16 @@ exec </dev/null
. ./test-lib.sh
+test_did_you_mean ()
+{
+ sq="'" &&
+ cat >expected <<-EOF &&
+ fatal: Path '$2$3' $4, but not ${5:-$sq$3$sq}.
+ Did you mean '$1:$2$3'${2:+ aka $sq$1:./$3$sq}?
+ EOF
+ test_cmp expected error
+}
+
HASH_file=
test_expect_success 'set up basic repo' '
@@ -106,7 +116,7 @@ test_expect_success 'incorrect file in sha1:path' '
grep "fatal: Path '"'"'index-only.txt'"'"' exists on disk, but not in '"'"'HEAD'"'"'." error &&
(cd subdir &&
test_must_fail git rev-parse HEAD:file2.txt 2> error &&
- grep "Did you mean '"'"'HEAD:subdir/file2.txt'"'"'?" error )
+ test_did_you_mean HEAD subdir/ file2.txt exists )
'
test_expect_success 'incorrect file in :path and :N:path' '
@@ -115,14 +125,14 @@ test_expect_success 'incorrect file in :path and :N:path' '
test_must_fail git rev-parse :1:nothing.txt 2> error &&
grep "Path '"'"'nothing.txt'"'"' does not exist (neither on disk nor in the index)." error &&
test_must_fail git rev-parse :1:file.txt 2> error &&
- grep "Did you mean '"'"':0:file.txt'"'"'?" error &&
+ test_did_you_mean ":0" "" file.txt "is in the index" "at stage 1" &&
(cd subdir &&
test_must_fail git rev-parse :1:file.txt 2> error &&
- grep "Did you mean '"'"':0:file.txt'"'"'?" error &&
+ test_did_you_mean ":0" "" file.txt "is in the index" "at stage 1" &&
test_must_fail git rev-parse :file2.txt 2> error &&
- grep "Did you mean '"'"':0:subdir/file2.txt'"'"'?" error &&
+ test_did_you_mean ":0" subdir/ file2.txt "is in the index" &&
test_must_fail git rev-parse :2:file2.txt 2> error &&
- grep "Did you mean '"'"':0:subdir/file2.txt'"'"'?" error) &&
+ test_did_you_mean :0 subdir/ file2.txt "is in the index") &&
test_must_fail git rev-parse :disk-only.txt 2> error &&
grep "fatal: Path '"'"'disk-only.txt'"'"' exists on disk, but not in the index." error
'
diff --git a/t/t1510-repo-setup.sh b/t/t1510-repo-setup.sh
index 15101d5e03..ec50a9ad70 100755
--- a/t/t1510-repo-setup.sh
+++ b/t/t1510-repo-setup.sh
@@ -57,7 +57,7 @@ test_repo () {
export GIT_WORK_TREE
fi &&
rm -f trace &&
- GIT_TRACE="$(pwd)/trace" git symbolic-ref HEAD >/dev/null &&
+ GIT_TRACE_SETUP="$(pwd)/trace" git symbolic-ref HEAD >/dev/null &&
grep '^setup: ' trace >result &&
test_cmp expected result
)
diff --git a/t/t2011-checkout-invalid-head.sh b/t/t2011-checkout-invalid-head.sh
index 15ebdc26eb..300f8bf25c 100755
--- a/t/t2011-checkout-invalid-head.sh
+++ b/t/t2011-checkout-invalid-head.sh
@@ -15,7 +15,7 @@ test_expect_success 'checkout should not start branch from a tree' '
'
test_expect_success 'checkout master from invalid HEAD' '
- echo 0000000000000000000000000000000000000000 >.git/HEAD &&
+ echo $_z40 >.git/HEAD &&
git checkout master --
'
diff --git a/t/t2018-checkout-branch.sh b/t/t2018-checkout-branch.sh
index fa69016381..75874e85df 100755
--- a/t/t2018-checkout-branch.sh
+++ b/t/t2018-checkout-branch.sh
@@ -118,6 +118,15 @@ test_expect_success 'checkout -b to an existing branch fails' '
test_must_fail do_checkout branch2 $HEAD2
'
+test_expect_success 'checkout -b to @{-1} fails with the right branch name' '
+ git reset --hard HEAD &&
+ git checkout branch1 &&
+ git checkout branch2 &&
+ echo >expect "fatal: A branch named '\''branch1'\'' already exists." &&
+ test_must_fail git checkout -b @{-1} 2>actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'checkout -B to an existing branch resets branch to HEAD' '
git checkout branch1 &&
@@ -169,4 +178,23 @@ test_expect_success 'checkout -f -B to an existing branch with mergeable changes
test_must_fail test_dirty_mergeable
'
+test_expect_success 'checkout -b <describe>' '
+ git tag -f -m "First commit" initial initial &&
+ git checkout -f change1 &&
+ name=$(git describe) &&
+ git checkout -b $name &&
+ git diff --exit-code change1 &&
+ echo "refs/heads/$name" >expect &&
+ git symbolic-ref HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'checkout -B to the current branch fails before merging' '
+ git checkout branch1 &&
+ setup_dirty_mergeable &&
+ git commit -mfooble &&
+ test_must_fail git checkout -B branch1 initial &&
+ test_must_fail test_dirty_mergeable
+'
+
test_done
diff --git a/t/t2019-checkout-ambiguous-ref.sh b/t/t2019-checkout-ambiguous-ref.sh
new file mode 100755
index 0000000000..b99d5192a9
--- /dev/null
+++ b/t/t2019-checkout-ambiguous-ref.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+
+test_description='checkout handling of ambiguous (branch/tag) refs'
+. ./test-lib.sh
+
+test_expect_success 'setup ambiguous refs' '
+ test_commit branch file &&
+ git branch ambiguity &&
+ git branch vagueness &&
+ test_commit tag file &&
+ git tag ambiguity &&
+ git tag vagueness HEAD:file &&
+ test_commit other file
+'
+
+test_expect_success 'checkout ambiguous ref succeeds' '
+ git checkout ambiguity >stdout 2>stderr
+'
+
+test_expect_success 'checkout produces ambiguity warning' '
+ grep "warning.*ambiguous" stderr
+'
+
+test_expect_success 'checkout chooses branch over tag' '
+ echo refs/heads/ambiguity >expect &&
+ git symbolic-ref HEAD >actual &&
+ test_cmp expect actual &&
+ echo branch >expect &&
+ test_cmp expect file
+'
+
+test_expect_success 'checkout reports switch to branch' '
+ test_i18ngrep "Switched to branch" stderr &&
+ test_i18ngrep ! "^HEAD is now at" stderr
+'
+
+test_expect_success 'checkout vague ref succeeds' '
+ git checkout vagueness >stdout 2>stderr &&
+ test_set_prereq VAGUENESS_SUCCESS
+'
+
+test_expect_success VAGUENESS_SUCCESS 'checkout produces ambiguity warning' '
+ grep "warning.*ambiguous" stderr
+'
+
+test_expect_success VAGUENESS_SUCCESS 'checkout chooses branch over tag' '
+ echo refs/heads/vagueness >expect &&
+ git symbolic-ref HEAD >actual &&
+ test_cmp expect actual &&
+ echo branch >expect &&
+ test_cmp expect file
+'
+
+test_expect_success VAGUENESS_SUCCESS 'checkout reports switch to branch' '
+ test_i18ngrep "Switched to branch" stderr &&
+ test_i18ngrep ! "^HEAD is now at" stderr
+'
+
+test_done
diff --git a/t/t2020-checkout-detach.sh b/t/t2020-checkout-detach.sh
new file mode 100755
index 0000000000..068fba4c8e
--- /dev/null
+++ b/t/t2020-checkout-detach.sh
@@ -0,0 +1,154 @@
+#!/bin/sh
+
+test_description='checkout into detached HEAD state'
+. ./test-lib.sh
+
+check_detached () {
+ test_must_fail git symbolic-ref -q HEAD >/dev/null
+}
+
+check_not_detached () {
+ git symbolic-ref -q HEAD >/dev/null
+}
+
+ORPHAN_WARNING='you are leaving .* commit.*behind'
+PREV_HEAD_DESC='Previous HEAD position was'
+check_orphan_warning() {
+ test_i18ngrep "$ORPHAN_WARNING" "$1" &&
+ test_i18ngrep ! "$PREV_HEAD_DESC" "$1"
+}
+check_no_orphan_warning() {
+ test_i18ngrep ! "$ORPHAN_WARNING" "$1" &&
+ test_i18ngrep "$PREV_HEAD_DESC" "$1"
+}
+
+reset () {
+ git checkout master &&
+ check_not_detached
+}
+
+test_expect_success 'setup' '
+ test_commit one &&
+ test_commit two &&
+ test_commit three && git tag -d three &&
+ test_commit four && git tag -d four &&
+ git branch branch &&
+ git tag tag
+'
+
+test_expect_success 'checkout branch does not detach' '
+ reset &&
+ git checkout branch &&
+ check_not_detached
+'
+
+test_expect_success 'checkout tag detaches' '
+ reset &&
+ git checkout tag &&
+ check_detached
+'
+
+test_expect_success 'checkout branch by full name detaches' '
+ reset &&
+ git checkout refs/heads/branch &&
+ check_detached
+'
+
+test_expect_success 'checkout non-ref detaches' '
+ reset &&
+ git checkout branch^ &&
+ check_detached
+'
+
+test_expect_success 'checkout ref^0 detaches' '
+ reset &&
+ git checkout branch^0 &&
+ check_detached
+'
+
+test_expect_success 'checkout --detach detaches' '
+ reset &&
+ git checkout --detach branch &&
+ check_detached
+'
+
+test_expect_success 'checkout --detach without branch name' '
+ reset &&
+ git checkout --detach &&
+ check_detached
+'
+
+test_expect_success 'checkout --detach errors out for non-commit' '
+ reset &&
+ test_must_fail git checkout --detach one^{tree} &&
+ check_not_detached
+'
+
+test_expect_success 'checkout --detach errors out for extra argument' '
+ reset &&
+ git checkout master &&
+ test_must_fail git checkout --detach tag one.t &&
+ check_not_detached
+'
+
+test_expect_success 'checkout --detached and -b are incompatible' '
+ reset &&
+ test_must_fail git checkout --detach -b newbranch tag &&
+ check_not_detached
+'
+
+test_expect_success 'checkout --detach moves HEAD' '
+ reset &&
+ git checkout one &&
+ git checkout --detach two &&
+ git diff --exit-code HEAD &&
+ git diff --exit-code two
+'
+
+test_expect_success 'checkout warns on orphan commits' '
+ reset &&
+ git checkout --detach two &&
+ echo content >orphan &&
+ git add orphan &&
+ git commit -a -m orphan &&
+ git checkout master 2>stderr
+'
+
+test_expect_success 'checkout warns on orphan commits: output' '
+ check_orphan_warning stderr
+'
+
+test_expect_success 'checkout does not warn leaving ref tip' '
+ reset &&
+ git checkout --detach two &&
+ git checkout master 2>stderr
+'
+
+test_expect_success 'checkout does not warn leaving ref tip' '
+ check_no_orphan_warning stderr
+'
+
+test_expect_success 'checkout does not warn leaving reachable commit' '
+ reset &&
+ git checkout --detach HEAD^ &&
+ git checkout master 2>stderr
+'
+
+test_expect_success 'checkout does not warn leaving reachable commit' '
+ check_no_orphan_warning stderr
+'
+
+cat >expect <<'EOF'
+Your branch is behind 'master' by 1 commit, and can be fast-forwarded.
+EOF
+test_expect_success 'tracking count is accurate after orphan check' '
+ reset &&
+ git branch child master^ &&
+ git config branch.child.remote . &&
+ git config branch.child.merge refs/heads/master &&
+ git checkout child^ &&
+ git checkout child >stdout &&
+ test_cmp expect stdout
+'
+
+test_done
diff --git a/t/t2021-checkout-overwrite.sh b/t/t2021-checkout-overwrite.sh
new file mode 100755
index 0000000000..5da63e9fa2
--- /dev/null
+++ b/t/t2021-checkout-overwrite.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+test_description='checkout must not overwrite an untracked objects'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+
+ mkdir -p a/b/c &&
+ >a/b/c/d &&
+ git add -A &&
+ git commit -m base &&
+ git tag start
+'
+
+test_expect_success 'create a commit where dir a/b changed to file' '
+
+ git checkout -b file &&
+ rm -rf a/b &&
+ >a/b &&
+ git add -A &&
+ git commit -m "dir to file"
+'
+
+test_expect_success 'checkout commit with dir must not remove untracked a/b' '
+
+ git rm --cached a/b &&
+ git commit -m "un-track the file" &&
+ test_must_fail git checkout start &&
+ test -f a/b
+'
+
+test_expect_success SYMLINKS 'create a commit where dir a/b changed to symlink' '
+
+ rm -rf a/b && # cleanup if previous test failed
+ git checkout -f -b symlink start &&
+ rm -rf a/b &&
+ ln -s foo a/b &&
+ git add -A &&
+ git commit -m "dir to symlink"
+'
+
+test_expect_success SYMLINKS 'checkout commit with dir must not remove untracked a/b' '
+
+ git rm --cached a/b &&
+ git commit -m "un-track the symlink" &&
+ test_must_fail git checkout start &&
+ test -h a/b
+'
+
+test_done
diff --git a/t/t2022-checkout-paths.sh b/t/t2022-checkout-paths.sh
new file mode 100755
index 0000000000..56090d2eba
--- /dev/null
+++ b/t/t2022-checkout-paths.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+test_description='checkout $tree -- $paths'
+. ./test-lib.sh
+
+test_expect_success setup '
+ mkdir dir &&
+ >dir/master &&
+ echo common >dir/common &&
+ git add dir/master dir/common &&
+ test_tick && git commit -m "master has dir/master" &&
+ git checkout -b next &&
+ git mv dir/master dir/next0 &&
+ echo next >dir/next1 &&
+ git add dir &&
+ test_tick && git commit -m "next has dir/next but not dir/master"
+'
+
+test_expect_success 'checking out paths out of a tree does not clobber unrelated paths' '
+ git checkout next &&
+ git reset --hard &&
+ rm dir/next0 &&
+ cat dir/common >expect.common &&
+ echo modified >expect.next1 &&
+ cat expect.next1 >dir/next1 &&
+ echo untracked >expect.next2 &&
+ cat expect.next2 >dir/next2 &&
+
+ git checkout master dir &&
+
+ test_cmp expect.common dir/common &&
+ test_path_is_file dir/master &&
+ git diff --exit-code master dir/master &&
+
+ test_path_is_missing dir/next0 &&
+ test_cmp expect.next1 dir/next1 &&
+ test_path_is_file dir/next2 &&
+ test_must_fail git ls-files --error-unmatch dir/next2 &&
+ test_cmp expect.next2 dir/next2
+'
+
+test_done
diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh
index 0692427cb6..4cdebda6a5 100755
--- a/t/t2200-add-update.sh
+++ b/t/t2200-add-update.sh
@@ -124,7 +124,7 @@ test_expect_success 'add -n -u should not add but just report' '
after=$(git ls-files -s check top) &&
test "$before" = "$after" &&
- test_cmp expect actual
+ test_i18ncmp expect actual
'
@@ -149,31 +149,21 @@ test_expect_success 'add -u resolves unmerged paths' '
echo 3 >path1 &&
echo 2 >path3 &&
echo 2 >path5 &&
- git add -u &&
- git ls-files -s path1 path2 path3 path4 path5 path6 >actual &&
- {
- echo "100644 $three 0 path1"
- echo "100644 $one 1 path3"
- echo "100644 $one 1 path4"
- echo "100644 $one 3 path5"
- echo "100644 $one 3 path6"
- } >expect &&
- test_cmp expect actual &&
- # Bonus tests. Explicit resolving
- git add path3 path5 &&
+ # Explicit resolving by adding removed paths should fail
test_must_fail git add path4 &&
test_must_fail git add path6 &&
- git rm path4 &&
- git rm path6 &&
- git ls-files -s "path?" >actual &&
+ # "add -u" should notice removals no matter what stages
+ # the index entries are in.
+ git add -u &&
+ git ls-files -s path1 path2 path3 path4 path5 path6 >actual &&
{
echo "100644 $three 0 path1"
echo "100644 $two 0 path3"
echo "100644 $two 0 path5"
- } >expect
-
+ } >expect &&
+ test_cmp expect actual
'
test_expect_success '"add -u non-existent" should fail' '
diff --git a/t/t2201-add-update-typechange.sh b/t/t2201-add-update-typechange.sh
index 2e8f702452..954fc51e5b 100755
--- a/t/t2201-add-update-typechange.sh
+++ b/t/t2201-add-update-typechange.sh
@@ -4,8 +4,6 @@ test_description='more git add -u'
. ./test-lib.sh
-_z40=0000000000000000000000000000000000000000
-
test_expect_success setup '
>xyzzy &&
_empty=$(git hash-object --stdin <xyzzy) &&
diff --git a/t/t2204-add-ignored.sh b/t/t2204-add-ignored.sh
index 24afdabab7..8340ac2f07 100755
--- a/t/t2204-add-ignored.sh
+++ b/t/t2204-add-ignored.sh
@@ -31,18 +31,21 @@ do
rm -f .git/index &&
test_must_fail git add "$i" 2>err &&
git ls-files "$i" >out &&
- ! test -s out &&
- grep -e "Use -f if" err &&
- cat err
+ ! test -s out
+ '
+
+ test_expect_success "complaints for ignored $i output" '
+ test_i18ngrep -e "Use -f if" err
'
test_expect_success "complaints for ignored $i with unignored file" '
rm -f .git/index &&
test_must_fail git add "$i" file 2>err &&
git ls-files "$i" >out &&
- ! test -s out &&
- grep -e "Use -f if" err &&
- cat err
+ ! test -s out
+ '
+ test_expect_success "complaints for ignored $i with unignored file output" '
+ test_i18ngrep -e "Use -f if" err
'
done
@@ -54,9 +57,14 @@ do
cd dir &&
test_must_fail git add "$i" 2>err &&
git ls-files "$i" >out &&
- ! test -s out &&
- grep -e "Use -f if" err &&
- cat err
+ ! test -s out
+ )
+ '
+
+ test_expect_success "complaints for ignored $i in dir output" '
+ (
+ cd dir &&
+ test_i18ngrep -e "Use -f if" err
)
'
done
@@ -69,9 +77,14 @@ do
cd sub &&
test_must_fail git add "$i" 2>err &&
git ls-files "$i" >out &&
- ! test -s out &&
- grep -e "Use -f if" err &&
- cat err
+ ! test -s out
+ )
+ '
+
+ test_expect_success "complaints for ignored $i in sub output" '
+ (
+ cd sub &&
+ test_i18ngrep -e "Use -f if" err
)
'
done
diff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh
index 2eec0118c4..88be904c09 100755
--- a/t/t3000-ls-files-others.sh
+++ b/t/t3000-ls-files-others.sh
@@ -65,4 +65,23 @@ test_expect_success '--no-empty-directory hides empty directory' '
test_cmp expected3 output
'
+test_expect_success SYMLINKS 'ls-files --others with symlinked submodule' '
+ git init super &&
+ git init sub &&
+ (
+ cd sub &&
+ >a &&
+ git add a &&
+ git commit -m sub &&
+ git pack-refs --all
+ ) &&
+ (
+ cd super &&
+ "$SHELL_PATH" "$TEST_DIRECTORY/../contrib/workdir/git-new-workdir" ../sub sub
+ git ls-files --others --exclude-standard >../actual
+ ) &&
+ echo sub/ >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t3005-ls-files-relative.sh b/t/t3005-ls-files-relative.sh
new file mode 100755
index 0000000000..377869432e
--- /dev/null
+++ b/t/t3005-ls-files-relative.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+test_description='ls-files tests with relative paths
+
+This test runs git ls-files with various relative path arguments.
+'
+
+. ./test-lib.sh
+
+new_line='
+'
+sq=\'
+
+test_expect_success 'prepare' '
+ : >never-mind-me &&
+ git add never-mind-me &&
+ mkdir top &&
+ (
+ cd top &&
+ mkdir sub &&
+ x="x xa xbc xdef xghij xklmno" &&
+ y=$(echo "$x" | tr x y) &&
+ touch $x &&
+ touch $y &&
+ cd sub &&
+ git add ../x*
+ )
+'
+
+test_expect_success 'ls-files with mixed levels' '
+ (
+ cd top/sub &&
+ cat >expect <<-EOF &&
+ ../../never-mind-me
+ ../x
+ EOF
+ git ls-files $(cat expect) >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'ls-files -c' '
+ (
+ cd top/sub &&
+ for f in ../y*
+ do
+ echo "error: pathspec $sq$f$sq did not match any file(s) known to git."
+ done >expect.err &&
+ echo "Did you forget to ${sq}git add${sq}?" >>expect.err &&
+ ls ../x* >expect.out &&
+ test_must_fail git ls-files -c --error-unmatch ../[xy]* >actual.out 2>actual.err &&
+ test_cmp expect.out actual.out &&
+ test_cmp expect.err actual.err
+ )
+'
+
+test_expect_success 'ls-files -o' '
+ (
+ cd top/sub &&
+ for f in ../x*
+ do
+ echo "error: pathspec $sq$f$sq did not match any file(s) known to git."
+ done >expect.err &&
+ echo "Did you forget to ${sq}git add${sq}?" >>expect.err &&
+ ls ../y* >expect.out &&
+ test_must_fail git ls-files -o --error-unmatch ../[xy]* >actual.out 2>actual.err &&
+ test_cmp expect.out actual.out &&
+ test_cmp expect.err actual.err
+ )
+'
+
+test_done
diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh
index 34794f8a70..55ef1895d7 100755
--- a/t/t3030-merge-recursive.sh
+++ b/t/t3030-merge-recursive.sh
@@ -267,7 +267,8 @@ test_expect_success 'setup 8' '
ln -s e a &&
git add a e &&
test_tick &&
- git commit -m "rename a->e, symlink a->e"
+ git commit -m "rename a->e, symlink a->e" &&
+ oln=`printf e | git hash-object --stdin`
fi
'
@@ -319,13 +320,13 @@ test_expect_success 'fail if the index has unresolved entries' '
test_must_fail git merge "$c5" &&
test_must_fail git merge "$c5" 2> out &&
- grep "not possible because you have unmerged files" out &&
+ test_i18ngrep "not possible because you have unmerged files" out &&
git add -u &&
test_must_fail git merge "$c5" 2> out &&
- grep "You have not concluded your merge" out &&
+ test_i18ngrep "You have not concluded your merge" out &&
rm -f .git/MERGE_HEAD &&
test_must_fail git merge "$c5" 2> out &&
- grep "Your local changes to the following files would be overwritten by merge:" out
+ test_i18ngrep "Your local changes to the following files would be overwritten by merge:" out
'
test_expect_success 'merge-recursive remove conflict' '
@@ -630,16 +631,18 @@ test_expect_success 'merge-recursive copy vs. rename' '
if test_have_prereq SYMLINKS
then
- test_expect_success 'merge-recursive rename vs. rename/symlink' '
+ test_expect_failure 'merge-recursive rename vs. rename/symlink' '
git checkout -f rename &&
git merge rename-ln &&
( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
(
+ echo "120000 blob $oln a"
echo "100644 blob $o0 b"
echo "100644 blob $o0 c"
echo "100644 blob $o0 d/e"
echo "100644 blob $o0 e"
+ echo "120000 $oln 0 a"
echo "100644 $o0 0 b"
echo "100644 $o0 0 c"
echo "100644 $o0 0 d/e"
diff --git a/t/t3032-merge-recursive-options.sh b/t/t3032-merge-recursive-options.sh
index 44f5421be4..2b17311cb0 100755
--- a/t/t3032-merge-recursive-options.sh
+++ b/t/t3032-merge-recursive-options.sh
@@ -110,6 +110,20 @@ test_expect_success '--ignore-space-change makes merge succeed' '
git merge-recursive --ignore-space-change HEAD^ -- HEAD remote
'
+test_expect_success 'naive cherry-pick fails' '
+ git read-tree --reset -u HEAD &&
+ test_must_fail git cherry-pick --no-commit remote &&
+ git read-tree --reset -u HEAD &&
+ test_must_fail git cherry-pick remote &&
+ test_must_fail git update-index --refresh &&
+ grep "<<<<<<" text.txt
+'
+
+test_expect_success '-Xignore-space-change makes cherry-pick succeed' '
+ git read-tree --reset -u HEAD &&
+ git cherry-pick --no-commit -Xignore-space-change remote
+'
+
test_expect_success '--ignore-space-change: our w/s-only change wins' '
q_to_cr <<-\EOF >expected &&
justice and holiness and is the nurse of his age and theQ
diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
new file mode 100755
index 0000000000..c286854485
--- /dev/null
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+test_description='ls-tree with(out) globs'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ mkdir a aa "a[a]" &&
+ touch a/one aa/two "a[a]/three" &&
+ git add a/one aa/two "a[a]/three" &&
+ git commit -m test
+'
+
+test_expect_success 'ls-tree a[a] matches literally' '
+ cat >expected <<EOF &&
+100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a[a]/three
+EOF
+ git ls-tree -r HEAD "a[a]" >actual &&
+ test_cmp expected actual
+'
+
+test_done
diff --git a/t/t3103-ls-tree-misc.sh b/t/t3103-ls-tree-misc.sh
new file mode 100755
index 0000000000..09dcf043fd
--- /dev/null
+++ b/t/t3103-ls-tree-misc.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+test_description='
+Miscellaneous tests for git ls-tree.
+
+ 1. git ls-tree fails in presence of tree damage.
+
+'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ mkdir a &&
+ touch a/one &&
+ git add a/one &&
+ git commit -m test
+'
+
+test_expect_success 'ls-tree fails with non-zero exit code on broken tree' '
+ rm -f .git/objects/5f/cffbd6e4c5c5b8d81f5e9314b20e338e3ffff5 &&
+ test_must_fail git ls-tree -r HEAD
+'
+
+test_done
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index f308235f5d..2f5eada0d2 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -23,7 +23,7 @@ test_expect_success \
test_expect_success \
'git branch --help should not have created a bogus branch' '
git branch --help </dev/null >/dev/null 2>/dev/null;
- ! test -f .git/refs/heads/--help
+ test_path_is_missing .git/refs/heads/--help
'
test_expect_success 'branch -h in broken repository' '
@@ -39,28 +39,28 @@ test_expect_success 'branch -h in broken repository' '
test_expect_success \
'git branch abc should create a branch' \
- 'git branch abc && test -f .git/refs/heads/abc'
+ 'git branch abc && test_path_is_file .git/refs/heads/abc'
test_expect_success \
'git branch a/b/c should create a branch' \
- 'git branch a/b/c && test -f .git/refs/heads/a/b/c'
+ 'git branch a/b/c && test_path_is_file .git/refs/heads/a/b/c'
cat >expect <<EOF
-0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master
+$_z40 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master
EOF
test_expect_success \
'git branch -l d/e/f should create a branch and a log' \
'GIT_COMMITTER_DATE="2005-05-26 23:30" \
git branch -l d/e/f &&
- test -f .git/refs/heads/d/e/f &&
- test -f .git/logs/refs/heads/d/e/f &&
+ test_path_is_file .git/refs/heads/d/e/f &&
+ test_path_is_file .git/logs/refs/heads/d/e/f &&
test_cmp expect .git/logs/refs/heads/d/e/f'
test_expect_success \
'git branch -d d/e/f should delete a branch and a log' \
'git branch -d d/e/f &&
- test ! -f .git/refs/heads/d/e/f &&
- test ! -f .git/logs/refs/heads/d/e/f'
+ test_path_is_missing .git/refs/heads/d/e/f &&
+ test_path_is_missing .git/logs/refs/heads/d/e/f'
test_expect_success \
'git branch j/k should work after branch j has been deleted' \
@@ -78,13 +78,13 @@ test_expect_success \
'git branch -m m m/m should work' \
'git branch -l m &&
git branch -m m m/m &&
- test -f .git/logs/refs/heads/m/m'
+ test_path_is_file .git/logs/refs/heads/m/m'
test_expect_success \
'git branch -m n/n n should work' \
'git branch -l n/n &&
git branch -m n/n n
- test -f .git/logs/refs/heads/n'
+ test_path_is_file .git/logs/refs/heads/n'
test_expect_success 'git branch -m o/o o should fail when o/p exists' '
git branch o/o &&
@@ -98,6 +98,50 @@ test_expect_success 'git branch -m q r/q should fail when r exists' '
test_must_fail git branch -m q r/q
'
+test_expect_success 'git branch -M foo bar should fail when bar is checked out' '
+ git branch bar &&
+ git checkout -b foo &&
+ test_must_fail git branch -M bar foo
+'
+
+test_expect_success 'git branch -M baz bam should succeed when baz is checked out' '
+ git checkout -b baz &&
+ git branch bam &&
+ git branch -M baz bam
+'
+
+test_expect_success 'git branch -v -d t should work' '
+ git branch t &&
+ test_path_is_file .git/refs/heads/t &&
+ git branch -v -d t &&
+ test_path_is_missing .git/refs/heads/t
+'
+
+test_expect_success 'git branch -v -m t s should work' '
+ git branch t &&
+ test_path_is_file .git/refs/heads/t &&
+ git branch -v -m t s &&
+ test_path_is_missing .git/refs/heads/t &&
+ test_path_is_file .git/refs/heads/s &&
+ git branch -d s
+'
+
+test_expect_success 'git branch -m -d t s should fail' '
+ git branch t &&
+ test_path_is_file .git/refs/heads/t &&
+ test_must_fail git branch -m -d t s &&
+ git branch -d t &&
+ test_path_is_missing .git/refs/heads/t
+'
+
+test_expect_success 'git branch --list -d t should fail' '
+ git branch t &&
+ test_path_is_file .git/refs/heads/t &&
+ test_must_fail git branch --list -d t &&
+ git branch -d t &&
+ test_path_is_missing .git/refs/heads/t
+'
+
mv .git/config .git/config-saved
test_expect_success 'git branch -m q q2 without config should succeed' '
@@ -112,12 +156,12 @@ git config branch.s/s.dummy Hello
test_expect_success \
'git branch -m s/s s should work when s/t is deleted' \
'git branch -l s/s &&
- test -f .git/logs/refs/heads/s/s &&
+ test_path_is_file .git/logs/refs/heads/s/s &&
git branch -l s/t &&
- test -f .git/logs/refs/heads/s/t &&
+ test_path_is_file .git/logs/refs/heads/s/t &&
git branch -d s/t &&
git branch -m s/s s &&
- test -f .git/logs/refs/heads/s'
+ test_path_is_file .git/logs/refs/heads/s'
test_expect_success 'config information was renamed, too' \
"test $(git config branch.s.dummy) = Hello &&
@@ -128,8 +172,8 @@ test_expect_success 'renaming a symref is not allowed' \
git symbolic-ref refs/heads/master2 refs/heads/master &&
test_must_fail git branch -m master2 master3 &&
git symbolic-ref refs/heads/master2 &&
- test -f .git/refs/heads/master &&
- ! test -f .git/refs/heads/master3
+ test_path_is_file .git/refs/heads/master &&
+ test_path_is_missing .git/refs/heads/master3
'
test_expect_success SYMLINKS \
@@ -206,7 +250,9 @@ test_expect_success 'test deleting branch deletes branch config' \
test_expect_success 'test deleting branch without config' \
'git branch my7 s &&
sha1=$(git rev-parse my7 | cut -c 1-7) &&
- test "$(git branch -d my7 2>&1)" = "Deleted branch my7 (was $sha1)."'
+ echo "Deleted branch my7 (was $sha1)." >expect &&
+ git branch -d my7 >actual 2>&1 &&
+ test_i18ncmp expect actual'
test_expect_success 'test --track without .fetch entries' \
'git branch --track my8 &&
@@ -223,16 +269,21 @@ test_expect_success \
'branch from non-branch HEAD w/--track causes failure' \
'test_must_fail git branch --track my10 HEAD^'
+test_expect_success \
+ 'branch from tag w/--track causes failure' \
+ 'git tag foobar &&
+ test_must_fail git branch --track my11 foobar'
+
# Keep this test last, as it changes the current branch
cat >expect <<EOF
-0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master
+$_z40 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master
EOF
test_expect_success \
'git checkout -b g/h/i -l should create a branch and a log' \
'GIT_COMMITTER_DATE="2005-05-26 23:30" \
git checkout -b g/h/i -l master &&
- test -f .git/refs/heads/g/h/i &&
- test -f .git/logs/refs/heads/g/h/i &&
+ test_path_is_file .git/refs/heads/g/h/i &&
+ test_path_is_file .git/logs/refs/heads/g/h/i &&
test_cmp expect .git/logs/refs/heads/g/h/i'
test_expect_success 'checkout -b makes reflog by default' '
@@ -488,6 +539,15 @@ test_expect_success 'autosetuprebase always on an untracked remote branch' '
test "z$(git config branch.myr20.rebase)" = z
'
+test_expect_success 'autosetuprebase always on detached HEAD' '
+ git config branch.autosetupmerge always &&
+ test_when_finished git checkout master &&
+ git checkout HEAD^0 &&
+ git branch my11 &&
+ test -z "$(git config branch.my11.remote)" &&
+ test -z "$(git config branch.my11.merge)"
+'
+
test_expect_success 'detect misconfigured autosetuprebase (bad value)' '
git config branch.autosetuprebase garbage &&
test_must_fail git branch
@@ -526,4 +586,17 @@ test_expect_success 'attempt to delete a branch merged to its base' '
test_must_fail git branch -d my10
'
+test_expect_success 'use set-upstream on the current branch' '
+ git checkout master &&
+ git --bare init myupstream.git &&
+ git push myupstream.git master:refs/heads/frotz &&
+ git remote add origin myupstream.git &&
+ git fetch &&
+ git branch --set-upstream master origin/frotz &&
+
+ test "z$(git config branch.master.remote)" = "zorigin" &&
+ test "z$(git config branch.master.merge)" = "zrefs/heads/frotz"
+
+'
+
test_done
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index 6028748c6c..76fe7e0060 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -32,6 +32,20 @@ test_expect_success 'git branch shows local branches' '
test_cmp expect actual
'
+test_expect_success 'git branch --list shows local branches' '
+ git branch --list >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+ branch-one
+ branch-two
+EOF
+test_expect_success 'git branch --list pattern shows matching local branches' '
+ git branch --list branch* >actual &&
+ test_cmp expect actual
+'
+
cat >expect <<'EOF'
origin/HEAD -> origin/branch-one
origin/branch-one
@@ -67,6 +81,20 @@ test_expect_success 'git branch -v shows branch summaries' '
'
cat >expect <<'EOF'
+two
+one
+EOF
+test_expect_success 'git branch --list -v pattern shows branch summaries' '
+ git branch --list -v branch* >tmp &&
+ awk "{print \$NF}" <tmp >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git branch -v pattern does not show branch summaries' '
+ test_must_fail git branch -v branch*
+'
+
+cat >expect <<'EOF'
* (no branch)
branch-one
branch-two
@@ -75,7 +103,7 @@ EOF
test_expect_success 'git branch shows detached HEAD properly' '
git checkout HEAD^0 &&
git branch >actual &&
- test_cmp expect actual
+ test_i18ncmp expect actual
'
test_done
diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh
index 1921ca3a73..16de05aff9 100755
--- a/t/t3301-notes.sh
+++ b/t/t3301-notes.sh
@@ -101,8 +101,8 @@ test_expect_success 'edit existing notes' '
test_must_fail git notes show HEAD^
'
-test_expect_success 'cannot add note where one exists' '
- ! MSG=b2 git notes add &&
+test_expect_success 'cannot "git notes add -m" where notes already exists' '
+ test_must_fail git notes add -m "b2" &&
test ! -f .git/NOTES_EDITMSG &&
test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
test b3 = $(git notes show) &&
@@ -110,6 +110,24 @@ test_expect_success 'cannot add note where one exists' '
test_must_fail git notes show HEAD^
'
+test_expect_success 'can overwrite existing note with "git notes add -f -m"' '
+ git notes add -f -m "b1" &&
+ test ! -f .git/NOTES_EDITMSG &&
+ test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
+ test b1 = $(git notes show) &&
+ git show HEAD^ &&
+ test_must_fail git notes show HEAD^
+'
+
+test_expect_success 'add w/no options on existing note morphs into edit' '
+ MSG=b2 git notes add &&
+ test ! -f .git/NOTES_EDITMSG &&
+ test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
+ test b2 = $(git notes show) &&
+ git show HEAD^ &&
+ test_must_fail git notes show HEAD^
+'
+
test_expect_success 'can overwrite existing note with "git notes add -f"' '
MSG=b1 git notes add -f &&
test ! -f .git/NOTES_EDITMSG &&
@@ -194,6 +212,13 @@ test_expect_success 'show -F notes' '
test_cmp expect-F output
'
+test_expect_success 'Re-adding -F notes without -f fails' '
+ echo "zyxxy" > note5 &&
+ test_must_fail git notes add -F note5 &&
+ git log -3 > output &&
+ test_cmp expect-F output
+'
+
cat >expect << EOF
commit 15023535574ded8b1a89052b32673f84cf9582b8
tree e070e3af51011e47b183c33adf9736736a525709
@@ -247,6 +272,44 @@ do
'
done
+test_expect_success 'setup alternate notes ref' '
+ git notes --ref=alternate add -m alternate
+'
+
+test_expect_success 'git log --notes shows default notes' '
+ git log -1 --notes >output &&
+ grep xyzzy output &&
+ ! grep alternate output
+'
+
+test_expect_success 'git log --notes=X shows only X' '
+ git log -1 --notes=alternate >output &&
+ ! grep xyzzy output &&
+ grep alternate output
+'
+
+test_expect_success 'git log --notes --notes=X shows both' '
+ git log -1 --notes --notes=alternate >output &&
+ grep xyzzy output &&
+ grep alternate output
+'
+
+test_expect_success 'git log --no-notes resets default state' '
+ git log -1 --notes --notes=alternate \
+ --no-notes --notes=alternate \
+ >output &&
+ ! grep xyzzy output &&
+ grep alternate output
+'
+
+test_expect_success 'git log --no-notes resets ref list' '
+ git log -1 --notes --notes=alternate \
+ --no-notes --notes \
+ >output &&
+ grep xyzzy output &&
+ ! grep alternate output
+'
+
test_expect_success 'create -m notes (setup)' '
: > a5 &&
git add a5 &&
@@ -372,6 +435,81 @@ test_expect_success 'removing non-existing note should not create new commit' '
test_cmp before_commit after_commit
'
+test_expect_success 'removing more than one' '
+ before=$(git rev-parse --verify refs/notes/commits) &&
+ test_when_finished "git update-ref refs/notes/commits $before" &&
+
+ # We have only two -- add another and make sure it stays
+ git notes add -m "extra" &&
+ git notes list HEAD >after-removal-expect &&
+ git notes remove HEAD^^ HEAD^^^ &&
+ git notes list | sed -e "s/ .*//" >actual &&
+ test_cmp after-removal-expect actual
+'
+
+test_expect_success 'removing is atomic' '
+ before=$(git rev-parse --verify refs/notes/commits) &&
+ test_when_finished "git update-ref refs/notes/commits $before" &&
+ test_must_fail git notes remove HEAD^^ HEAD^^^ HEAD^ &&
+ after=$(git rev-parse --verify refs/notes/commits) &&
+ test "$before" = "$after"
+'
+
+test_expect_success 'removing with --ignore-missing' '
+ before=$(git rev-parse --verify refs/notes/commits) &&
+ test_when_finished "git update-ref refs/notes/commits $before" &&
+
+ # We have only two -- add another and make sure it stays
+ git notes add -m "extra" &&
+ git notes list HEAD >after-removal-expect &&
+ git notes remove --ignore-missing HEAD^^ HEAD^^^ HEAD^ &&
+ git notes list | sed -e "s/ .*//" >actual &&
+ test_cmp after-removal-expect actual
+'
+
+test_expect_success 'removing with --ignore-missing but bogus ref' '
+ before=$(git rev-parse --verify refs/notes/commits) &&
+ test_when_finished "git update-ref refs/notes/commits $before" &&
+ test_must_fail git notes remove --ignore-missing HEAD^^ HEAD^^^ NO-SUCH-COMMIT &&
+ after=$(git rev-parse --verify refs/notes/commits) &&
+ test "$before" = "$after"
+'
+
+test_expect_success 'remove reads from --stdin' '
+ before=$(git rev-parse --verify refs/notes/commits) &&
+ test_when_finished "git update-ref refs/notes/commits $before" &&
+
+ # We have only two -- add another and make sure it stays
+ git notes add -m "extra" &&
+ git notes list HEAD >after-removal-expect &&
+ git rev-parse HEAD^^ HEAD^^^ >input &&
+ git notes remove --stdin <input &&
+ git notes list | sed -e "s/ .*//" >actual &&
+ test_cmp after-removal-expect actual
+'
+
+test_expect_success 'remove --stdin is also atomic' '
+ before=$(git rev-parse --verify refs/notes/commits) &&
+ test_when_finished "git update-ref refs/notes/commits $before" &&
+ git rev-parse HEAD^^ HEAD^^^ HEAD^ >input &&
+ test_must_fail git notes remove --stdin <input &&
+ after=$(git rev-parse --verify refs/notes/commits) &&
+ test "$before" = "$after"
+'
+
+test_expect_success 'removing with --stdin --ignore-missing' '
+ before=$(git rev-parse --verify refs/notes/commits) &&
+ test_when_finished "git update-ref refs/notes/commits $before" &&
+
+ # We have only two -- add another and make sure it stays
+ git notes add -m "extra" &&
+ git notes list HEAD >after-removal-expect &&
+ git rev-parse HEAD^^ HEAD^^^ HEAD^ >input &&
+ git notes remove --ignore-missing --stdin <input &&
+ git notes list | sed -e "s/ .*//" >actual &&
+ test_cmp after-removal-expect actual
+'
+
test_expect_success 'list notes with "git notes list"' '
git notes list > output &&
test_cmp expect output
diff --git a/t/t3306-notes-prune.sh b/t/t3306-notes-prune.sh
index c4282179b3..86bf909ee3 100755
--- a/t/t3306-notes-prune.sh
+++ b/t/t3306-notes-prune.sh
@@ -20,6 +20,9 @@ test_expect_success 'setup: create a few commits with notes' '
git add file3 &&
test_tick &&
git commit -m 3rd &&
+ COMMIT_FILE=.git/objects/5e/e1c35e83ea47cd3cc4f8cbee0568915fbbbd29 &&
+ test -f $COMMIT_FILE &&
+ test-chmtime =+0 $COMMIT_FILE &&
git notes add -m "Note #3"
'
diff --git a/t/t3307-notes-man.sh b/t/t3307-notes-man.sh
index 2ea3be6546..1aa366a410 100755
--- a/t/t3307-notes-man.sh
+++ b/t/t3307-notes-man.sh
@@ -26,13 +26,13 @@ test_expect_success 'example 1: notes to add an Acked-by line' '
'
test_expect_success 'example 2: binary notes' '
- cp "$TEST_DIRECTORY"/test4012.png . &&
+ cp "$TEST_DIRECTORY"/test-binary-1.png . &&
git checkout B &&
- blob=$(git hash-object -w test4012.png) &&
+ blob=$(git hash-object -w test-binary-1.png) &&
git notes --ref=logo add -C "$blob" &&
git notes --ref=logo copy B C &&
git notes --ref=logo show C >actual &&
- test_cmp test4012.png actual
+ test_cmp test-binary-1.png actual
'
test_done
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 349eebd542..6eaecec906 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -158,15 +158,24 @@ test_expect_success 'Show verbose error when HEAD could not be detached' '
'
rm -f B
-test_expect_success 'dump usage when upstream arg is missing' '
- git checkout -b usage topic &&
- test_must_fail git rebase 2>error1 &&
- grep "[Uu]sage" error1 &&
- test_must_fail git rebase --abort 2>error2 &&
- grep "No rebase in progress" error2 &&
- test_must_fail git rebase --onto master 2>error3 &&
- grep "[Uu]sage" error3 &&
- ! grep "can.t shift" error3
+test_expect_success 'fail when upstream arg is missing and not on branch' '
+ git checkout topic &&
+ test_must_fail git rebase >output.out &&
+ grep "You are not currently on a branch" output.out
+'
+
+test_expect_success 'fail when upstream arg is missing and not configured' '
+ git checkout -b no-config topic &&
+ test_must_fail git rebase >output.out &&
+ grep "branch.no-config.merge" output.out
+'
+
+test_expect_success 'default to @{upstream} when upstream arg is missing' '
+ git checkout -b default topic &&
+ git config branch.default.remote .
+ git config branch.default.merge refs/heads/master
+ git rebase &&
+ test "$(git rev-parse default~1)" = "$(git rev-parse master)"
'
test_expect_success 'rebase -q is quiet' '
diff --git a/t/t3403-rebase-skip.sh b/t/t3403-rebase-skip.sh
index 64446e3db3..826500bd18 100755
--- a/t/t3403-rebase-skip.sh
+++ b/t/t3403-rebase-skip.sh
@@ -35,6 +35,11 @@ test_expect_success 'rebase with git am -3 (default)' '
test_must_fail git rebase master
'
+test_expect_success 'rebase --skip can not be used with other options' '
+ test_must_fail git rebase -v --skip &&
+ test_must_fail git rebase --skip -v
+'
+
test_expect_success 'rebase --skip with am -3' '
git rebase --skip
'
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 7d8147bb93..b981572d73 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -295,7 +295,7 @@ test_expect_success 'preserve merges with -p' '
'
test_expect_success 'edit ancestor with -p' '
- FAKE_LINES="1 edit 2 3 4" git rebase -i -p HEAD~3 &&
+ FAKE_LINES="1 2 edit 3 4" git rebase -i -p HEAD~3 &&
echo 2 > unrelated-file &&
test_tick &&
git commit -m L2-modified --amend unrelated-file &&
@@ -317,7 +317,7 @@ test_expect_success '--continue tries to commit' '
'
test_expect_success 'verbose flag is heeded, even after --continue' '
- git reset --hard HEAD@{1} &&
+ git reset --hard master@{1} &&
test_tick &&
test_must_fail git rebase -v -i --onto new-branch1 HEAD^ &&
echo resolved > file1 &&
@@ -527,6 +527,20 @@ test_expect_success 'auto-amend only edited commits after "edit"' '
git rebase --abort
'
+test_expect_success 'clean error after failed "exec"' '
+ test_tick &&
+ test_when_finished "git rebase --abort || :" &&
+ (
+ FAKE_LINES="1 exec_false" &&
+ export FAKE_LINES &&
+ test_must_fail git rebase -i HEAD^
+ ) &&
+ echo "edited again" > file7 &&
+ git add file7 &&
+ test_must_fail git rebase --continue 2>error &&
+ grep "You have staged changes in your working tree." error
+'
+
test_expect_success 'rebase a detached HEAD' '
grandparent=$(git rev-parse HEAD~2) &&
git checkout $(git rev-parse HEAD) &&
diff --git a/t/t3407-rebase-abort.sh b/t/t3407-rebase-abort.sh
index e573dc845b..a6a6c40a98 100755
--- a/t/t3407-rebase-abort.sh
+++ b/t/t3407-rebase-abort.sh
@@ -84,6 +84,16 @@ testrebase() {
test_cmp reflog_before reflog_after &&
rm reflog_before reflog_after
'
+
+ test_expect_success 'rebase --abort can not be used with other options' '
+ cd "$work_dir" &&
+ # Clean up the state from the previous one
+ git reset --hard pre-rebase &&
+ test_must_fail git rebase$type master &&
+ test_must_fail git rebase -v --abort &&
+ test_must_fail git rebase --abort -v &&
+ git rebase --abort
+ '
}
testrebase "" .git/rebase-apply
diff --git a/t/t3409-rebase-preserve-merges.sh b/t/t3409-rebase-preserve-merges.sh
index 19341e5ca1..6de4e2263f 100755
--- a/t/t3409-rebase-preserve-merges.sh
+++ b/t/t3409-rebase-preserve-merges.sh
@@ -27,7 +27,25 @@ export GIT_AUTHOR_EMAIL
# \
# B2 <-- origin/topic
#
-# In both cases, 'topic' is rebased onto 'origin/topic'.
+# Clone 3 (no-ff merge):
+#
+# A1--A2--B3 <-- origin/master
+# \
+# B1------M <-- topic
+# \ /
+# \--A3 <-- topic2
+# \
+# B2 <-- origin/topic
+#
+# Clone 4 (merge using second parent as base):
+#
+# A1--A2--B3 <-- origin/master
+# \
+# B1--A3--M <-- topic
+# \ /
+# \--A4 <-- topic2
+# \
+# B2 <-- origin/topic
test_expect_success 'setup for merge-preserving rebase' \
'echo First > A &&
@@ -47,6 +65,13 @@ test_expect_success 'setup for merge-preserving rebase' \
git merge origin/master
) &&
+ git clone ./. clone4 &&
+ (
+ cd clone4 &&
+ git checkout -b topic origin/topic &&
+ git merge origin/master
+ ) &&
+
echo Fifth > B &&
git add B &&
git commit -m "Add different B" &&
@@ -61,6 +86,16 @@ test_expect_success 'setup for merge-preserving rebase' \
git commit -m "Merge origin/master into topic"
) &&
+ git clone ./. clone3 &&
+ (
+ cd clone3 &&
+ git checkout -b topic2 origin/topic &&
+ echo Sixth > A &&
+ git commit -a -m "Modify A3" &&
+ git checkout -b topic origin/topic &&
+ git merge --no-ff topic2
+ ) &&
+
git checkout topic &&
echo Fourth >> B &&
git commit -a -m "Modify B2"
@@ -93,4 +128,25 @@ test_expect_success '--continue works after a conflict' '
)
'
+test_expect_success 'rebase -p preserves no-ff merges' '
+ (
+ cd clone3 &&
+ git fetch &&
+ git rebase -p origin/topic &&
+ test 3 = $(git rev-list --all --pretty=oneline | grep "Modify A" | wc -l) &&
+ test 1 = $(git rev-list --all --pretty=oneline | grep "Merge branch" | wc -l)
+ )
+'
+
+test_expect_success 'rebase -p works when base inside second parent' '
+ (
+ cd clone4 &&
+ git fetch &&
+ git rebase -p HEAD^2 &&
+ test 1 = $(git rev-list --all --pretty=oneline | grep "Modify A" | wc -l) &&
+ test 1 = $(git rev-list --all --pretty=oneline | grep "Modify B" | wc -l) &&
+ test 1 = $(git rev-list --all --pretty=oneline | grep "Merge remote-tracking branch " | wc -l)
+ )
+'
+
test_done
diff --git a/t/t3411-rebase-preserve-around-merges.sh b/t/t3411-rebase-preserve-around-merges.sh
index 14a23cd872..ace8e54e9b 100755
--- a/t/t3411-rebase-preserve-around-merges.sh
+++ b/t/t3411-rebase-preserve-around-merges.sh
@@ -37,7 +37,7 @@ test_expect_success 'setup' '
# -- C1 --
#
test_expect_success 'squash F1 into D1' '
- FAKE_LINES="1 squash 3 2" git rebase -i -p B1 &&
+ FAKE_LINES="1 squash 4 2 3" git rebase -i -p B1 &&
test "$(git rev-parse HEAD^2)" = "$(git rev-parse C1)" &&
test "$(git rev-parse HEAD~2)" = "$(git rev-parse B1)" &&
git tag E2
diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh
index 3b0d27350e..1e855cdae5 100755
--- a/t/t3418-rebase-continue.sh
+++ b/t/t3418-rebase-continue.sh
@@ -40,4 +40,59 @@ test_expect_success 'non-interactive rebase --continue works with touched file'
git rebase --continue
'
+test_expect_success 'rebase --continue can not be used with other options' '
+ test_must_fail git rebase -v --continue &&
+ test_must_fail git rebase --continue -v
+'
+
+test_expect_success 'rebase --continue remembers merge strategy and options' '
+ rm -fr .git/rebase-* &&
+ git reset --hard commit-new-file-F2-on-topic-branch &&
+ test_commit "commit-new-file-F3-on-topic-branch" F3 32 &&
+ test_when_finished "rm -fr test-bin funny.was.run" &&
+ mkdir test-bin &&
+ cat >test-bin/git-merge-funny <<-EOF
+ #!$SHELL_PATH
+ case "\$1" in --opt) ;; *) exit 2 ;; esac
+ shift &&
+ >funny.was.run &&
+ exec git merge-recursive "\$@"
+ EOF
+ chmod +x test-bin/git-merge-funny &&
+ (
+ PATH=./test-bin:$PATH
+ test_must_fail git rebase -s funny -Xopt master topic
+ ) &&
+ test -f funny.was.run &&
+ rm funny.was.run &&
+ echo "Resolved" >F2 &&
+ git add F2 &&
+ (
+ PATH=./test-bin:$PATH
+ git rebase --continue
+ ) &&
+ test -f funny.was.run
+'
+
+test_expect_success 'rebase --continue remembers --rerere-autoupdate' '
+ rm -fr .git/rebase-* &&
+ git reset --hard commit-new-file-F3-on-topic-branch &&
+ git checkout master
+ test_commit "commit-new-file-F3" F3 3 &&
+ git config rerere.enabled true &&
+ test_must_fail git rebase -m master topic &&
+ echo "Resolved" >F2 &&
+ git add F2 &&
+ test_must_fail git rebase --continue &&
+ echo "Resolved" >F3 &&
+ git add F3 &&
+ git rebase --continue &&
+ git reset --hard topic@{1} &&
+ test_must_fail git rebase -m --rerere-autoupdate master &&
+ test "$(cat F2)" = "Resolved" &&
+ test_must_fail git rebase --continue &&
+ test "$(cat F3)" = "Resolved" &&
+ git rebase --continue
+'
+
test_done
diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh
index 043954422c..595d2ff990 100755
--- a/t/t3501-revert-cherry-pick.sh
+++ b/t/t3501-revert-cherry-pick.sh
@@ -96,7 +96,7 @@ test_expect_success 'revert forbidden on dirty working tree' '
echo content >extra_file &&
git add extra_file &&
test_must_fail git revert HEAD 2>errors &&
- grep "Your local changes would be overwritten by " errors
+ test_i18ngrep "Your local changes would be overwritten by " errors
'
diff --git a/t/t3503-cherry-pick-root.sh b/t/t3503-cherry-pick-root.sh
index b0faa29918..e27f39d1e5 100755
--- a/t/t3503-cherry-pick-root.sh
+++ b/t/t3503-cherry-pick-root.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-test_description='test cherry-picking a root commit'
+test_description='test cherry-picking (and reverting) a root commit'
. ./test-lib.sh
@@ -16,14 +16,62 @@ test_expect_success setup '
echo second > file2 &&
git add file2 &&
test_tick &&
- git commit -m "second"
+ git commit -m "second" &&
+
+ git symbolic-ref HEAD refs/heads/third &&
+ rm .git/index file2 &&
+ echo third > file3 &&
+ git add file3 &&
+ test_tick &&
+ git commit -m "third"
'
test_expect_success 'cherry-pick a root commit' '
+ git checkout second^0 &&
git cherry-pick master &&
- test first = $(cat file1)
+ echo first >expect &&
+ test_cmp expect file1
+
+'
+
+test_expect_success 'revert a root commit' '
+
+ git revert master &&
+ test_path_is_missing file1
+
+'
+
+test_expect_success 'cherry-pick a root commit with an external strategy' '
+
+ git cherry-pick --strategy=resolve master &&
+ echo first >expect &&
+ test_cmp expect file1
+
+'
+
+test_expect_success 'revert a root commit with an external strategy' '
+
+ git revert --strategy=resolve master &&
+ test_path_is_missing file1
+
+'
+
+test_expect_success 'cherry-pick two root commits' '
+
+ echo first >expect.file1 &&
+ echo second >expect.file2 &&
+ echo third >expect.file3 &&
+
+ git checkout second^0 &&
+ git cherry-pick master third &&
+
+ test_cmp expect.file1 file1 &&
+ test_cmp expect.file2 file2 &&
+ test_cmp expect.file3 file3 &&
+ git rev-parse --verify HEAD^^ &&
+ test_must_fail git rev-parse --verify HEAD^^^
'
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index 607bf25d8f..cb45574a7b 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -11,6 +11,18 @@ test_description='test cherry-pick and revert with conflicts
. ./test-lib.sh
+test_cmp_rev () {
+ git rev-parse --verify "$1" >expect.rev &&
+ git rev-parse --verify "$2" >actual.rev &&
+ test_cmp expect.rev actual.rev
+}
+
+pristine_detach () {
+ git checkout -f "$1^0" &&
+ git read-tree -u --reset HEAD &&
+ git clean -d -f -f -q -x
+}
+
test_expect_success setup '
echo unrelated >unrelated &&
@@ -23,13 +35,7 @@ test_expect_success setup '
'
test_expect_success 'failed cherry-pick does not advance HEAD' '
-
- git checkout -f initial^0 &&
- git read-tree -u --reset HEAD &&
- git clean -d -f -f -q -x &&
-
- git update-index --refresh &&
- git diff-index --exit-code HEAD &&
+ pristine_detach initial &&
head=$(git rev-parse HEAD) &&
test_must_fail git cherry-pick picked &&
@@ -39,33 +45,111 @@ test_expect_success 'failed cherry-pick does not advance HEAD' '
'
test_expect_success 'advice from failed cherry-pick' "
- git checkout -f initial^0 &&
- git read-tree -u --reset HEAD &&
- git clean -d -f -f -q -x &&
-
- git update-index --refresh &&
- git diff-index --exit-code HEAD &&
+ pristine_detach initial &&
picked=\$(git rev-parse --short picked) &&
cat <<-EOF >expected &&
error: could not apply \$picked... picked
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
- hint: and commit the result with 'git commit -c \$picked'
+ hint: and commit the result with 'git commit'
EOF
test_must_fail git cherry-pick picked 2>actual &&
- test_cmp expected actual
+ test_i18ncmp expected actual
"
-test_expect_success 'failed cherry-pick produces dirty index' '
+test_expect_success 'failed cherry-pick sets CHERRY_PICK_HEAD' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick picked &&
+ test_cmp_rev picked CHERRY_PICK_HEAD
+'
- git checkout -f initial^0 &&
- git read-tree -u --reset HEAD &&
- git clean -d -f -f -q -x &&
+test_expect_success 'successful cherry-pick does not set CHERRY_PICK_HEAD' '
+ pristine_detach initial &&
+ git cherry-pick base &&
+ test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
+'
+
+test_expect_success 'cherry-pick --no-commit does not set CHERRY_PICK_HEAD' '
+ pristine_detach initial &&
+ git cherry-pick --no-commit base &&
+ test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
+'
- git update-index --refresh &&
- git diff-index --exit-code HEAD &&
+test_expect_success 'cherry-pick w/dirty tree does not set CHERRY_PICK_HEAD' '
+ pristine_detach initial &&
+ echo foo > foo &&
+ test_must_fail git cherry-pick base &&
+ test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
+'
+
+test_expect_success \
+ 'cherry-pick --strategy=resolve w/dirty tree does not set CHERRY_PICK_HEAD' '
+ pristine_detach initial &&
+ echo foo > foo &&
+ test_must_fail git cherry-pick --strategy=resolve base &&
+ test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
+'
+
+test_expect_success 'GIT_CHERRY_PICK_HELP suppresses CHERRY_PICK_HEAD' '
+ pristine_detach initial &&
+ (
+ GIT_CHERRY_PICK_HELP="and then do something else" &&
+ export GIT_CHERRY_PICK_HELP &&
+ test_must_fail git cherry-pick picked
+ ) &&
+ test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
+'
+
+test_expect_success 'git reset clears CHERRY_PICK_HEAD' '
+ pristine_detach initial &&
+
+ test_must_fail git cherry-pick picked &&
+ git reset &&
+
+ test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
+'
+
+test_expect_success 'failed commit does not clear CHERRY_PICK_HEAD' '
+ pristine_detach initial &&
+
+ test_must_fail git cherry-pick picked &&
+ test_must_fail git commit &&
+
+ test_cmp_rev picked CHERRY_PICK_HEAD
+'
+
+test_expect_success 'cancelled commit does not clear CHERRY_PICK_HEAD' '
+ pristine_detach initial &&
+
+ test_must_fail git cherry-pick picked &&
+ echo resolved >foo &&
+ git add foo &&
+ git update-index --refresh -q &&
+ test_must_fail git diff-index --exit-code HEAD &&
+ (
+ GIT_EDITOR=false &&
+ export GIT_EDITOR &&
+ test_must_fail git commit
+ ) &&
+
+ test_cmp_rev picked CHERRY_PICK_HEAD
+'
+
+test_expect_success 'successful commit clears CHERRY_PICK_HEAD' '
+ pristine_detach initial &&
+
+ test_must_fail git cherry-pick picked &&
+ echo resolved >foo &&
+ git add foo &&
+ git commit &&
+
+ test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
+'
+
+test_expect_success 'failed cherry-pick produces dirty index' '
+ pristine_detach initial &&
test_must_fail git cherry-pick picked &&
@@ -74,9 +158,7 @@ test_expect_success 'failed cherry-pick produces dirty index' '
'
test_expect_success 'failed cherry-pick registers participants in index' '
-
- git read-tree -u --reset HEAD &&
- git clean -d -f -f -q -x &&
+ pristine_detach initial &&
{
git checkout base -- foo &&
git ls-files --stage foo &&
@@ -90,10 +172,7 @@ test_expect_success 'failed cherry-pick registers participants in index' '
2 s/ 0 / 2 /
3 s/ 0 / 3 /
" < stages > expected &&
- git checkout -f initial^0 &&
-
- git update-index --refresh &&
- git diff-index --exit-code HEAD &&
+ git read-tree -u --reset HEAD &&
test_must_fail git cherry-pick picked &&
git ls-files --stage --unmerged > actual &&
@@ -102,10 +181,7 @@ test_expect_success 'failed cherry-pick registers participants in index' '
'
test_expect_success 'failed cherry-pick describes conflict in work tree' '
-
- git checkout -f initial^0 &&
- git read-tree -u --reset HEAD &&
- git clean -d -f -f -q -x &&
+ pristine_detach initial &&
cat <<-EOF > expected &&
<<<<<<< HEAD
a
@@ -114,9 +190,6 @@ test_expect_success 'failed cherry-pick describes conflict in work tree' '
>>>>>>> objid picked
EOF
- git update-index --refresh &&
- git diff-index --exit-code HEAD &&
-
test_must_fail git cherry-pick picked &&
sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
@@ -124,11 +197,8 @@ test_expect_success 'failed cherry-pick describes conflict in work tree' '
'
test_expect_success 'diff3 -m style' '
-
+ pristine_detach initial &&
git config merge.conflictstyle diff3 &&
- git checkout -f initial^0 &&
- git read-tree -u --reset HEAD &&
- git clean -d -f -f -q -x &&
cat <<-EOF > expected &&
<<<<<<< HEAD
a
@@ -139,9 +209,6 @@ test_expect_success 'diff3 -m style' '
>>>>>>> objid picked
EOF
- git update-index --refresh &&
- git diff-index --exit-code HEAD &&
-
test_must_fail git cherry-pick picked &&
sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
@@ -149,10 +216,8 @@ test_expect_success 'diff3 -m style' '
'
test_expect_success 'revert also handles conflicts sanely' '
-
git config --unset merge.conflictstyle &&
- git read-tree -u --reset HEAD &&
- git clean -d -f -f -q -x &&
+ pristine_detach initial &&
cat <<-EOF > expected &&
<<<<<<< HEAD
a
@@ -173,10 +238,7 @@ test_expect_success 'revert also handles conflicts sanely' '
2 s/ 0 / 2 /
3 s/ 0 / 3 /
" < stages > expected-stages &&
- git checkout -f initial^0 &&
-
- git update-index --refresh &&
- git diff-index --exit-code HEAD &&
+ git read-tree -u --reset HEAD &&
head=$(git rev-parse HEAD) &&
test_must_fail git revert picked &&
@@ -192,10 +254,8 @@ test_expect_success 'revert also handles conflicts sanely' '
'
test_expect_success 'revert conflict, diff3 -m style' '
+ pristine_detach initial &&
git config merge.conflictstyle diff3 &&
- git checkout -f initial^0 &&
- git read-tree -u --reset HEAD &&
- git clean -d -f -f -q -x &&
cat <<-EOF > expected &&
<<<<<<< HEAD
a
@@ -206,9 +266,6 @@ test_expect_success 'revert conflict, diff3 -m style' '
>>>>>>> parent of objid picked
EOF
- git update-index --refresh &&
- git diff-index --exit-code HEAD &&
-
test_must_fail git revert picked &&
sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
diff --git a/t/t3509-cherry-pick-merge-df.sh b/t/t3509-cherry-pick-merge-df.sh
index 948ca1bce6..df921d1f33 100755
--- a/t/t3509-cherry-pick-merge-df.sh
+++ b/t/t3509-cherry-pick-merge-df.sh
@@ -3,12 +3,14 @@
test_description='Test cherry-pick with directory/file conflicts'
. ./test-lib.sh
-test_expect_success SYMLINKS 'Setup rename across paths each below D/F conflicts' '
+test_expect_success 'Initialize repository' '
mkdir a &&
>a/f &&
git add a &&
- git commit -m a &&
+ git commit -m a
+'
+test_expect_success SYMLINKS 'Setup rename across paths each below D/F conflicts' '
mkdir b &&
ln -s ../a b/a &&
git add b &&
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
new file mode 100755
index 0000000000..3bca2b3dd5
--- /dev/null
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -0,0 +1,214 @@
+#!/bin/sh
+
+test_description='Test cherry-pick continuation features
+
+ + anotherpick: rewrites foo to d
+ + picked: rewrites foo to c
+ + unrelatedpick: rewrites unrelated to reallyunrelated
+ + base: rewrites foo to b
+ + initial: writes foo as a, unrelated as unrelated
+
+'
+
+. ./test-lib.sh
+
+pristine_detach () {
+ git cherry-pick --reset &&
+ git checkout -f "$1^0" &&
+ git read-tree -u --reset HEAD &&
+ git clean -d -f -f -q -x
+}
+
+test_expect_success setup '
+ echo unrelated >unrelated &&
+ git add unrelated &&
+ test_commit initial foo a &&
+ test_commit base foo b &&
+ test_commit unrelatedpick unrelated reallyunrelated &&
+ test_commit picked foo c &&
+ test_commit anotherpick foo d &&
+ git config advice.detachedhead false
+
+'
+
+test_expect_success 'cherry-pick persists data on failure' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick -s base..anotherpick &&
+ test_path_is_dir .git/sequencer &&
+ test_path_is_file .git/sequencer/head &&
+ test_path_is_file .git/sequencer/todo &&
+ test_path_is_file .git/sequencer/opts
+'
+
+test_expect_success 'cherry-pick persists opts correctly' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick -s -m 1 --strategy=recursive -X patience -X ours base..anotherpick &&
+ test_path_is_dir .git/sequencer &&
+ test_path_is_file .git/sequencer/head &&
+ test_path_is_file .git/sequencer/todo &&
+ test_path_is_file .git/sequencer/opts &&
+ echo "true" >expect &&
+ git config --file=.git/sequencer/opts --get-all options.signoff >actual &&
+ test_cmp expect actual &&
+ echo "1" >expect &&
+ git config --file=.git/sequencer/opts --get-all options.mainline >actual &&
+ test_cmp expect actual &&
+ echo "recursive" >expect &&
+ git config --file=.git/sequencer/opts --get-all options.strategy >actual &&
+ test_cmp expect actual &&
+ cat >expect <<-\EOF &&
+ patience
+ ours
+ EOF
+ git config --file=.git/sequencer/opts --get-all options.strategy-option >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cherry-pick cleans up sequencer state upon success' '
+ pristine_detach initial &&
+ git cherry-pick initial..picked &&
+ test_path_is_missing .git/sequencer
+'
+
+test_expect_success '--reset does not complain when no cherry-pick is in progress' '
+ pristine_detach initial &&
+ git cherry-pick --reset
+'
+
+test_expect_success '--reset cleans up sequencer state' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick base..picked &&
+ git cherry-pick --reset &&
+ test_path_is_missing .git/sequencer
+'
+
+test_expect_success 'cherry-pick cleans up sequencer state when one commit is left' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick base..picked &&
+ test_path_is_missing .git/sequencer &&
+ echo "resolved" >foo &&
+ git add foo &&
+ git commit &&
+ {
+ git rev-list HEAD |
+ git diff-tree --root --stdin |
+ sed "s/$_x40/OBJID/g"
+ } >actual &&
+ cat >expect <<-\EOF &&
+ OBJID
+ :100644 100644 OBJID OBJID M foo
+ OBJID
+ :100644 100644 OBJID OBJID M unrelated
+ OBJID
+ :000000 100644 OBJID OBJID A foo
+ :000000 100644 OBJID OBJID A unrelated
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'cherry-pick does not implicitly stomp an existing operation' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick base..anotherpick &&
+ test-chmtime -v +0 .git/sequencer >expect &&
+ test_must_fail git cherry-pick unrelatedpick &&
+ test-chmtime -v +0 .git/sequencer >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--continue complains when no cherry-pick is in progress' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick --continue
+'
+
+test_expect_success '--continue complains when there are unresolved conflicts' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick base..anotherpick &&
+ test_must_fail git cherry-pick --continue
+'
+
+test_expect_success '--continue continues after conflicts are resolved' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick base..anotherpick &&
+ echo "c" >foo &&
+ git add foo &&
+ git commit &&
+ git cherry-pick --continue &&
+ test_path_is_missing .git/sequencer &&
+ {
+ git rev-list HEAD |
+ git diff-tree --root --stdin |
+ sed "s/$_x40/OBJID/g"
+ } >actual &&
+ cat >expect <<-\EOF &&
+ OBJID
+ :100644 100644 OBJID OBJID M foo
+ OBJID
+ :100644 100644 OBJID OBJID M foo
+ OBJID
+ :100644 100644 OBJID OBJID M unrelated
+ OBJID
+ :000000 100644 OBJID OBJID A foo
+ :000000 100644 OBJID OBJID A unrelated
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success '--continue respects opts' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick -x base..anotherpick &&
+ echo "c" >foo &&
+ git add foo &&
+ git commit &&
+ git cherry-pick --continue &&
+ test_path_is_missing .git/sequencer &&
+ git cat-file commit HEAD >anotherpick_msg &&
+ git cat-file commit HEAD~1 >picked_msg &&
+ git cat-file commit HEAD~2 >unrelatedpick_msg &&
+ git cat-file commit HEAD~3 >initial_msg &&
+ test_must_fail grep "cherry picked from" initial_msg &&
+ grep "cherry picked from" unrelatedpick_msg &&
+ grep "cherry picked from" picked_msg &&
+ grep "cherry picked from" anotherpick_msg
+'
+
+test_expect_success '--signoff is not automatically propagated to resolved conflict' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick --signoff base..anotherpick &&
+ echo "c" >foo &&
+ git add foo &&
+ git commit &&
+ git cherry-pick --continue &&
+ test_path_is_missing .git/sequencer &&
+ git cat-file commit HEAD >anotherpick_msg &&
+ git cat-file commit HEAD~1 >picked_msg &&
+ git cat-file commit HEAD~2 >unrelatedpick_msg &&
+ git cat-file commit HEAD~3 >initial_msg &&
+ test_must_fail grep "Signed-off-by:" initial_msg &&
+ grep "Signed-off-by:" unrelatedpick_msg &&
+ test_must_fail grep "Signed-off-by:" picked_msg &&
+ grep "Signed-off-by:" anotherpick_msg
+'
+
+test_expect_success 'malformed instruction sheet 1' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick base..anotherpick &&
+ echo "resolved" >foo &&
+ git add foo &&
+ git commit &&
+ sed "s/pick /pick/" .git/sequencer/todo >new_sheet &&
+ cp new_sheet .git/sequencer/todo &&
+ test_must_fail git cherry-pick --continue
+'
+
+test_expect_success 'malformed instruction sheet 2' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick base..anotherpick &&
+ echo "resolved" >foo &&
+ git add foo &&
+ git commit &&
+ sed "s/pick/revert/" .git/sequencer/todo >new_sheet &&
+ cp new_sheet .git/sequencer/todo &&
+ test_must_fail git cherry-pick --continue
+'
+
+test_done
diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh
index cd093bd347..9fd28bcf34 100755
--- a/t/t3600-rm.sh
+++ b/t/t3600-rm.sh
@@ -240,11 +240,10 @@ test_expect_success 'refresh index before checking if it is up-to-date' '
test_expect_success 'choking "git rm" should not let it die with cruft' '
git reset -q --hard &&
- H=0000000000000000000000000000000000000000 &&
i=0 &&
while test $i -lt 12000
do
- echo "100644 $H 0 some-file-$i"
+ echo "100644 $_z40 0 some-file-$i"
i=$(( $i + 1 ))
done | git update-index --index-info &&
git rm -n "some-file-*" | :;
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index ec7108358e..575d9508a0 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -268,8 +268,12 @@ test_expect_success 'git add --dry-run of existing changed file' "
test_expect_success 'git add --dry-run of non-existing file' "
echo ignored-file >>.gitignore &&
- test_must_fail git add --dry-run track-this ignored-file >actual 2>&1 &&
- echo \"fatal: pathspec 'ignored-file' did not match any files\" | test_cmp - actual
+ test_must_fail git add --dry-run track-this ignored-file >actual 2>&1
+"
+
+test_expect_success 'git add --dry-run of an existing file output' "
+ echo \"fatal: pathspec 'ignored-file' did not match any files\" >expect &&
+ test_i18ncmp expect actual
"
cat >expect.err <<\EOF
@@ -283,9 +287,12 @@ add 'track-this'
EOF
test_expect_success 'git add --dry-run --ignore-missing of non-existing file' '
- test_must_fail git add --dry-run --ignore-missing track-this ignored-file >actual.out 2>actual.err &&
- test_cmp expect.out actual.out &&
- test_cmp expect.err actual.err
+ test_must_fail git add --dry-run --ignore-missing track-this ignored-file >actual.out 2>actual.err
+'
+
+test_expect_success 'git add --dry-run --ignore-missing of non-existing file output' '
+ test_i18ncmp expect.out actual.out &&
+ test_i18ncmp expect.err actual.err
'
test_done
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index d6327e7c74..9e236f9cc0 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -82,10 +82,9 @@ EOF
'
test_expect_success PERL 'setup fake editor' '
- cat >fake_editor.sh <<EOF
- EOF
+ >fake_editor.sh &&
chmod a+x fake_editor.sh &&
- test_set_editor "$(pwd)/fake_editor.sh" &&
+ test_set_editor "$(pwd)/fake_editor.sh"
'
test_expect_success PERL 'dummy edit works' '
@@ -295,4 +294,40 @@ test_expect_success PERL 'deleting an empty file' '
test_cmp expected diff
'
+test_expect_success PERL 'split hunk setup' '
+ git reset --hard &&
+ for i in 10 20 30 40 50 60
+ do
+ echo $i
+ done >test &&
+ git add test &&
+ test_tick &&
+ git commit -m test &&
+
+ for i in 10 15 20 21 22 23 24 30 40 50 60
+ do
+ echo $i
+ done >test
+'
+
+test_expect_success PERL 'split hunk "add -p (edit)"' '
+ # Split, say Edit and do nothing. Then:
+ #
+ # 1. Broken version results in a patch that does not apply and
+ # only takes [y/n] (edit again) so the first q is discarded
+ # and then n attempts to discard the edit. Repeat q enough
+ # times to get out.
+ #
+ # 2. Correct version applies the (not)edited version, and asks
+ # about the next hunk, against wich we say q and program
+ # exits.
+ for a in s e q n q q
+ do
+ echo $a
+ done |
+ EDITOR=: git add -p &&
+ git diff >actual &&
+ ! grep "^+15" actual
+'
+
test_done
diff --git a/t/t3703-add-magic-pathspec.sh b/t/t3703-add-magic-pathspec.sh
new file mode 100755
index 0000000000..5115de7036
--- /dev/null
+++ b/t/t3703-add-magic-pathspec.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+test_description='magic pathspec tests using git-add'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ mkdir sub anothersub &&
+ : >sub/foo &&
+ : >anothersub/foo
+'
+
+test_expect_success 'add :/' "
+ cat >expected <<-EOF &&
+ add 'anothersub/foo'
+ add 'expected'
+ add 'sub/actual'
+ add 'sub/foo'
+ EOF
+ (cd sub && git add -n :/ >actual) &&
+ test_cmp expected sub/actual
+"
+
+cat >expected <<EOF
+add 'anothersub/foo'
+EOF
+
+test_expect_success 'add :/anothersub' '
+ (cd sub && git add -n :/anothersub >actual) &&
+ test_cmp expected sub/actual
+'
+
+test_expect_success 'add :/non-existent' '
+ (cd sub && test_must_fail git add -n :/non-existent)
+'
+
+cat >expected <<EOF
+add 'sub/foo'
+EOF
+
+if mkdir ":" 2>/dev/null
+then
+ test_set_prereq COLON_DIR
+fi
+
+test_expect_success COLON_DIR 'a file with the same (long) magic name exists' '
+ : >":(icase)ha" &&
+ test_must_fail git add -n ":(icase)ha" &&
+ git add -n "./:(icase)ha"
+'
+
+test_expect_success COLON_DIR 'a file with the same (short) magic name exists' '
+ : >":/bar" &&
+ test_must_fail git add -n :/bar &&
+ git add -n "./:/bar"
+'
+
+test_done
diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh
index c06a5ee766..1f62c151b0 100755
--- a/t/t3900-i18n-commit.sh
+++ b/t/t3900-i18n-commit.sh
@@ -147,7 +147,7 @@ test_commit_autosquash_flags () {
git commit -a -m "intermediate commit" &&
test_tick &&
echo $H $flag >>F &&
- git commit -a --$flag HEAD~1 $3 &&
+ git commit -a --$flag HEAD~1 &&
E=$(git cat-file commit '$H-$flag' |
sed -ne "s/^encoding //p") &&
test "z$E" = "z$H" &&
@@ -160,6 +160,6 @@ test_commit_autosquash_flags () {
test_commit_autosquash_flags eucJP fixup
-test_commit_autosquash_flags ISO-2022-JP squash '-m "squash message"'
+test_commit_autosquash_flags ISO-2022-JP squash
test_done
diff --git a/t/t3902-quoted.sh b/t/t3902-quoted.sh
index da82b655b3..534ee08a44 100755
--- a/t/t3902-quoted.sh
+++ b/t/t3902-quoted.sh
@@ -10,8 +10,6 @@ test_description='quoted output'
FN='濱野'
GN='ç´”'
HT=' '
-LF='
-'
DQ='"'
echo foo 2>/dev/null > "Name and an${HT}HT"
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 6fd560ccf1..fcdb18217a 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -37,14 +37,32 @@ test_expect_success 'parents of stash' '
test_cmp output expect
'
-test_expect_success 'apply needs clean working directory' '
- echo 4 > other-file &&
+test_expect_success 'applying bogus stash does nothing' '
+ test_must_fail git stash apply stash@{1} &&
+ echo 1 >expect &&
+ test_cmp expect file
+'
+
+test_expect_success 'apply does not need clean working directory' '
+ echo 4 >other-file &&
git add other-file &&
- echo 5 > other-file &&
- test_must_fail git stash apply
+ echo 5 >other-file &&
+ git stash apply &&
+ echo 3 >expect &&
+ test_cmp expect file
+'
+
+test_expect_success 'apply does not clobber working directory changes' '
+ git reset --hard &&
+ echo 4 >file &&
+ test_must_fail git stash apply &&
+ echo 4 >expect &&
+ test_cmp expect file
'
test_expect_success 'apply stashed changes' '
+ git reset --hard &&
+ echo 5 >other-file &&
git add other-file &&
test_tick &&
git commit -m other-file &&
@@ -218,6 +236,14 @@ test_expect_success 'stash -k' '
test bar,bar4 = $(cat file),$(cat file2)
'
+test_expect_success 'stash --no-keep-index' '
+ echo bar33 > file &&
+ echo bar44 > file2 &&
+ git add file2 &&
+ git stash --no-keep-index &&
+ test bar,bar2 = $(cat file),$(cat file2)
+'
+
test_expect_success 'stash --invalid-option' '
echo bar5 > file &&
echo bar6 > file2 &&
@@ -510,13 +536,13 @@ test_expect_success 'stash pop - fail early if specified stash is not a stash re
git reset --hard HEAD
'
-test_expect_success 'ref with non-existant reflog' '
+test_expect_success 'ref with non-existent reflog' '
git stash clear &&
echo bar5 > file &&
echo bar6 > file2 &&
git add file2 &&
git stash &&
- ! "git rev-parse --quiet --verify does-not-exist" &&
+ test_must_fail git rev-parse --quiet --verify does-not-exist &&
test_must_fail git stash drop does-not-exist &&
test_must_fail git stash drop does-not-exist@{0} &&
test_must_fail git stash pop does-not-exist &&
@@ -537,11 +563,11 @@ test_expect_success 'invalid ref of the form stash@{n}, n >= N' '
echo bar6 > file2 &&
git add file2 &&
git stash &&
- test_must_fail git drop stash@{1} &&
- test_must_fail git pop stash@{1} &&
- test_must_fail git apply stash@{1} &&
- test_must_fail git show stash@{1} &&
- test_must_fail git branch tmp stash@{1} &&
+ test_must_fail git stash drop stash@{1} &&
+ test_must_fail git stash pop stash@{1} &&
+ test_must_fail git stash apply stash@{1} &&
+ test_must_fail git stash show stash@{1} &&
+ test_must_fail git stash branch tmp stash@{1} &&
git stash drop
'
@@ -556,4 +582,23 @@ test_expect_success 'stash branch should not drop the stash if the branch exists
git rev-parse stash@{0} --
'
+test_expect_success 'stash apply shows status same as git status (relative to current directory)' '
+ git stash clear &&
+ echo 1 >subdir/subfile1 &&
+ echo 2 >subdir/subfile2 &&
+ git add subdir/subfile1 &&
+ git commit -m subdir &&
+ (
+ cd subdir &&
+ echo x >subfile1 &&
+ echo x >../file &&
+ git status >../expect &&
+ git stash &&
+ sane_unset GIT_MERGE_VERBOSITY &&
+ git stash apply
+ ) |
+ sed -e 1,2d >actual && # drop "Saved..." and "HEAD is now..."
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t3904-stash-patch.sh b/t/t3904-stash-patch.sh
index 1e7193ac0b..781fd71681 100755
--- a/t/t3904-stash-patch.sh
+++ b/t/t3904-stash-patch.sh
@@ -48,6 +48,18 @@ test_expect_success PERL 'git stash -p --no-keep-index' '
verify_state bar dummy bar_index
'
+test_expect_success PERL 'git stash --no-keep-index -p' '
+ set_state dir/foo work index &&
+ set_state bar bar_work bar_index &&
+ (echo n; echo y) | git stash save --no-keep-index -p &&
+ verify_state dir/foo head head &&
+ verify_state bar bar_work dummy &&
+ git reset --hard &&
+ git stash apply --index &&
+ verify_state dir/foo work index &&
+ verify_state bar dummy bar_index
+'
+
test_expect_success PERL 'none of this moved HEAD' '
verify_saved_head
'
diff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh
new file mode 100755
index 0000000000..ef44fb2260
--- /dev/null
+++ b/t/t3905-stash-include-untracked.sh
@@ -0,0 +1,175 @@
+#!/bin/sh
+#
+# Copyright (c) 2011 David Caldwell
+#
+
+test_description='Test git stash --include-untracked'
+
+. ./test-lib.sh
+
+test_expect_success 'stash save --include-untracked some dirty working directory' '
+ echo 1 > file &&
+ git add file &&
+ test_tick &&
+ git commit -m initial &&
+ echo 2 > file &&
+ git add file &&
+ echo 3 > file &&
+ test_tick &&
+ echo 1 > file2 &&
+ mkdir untracked &&
+ echo untracked >untracked/untracked &&
+ git stash --include-untracked &&
+ git diff-files --quiet &&
+ git diff-index --cached --quiet HEAD
+'
+
+cat > expect <<EOF
+?? actual
+?? expect
+EOF
+
+test_expect_success 'stash save --include-untracked cleaned the untracked files' '
+ git status --porcelain >actual &&
+ test_cmp expect actual
+'
+
+cat > expect.diff <<EOF
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..d00491f
+--- /dev/null
++++ b/file2
+@@ -0,0 +1 @@
++1
+diff --git a/untracked/untracked b/untracked/untracked
+new file mode 100644
+index 0000000..5a72eb2
+--- /dev/null
++++ b/untracked/untracked
+@@ -0,0 +1 @@
++untracked
+EOF
+cat > expect.lstree <<EOF
+file2
+untracked
+EOF
+
+test_expect_success 'stash save --include-untracked stashed the untracked files' '
+ test "!" -f file2 &&
+ test ! -e untracked &&
+ git diff HEAD stash^3 -- file2 untracked >actual &&
+ test_cmp expect.diff actual &&
+ git ls-tree --name-only stash^3: >actual &&
+ test_cmp expect.lstree actual
+'
+test_expect_success 'stash save --patch --include-untracked fails' '
+ test_must_fail git stash --patch --include-untracked
+'
+
+test_expect_success 'stash save --patch --all fails' '
+ test_must_fail git stash --patch --all
+'
+
+git clean --force --quiet
+
+cat > expect <<EOF
+ M file
+?? actual
+?? expect
+?? file2
+?? untracked/
+EOF
+
+test_expect_success 'stash pop after save --include-untracked leaves files untracked again' '
+ git stash pop &&
+ git status --porcelain >actual &&
+ test_cmp expect actual &&
+ test "1" = "`cat file2`" &&
+ test untracked = "`cat untracked/untracked`"
+'
+
+git clean --force --quiet -d
+
+test_expect_success 'stash save -u dirty index' '
+ echo 4 > file3 &&
+ git add file3 &&
+ test_tick &&
+ git stash -u
+'
+
+cat > expect <<EOF
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..b8626c4
+--- /dev/null
++++ b/file3
+@@ -0,0 +1 @@
++4
+EOF
+
+test_expect_success 'stash save --include-untracked dirty index got stashed' '
+ git stash pop --index &&
+ git diff --cached >actual &&
+ test_cmp expect actual
+'
+
+git reset > /dev/null
+
+test_expect_success 'stash save --include-untracked -q is quiet' '
+ echo 1 > file5 &&
+ git stash save --include-untracked --quiet > output.out 2>&1 &&
+ test ! -s output.out
+'
+
+test_expect_success 'stash save --include-untracked removed files' '
+ rm -f file &&
+ git stash save --include-untracked &&
+ echo 1 > expect &&
+ test_cmp file expect
+'
+
+rm -f expect
+
+test_expect_success 'stash save --include-untracked removed files got stashed' '
+ git stash pop &&
+ test ! -f file
+'
+
+cat > .gitignore <<EOF
+.gitignore
+ignored
+ignored.d/
+EOF
+
+test_expect_success 'stash save --include-untracked respects .gitignore' '
+ echo ignored > ignored &&
+ mkdir ignored.d &&
+ echo ignored >ignored.d/untracked &&
+ git stash -u &&
+ test -s ignored &&
+ test -s ignored.d/untracked &&
+ test -s .gitignore
+'
+
+test_expect_success 'stash save -u can stash with only untracked files different' '
+ echo 4 > file4 &&
+ git stash -u &&
+ test "!" -f file4
+'
+
+test_expect_success 'stash save --all does not respect .gitignore' '
+ git stash -a &&
+ test "!" -f ignored &&
+ test "!" -e ignored.d &&
+ test "!" -f .gitignore
+'
+
+test_expect_success 'stash save --all is stash poppable' '
+ git stash pop &&
+ test -s ignored &&
+ test -s ignored.d/untracked &&
+ test -s .gitignore
+'
+
+test_done
diff --git a/t/t4001-diff-rename.sh b/t/t4001-diff-rename.sh
index 71bac83dd5..844277cfa6 100755
--- a/t/t4001-diff-rename.sh
+++ b/t/t4001-diff-rename.sh
@@ -71,10 +71,35 @@ test_expect_success 'favour same basenames over different ones' '
git rm path1 &&
mkdir subdir &&
git mv another-path subdir/path1 &&
- git status | grep "renamed: .*path1 -> subdir/path1"'
+ git status | test_i18ngrep "renamed: .*path1 -> subdir/path1"'
-test_expect_success 'favour same basenames even with minor differences' '
+test_expect_success 'favour same basenames even with minor differences' '
git show HEAD:path1 | sed "s/15/16/" > subdir/path1 &&
- git status | grep "renamed: .*path1 -> subdir/path1"'
+ git status | test_i18ngrep "renamed: .*path1 -> subdir/path1"'
+
+test_expect_success 'setup for many rename source candidates' '
+ git reset --hard &&
+ for i in 0 1 2 3 4 5 6 7 8 9;
+ do
+ for j in 0 1 2 3 4 5 6 7 8 9;
+ do
+ echo "$i$j" >"path$i$j"
+ done
+ done &&
+ git add "path??" &&
+ test_tick &&
+ git commit -m "hundred" &&
+ (cat path1; echo new) >new-path &&
+ echo old >>path1 &&
+ git add new-path path1 &&
+ git diff -l 4 -C -C --cached --name-status >actual 2>actual.err &&
+ sed -e "s/^\([CM]\)[0-9]* /\1 /" actual >actual.munged &&
+ cat >expect <<-EOF &&
+ C path1 new-path
+ M path1
+ EOF
+ test_cmp expect actual.munged &&
+ grep warning actual.err
+'
test_done
diff --git a/t/t4002-diff-basic.sh b/t/t4002-diff-basic.sh
index 9fb8ca06a8..a5e8b83083 100755
--- a/t/t4002-diff-basic.sh
+++ b/t/t4002-diff-basic.sh
@@ -126,15 +126,12 @@ cat >.test-recursive-AB <<\EOF
:100644 100644 3fdbe17fd013303a2e981e1ca1c6cd6e72789087 7e09d6a3a14bd630913e8c75693cea32157b606d M Z/NM
EOF
-x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
-x40="$x40$x40$x40$x40$x40$x40$x40$x40"
-z40='0000000000000000000000000000000000000000'
cmp_diff_files_output () {
# diff-files never reports additions. Also it does not fill in the
# object ID for the changed files because it wants you to look at the
# filesystem.
sed <"$2" >.test-tmp \
- -e '/^:000000 /d;s/'$x40'\( [MCRNDU][0-9]*\) /'$z40'\1 /' &&
+ -e '/^:000000 /d;s/'$_x40'\( [MCRNDU][0-9]*\) /'$_z40'\1 /' &&
test_cmp "$1" .test-tmp
}
diff --git a/t/t4003-diff-rename-1.sh b/t/t4003-diff-rename-1.sh
index c6130c4019..bfa8835638 100755
--- a/t/t4003-diff-rename-1.sh
+++ b/t/t4003-diff-rename-1.sh
@@ -29,7 +29,7 @@ test_expect_success \
# copy-and-edit one, and rename-and-edit the other. We do not say
# anything about rezrov.
-GIT_DIFF_OPTS=--unified=0 git diff-index -M -p $tree >current
+GIT_DIFF_OPTS=--unified=0 git diff-index -C -p $tree >current
cat >expected <<\EOF
diff --git a/COPYING b/COPYING.1
copy from COPYING
diff --git a/t/t4004-diff-rename-symlink.sh b/t/t4004-diff-rename-symlink.sh
index 92a65f4852..6e562c80d1 100755
--- a/t/t4004-diff-rename-symlink.sh
+++ b/t/t4004-diff-rename-symlink.sh
@@ -35,7 +35,7 @@ test_expect_success SYMLINKS \
# a new creation.
test_expect_success SYMLINKS 'setup diff output' "
- GIT_DIFF_OPTS=--unified=0 git diff-index -M -p $tree >current &&
+ GIT_DIFF_OPTS=--unified=0 git diff-index -C -p $tree >current &&
cat >expected <<\EOF
diff --git a/bozbar b/bozbar
new file mode 120000
diff --git a/t/t4005-diff-rename-2.sh b/t/t4005-diff-rename-2.sh
index 1ba359d478..77d7f4946f 100755
--- a/t/t4005-diff-rename-2.sh
+++ b/t/t4005-diff-rename-2.sh
@@ -29,7 +29,7 @@ test_expect_success \
# and COPYING.2 are based on COPYING, and do not say anything about
# rezrov.
-git diff-index -M $tree >current
+git diff-index -C $tree >current
cat >expected <<\EOF
:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 0603b3238a076dc6c8022aedc6648fa523a17178 C1234 COPYING COPYING.1
diff --git a/t/t4008-diff-break-rewrite.sh b/t/t4008-diff-break-rewrite.sh
index d79d9e1e71..73b4a24f5e 100755
--- a/t/t4008-diff-break-rewrite.sh
+++ b/t/t4008-diff-break-rewrite.sh
@@ -173,8 +173,8 @@ test_expect_success \
'compare_diff_raw expected current'
test_expect_success \
- 'run diff with -B -M' \
- 'git diff-index -B -M "$tree" >current'
+ 'run diff with -B -C' \
+ 'git diff-index -B -C "$tree" >current'
cat >expected <<\EOF
:100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 08bb2fb671deff4c03a4d4a0a1315dff98d5732c C095 file0 file1
diff --git a/t/t4009-diff-rename-4.sh b/t/t4009-diff-rename-4.sh
index de3f17478e..f22c8e3dba 100755
--- a/t/t4009-diff-rename-4.sh
+++ b/t/t4009-diff-rename-4.sh
@@ -29,7 +29,7 @@ test_expect_success \
# and COPYING.2 are based on COPYING, and do not say anything about
# rezrov.
-git diff-index -z -M $tree >current
+git diff-index -z -C $tree >current
cat >expected <<\EOF
:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 0603b3238a076dc6c8022aedc6648fa523a17178 C1234
diff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh
index 94df7ae53a..fbc8cd8f05 100755
--- a/t/t4010-diff-pathspec.sh
+++ b/t/t4010-diff-pathspec.sh
@@ -70,4 +70,36 @@ test_expect_success 'diff-tree pathspec' '
test_cmp expected current
'
+EMPTY_TREE=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+
+test_expect_success 'diff-tree with wildcard shows dir also matches' '
+ git diff-tree --name-only $EMPTY_TREE $tree -- "f*" >result &&
+ echo file0 >expected &&
+ test_cmp expected result
+'
+
+test_expect_success 'diff-tree -r with wildcard' '
+ git diff-tree -r --name-only $EMPTY_TREE $tree -- "*file1" >result &&
+ echo path1/file1 >expected &&
+ test_cmp expected result
+'
+
+test_expect_success 'diff-tree with wildcard shows dir also matches' '
+ git diff-tree --name-only $tree $tree2 -- "path1/f*" >result &&
+ echo path1 >expected &&
+ test_cmp expected result
+'
+
+test_expect_success 'diff-tree -r with wildcard from beginning' '
+ git diff-tree -r --name-only $tree $tree2 -- "path1/*file1" >result &&
+ echo path1/file1 >expected &&
+ test_cmp expected result
+'
+
+test_expect_success 'diff-tree -r with wildcard' '
+ git diff-tree -r --name-only $tree $tree2 -- "path1/f*" >result &&
+ echo path1/file1 >expected &&
+ test_cmp expected result
+'
+
test_done
diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh
index 05ec062832..2d9f9a0cf1 100755
--- a/t/t4012-diff-binary.sh
+++ b/t/t4012-diff-binary.sh
@@ -12,7 +12,7 @@ test_expect_success 'prepare repository' \
'echo AIT >a && echo BIT >b && echo CIT >c && echo DIT >d &&
git update-index --add a b c d &&
echo git >a &&
- cat "$TEST_DIRECTORY"/test4012.png >b &&
+ cat "$TEST_DIRECTORY"/test-binary-1.png >b &&
echo git >c &&
cat b b >d'
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 9a66520588..93a6f20871 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -80,18 +80,31 @@ test_expect_success setup '
git config log.showroot false &&
git commit --amend &&
+
+ GIT_AUTHOR_DATE="2006-06-26 00:06:00 +0000" &&
+ GIT_COMMITTER_DATE="2006-06-26 00:06:00 +0000" &&
+ export GIT_AUTHOR_DATE GIT_COMMITTER_DATE &&
+ git checkout -b rearrange initial &&
+ for i in B A; do echo $i; done >dir/sub &&
+ git add dir/sub &&
+ git commit -m "Rearranged lines in dir/sub" &&
+ git checkout master &&
+
git show-branch
'
: <<\EOF
! [initial] Initial
* [master] Merge branch 'side'
- ! [side] Side
----
- - [master] Merge branch 'side'
- *+ [side] Side
- * [master^] Second
-+*+ [initial] Initial
+ ! [rearrange] Rearranged lines in dir/sub
+ ! [side] Side
+----
+ + [rearrange] Rearranged lines in dir/sub
+ - [master] Merge branch 'side'
+ * + [side] Side
+ * [master^] Third
+ * [master~2] Second
++*++ [initial] Initial
EOF
V=`git version | sed -e 's/^git version //' -e 's/\./\\./g'`
@@ -210,6 +223,9 @@ log -m -p master
log -SF master
log -S F master
log -SF -p master
+log -SF master --max-count=0
+log -SF master --max-count=1
+log -SF master --max-count=2
log -GF master
log -GF -p master
log -GF -p --pickaxe-all master
@@ -284,10 +300,23 @@ diff --no-index --name-status -- dir2 dir
diff --no-index dir dir3
diff master master^ side
diff --dirstat master~1 master~2
+diff --dirstat initial rearrange
+diff --dirstat-by-file initial rearrange
EOF
test_expect_success 'log -S requires an argument' '
test_must_fail git log -S
'
+test_expect_success 'diff --cached on unborn branch' '
+ echo ref: refs/heads/unborn >.git/HEAD &&
+ git diff --cached >result &&
+ test_cmp "$TEST_DIRECTORY/t4013/diff.diff_--cached" result
+'
+
+test_expect_success 'diff --cached -- file on unborn branch' '
+ git diff --cached -- file0 >result &&
+ test_cmp "$TEST_DIRECTORY/t4013/diff.diff_--cached_--_file0" result
+'
+
test_done
diff --git a/t/t4013/diff.diff_--cached b/t/t4013/diff.diff_--cached
new file mode 100644
index 0000000000..ff16e83e7c
--- /dev/null
+++ b/t/t4013/diff.diff_--cached
@@ -0,0 +1,38 @@
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..992913c
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,8 @@
++A
++B
++C
++D
++E
++F
++1
++2
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..10a8a9f
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,9 @@
++1
++2
++3
++4
++5
++6
++A
++B
++C
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
diff --git a/t/t4013/diff.diff_--cached_--_file0 b/t/t4013/diff.diff_--cached_--_file0
new file mode 100644
index 0000000000..b9bb858a03
--- /dev/null
+++ b/t/t4013/diff.diff_--cached_--_file0
@@ -0,0 +1,15 @@
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..10a8a9f
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,9 @@
++1
++2
++3
++4
++5
++6
++A
++B
++C
diff --git a/t/t4013/diff.diff_--dirstat-by-file_initial_rearrange b/t/t4013/diff.diff_--dirstat-by-file_initial_rearrange
new file mode 100644
index 0000000000..e48e33f678
--- /dev/null
+++ b/t/t4013/diff.diff_--dirstat-by-file_initial_rearrange
@@ -0,0 +1,3 @@
+$ git diff --dirstat-by-file initial rearrange
+ 100.0% dir/
+$
diff --git a/t/t4013/diff.diff_--dirstat_initial_rearrange b/t/t4013/diff.diff_--dirstat_initial_rearrange
new file mode 100644
index 0000000000..5fb02c13bc
--- /dev/null
+++ b/t/t4013/diff.diff_--dirstat_initial_rearrange
@@ -0,0 +1,3 @@
+$ git diff --dirstat initial rearrange
+ 100.0% dir/
+$
diff --git a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
index 1f0f9ad44b..3b4e113012 100644
--- a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
+++ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
@@ -1,7 +1,7 @@
$ git format-patch --stdout --cover-letter -n initial..master^
From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001
From: C O Mitter <committer@example.com>
-Date: Mon, 26 Jun 2006 00:05:00 +0000
+Date: Mon, 26 Jun 2006 00:06:00 +0000
Subject: [DIFFERENT_PREFIX 0/2] *** SUBJECT HERE ***
*** BLURB HERE ***
diff --git a/t/t4013/diff.log_--decorate=full_--all b/t/t4013/diff.log_--decorate=full_--all
index d155e0bab2..44d45257da 100644
--- a/t/t4013/diff.log_--decorate=full_--all
+++ b/t/t4013/diff.log_--decorate=full_--all
@@ -1,4 +1,10 @@
$ git log --decorate=full --all
+commit cd4e72fd96faed3f0ba949dc42967430374e2290 (refs/heads/rearrange)
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:06:00 2006 +0000
+
+ Rearranged lines in dir/sub
+
commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, refs/heads/master)
Merge: 9a6d494 c7a2ab9
Author: A U Thor <author@example.com>
diff --git a/t/t4013/diff.log_--decorate_--all b/t/t4013/diff.log_--decorate_--all
index fd7c3e6439..27d3eabc26 100644
--- a/t/t4013/diff.log_--decorate_--all
+++ b/t/t4013/diff.log_--decorate_--all
@@ -1,4 +1,10 @@
$ git log --decorate --all
+commit cd4e72fd96faed3f0ba949dc42967430374e2290 (rearrange)
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:06:00 2006 +0000
+
+ Rearranged lines in dir/sub
+
commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, master)
Merge: 9a6d494 c7a2ab9
Author: A U Thor <author@example.com>
diff --git a/t/t4013/diff.log_-SF_master_--max-count=0 b/t/t4013/diff.log_-SF_master_--max-count=0
new file mode 100644
index 0000000000..c1fc6c8731
--- /dev/null
+++ b/t/t4013/diff.log_-SF_master_--max-count=0
@@ -0,0 +1,2 @@
+$ git log -SF master --max-count=0
+$
diff --git a/t/t4013/diff.log_-SF_master_--max-count=1 b/t/t4013/diff.log_-SF_master_--max-count=1
new file mode 100644
index 0000000000..c981a03814
--- /dev/null
+++ b/t/t4013/diff.log_-SF_master_--max-count=1
@@ -0,0 +1,7 @@
+$ git log -SF master --max-count=1
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+$
diff --git a/t/t4013/diff.log_-SF_master_--max-count=2 b/t/t4013/diff.log_-SF_master_--max-count=2
new file mode 100644
index 0000000000..a6c55fd482
--- /dev/null
+++ b/t/t4013/diff.log_-SF_master_--max-count=2
@@ -0,0 +1,7 @@
+$ git log -SF master --max-count=2
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+$
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 027c13d52c..67975129bc 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -179,12 +179,21 @@ test_expect_success 'configuration To: header' '
grep "^To: R. E. Cipient <rcipient@example.com>\$" patch9
'
+# check_patch <patch>: Verify that <patch> looks like a half-sane
+# patch email to avoid a false positive with !grep
+check_patch () {
+ grep -e "^From:" "$1" &&
+ grep -e "^Date:" "$1" &&
+ grep -e "^Subject:" "$1"
+}
+
test_expect_success '--no-to overrides config.to' '
git config --replace-all format.to \
"R. E. Cipient <rcipient@example.com>" &&
git format-patch --no-to --stdout master..side |
sed -e "/^\$/q" >patch10 &&
+ check_patch patch10 &&
! grep "^To: R. E. Cipient <rcipient@example.com>\$" patch10
'
@@ -195,6 +204,7 @@ test_expect_success '--no-to and --to replaces config.to' '
git format-patch --no-to --to="Someone Else <else@out.there>" \
--stdout master..side |
sed -e "/^\$/q" >patch11 &&
+ check_patch patch11 &&
! grep "^To: Someone <someone@out.there>\$" patch11 &&
grep "^To: Someone Else <else@out.there>\$" patch11
'
@@ -205,15 +215,17 @@ test_expect_success '--no-cc overrides config.cc' '
"C. E. Cipient <rcipient@example.com>" &&
git format-patch --no-cc --stdout master..side |
sed -e "/^\$/q" >patch12 &&
+ check_patch patch12 &&
! grep "^Cc: C. E. Cipient <rcipient@example.com>\$" patch12
'
-test_expect_success '--no-add-headers overrides config.headers' '
+test_expect_success '--no-add-header overrides config.headers' '
git config --replace-all format.headers \
"Header1: B. E. Cipient <rcipient@example.com>" &&
- git format-patch --no-add-headers --stdout master..side |
+ git format-patch --no-add-header --stdout master..side |
sed -e "/^\$/q" >patch13 &&
+ check_patch patch13 &&
! grep "^Header1: B. E. Cipient <rcipient@example.com>\$" patch13
'
@@ -445,22 +457,22 @@ test_expect_success 'thread deep cover-letter in-reply-to' '
'
test_expect_success 'thread via config' '
- git config format.thread true &&
+ test_config format.thread true &&
check_threading expect.thread master
'
test_expect_success 'thread deep via config' '
- git config format.thread deep &&
+ test_config format.thread deep &&
check_threading expect.deep master
'
test_expect_success 'thread config + override' '
- git config format.thread deep &&
+ test_config format.thread deep &&
check_threading expect.thread --thread master
'
test_expect_success 'thread config + --no-thread' '
- git config format.thread deep &&
+ test_config format.thread deep &&
check_threading expect.no-threading --no-thread master
'
@@ -480,6 +492,7 @@ test_expect_success 'cover-letter inherits diff options' '
git mv file foo &&
git commit -m foo &&
git format-patch --cover-letter -1 &&
+ check_patch 0000-cover-letter.patch &&
! grep "file => foo .* 0 *\$" 0000-cover-letter.patch &&
git format-patch --cover-letter -1 -M &&
grep "file => foo .* 0 *\$" 0000-cover-letter.patch
@@ -616,11 +629,11 @@ echo "fatal: --check does not make sense" > expect.check
test_expect_success 'options no longer allowed for format-patch' '
test_must_fail git format-patch --name-only 2> output &&
- test_cmp expect.name-only output &&
+ test_i18ncmp expect.name-only output &&
test_must_fail git format-patch --name-status 2> output &&
- test_cmp expect.name-status output &&
+ test_i18ncmp expect.name-status output &&
test_must_fail git format-patch --check 2> output &&
- test_cmp expect.check output'
+ test_i18ncmp expect.check output'
test_expect_success 'format-patch --numstat should produce a patch' '
git format-patch --numstat --stdout master..side > output &&
@@ -657,6 +670,7 @@ test_expect_success 'format-patch --no-signature ignores format.signature' '
git config format.signature "config sig" &&
git format-patch --stdout --signature="my sig" --no-signature \
-1 >output &&
+ check_patch output &&
! grep "config sig" output &&
! grep "my sig" output &&
! grep "^-- \$" output
@@ -673,17 +687,20 @@ test_expect_success 'format-patch --signature --cover-letter' '
test_expect_success 'format.signature="" supresses signatures' '
git config format.signature "" &&
git format-patch --stdout -1 >output &&
+ check_patch output &&
! grep "^-- \$" output
'
test_expect_success 'format-patch --no-signature supresses signatures' '
git config --unset-all format.signature &&
git format-patch --stdout --no-signature -1 >output &&
+ check_patch output &&
! grep "^-- \$" output
'
test_expect_success 'format-patch --signature="" supresses signatures' '
- git format-patch --signature="" -1 >output &&
+ git format-patch --stdout --signature="" -1 >output &&
+ check_patch output &&
! grep "^-- \$" output
'
@@ -709,4 +726,172 @@ test_expect_success TTY 'format-patch --stdout paginates' '
test_path_is_missing .git/pager_used
'
+test_expect_success 'format-patch handles multi-line subjects' '
+ rm -rf patches/ &&
+ echo content >>file &&
+ for i in one two three; do echo $i; done >msg &&
+ git add file &&
+ git commit -F msg &&
+ git format-patch -o patches -1 &&
+ grep ^Subject: patches/0001-one.patch >actual &&
+ echo "Subject: [PATCH] one two three" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'format-patch handles multi-line encoded subjects' '
+ rm -rf patches/ &&
+ echo content >>file &&
+ for i in en två tre; do echo $i; done >msg &&
+ git add file &&
+ git commit -F msg &&
+ git format-patch -o patches -1 &&
+ grep ^Subject: patches/0001-en.patch >actual &&
+ echo "Subject: [PATCH] =?UTF-8?q?en=20tv=C3=A5=20tre?=" >expect &&
+ test_cmp expect actual
+'
+
+M8="foo bar "
+M64=$M8$M8$M8$M8$M8$M8$M8$M8
+M512=$M64$M64$M64$M64$M64$M64$M64$M64
+cat >expect <<'EOF'
+Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar
+EOF
+test_expect_success 'format-patch wraps extremely long headers (ascii)' '
+ echo content >>file &&
+ git add file &&
+ git commit -m "$M512" &&
+ git format-patch --stdout -1 >patch &&
+ sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
+ test_cmp expect subject
+'
+
+M8="föö bar "
+M64=$M8$M8$M8$M8$M8$M8$M8$M8
+M512=$M64$M64$M64$M64$M64$M64$M64$M64
+cat >expect <<'EOF'
+Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
+EOF
+test_expect_success 'format-patch wraps extremely long headers (rfc2047)' '
+ rm -rf patches/ &&
+ echo content >>file &&
+ git add file &&
+ git commit -m "$M512" &&
+ git format-patch --stdout -1 >patch &&
+ sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
+ test_cmp expect subject
+'
+
+M8="foo_bar_"
+M64=$M8$M8$M8$M8$M8$M8$M8$M8
+cat >expect <<EOF
+From: $M64
+ <foobar@foo.bar>
+EOF
+test_expect_success 'format-patch wraps non-quotable headers' '
+ rm -rf patches/ &&
+ echo content >>file &&
+ git add file &&
+ git commit -mfoo --author "$M64 <foobar@foo.bar>" &&
+ git format-patch --stdout -1 >patch &&
+ sed -n "/^From: /p; /^ /p; /^$/q" <patch >from &&
+ test_cmp expect from
+'
+
+check_author() {
+ echo content >>file &&
+ git add file &&
+ GIT_AUTHOR_NAME=$1 git commit -m author-check &&
+ git format-patch --stdout -1 >patch &&
+ grep ^From: patch >actual &&
+ test_cmp expect actual
+}
+
+cat >expect <<'EOF'
+From: "Foo B. Bar" <author@example.com>
+EOF
+test_expect_success 'format-patch quotes dot in headers' '
+ check_author "Foo B. Bar"
+'
+
+cat >expect <<'EOF'
+From: "Foo \"The Baz\" Bar" <author@example.com>
+EOF
+test_expect_success 'format-patch quotes double-quote in headers' '
+ check_author "Foo \"The Baz\" Bar"
+'
+
+cat >expect <<'EOF'
+From: =?UTF-8?q?"F=C3=B6o=20B.=20Bar"?= <author@example.com>
+EOF
+test_expect_success 'rfc2047-encoded headers also double-quote 822 specials' '
+ check_author "Föo B. Bar"
+'
+
+cat >expect <<'EOF'
+Subject: header with . in it
+EOF
+test_expect_success 'subject lines do not have 822 atom-quoting' '
+ echo content >>file &&
+ git add file &&
+ git commit -m "header with . in it" &&
+ git format-patch -k -1 --stdout >patch &&
+ grep ^Subject: patch >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+Subject: [PREFIX 1/1] header with . in it
+EOF
+test_expect_success 'subject prefixes have space prepended' '
+ git format-patch -n -1 --stdout --subject-prefix=PREFIX >patch &&
+ grep ^Subject: patch >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+Subject: [1/1] header with . in it
+EOF
+test_expect_success 'empty subject prefix does not have extra space' '
+ git format-patch -n -1 --stdout --subject-prefix= >patch &&
+ grep ^Subject: patch >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'format patch ignores color.ui' '
+ test_unconfig color.ui &&
+ git format-patch --stdout -1 >expect &&
+ test_config color.ui always &&
+ git format-patch --stdout -1 >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
index 3646930623..b68c56b68c 100755
--- a/t/t4018-diff-funcname.sh
+++ b/t/t4018-diff-funcname.sh
@@ -9,8 +9,7 @@ test_description='Test custom diff function name patterns'
LF='
'
-
-cat > Beer.java << EOF
+cat >Beer.java <<\EOF
public class Beer
{
int special;
@@ -29,61 +28,163 @@ public class Beer
}
}
EOF
+sed 's/beer\\/beer,\\/' <Beer.java >Beer-correct.java
+cat >Beer.perl <<\EOT
+package Beer;
+
+use strict;
+use warnings;
+use parent qw(Exporter);
+our @EXPORT_OK = qw(round finalround);
+
+sub other; # forward declaration
+
+# hello
+
+sub round {
+ my ($n) = @_;
+ print "$n bottles of beer on the wall ";
+ print "$n bottles of beer\n";
+ print "Take one down, pass it around, ";
+ $n = $n - 1;
+ print "$n bottles of beer on the wall.\n";
+}
+
+sub finalround
+{
+ print "Go to the store, buy some more\n";
+ print "99 bottles of beer on the wall.\n");
+}
+
+sub withheredocument {
+ print <<"EOF"
+decoy here-doc
+EOF
+ # some lines of context
+ # to pad it out
+ print "hello\n";
+}
+
+__END__
+
+=head1 NAME
+
+Beer - subroutine to output fragment of a drinking song
+
+=head1 SYNOPSIS
+
+ use Beer qw(round finalround);
+
+ sub song {
+ for (my $i = 99; $i > 0; $i--) {
+ round $i;
+ }
+ finalround;
+ }
-sed 's/beer\\/beer,\\/' < Beer.java > Beer-correct.java
+ song;
-builtin_patterns="bibtex cpp csharp fortran html java objc pascal perl php python ruby tex"
-for p in $builtin_patterns
+=cut
+EOT
+sed -e '
+ s/hello/goodbye/
+ s/beer\\/beer,\\/
+ s/more\\/more,\\/
+ s/song;/song();/
+' <Beer.perl >Beer-correct.perl
+
+test_config () {
+ git config "$1" "$2" &&
+ test_when_finished "git config --unset $1"
+}
+
+test_expect_funcname () {
+ lang=${2-java}
+ test_expect_code 1 git diff --no-index -U1 \
+ "Beer.$lang" "Beer-correct.$lang" >diff &&
+ grep "^@@.*@@ $1" diff
+}
+
+for p in bibtex cpp csharp fortran html java objc pascal perl php python ruby tex
do
test_expect_success "builtin $p pattern compiles" '
- echo "*.java diff=$p" > .gitattributes &&
- ! { git diff --no-index Beer.java Beer-correct.java 2>&1 |
- grep "fatal" > /dev/null; }
+ echo "*.java diff=$p" >.gitattributes &&
+ test_expect_code 1 git diff --no-index \
+ Beer.java Beer-correct.java 2>msg &&
+ ! grep fatal msg &&
+ ! grep error msg
'
test_expect_success "builtin $p wordRegex pattern compiles" '
- ! { git diff --no-index --word-diff \
- Beer.java Beer-correct.java 2>&1 |
- grep "fatal" > /dev/null; }
+ echo "*.java diff=$p" >.gitattributes &&
+ test_expect_code 1 git diff --no-index --word-diff \
+ Beer.java Beer-correct.java 2>msg &&
+ ! grep fatal msg &&
+ ! grep error msg
'
done
test_expect_success 'default behaviour' '
rm -f .gitattributes &&
- git diff --no-index Beer.java Beer-correct.java |
- grep "^@@.*@@ public class Beer"
+ test_expect_funcname "public class Beer\$"
+'
+
+test_expect_success 'set up .gitattributes declaring drivers to test' '
+ cat >.gitattributes <<-\EOF
+ *.java diff=java
+ *.perl diff=perl
+ EOF
'
test_expect_success 'preset java pattern' '
- echo "*.java diff=java" >.gitattributes &&
- git diff --no-index Beer.java Beer-correct.java |
- grep "^@@.*@@ public static void main("
+ test_expect_funcname "public static void main("
'
-git config diff.java.funcname '!static
-!String
-[^ ].*s.*'
+test_expect_success 'preset perl pattern' '
+ test_expect_funcname "sub round {\$" perl
+'
+
+test_expect_success 'perl pattern accepts K&R style brace placement, too' '
+ test_expect_funcname "sub finalround\$" perl
+'
+
+test_expect_success 'but is not distracted by end of <<here document' '
+ test_expect_funcname "sub withheredocument {\$" perl
+'
+
+test_expect_success 'perl pattern is not distracted by sub within POD' '
+ test_expect_funcname "=head" perl
+'
+
+test_expect_success 'perl pattern gets full line of POD header' '
+ test_expect_funcname "=head1 SYNOPSIS\$" perl
+'
+
+test_expect_success 'perl pattern is not distracted by forward declaration' '
+ test_expect_funcname "package Beer;\$" perl
+'
test_expect_success 'custom pattern' '
- git diff --no-index Beer.java Beer-correct.java |
- grep "^@@.*@@ int special;$"
+ test_config diff.java.funcname "!static
+!String
+[^ ].*s.*" &&
+ test_expect_funcname "int special;\$"
'
test_expect_success 'last regexp must not be negated' '
- git config diff.java.funcname "!static" &&
- git diff --no-index Beer.java Beer-correct.java 2>&1 |
- grep "fatal: Last expression must not be negated:"
+ test_config diff.java.funcname "!static" &&
+ test_expect_code 128 git diff --no-index Beer.java Beer-correct.java 2>msg &&
+ grep ": Last expression must not be negated:" msg
'
test_expect_success 'pattern which matches to end of line' '
- git config diff.java.funcname "Beer$" &&
- git diff --no-index Beer.java Beer-correct.java |
- grep "^@@.*@@ Beer"
+ test_config diff.java.funcname "Beer\$" &&
+ test_expect_funcname "Beer\$"
'
test_expect_success 'alternation in pattern' '
- git config diff.java.xfuncname "^[ ]*((public|static).*)$" &&
- git diff --no-index Beer.java Beer-correct.java |
- grep "^@@.*@@ public static void main("
+ test_config diff.java.funcname "Beer$" &&
+ test_config diff.java.xfuncname "^[ ]*((public|static).*)$" &&
+ test_expect_funcname "public static void main("
'
test_done
diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh
index a7602cf923..083f62d1d6 100755
--- a/t/t4020-diff-external.sh
+++ b/t/t4020-diff-external.sh
@@ -4,8 +4,6 @@ test_description='external diff interface test'
. ./test-lib.sh
-_z40=0000000000000000000000000000000000000000
-
test_expect_success setup '
test_tick &&
diff --git a/t/t4022-diff-rewrite.sh b/t/t4022-diff-rewrite.sh
index 2a537a21e8..c00a94b9ba 100755
--- a/t/t4022-diff-rewrite.sh
+++ b/t/t4022-diff-rewrite.sh
@@ -11,7 +11,9 @@ test_expect_success setup '
tr \
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM" \
- <"$TEST_DIRECTORY"/../COPYING >test
+ <"$TEST_DIRECTORY"/../COPYING >test &&
+ echo "to be deleted" >test2 &&
+ git add test2
'
@@ -25,5 +27,44 @@ test_expect_success 'detect rewrite' '
'
+cat >expect <<EOF
+diff --git a/test2 b/test2
+deleted file mode 100644
+index 4202011..0000000
+--- a/test2
++++ /dev/null
+@@ -1 +0,0 @@
+-to be deleted
+EOF
+test_expect_success 'show deletion diff without -D' '
+
+ rm test2 &&
+ git diff -- test2 >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<EOF
+diff --git a/test2 b/test2
+deleted file mode 100644
+index 4202011..0000000
+EOF
+test_expect_success 'suppress deletion diff with -D' '
+
+ git diff -D -- test2 >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'show deletion diff with -B' '
+
+ git diff -B -- test >actual &&
+ grep "Linus Torvalds" actual
+'
+
+test_expect_success 'suppress deletion diff with -B -D' '
+
+ git diff -B -D -- test >actual &&
+ grep -v "Linus Torvalds" actual
+'
+
test_done
diff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh
index 241a74d2a2..518bf9524e 100755
--- a/t/t4027-diff-submodule.sh
+++ b/t/t4027-diff-submodule.sh
@@ -5,7 +5,6 @@ test_description='difference in submodules'
. ./test-lib.sh
. "$TEST_DIRECTORY"/diff-lib.sh
-_z40=0000000000000000000000000000000000000000
test_expect_success setup '
test_tick &&
test_create_repo sub &&
diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh
index 7e7b307a24..7d7470f21b 100755
--- a/t/t4031-diff-rewrite-binary.sh
+++ b/t/t4031-diff-rewrite-binary.sh
@@ -44,6 +44,13 @@ test_expect_success 'rewrite diff can show binary patch' '
grep "GIT binary patch" diff
'
+test_expect_success 'rewrite diff --stat shows binary changes' '
+ git diff -B --stat --summary >diff &&
+ grep "Bin" diff &&
+ grep "0 insertions.*0 deletions" diff &&
+ grep " rewrite file" diff
+'
+
{
echo "#!$SHELL_PATH"
cat <<'EOF'
diff --git a/t/t4033-diff-patience.sh b/t/t4033-diff-patience.sh
index 1eb14989df..3c9932edf3 100755
--- a/t/t4033-diff-patience.sh
+++ b/t/t4033-diff-patience.sh
@@ -3,166 +3,10 @@
test_description='patience diff algorithm'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-diff-alternative.sh
-cat >file1 <<\EOF
-#include <stdio.h>
+test_diff_frobnitz "patience"
-// Frobs foo heartily
-int frobnitz(int foo)
-{
- int i;
- for(i = 0; i < 10; i++)
- {
- printf("Your answer is: ");
- printf("%d\n", foo);
- }
-}
-
-int fact(int n)
-{
- if(n > 1)
- {
- return fact(n-1) * n;
- }
- return 1;
-}
-
-int main(int argc, char **argv)
-{
- frobnitz(fact(10));
-}
-EOF
-
-cat >file2 <<\EOF
-#include <stdio.h>
-
-int fib(int n)
-{
- if(n > 2)
- {
- return fib(n-1) + fib(n-2);
- }
- return 1;
-}
-
-// Frobs foo heartily
-int frobnitz(int foo)
-{
- int i;
- for(i = 0; i < 10; i++)
- {
- printf("%d\n", foo);
- }
-}
-
-int main(int argc, char **argv)
-{
- frobnitz(fib(10));
-}
-EOF
-
-cat >expect <<\EOF
-diff --git a/file1 b/file2
-index 6faa5a3..e3af329 100644
---- a/file1
-+++ b/file2
-@@ -1,26 +1,25 @@
- #include <stdio.h>
-
-+int fib(int n)
-+{
-+ if(n > 2)
-+ {
-+ return fib(n-1) + fib(n-2);
-+ }
-+ return 1;
-+}
-+
- // Frobs foo heartily
- int frobnitz(int foo)
- {
- int i;
- for(i = 0; i < 10; i++)
- {
-- printf("Your answer is: ");
- printf("%d\n", foo);
- }
- }
-
--int fact(int n)
--{
-- if(n > 1)
-- {
-- return fact(n-1) * n;
-- }
-- return 1;
--}
--
- int main(int argc, char **argv)
- {
-- frobnitz(fact(10));
-+ frobnitz(fib(10));
- }
-EOF
-
-test_expect_success 'patience diff' '
-
- test_must_fail git diff --no-index --patience file1 file2 > output &&
- test_cmp expect output
-
-'
-
-test_expect_success 'patience diff output is valid' '
-
- mv file2 expect &&
- git apply < output &&
- test_cmp expect file2
-
-'
-
-cat >uniq1 <<\EOF
-1
-2
-3
-4
-5
-6
-EOF
-
-cat >uniq2 <<\EOF
-a
-b
-c
-d
-e
-f
-EOF
-
-cat >expect <<\EOF
-diff --git a/uniq1 b/uniq2
-index b414108..0fdf397 100644
---- a/uniq1
-+++ b/uniq2
-@@ -1,6 +1,6 @@
--1
--2
--3
--4
--5
--6
-+a
-+b
-+c
-+d
-+e
-+f
-EOF
-
-test_expect_success 'completely different files' '
-
- test_must_fail git diff --no-index --patience uniq1 uniq2 > output &&
- test_cmp expect output
-
-'
+test_diff_unique "patience"
test_done
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index 8096d8a337..c374aa4c1c 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -4,331 +4,333 @@ test_description='word diff colors'
. ./test-lib.sh
-test_expect_success setup '
+cat >pre.simple <<-\EOF
+ h(4)
- git config diff.color.old red &&
- git config diff.color.new green &&
- git config diff.color.func magenta
+ a = b + c
+EOF
+cat >post.simple <<-\EOF
+ h(4),hh[44]
-'
+ a = b + c
-word_diff () {
- test_must_fail git diff --no-index "$@" pre post > output &&
- test_decode_color <output >output.decrypted &&
- test_cmp expect output.decrypted
-}
+ aa = a
-cat > pre <<\EOF
-h(4)
-
-a = b + c
+ aeff = aeff * ( aaa )
EOF
+cat >expect.letter-runs-are-words <<-\EOF
+ <BOLD>diff --git a/pre b/post<RESET>
+ <BOLD>index 330b04f..5ed8eff 100644<RESET>
+ <BOLD>--- a/pre<RESET>
+ <BOLD>+++ b/post<RESET>
+ <CYAN>@@ -1,3 +1,7 @@<RESET>
+ h(4),<GREEN>hh<RESET>[44]
-cat > post <<\EOF
-h(4),hh[44]
-
-a = b + c
+ a = b + c<RESET>
-aa = a
+ <GREEN>aa = a<RESET>
-aeff = aeff * ( aaa )
+ <GREEN>aeff = aeff * ( aaa<RESET> )
EOF
+cat >expect.non-whitespace-is-word <<-\EOF
+ <BOLD>diff --git a/pre b/post<RESET>
+ <BOLD>index 330b04f..5ed8eff 100644<RESET>
+ <BOLD>--- a/pre<RESET>
+ <BOLD>+++ b/post<RESET>
+ <CYAN>@@ -1,3 +1,7 @@<RESET>
+ h(4)<GREEN>,hh[44]<RESET>
-cat > expect <<\EOF
-<BOLD>diff --git a/pre b/post<RESET>
-<BOLD>index 330b04f..5ed8eff 100644<RESET>
-<BOLD>--- a/pre<RESET>
-<BOLD>+++ b/post<RESET>
-<CYAN>@@ -1,3 +1,7 @@<RESET>
-<RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET>
-
-a = b + c<RESET>
+ a = b + c<RESET>
-<GREEN>aa = a<RESET>
+ <GREEN>aa = a<RESET>
-<GREEN>aeff = aeff * ( aaa )<RESET>
+ <GREEN>aeff = aeff * ( aaa )<RESET>
EOF
-test_expect_success 'word diff with runs of whitespace' '
+word_diff () {
+ test_must_fail git diff --no-index "$@" pre post >output &&
+ test_decode_color <output >output.decrypted &&
+ test_cmp expect output.decrypted
+}
- word_diff --color-words
+test_language_driver () {
+ lang=$1
+ test_expect_success "diff driver '$lang'" '
+ cp "$TEST_DIRECTORY/t4034/'"$lang"'/pre" \
+ "$TEST_DIRECTORY/t4034/'"$lang"'/post" \
+ "$TEST_DIRECTORY/t4034/'"$lang"'/expect" . &&
+ echo "* diff='"$lang"'" >.gitattributes &&
+ word_diff --color-words
+ '
+}
+test_expect_success setup '
+ git config diff.color.old red &&
+ git config diff.color.new green &&
+ git config diff.color.func magenta
'
-test_expect_success '--word-diff=color' '
-
- word_diff --word-diff=color
-
+test_expect_success 'set up pre and post with runs of whitespace' '
+ cp pre.simple pre &&
+ cp post.simple post
'
-test_expect_success '--color --word-diff=color' '
-
+test_expect_success 'word diff with runs of whitespace' '
+ cat >expect <<-\EOF &&
+ <BOLD>diff --git a/pre b/post<RESET>
+ <BOLD>index 330b04f..5ed8eff 100644<RESET>
+ <BOLD>--- a/pre<RESET>
+ <BOLD>+++ b/post<RESET>
+ <CYAN>@@ -1,3 +1,7 @@<RESET>
+ <RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET>
+
+ a = b + c<RESET>
+
+ <GREEN>aa = a<RESET>
+
+ <GREEN>aeff = aeff * ( aaa )<RESET>
+ EOF
+ word_diff --color-words &&
+ word_diff --word-diff=color &&
word_diff --color --word-diff=color
-
'
-sed 's/#.*$//' > expect <<EOF
-diff --git a/pre b/post
-index 330b04f..5ed8eff 100644
---- a/pre
-+++ b/post
-@@ -1,3 +1,7 @@
--h(4)
-+h(4),hh[44]
-~
- # significant space
-~
- a = b + c
-~
-~
-+aa = a
-~
-~
-+aeff = aeff * ( aaa )
-~
-EOF
-
test_expect_success '--word-diff=porcelain' '
-
+ sed 's/#.*$//' >expect <<-\EOF &&
+ diff --git a/pre b/post
+ index 330b04f..5ed8eff 100644
+ --- a/pre
+ +++ b/post
+ @@ -1,3 +1,7 @@
+ -h(4)
+ +h(4),hh[44]
+ ~
+ # significant space
+ ~
+ a = b + c
+ ~
+ ~
+ +aa = a
+ ~
+ ~
+ +aeff = aeff * ( aaa )
+ ~
+ EOF
word_diff --word-diff=porcelain
-
'
-cat > expect <<EOF
-diff --git a/pre b/post
-index 330b04f..5ed8eff 100644
---- a/pre
-+++ b/post
-@@ -1,3 +1,7 @@
-[-h(4)-]{+h(4),hh[44]+}
-
-a = b + c
-
-{+aa = a+}
-
-{+aeff = aeff * ( aaa )+}
-EOF
-
test_expect_success '--word-diff=plain' '
+ cat >expect <<-\EOF &&
+ diff --git a/pre b/post
+ index 330b04f..5ed8eff 100644
+ --- a/pre
+ +++ b/post
+ @@ -1,3 +1,7 @@
+ [-h(4)-]{+h(4),hh[44]+}
- word_diff --word-diff=plain
-
-'
+ a = b + c
-test_expect_success '--word-diff=plain --no-color' '
+ {+aa = a+}
+ {+aeff = aeff * ( aaa )+}
+ EOF
+ word_diff --word-diff=plain &&
word_diff --word-diff=plain --no-color
-
'
-cat > expect <<EOF
-<BOLD>diff --git a/pre b/post<RESET>
-<BOLD>index 330b04f..5ed8eff 100644<RESET>
-<BOLD>--- a/pre<RESET>
-<BOLD>+++ b/post<RESET>
-<CYAN>@@ -1,3 +1,7 @@<RESET>
-<RED>[-h(4)-]<RESET><GREEN>{+h(4),hh[44]+}<RESET>
-
-a = b + c<RESET>
-
-<GREEN>{+aa = a+}<RESET>
+test_expect_success '--word-diff=plain --color' '
+ cat >expect <<-\EOF &&
+ <BOLD>diff --git a/pre b/post<RESET>
+ <BOLD>index 330b04f..5ed8eff 100644<RESET>
+ <BOLD>--- a/pre<RESET>
+ <BOLD>+++ b/post<RESET>
+ <CYAN>@@ -1,3 +1,7 @@<RESET>
+ <RED>[-h(4)-]<RESET><GREEN>{+h(4),hh[44]+}<RESET>
-<GREEN>{+aeff = aeff * ( aaa )+}<RESET>
-EOF
+ a = b + c<RESET>
-test_expect_success '--word-diff=plain --color' '
+ <GREEN>{+aa = a+}<RESET>
+ <GREEN>{+aeff = aeff * ( aaa )+}<RESET>
+ EOF
word_diff --word-diff=plain --color
-
'
-cat > expect <<\EOF
-<BOLD>diff --git a/pre b/post<RESET>
-<BOLD>index 330b04f..5ed8eff 100644<RESET>
-<BOLD>--- a/pre<RESET>
-<BOLD>+++ b/post<RESET>
-<CYAN>@@ -1 +1 @@<RESET>
-<RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET>
-<CYAN>@@ -3,0 +4,4 @@<RESET> <RESET><MAGENTA>a = b + c<RESET>
-
-<GREEN>aa = a<RESET>
-
-<GREEN>aeff = aeff * ( aaa )<RESET>
-EOF
-
test_expect_success 'word diff without context' '
-
+ cat >expect <<-\EOF &&
+ <BOLD>diff --git a/pre b/post<RESET>
+ <BOLD>index 330b04f..5ed8eff 100644<RESET>
+ <BOLD>--- a/pre<RESET>
+ <BOLD>+++ b/post<RESET>
+ <CYAN>@@ -1 +1 @@<RESET>
+ <RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET>
+ <CYAN>@@ -3,0 +4,4 @@<RESET> <RESET><MAGENTA>a = b + c<RESET>
+
+ <GREEN>aa = a<RESET>
+
+ <GREEN>aeff = aeff * ( aaa )<RESET>
+ EOF
word_diff --color-words --unified=0
-
'
-cat > expect <<\EOF
-<BOLD>diff --git a/pre b/post<RESET>
-<BOLD>index 330b04f..5ed8eff 100644<RESET>
-<BOLD>--- a/pre<RESET>
-<BOLD>+++ b/post<RESET>
-<CYAN>@@ -1,3 +1,7 @@<RESET>
-h(4),<GREEN>hh<RESET>[44]
-
-a = b + c<RESET>
-
-<GREEN>aa = a<RESET>
-
-<GREEN>aeff = aeff * ( aaa<RESET> )
-EOF
-cp expect expect.letter-runs-are-words
-
test_expect_success 'word diff with a regular expression' '
-
+ cp expect.letter-runs-are-words expect &&
word_diff --color-words="[a-z]+"
-
'
-test_expect_success 'set a diff driver' '
+test_expect_success 'set up a diff driver' '
git config diff.testdriver.wordRegex "[^[:space:]]" &&
- cat <<EOF > .gitattributes
-pre diff=testdriver
-post diff=testdriver
-EOF
+ cat <<-\EOF >.gitattributes
+ pre diff=testdriver
+ post diff=testdriver
+ EOF
'
test_expect_success 'option overrides .gitattributes' '
-
+ cp expect.letter-runs-are-words expect &&
word_diff --color-words="[a-z]+"
-
'
-cat > expect <<\EOF
-<BOLD>diff --git a/pre b/post<RESET>
-<BOLD>index 330b04f..5ed8eff 100644<RESET>
-<BOLD>--- a/pre<RESET>
-<BOLD>+++ b/post<RESET>
-<CYAN>@@ -1,3 +1,7 @@<RESET>
-h(4)<GREEN>,hh[44]<RESET>
-
-a = b + c<RESET>
-
-<GREEN>aa = a<RESET>
-
-<GREEN>aeff = aeff * ( aaa )<RESET>
-EOF
-cp expect expect.non-whitespace-is-word
-
test_expect_success 'use regex supplied by driver' '
-
+ cp expect.non-whitespace-is-word expect &&
word_diff --color-words
-
'
-test_expect_success 'set diff.wordRegex option' '
+test_expect_success 'set up diff.wordRegex option' '
git config diff.wordRegex "[[:alnum:]]+"
'
-cp expect.letter-runs-are-words expect
-
test_expect_success 'command-line overrides config' '
+ cp expect.letter-runs-are-words expect &&
word_diff --color-words="[a-z]+"
'
-cat > expect <<\EOF
-<BOLD>diff --git a/pre b/post<RESET>
-<BOLD>index 330b04f..5ed8eff 100644<RESET>
-<BOLD>--- a/pre<RESET>
-<BOLD>+++ b/post<RESET>
-<CYAN>@@ -1,3 +1,7 @@<RESET>
-h(4),<GREEN>{+hh+}<RESET>[44]
-
-a = b + c<RESET>
+test_expect_success 'command-line overrides config: --word-diff-regex' '
+ cat >expect <<-\EOF &&
+ <BOLD>diff --git a/pre b/post<RESET>
+ <BOLD>index 330b04f..5ed8eff 100644<RESET>
+ <BOLD>--- a/pre<RESET>
+ <BOLD>+++ b/post<RESET>
+ <CYAN>@@ -1,3 +1,7 @@<RESET>
+ h(4),<GREEN>{+hh+}<RESET>[44]
-<GREEN>{+aa = a+}<RESET>
+ a = b + c<RESET>
-<GREEN>{+aeff = aeff * ( aaa+}<RESET> )
-EOF
+ <GREEN>{+aa = a+}<RESET>
-test_expect_success 'command-line overrides config: --word-diff-regex' '
+ <GREEN>{+aeff = aeff * ( aaa+}<RESET> )
+ EOF
word_diff --color --word-diff-regex="[a-z]+"
'
-cp expect.non-whitespace-is-word expect
-
test_expect_success '.gitattributes override config' '
+ cp expect.non-whitespace-is-word expect &&
word_diff --color-words
'
-test_expect_success 'remove diff driver regex' '
- git config --unset diff.testdriver.wordRegex
+test_expect_success 'setup: remove diff driver regex' '
+ test_might_fail git config --unset diff.testdriver.wordRegex
'
-cat > expect <<\EOF
-<BOLD>diff --git a/pre b/post<RESET>
-<BOLD>index 330b04f..5ed8eff 100644<RESET>
-<BOLD>--- a/pre<RESET>
-<BOLD>+++ b/post<RESET>
-<CYAN>@@ -1,3 +1,7 @@<RESET>
-h(4),<GREEN>hh[44<RESET>]
-
-a = b + c<RESET>
+test_expect_success 'use configured regex' '
+ cat >expect <<-\EOF &&
+ <BOLD>diff --git a/pre b/post<RESET>
+ <BOLD>index 330b04f..5ed8eff 100644<RESET>
+ <BOLD>--- a/pre<RESET>
+ <BOLD>+++ b/post<RESET>
+ <CYAN>@@ -1,3 +1,7 @@<RESET>
+ h(4),<GREEN>hh[44<RESET>]
-<GREEN>aa = a<RESET>
+ a = b + c<RESET>
-<GREEN>aeff = aeff * ( aaa<RESET> )
-EOF
+ <GREEN>aa = a<RESET>
-test_expect_success 'use configured regex' '
+ <GREEN>aeff = aeff * ( aaa<RESET> )
+ EOF
word_diff --color-words
'
-echo 'aaa (aaa)' > pre
-echo 'aaa (aaa) aaa' > post
-
-cat > expect <<\EOF
-<BOLD>diff --git a/pre b/post<RESET>
-<BOLD>index c29453b..be22f37 100644<RESET>
-<BOLD>--- a/pre<RESET>
-<BOLD>+++ b/post<RESET>
-<CYAN>@@ -1 +1 @@<RESET>
-aaa (aaa) <GREEN>aaa<RESET>
-EOF
-
test_expect_success 'test parsing words for newline' '
-
+ echo "aaa (aaa)" >pre &&
+ echo "aaa (aaa) aaa" >post &&
+ cat >expect <<-\EOF &&
+ <BOLD>diff --git a/pre b/post<RESET>
+ <BOLD>index c29453b..be22f37 100644<RESET>
+ <BOLD>--- a/pre<RESET>
+ <BOLD>+++ b/post<RESET>
+ <CYAN>@@ -1 +1 @@<RESET>
+ aaa (aaa) <GREEN>aaa<RESET>
+ EOF
word_diff --color-words="a+"
-
-
'
-echo '(:' > pre
-echo '(' > post
-
-cat > expect <<\EOF
-<BOLD>diff --git a/pre b/post<RESET>
-<BOLD>index 289cb9d..2d06f37 100644<RESET>
-<BOLD>--- a/pre<RESET>
-<BOLD>+++ b/post<RESET>
-<CYAN>@@ -1 +1 @@<RESET>
-(<RED>:<RESET>
-EOF
-
test_expect_success 'test when words are only removed at the end' '
-
+ echo "(:" >pre &&
+ echo "(" >post &&
+ cat >expect <<-\EOF &&
+ <BOLD>diff --git a/pre b/post<RESET>
+ <BOLD>index 289cb9d..2d06f37 100644<RESET>
+ <BOLD>--- a/pre<RESET>
+ <BOLD>+++ b/post<RESET>
+ <CYAN>@@ -1 +1 @@<RESET>
+ (<RED>:<RESET>
+ EOF
word_diff --color-words=.
-
'
-cat > expect <<\EOF
-diff --git a/pre b/post
-index 289cb9d..2d06f37 100644
---- a/pre
-+++ b/post
-@@ -1 +1 @@
--(:
-+(
-EOF
-
test_expect_success '--word-diff=none' '
-
+ echo "(:" >pre &&
+ echo "(" >post &&
+ cat >expect <<-\EOF &&
+ diff --git a/pre b/post
+ index 289cb9d..2d06f37 100644
+ --- a/pre
+ +++ b/post
+ @@ -1 +1 @@
+ -(:
+ +(
+ EOF
word_diff --word-diff=plain --word-diff=none
+'
+test_language_driver bibtex
+test_language_driver cpp
+test_language_driver csharp
+test_language_driver fortran
+test_language_driver html
+test_language_driver java
+test_language_driver objc
+test_language_driver pascal
+test_language_driver perl
+test_language_driver php
+test_language_driver python
+test_language_driver ruby
+test_language_driver tex
+
+test_expect_success 'word-diff with diff.sbe' '
+ cat >expect <<-\EOF &&
+ diff --git a/pre b/post
+ index a1a53b5..bc8fe6d 100644
+ --- a/pre
+ +++ b/post
+ @@ -1,3 +1,3 @@
+ a
+
+ [-b-]{+c+}
+ EOF
+ cat >pre <<-\EOF &&
+ a
+
+ b
+ EOF
+ cat >post <<-\EOF &&
+ a
+
+ c
+ EOF
+ test_when_finished "git config --unset diff.suppress-blank-empty" &&
+ git config diff.suppress-blank-empty true &&
+ word_diff --word-diff=plain
'
test_done
diff --git a/t/t4034/bibtex/expect b/t/t4034/bibtex/expect
new file mode 100644
index 0000000000..a157774f9d
--- /dev/null
+++ b/t/t4034/bibtex/expect
@@ -0,0 +1,15 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 95cd55b..ddcba9b 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,9 +1,10 @@<RESET>
+@article{aldous1987uie,<RESET>
+ title={{Ultimate instability of exponential back-off protocol for acknowledgment-based transmission control of random access communication channels}},<RESET>
+ author={Aldous, <RED>D.<RESET><GREEN>David<RESET>},
+ journal={Information Theory, IEEE Transactions on},<RESET>
+ volume={<RED>33<RESET><GREEN>Bogus.<RESET>},
+ number={<RED>2<RESET><GREEN>4<RESET>},
+ pages={219--223},<RESET>
+ year=<GREEN>1987,<RESET>
+<GREEN> note={This is in fact a rather funny read since ethernet works well in practice. The<RESET> {<RED>1987<RESET><GREEN>\em pre} reference is the right one, however.<RESET>}<RED>,<RESET>
+}<RESET>
diff --git a/t/t4034/bibtex/post b/t/t4034/bibtex/post
new file mode 100644
index 0000000000..ddcba9b2fc
--- /dev/null
+++ b/t/t4034/bibtex/post
@@ -0,0 +1,10 @@
+@article{aldous1987uie,
+ title={{Ultimate instability of exponential back-off protocol for acknowledgment-based transmission control of random access communication channels}},
+ author={Aldous, David},
+ journal={Information Theory, IEEE Transactions on},
+ volume={Bogus.},
+ number={4},
+ pages={219--223},
+ year=1987,
+ note={This is in fact a rather funny read since ethernet works well in practice. The {\em pre} reference is the right one, however.}
+}
diff --git a/t/t4034/bibtex/pre b/t/t4034/bibtex/pre
new file mode 100644
index 0000000000..95cd55bd7b
--- /dev/null
+++ b/t/t4034/bibtex/pre
@@ -0,0 +1,9 @@
+@article{aldous1987uie,
+ title={{Ultimate instability of exponential back-off protocol for acknowledgment-based transmission control of random access communication channels}},
+ author={Aldous, D.},
+ journal={Information Theory, IEEE Transactions on},
+ volume={33},
+ number={2},
+ pages={219--223},
+ year={1987},
+}
diff --git a/t/t4034/cpp/expect b/t/t4034/cpp/expect
new file mode 100644
index 0000000000..37d1ea2587
--- /dev/null
+++ b/t/t4034/cpp/expect
@@ -0,0 +1,36 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 23d5c8a..7e8c026 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,19 +1,19 @@<RESET>
+Foo() : x(0<RED>&&1<RESET><GREEN>&42<RESET>) { <GREEN>bar(x);<RESET> }
+cout<<"Hello World<RED>!<RESET><GREEN>?<RESET>\n"<<endl;
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>|<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z
+<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,y
+<RED>a<RESET><GREEN>x<RESET>::<RED>b<RESET><GREEN>y<RESET>
diff --git a/t/t4034/cpp/post b/t/t4034/cpp/post
new file mode 100644
index 0000000000..7e8c026cef
--- /dev/null
+++ b/t/t4034/cpp/post
@@ -0,0 +1,19 @@
+Foo() : x(0&42) { bar(x); }
+cout<<"Hello World?\n"<<endl;
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x ~x x++ x-- x*y x&y
+x*y x/y x%y
+x+y x-y
+x<<y x>>y
+x<y x<=y x>y x>=y
+x==y x!=y
+x&y
+x^y
+x|y
+x&&y
+x||y
+x?y:z
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+x,y
+x::y
diff --git a/t/t4034/cpp/pre b/t/t4034/cpp/pre
new file mode 100644
index 0000000000..23d5c8adf5
--- /dev/null
+++ b/t/t4034/cpp/pre
@@ -0,0 +1,19 @@
+Foo():x(0&&1){}
+cout<<"Hello World!\n"<<endl;
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a ~a a++ a-- a*b a&b
+a*b a/b a%b
+a+b a-b
+a<<b a>>b
+a<b a<=b a>b a>=b
+a==b a!=b
+a&b
+a^b
+a|b
+a&&b
+a||b
+a?b:z
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a,y
+a::b
diff --git a/t/t4034/csharp/expect b/t/t4034/csharp/expect
new file mode 100644
index 0000000000..e5d1dd2b3d
--- /dev/null
+++ b/t/t4034/csharp/expect
@@ -0,0 +1,35 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 9106d63..dd5f421 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,18 +1,18 @@<RESET>
+Foo() : x(0<RED>&&1<RESET><GREEN>&42<RESET>) { <GREEN>bar(x);<RESET> }
+cout<<"Hello World<RED>!<RESET><GREEN>?<RESET>\n"<<endl;
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>|<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z
+<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,y
diff --git a/t/t4034/csharp/post b/t/t4034/csharp/post
new file mode 100644
index 0000000000..dd5f4218a6
--- /dev/null
+++ b/t/t4034/csharp/post
@@ -0,0 +1,18 @@
+Foo() : x(0&42) { bar(x); }
+cout<<"Hello World?\n"<<endl;
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x ~x x++ x-- x*y x&y
+x*y x/y x%y
+x+y x-y
+x<<y x>>y
+x<y x<=y x>y x>=y
+x==y x!=y
+x&y
+x^y
+x|y
+x&&y
+x||y
+x?y:z
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+x,y
diff --git a/t/t4034/csharp/pre b/t/t4034/csharp/pre
new file mode 100644
index 0000000000..9106d63e87
--- /dev/null
+++ b/t/t4034/csharp/pre
@@ -0,0 +1,18 @@
+Foo():x(0&&1){}
+cout<<"Hello World!\n"<<endl;
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a ~a a++ a-- a*b a&b
+a*b a/b a%b
+a+b a-b
+a<<b a>>b
+a<b a<=b a>b a>=b
+a==b a!=b
+a&b
+a^b
+a|b
+a&&b
+a||b
+a?b:z
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a,y
diff --git a/t/t4034/fortran/expect b/t/t4034/fortran/expect
new file mode 100644
index 0000000000..b233dbd621
--- /dev/null
+++ b/t/t4034/fortran/expect
@@ -0,0 +1,10 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 87f0d0b..d308da2 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,5 +1,5 @@<RESET>
+print *, "Hello World<RED>!<RESET><GREEN>?<RESET>"
+
+DO10I = 1,10<RESET>
+<RED>DO10I<RESET><GREEN>DO 10 I<RESET> = 1,10
+<RED>DO10I<RESET><GREEN>DO 1 0 I<RESET> = 1,10
diff --git a/t/t4034/fortran/post b/t/t4034/fortran/post
new file mode 100644
index 0000000000..d308da2ad2
--- /dev/null
+++ b/t/t4034/fortran/post
@@ -0,0 +1,5 @@
+print *, "Hello World?"
+
+DO10I = 1,10
+DO 10 I = 1,10
+DO 1 0 I = 1,10
diff --git a/t/t4034/fortran/pre b/t/t4034/fortran/pre
new file mode 100644
index 0000000000..87f0d0b031
--- /dev/null
+++ b/t/t4034/fortran/pre
@@ -0,0 +1,5 @@
+print *, "Hello World!"
+
+DO10I = 1,10
+DO10I = 1,10
+DO10I = 1,10
diff --git a/t/t4034/html/expect b/t/t4034/html/expect
new file mode 100644
index 0000000000..447b49ab6d
--- /dev/null
+++ b/t/t4034/html/expect
@@ -0,0 +1,8 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 8ca4aea..46921e5 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,3 +1,3 @@<RESET>
+<tag <GREEN>newattr="newvalue"<RESET>><GREEN>added<RESET> content</tag>
+<tag attr=<RED>"value"<RESET><GREEN>"newvalue"<RESET>><RED>content<RESET><GREEN>changed<RESET></tag>
+<<RED>tag<RESET><GREEN>newtag<RESET>>content <RED>&entity;<RESET><GREEN>&newentity;<RESET><<RED>/tag<RESET><GREEN>/newtag<RESET>>
diff --git a/t/t4034/html/post b/t/t4034/html/post
new file mode 100644
index 0000000000..46921e586c
--- /dev/null
+++ b/t/t4034/html/post
@@ -0,0 +1,3 @@
+<tag newattr="newvalue">added content</tag>
+<tag attr="newvalue">changed</tag>
+<newtag>content &newentity;</newtag>
diff --git a/t/t4034/html/pre b/t/t4034/html/pre
new file mode 100644
index 0000000000..8ca4aeae83
--- /dev/null
+++ b/t/t4034/html/pre
@@ -0,0 +1,3 @@
+<tag>content</tag>
+<tag attr="value">content</tag>
+<tag>content &entity;</tag>
diff --git a/t/t4034/java/expect b/t/t4034/java/expect
new file mode 100644
index 0000000000..37d1ea2587
--- /dev/null
+++ b/t/t4034/java/expect
@@ -0,0 +1,36 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 23d5c8a..7e8c026 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,19 +1,19 @@<RESET>
+Foo() : x(0<RED>&&1<RESET><GREEN>&42<RESET>) { <GREEN>bar(x);<RESET> }
+cout<<"Hello World<RED>!<RESET><GREEN>?<RESET>\n"<<endl;
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>|<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z
+<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,y
+<RED>a<RESET><GREEN>x<RESET>::<RED>b<RESET><GREEN>y<RESET>
diff --git a/t/t4034/java/post b/t/t4034/java/post
new file mode 100644
index 0000000000..7e8c026cef
--- /dev/null
+++ b/t/t4034/java/post
@@ -0,0 +1,19 @@
+Foo() : x(0&42) { bar(x); }
+cout<<"Hello World?\n"<<endl;
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x ~x x++ x-- x*y x&y
+x*y x/y x%y
+x+y x-y
+x<<y x>>y
+x<y x<=y x>y x>=y
+x==y x!=y
+x&y
+x^y
+x|y
+x&&y
+x||y
+x?y:z
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+x,y
+x::y
diff --git a/t/t4034/java/pre b/t/t4034/java/pre
new file mode 100644
index 0000000000..23d5c8adf5
--- /dev/null
+++ b/t/t4034/java/pre
@@ -0,0 +1,19 @@
+Foo():x(0&&1){}
+cout<<"Hello World!\n"<<endl;
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a ~a a++ a-- a*b a&b
+a*b a/b a%b
+a+b a-b
+a<<b a>>b
+a<b a<=b a>b a>=b
+a==b a!=b
+a&b
+a^b
+a|b
+a&&b
+a||b
+a?b:z
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a,y
+a::b
diff --git a/t/t4034/objc/expect b/t/t4034/objc/expect
new file mode 100644
index 0000000000..e5d1dd2b3d
--- /dev/null
+++ b/t/t4034/objc/expect
@@ -0,0 +1,35 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 9106d63..dd5f421 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,18 +1,18 @@<RESET>
+Foo() : x(0<RED>&&1<RESET><GREEN>&42<RESET>) { <GREEN>bar(x);<RESET> }
+cout<<"Hello World<RED>!<RESET><GREEN>?<RESET>\n"<<endl;
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>|<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z
+<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,y
diff --git a/t/t4034/objc/post b/t/t4034/objc/post
new file mode 100644
index 0000000000..dd5f4218a6
--- /dev/null
+++ b/t/t4034/objc/post
@@ -0,0 +1,18 @@
+Foo() : x(0&42) { bar(x); }
+cout<<"Hello World?\n"<<endl;
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x ~x x++ x-- x*y x&y
+x*y x/y x%y
+x+y x-y
+x<<y x>>y
+x<y x<=y x>y x>=y
+x==y x!=y
+x&y
+x^y
+x|y
+x&&y
+x||y
+x?y:z
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+x,y
diff --git a/t/t4034/objc/pre b/t/t4034/objc/pre
new file mode 100644
index 0000000000..9106d63e87
--- /dev/null
+++ b/t/t4034/objc/pre
@@ -0,0 +1,18 @@
+Foo():x(0&&1){}
+cout<<"Hello World!\n"<<endl;
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a ~a a++ a-- a*b a&b
+a*b a/b a%b
+a+b a-b
+a<<b a>>b
+a<b a<=b a>b a>=b
+a==b a!=b
+a&b
+a^b
+a|b
+a&&b
+a||b
+a?b:z
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a,y
diff --git a/t/t4034/pascal/expect b/t/t4034/pascal/expect
new file mode 100644
index 0000000000..2ce4230954
--- /dev/null
+++ b/t/t4034/pascal/expect
@@ -0,0 +1,35 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 077046c..8865e6b 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,18 +1,18 @@<RESET>
+writeln("Hello World<RED>!<RESET><GREEN>?<RESET>");
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>|<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z
+<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,y
+<RED>a<RESET><GREEN>x<RESET>::<RED>b<RESET><GREEN>y<RESET>
diff --git a/t/t4034/pascal/post b/t/t4034/pascal/post
new file mode 100644
index 0000000000..8865e6bddd
--- /dev/null
+++ b/t/t4034/pascal/post
@@ -0,0 +1,18 @@
+writeln("Hello World?");
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x ~x x++ x-- x*y x&y
+x*y x/y x%y
+x+y x-y
+x<<y x>>y
+x<y x<=y x>y x>=y
+x==y x!=y
+x&y
+x^y
+x|y
+x&&y
+x||y
+x?y:z
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+x,y
+x::y
diff --git a/t/t4034/pascal/pre b/t/t4034/pascal/pre
new file mode 100644
index 0000000000..077046c832
--- /dev/null
+++ b/t/t4034/pascal/pre
@@ -0,0 +1,18 @@
+writeln("Hello World!");
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a ~a a++ a-- a*b a&b
+a*b a/b a%b
+a+b a-b
+a<<b a>>b
+a<b a<=b a>b a>=b
+a==b a!=b
+a&b
+a^b
+a|b
+a&&b
+a||b
+a?b:z
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a,y
+a::b
diff --git a/t/t4034/perl/expect b/t/t4034/perl/expect
new file mode 100644
index 0000000000..a1deb6b6ad
--- /dev/null
+++ b/t/t4034/perl/expect
@@ -0,0 +1,13 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index f6610d3..e8b72ef 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -4,8 +4,8 @@<RESET>
+
+package Frotz;<RESET>
+sub new {<RESET>
+ my <GREEN>(<RESET>$class<GREEN>, %opts)<RESET> = <RED>shift<RESET><GREEN>@_<RESET>;
+ return bless { <GREEN>xyzzy => "nitfol", %opts<RESET> }, $class;
+}<RESET>
+
+__END__<RESET>
diff --git a/t/t4034/perl/post b/t/t4034/perl/post
new file mode 100644
index 0000000000..e8b72ef5dc
--- /dev/null
+++ b/t/t4034/perl/post
@@ -0,0 +1,22 @@
+#!/usr/bin/perl
+
+use strict;
+
+package Frotz;
+sub new {
+ my ($class, %opts) = @_;
+ return bless { xyzzy => "nitfol", %opts }, $class;
+}
+
+__END__
+=head1 NAME
+
+frotz - Frotz
+
+=head1 SYNOPSIS
+
+ use frotz;
+
+ $nitfol = new Frotz();
+
+=cut
diff --git a/t/t4034/perl/pre b/t/t4034/perl/pre
new file mode 100644
index 0000000000..f6610d37b8
--- /dev/null
+++ b/t/t4034/perl/pre
@@ -0,0 +1,22 @@
+#!/usr/bin/perl
+
+use strict;
+
+package Frotz;
+sub new {
+ my $class = shift;
+ return bless {}, $class;
+}
+
+__END__
+=head1 NAME
+
+frotz - Frotz
+
+=head1 SYNOPSIS
+
+ use frotz;
+
+ $nitfol = new Frotz();
+
+=cut
diff --git a/t/t4034/php/expect b/t/t4034/php/expect
new file mode 100644
index 0000000000..040440860a
--- /dev/null
+++ b/t/t4034/php/expect
@@ -0,0 +1,35 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index cf6e06b..4420a49 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,18 +1,18 @@<RESET>
+<GREEN>(<RESET>$var<GREEN>)<RESET> $ var
+<?="Hello World<RED>!<RESET><GREEN>?<RESET>"?>
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>|<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z
+<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,y
diff --git a/t/t4034/php/post b/t/t4034/php/post
new file mode 100644
index 0000000000..4420a49192
--- /dev/null
+++ b/t/t4034/php/post
@@ -0,0 +1,18 @@
+($var) $ var
+<?="Hello World?"?>
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x ~x x++ x-- x*y x&y
+x*y x/y x%y
+x+y x-y
+x<<y x>>y
+x<y x<=y x>y x>=y
+x==y x!=y
+x&y
+x^y
+x|y
+x&&y
+x||y
+x?y:z
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+x,y
diff --git a/t/t4034/php/pre b/t/t4034/php/pre
new file mode 100644
index 0000000000..cf6e06bc22
--- /dev/null
+++ b/t/t4034/php/pre
@@ -0,0 +1,18 @@
+$var $var
+<?= "Hello World!" ?>
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a ~a a++ a-- a*b a&b
+a*b a/b a%b
+a+b a-b
+a<<b a>>b
+a<b a<=b a>b a>=b
+a==b a!=b
+a&b
+a^b
+a|b
+a&&b
+a||b
+a?b:z
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a,y
diff --git a/t/t4034/python/expect b/t/t4034/python/expect
new file mode 100644
index 0000000000..8abb8a48b4
--- /dev/null
+++ b/t/t4034/python/expect
@@ -0,0 +1,34 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 438f776..68baf34 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,17 +1,17 @@<RESET>
+print<RED>u<RESET> "Hello World<RED>!<RESET><GREEN>?<RESET>\n"<GREEN>; print<RESET>
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>) u<RESET>'<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>|<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z
+<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,y
diff --git a/t/t4034/python/post b/t/t4034/python/post
new file mode 100644
index 0000000000..68baf34f0e
--- /dev/null
+++ b/t/t4034/python/post
@@ -0,0 +1,17 @@
+print "Hello World?\n"; print
+(1) (-1e10) (0xabcdef) u'y'
+[x] x->y x.y
+!x ~x x++ x-- x*y x&y
+x*y x/y x%y
+x+y x-y
+x<<y x>>y
+x<y x<=y x>y x>=y
+x==y x!=y
+x&y
+x^y
+x|y
+x&&y
+x||y
+x?y:z
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+x,y
diff --git a/t/t4034/python/pre b/t/t4034/python/pre
new file mode 100644
index 0000000000..438f776875
--- /dev/null
+++ b/t/t4034/python/pre
@@ -0,0 +1,17 @@
+print u"Hello World!\n"
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a ~a a++ a-- a*b a&b
+a*b a/b a%b
+a+b a-b
+a<<b a>>b
+a<b a<=b a>b a>=b
+a==b a!=b
+a&b
+a^b
+a|b
+a&&b
+a||b
+a?b:z
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a,y
diff --git a/t/t4034/ruby/expect b/t/t4034/ruby/expect
new file mode 100644
index 0000000000..16e1dd5674
--- /dev/null
+++ b/t/t4034/ruby/expect
@@ -0,0 +1,34 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 30ed9a1..7678f14 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,17 +1,17 @@<RESET>
+10.downto(1) {|<RED>x<RESET><GREEN>y<RESET>| puts <RED>x<RESET><GREEN>y<RESET>}
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>|<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>||<RED>b<RESET>
+<RED>a?b<RESET><GREEN>y<RESET>
+<GREEN>x?y<RESET>:z
+<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,y
diff --git a/t/t4034/ruby/post b/t/t4034/ruby/post
new file mode 100644
index 0000000000..7678f14e14
--- /dev/null
+++ b/t/t4034/ruby/post
@@ -0,0 +1,17 @@
+10.downto(1) {|y| puts y}
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x ~x x++ x-- x*y x&y
+x*y x/y x%y
+x+y x-y
+x<<y x>>y
+x<y x<=y x>y x>=y
+x==y x!=y
+x&y
+x^y
+x|y
+x&&y
+x||y
+x?y:z
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+x,y
diff --git a/t/t4034/ruby/pre b/t/t4034/ruby/pre
new file mode 100644
index 0000000000..30ed9a1595
--- /dev/null
+++ b/t/t4034/ruby/pre
@@ -0,0 +1,17 @@
+10.downto(1) {|x| puts x}
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a ~a a++ a-- a*b a&b
+a*b a/b a%b
+a+b a-b
+a<<b a>>b
+a<b a<=b a>b a>=b
+a==b a!=b
+a&b
+a^b
+a|b
+a&&b
+a||b
+a?b:z
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a,y
diff --git a/t/t4034/tex/expect b/t/t4034/tex/expect
new file mode 100644
index 0000000000..604969bcde
--- /dev/null
+++ b/t/t4034/tex/expect
@@ -0,0 +1,9 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 2b2dfcb..65cab61 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,4 +1,4 @@<RESET>
+\section{Something <GREEN>new<RESET>}
+<RED>\emph<RESET><GREEN>\textbf<RESET>{Macro style}
+{<RED>\em<RESET><GREEN>\bfseries<RESET> State toggle style}
+\\[<RED>1em<RESET><GREEN>1cm<RESET>]
diff --git a/t/t4034/tex/post b/t/t4034/tex/post
new file mode 100644
index 0000000000..65cab61a10
--- /dev/null
+++ b/t/t4034/tex/post
@@ -0,0 +1,4 @@
+\section{Something new}
+\textbf{Macro style}
+{\bfseries State toggle style}
+\\[1cm]
diff --git a/t/t4034/tex/pre b/t/t4034/tex/pre
new file mode 100644
index 0000000000..2b2dfcb65c
--- /dev/null
+++ b/t/t4034/tex/pre
@@ -0,0 +1,4 @@
+\section{Something}
+\emph{Macro style}
+{\em State toggle style}
+\\[1em]
diff --git a/t/t4040-whitespace-status.sh b/t/t4040-whitespace-status.sh
index a30b03bcf2..3c728a3ebf 100755
--- a/t/t4040-whitespace-status.sh
+++ b/t/t4040-whitespace-status.sh
@@ -60,4 +60,16 @@ test_expect_success 'diff-files -b -p --exit-code' '
git diff-files -b -p --exit-code
'
+test_expect_success 'diff-files --diff-filter --quiet' '
+ git reset --hard &&
+ rm a/d &&
+ echo x >>b/e &&
+ test_must_fail git diff-files --diff-filter=M --quiet
+'
+
+test_expect_success 'diff-tree --diff-filter --quiet' '
+ git commit -a -m "worktree state" &&
+ test_must_fail git diff-tree --diff-filter=M --quiet HEAD^ HEAD
+'
+
test_done
diff --git a/t/t4046-diff-unmerged.sh b/t/t4046-diff-unmerged.sh
new file mode 100755
index 0000000000..25d50a654a
--- /dev/null
+++ b/t/t4046-diff-unmerged.sh
@@ -0,0 +1,87 @@
+#!/bin/sh
+
+test_description='diff with unmerged index entries'
+. ./test-lib.sh
+
+test_expect_success setup '
+ for i in 0 1 2 3
+ do
+ blob=$(echo $i | git hash-object --stdin) &&
+ eval "blob$i=$blob" &&
+ eval "m$i=\"100644 \$blob$i $i\"" || break
+ done &&
+ paths= &&
+ for b in o x
+ do
+ for o in o x
+ do
+ for t in o x
+ do
+ path="$b$o$t" &&
+ case "$path" in ooo) continue ;; esac
+ paths="$paths$path " &&
+ p=" $path" &&
+ case "$b" in x) echo "$m1$p" ;; esac &&
+ case "$o" in x) echo "$m2$p" ;; esac &&
+ case "$t" in x) echo "$m3$p" ;; esac ||
+ break
+ done || break
+ done || break
+ done >ls-files-s.expect &&
+ git update-index --index-info <ls-files-s.expect &&
+ git ls-files -s >ls-files-s.actual &&
+ test_cmp ls-files-s.expect ls-files-s.actual
+'
+
+test_expect_success 'diff-files -0' '
+ for path in $paths
+ do
+ >"$path" &&
+ echo ":000000 100644 $_z40 $_z40 U $path"
+ done >diff-files-0.expect &&
+ git diff-files -0 >diff-files-0.actual &&
+ test_cmp diff-files-0.expect diff-files-0.actual
+'
+
+test_expect_success 'diff-files -1' '
+ for path in $paths
+ do
+ >"$path" &&
+ echo ":000000 100644 $_z40 $_z40 U $path" &&
+ case "$path" in
+ x??) echo ":100644 100644 $blob1 $_z40 M $path"
+ esac
+ done >diff-files-1.expect &&
+ git diff-files -1 >diff-files-1.actual &&
+ test_cmp diff-files-1.expect diff-files-1.actual
+'
+
+test_expect_success 'diff-files -2' '
+ for path in $paths
+ do
+ >"$path" &&
+ echo ":000000 100644 $_z40 $_z40 U $path" &&
+ case "$path" in
+ ?x?) echo ":100644 100644 $blob2 $_z40 M $path"
+ esac
+ done >diff-files-2.expect &&
+ git diff-files -2 >diff-files-2.actual &&
+ test_cmp diff-files-2.expect diff-files-2.actual &&
+ git diff-files >diff-files-default-2.actual &&
+ test_cmp diff-files-2.expect diff-files-default-2.actual
+'
+
+test_expect_success 'diff-files -3' '
+ for path in $paths
+ do
+ >"$path" &&
+ echo ":000000 100644 $_z40 $_z40 U $path" &&
+ case "$path" in
+ ??x) echo ":100644 100644 $blob3 $_z40 M $path"
+ esac
+ done >diff-files-3.expect &&
+ git diff-files -3 >diff-files-3.actual &&
+ test_cmp diff-files-3.expect diff-files-3.actual
+'
+
+test_done
diff --git a/t/t4047-diff-dirstat.sh b/t/t4047-diff-dirstat.sh
new file mode 100755
index 0000000000..29e80a58cd
--- /dev/null
+++ b/t/t4047-diff-dirstat.sh
@@ -0,0 +1,979 @@
+#!/bin/sh
+
+test_description='diff --dirstat tests'
+. ./test-lib.sh
+
+# set up two commits where the second commit has these files
+# (10 lines in each file):
+#
+# unchanged/text (unchanged from 1st commit)
+# changed/text (changed 1st line)
+# rearranged/text (swapped 1st and 2nd line)
+# dst/copy/unchanged/text (copied from src/copy/unchanged/text, unchanged)
+# dst/copy/changed/text (copied from src/copy/changed/text, changed)
+# dst/copy/rearranged/text (copied from src/copy/rearranged/text, rearranged)
+# dst/move/unchanged/text (moved from src/move/unchanged/text, unchanged)
+# dst/move/changed/text (moved from src/move/changed/text, changed)
+# dst/move/rearranged/text (moved from src/move/rearranged/text, rearranged)
+
+test_expect_success 'setup' '
+ mkdir unchanged &&
+ mkdir changed &&
+ mkdir rearranged &&
+ mkdir src &&
+ mkdir src/copy &&
+ mkdir src/copy/unchanged &&
+ mkdir src/copy/changed &&
+ mkdir src/copy/rearranged &&
+ mkdir src/move &&
+ mkdir src/move/unchanged &&
+ mkdir src/move/changed &&
+ mkdir src/move/rearranged &&
+ cat <<EOF >unchanged/text &&
+unchanged line #0
+unchanged line #1
+unchanged line #2
+unchanged line #3
+unchanged line #4
+unchanged line #5
+unchanged line #6
+unchanged line #7
+unchanged line #8
+unchanged line #9
+EOF
+ cat <<EOF >changed/text &&
+changed line #0
+changed line #1
+changed line #2
+changed line #3
+changed line #4
+changed line #5
+changed line #6
+changed line #7
+changed line #8
+changed line #9
+EOF
+ cat <<EOF >rearranged/text &&
+rearranged line #0
+rearranged line #1
+rearranged line #2
+rearranged line #3
+rearranged line #4
+rearranged line #5
+rearranged line #6
+rearranged line #7
+rearranged line #8
+rearranged line #9
+EOF
+ cat <<EOF >src/copy/unchanged/text &&
+copy unchanged line #0
+copy unchanged line #1
+copy unchanged line #2
+copy unchanged line #3
+copy unchanged line #4
+copy unchanged line #5
+copy unchanged line #6
+copy unchanged line #7
+copy unchanged line #8
+copy unchanged line #9
+EOF
+ cat <<EOF >src/copy/changed/text &&
+copy changed line #0
+copy changed line #1
+copy changed line #2
+copy changed line #3
+copy changed line #4
+copy changed line #5
+copy changed line #6
+copy changed line #7
+copy changed line #8
+copy changed line #9
+EOF
+ cat <<EOF >src/copy/rearranged/text &&
+copy rearranged line #0
+copy rearranged line #1
+copy rearranged line #2
+copy rearranged line #3
+copy rearranged line #4
+copy rearranged line #5
+copy rearranged line #6
+copy rearranged line #7
+copy rearranged line #8
+copy rearranged line #9
+EOF
+ cat <<EOF >src/move/unchanged/text &&
+move unchanged line #0
+move unchanged line #1
+move unchanged line #2
+move unchanged line #3
+move unchanged line #4
+move unchanged line #5
+move unchanged line #6
+move unchanged line #7
+move unchanged line #8
+move unchanged line #9
+EOF
+ cat <<EOF >src/move/changed/text &&
+move changed line #0
+move changed line #1
+move changed line #2
+move changed line #3
+move changed line #4
+move changed line #5
+move changed line #6
+move changed line #7
+move changed line #8
+move changed line #9
+EOF
+ cat <<EOF >src/move/rearranged/text &&
+move rearranged line #0
+move rearranged line #1
+move rearranged line #2
+move rearranged line #3
+move rearranged line #4
+move rearranged line #5
+move rearranged line #6
+move rearranged line #7
+move rearranged line #8
+move rearranged line #9
+EOF
+ git add . &&
+ git commit -m "initial" &&
+ mkdir dst &&
+ mkdir dst/copy &&
+ mkdir dst/copy/unchanged &&
+ mkdir dst/copy/changed &&
+ mkdir dst/copy/rearranged &&
+ mkdir dst/move &&
+ mkdir dst/move/unchanged &&
+ mkdir dst/move/changed &&
+ mkdir dst/move/rearranged &&
+ cat <<EOF >changed/text &&
+CHANGED XXXXXXX line #0
+changed line #1
+changed line #2
+changed line #3
+changed line #4
+changed line #5
+changed line #6
+changed line #7
+changed line #8
+changed line #9
+EOF
+ cat <<EOF >rearranged/text &&
+rearranged line #1
+rearranged line #0
+rearranged line #2
+rearranged line #3
+rearranged line #4
+rearranged line #5
+rearranged line #6
+rearranged line #7
+rearranged line #8
+rearranged line #9
+EOF
+ cat <<EOF >dst/copy/unchanged/text &&
+copy unchanged line #0
+copy unchanged line #1
+copy unchanged line #2
+copy unchanged line #3
+copy unchanged line #4
+copy unchanged line #5
+copy unchanged line #6
+copy unchanged line #7
+copy unchanged line #8
+copy unchanged line #9
+EOF
+ cat <<EOF >dst/copy/changed/text &&
+copy XXXCHANGED line #0
+copy changed line #1
+copy changed line #2
+copy changed line #3
+copy changed line #4
+copy changed line #5
+copy changed line #6
+copy changed line #7
+copy changed line #8
+copy changed line #9
+EOF
+ cat <<EOF >dst/copy/rearranged/text &&
+copy rearranged line #1
+copy rearranged line #0
+copy rearranged line #2
+copy rearranged line #3
+copy rearranged line #4
+copy rearranged line #5
+copy rearranged line #6
+copy rearranged line #7
+copy rearranged line #8
+copy rearranged line #9
+EOF
+ cat <<EOF >dst/move/unchanged/text &&
+move unchanged line #0
+move unchanged line #1
+move unchanged line #2
+move unchanged line #3
+move unchanged line #4
+move unchanged line #5
+move unchanged line #6
+move unchanged line #7
+move unchanged line #8
+move unchanged line #9
+EOF
+ cat <<EOF >dst/move/changed/text &&
+move XXXCHANGED line #0
+move changed line #1
+move changed line #2
+move changed line #3
+move changed line #4
+move changed line #5
+move changed line #6
+move changed line #7
+move changed line #8
+move changed line #9
+EOF
+ cat <<EOF >dst/move/rearranged/text &&
+move rearranged line #1
+move rearranged line #0
+move rearranged line #2
+move rearranged line #3
+move rearranged line #4
+move rearranged line #5
+move rearranged line #6
+move rearranged line #7
+move rearranged line #8
+move rearranged line #9
+EOF
+ git add . &&
+ git rm -r src/move/unchanged &&
+ git rm -r src/move/changed &&
+ git rm -r src/move/rearranged &&
+ git commit -m "changes"
+'
+
+cat <<EOF >expect_diff_stat
+ changed/text | 2 +-
+ dst/copy/changed/text | 10 ++++++++++
+ dst/copy/rearranged/text | 10 ++++++++++
+ dst/copy/unchanged/text | 10 ++++++++++
+ dst/move/changed/text | 10 ++++++++++
+ dst/move/rearranged/text | 10 ++++++++++
+ dst/move/unchanged/text | 10 ++++++++++
+ rearranged/text | 2 +-
+ src/move/changed/text | 10 ----------
+ src/move/rearranged/text | 10 ----------
+ src/move/unchanged/text | 10 ----------
+ 11 files changed, 62 insertions(+), 32 deletions(-)
+EOF
+
+cat <<EOF >expect_diff_stat_M
+ changed/text | 2 +-
+ dst/copy/changed/text | 10 ++++++++++
+ dst/copy/rearranged/text | 10 ++++++++++
+ dst/copy/unchanged/text | 10 ++++++++++
+ {src => dst}/move/changed/text | 2 +-
+ {src => dst}/move/rearranged/text | 2 +-
+ {src => dst}/move/unchanged/text | 0
+ rearranged/text | 2 +-
+ 8 files changed, 34 insertions(+), 4 deletions(-)
+EOF
+
+cat <<EOF >expect_diff_stat_CC
+ changed/text | 2 +-
+ {src => dst}/copy/changed/text | 2 +-
+ {src => dst}/copy/rearranged/text | 2 +-
+ {src => dst}/copy/unchanged/text | 0
+ {src => dst}/move/changed/text | 2 +-
+ {src => dst}/move/rearranged/text | 2 +-
+ {src => dst}/move/unchanged/text | 0
+ rearranged/text | 2 +-
+ 8 files changed, 6 insertions(+), 6 deletions(-)
+EOF
+
+test_expect_success 'sanity check setup (--stat)' '
+ git diff --stat HEAD^..HEAD >actual_diff_stat &&
+ test_cmp expect_diff_stat actual_diff_stat &&
+ git diff --stat -M HEAD^..HEAD >actual_diff_stat_M &&
+ test_cmp expect_diff_stat_M actual_diff_stat_M &&
+ git diff --stat -C -C HEAD^..HEAD >actual_diff_stat_CC &&
+ test_cmp expect_diff_stat_CC actual_diff_stat_CC
+'
+
+# changed/text and rearranged/text falls below default 3% threshold
+cat <<EOF >expect_diff_dirstat
+ 10.8% dst/copy/changed/
+ 10.8% dst/copy/rearranged/
+ 10.8% dst/copy/unchanged/
+ 10.8% dst/move/changed/
+ 10.8% dst/move/rearranged/
+ 10.8% dst/move/unchanged/
+ 10.8% src/move/changed/
+ 10.8% src/move/rearranged/
+ 10.8% src/move/unchanged/
+EOF
+
+# rearranged/text falls below default 3% threshold
+cat <<EOF >expect_diff_dirstat_M
+ 5.8% changed/
+ 29.3% dst/copy/changed/
+ 29.3% dst/copy/rearranged/
+ 29.3% dst/copy/unchanged/
+ 5.8% dst/move/changed/
+EOF
+
+# rearranged/text falls below default 3% threshold
+cat <<EOF >expect_diff_dirstat_CC
+ 32.6% changed/
+ 32.6% dst/copy/changed/
+ 32.6% dst/move/changed/
+EOF
+
+test_expect_success 'various ways to misspell --dirstat' '
+ test_must_fail git show --dirstat10 &&
+ test_must_fail git show --dirstat10,files &&
+ test_must_fail git show -X=20 &&
+ test_must_fail git show -X=20,cumulative
+'
+
+test_expect_success 'vanilla --dirstat' '
+ git diff --dirstat HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success 'vanilla -X' '
+ git diff -X HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff -X -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff -X -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success 'explicit defaults: --dirstat=changes,noncumulative,3' '
+ git diff --dirstat=changes,noncumulative,3 HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat=changes,noncumulative,3 -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat=changes,noncumulative,3 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success 'explicit defaults: -Xchanges,noncumulative,3' '
+ git diff -Xchanges,noncumulative,3 HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff -Xchanges,noncumulative,3 -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff -Xchanges,noncumulative,3 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success 'later options override earlier options:' '
+ git diff --dirstat=files,10,cumulative,changes,noncumulative,3 HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat=files,10,cumulative,changes,noncumulative,3 -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat=files,10,cumulative,changes,noncumulative,3 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+ git diff --dirstat=files --dirstat=10 --dirstat=cumulative --dirstat=changes --dirstat=noncumulative -X3 HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat=files --dirstat=10 --dirstat=cumulative --dirstat=changes --dirstat=noncumulative -X3 -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat=files --dirstat=10 --dirstat=cumulative --dirstat=changes --dirstat=noncumulative -X3 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success 'non-defaults in config overridden by explicit defaults on command line' '
+ git -c diff.dirstat=files,cumulative,50 diff --dirstat=changes,noncumulative,3 HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git -c diff.dirstat=files,cumulative,50 diff --dirstat=changes,noncumulative,3 -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git -c diff.dirstat=files,cumulative,50 diff --dirstat=changes,noncumulative,3 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+cat <<EOF >expect_diff_dirstat
+ 2.1% changed/
+ 10.8% dst/copy/changed/
+ 10.8% dst/copy/rearranged/
+ 10.8% dst/copy/unchanged/
+ 10.8% dst/move/changed/
+ 10.8% dst/move/rearranged/
+ 10.8% dst/move/unchanged/
+ 0.0% rearranged/
+ 10.8% src/move/changed/
+ 10.8% src/move/rearranged/
+ 10.8% src/move/unchanged/
+EOF
+
+cat <<EOF >expect_diff_dirstat_M
+ 5.8% changed/
+ 29.3% dst/copy/changed/
+ 29.3% dst/copy/rearranged/
+ 29.3% dst/copy/unchanged/
+ 5.8% dst/move/changed/
+ 0.1% dst/move/rearranged/
+ 0.1% rearranged/
+EOF
+
+cat <<EOF >expect_diff_dirstat_CC
+ 32.6% changed/
+ 32.6% dst/copy/changed/
+ 0.6% dst/copy/rearranged/
+ 32.6% dst/move/changed/
+ 0.6% dst/move/rearranged/
+ 0.6% rearranged/
+EOF
+
+test_expect_success '--dirstat=0' '
+ git diff --dirstat=0 HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat=0 -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat=0 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success '-X0' '
+ git diff -X0 HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff -X0 -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff -X0 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success 'diff.dirstat=0' '
+ git -c diff.dirstat=0 diff --dirstat HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git -c diff.dirstat=0 diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git -c diff.dirstat=0 diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+cat <<EOF >expect_diff_dirstat
+ 2.1% changed/
+ 10.8% dst/copy/changed/
+ 10.8% dst/copy/rearranged/
+ 10.8% dst/copy/unchanged/
+ 32.5% dst/copy/
+ 10.8% dst/move/changed/
+ 10.8% dst/move/rearranged/
+ 10.8% dst/move/unchanged/
+ 32.5% dst/move/
+ 65.1% dst/
+ 0.0% rearranged/
+ 10.8% src/move/changed/
+ 10.8% src/move/rearranged/
+ 10.8% src/move/unchanged/
+ 32.5% src/move/
+EOF
+
+cat <<EOF >expect_diff_dirstat_M
+ 5.8% changed/
+ 29.3% dst/copy/changed/
+ 29.3% dst/copy/rearranged/
+ 29.3% dst/copy/unchanged/
+ 88.0% dst/copy/
+ 5.8% dst/move/changed/
+ 0.1% dst/move/rearranged/
+ 5.9% dst/move/
+ 94.0% dst/
+ 0.1% rearranged/
+EOF
+
+cat <<EOF >expect_diff_dirstat_CC
+ 32.6% changed/
+ 32.6% dst/copy/changed/
+ 0.6% dst/copy/rearranged/
+ 33.3% dst/copy/
+ 32.6% dst/move/changed/
+ 0.6% dst/move/rearranged/
+ 33.3% dst/move/
+ 66.6% dst/
+ 0.6% rearranged/
+EOF
+
+test_expect_success '--dirstat=0 --cumulative' '
+ git diff --dirstat=0 --cumulative HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat=0 --cumulative -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat=0 --cumulative -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success '--dirstat=0,cumulative' '
+ git diff --dirstat=0,cumulative HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat=0,cumulative -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat=0,cumulative -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success '-X0,cumulative' '
+ git diff -X0,cumulative HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff -X0,cumulative -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff -X0,cumulative -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success 'diff.dirstat=0,cumulative' '
+ git -c diff.dirstat=0,cumulative diff --dirstat HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git -c diff.dirstat=0,cumulative diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git -c diff.dirstat=0,cumulative diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success 'diff.dirstat=0 & --dirstat=cumulative' '
+ git -c diff.dirstat=0 diff --dirstat=cumulative HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git -c diff.dirstat=0 diff --dirstat=cumulative -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git -c diff.dirstat=0 diff --dirstat=cumulative -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+cat <<EOF >expect_diff_dirstat
+ 9.0% changed/
+ 9.0% dst/copy/changed/
+ 9.0% dst/copy/rearranged/
+ 9.0% dst/copy/unchanged/
+ 9.0% dst/move/changed/
+ 9.0% dst/move/rearranged/
+ 9.0% dst/move/unchanged/
+ 9.0% rearranged/
+ 9.0% src/move/changed/
+ 9.0% src/move/rearranged/
+ 9.0% src/move/unchanged/
+EOF
+
+cat <<EOF >expect_diff_dirstat_M
+ 14.2% changed/
+ 14.2% dst/copy/changed/
+ 14.2% dst/copy/rearranged/
+ 14.2% dst/copy/unchanged/
+ 14.2% dst/move/changed/
+ 14.2% dst/move/rearranged/
+ 14.2% rearranged/
+EOF
+
+cat <<EOF >expect_diff_dirstat_CC
+ 16.6% changed/
+ 16.6% dst/copy/changed/
+ 16.6% dst/copy/rearranged/
+ 16.6% dst/move/changed/
+ 16.6% dst/move/rearranged/
+ 16.6% rearranged/
+EOF
+
+test_expect_success '--dirstat-by-file' '
+ git diff --dirstat-by-file HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat-by-file -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat-by-file -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success '--dirstat=files' '
+ git diff --dirstat=files HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat=files -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat=files -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success 'diff.dirstat=files' '
+ git -c diff.dirstat=files diff --dirstat HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git -c diff.dirstat=files diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git -c diff.dirstat=files diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+cat <<EOF >expect_diff_dirstat
+ 27.2% dst/copy/
+ 27.2% dst/move/
+ 27.2% src/move/
+EOF
+
+cat <<EOF >expect_diff_dirstat_M
+ 14.2% changed/
+ 14.2% dst/copy/changed/
+ 14.2% dst/copy/rearranged/
+ 14.2% dst/copy/unchanged/
+ 14.2% dst/move/changed/
+ 14.2% dst/move/rearranged/
+ 14.2% rearranged/
+EOF
+
+cat <<EOF >expect_diff_dirstat_CC
+ 16.6% changed/
+ 16.6% dst/copy/changed/
+ 16.6% dst/copy/rearranged/
+ 16.6% dst/move/changed/
+ 16.6% dst/move/rearranged/
+ 16.6% rearranged/
+EOF
+
+test_expect_success '--dirstat-by-file=10' '
+ git diff --dirstat-by-file=10 HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat-by-file=10 -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat-by-file=10 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success '--dirstat=files,10' '
+ git diff --dirstat=files,10 HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat=files,10 -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat=files,10 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success 'diff.dirstat=10,files' '
+ git -c diff.dirstat=10,files diff --dirstat HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git -c diff.dirstat=10,files diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git -c diff.dirstat=10,files diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+cat <<EOF >expect_diff_dirstat
+ 9.0% changed/
+ 9.0% dst/copy/changed/
+ 9.0% dst/copy/rearranged/
+ 9.0% dst/copy/unchanged/
+ 27.2% dst/copy/
+ 9.0% dst/move/changed/
+ 9.0% dst/move/rearranged/
+ 9.0% dst/move/unchanged/
+ 27.2% dst/move/
+ 54.5% dst/
+ 9.0% rearranged/
+ 9.0% src/move/changed/
+ 9.0% src/move/rearranged/
+ 9.0% src/move/unchanged/
+ 27.2% src/move/
+EOF
+
+cat <<EOF >expect_diff_dirstat_M
+ 14.2% changed/
+ 14.2% dst/copy/changed/
+ 14.2% dst/copy/rearranged/
+ 14.2% dst/copy/unchanged/
+ 42.8% dst/copy/
+ 14.2% dst/move/changed/
+ 14.2% dst/move/rearranged/
+ 28.5% dst/move/
+ 71.4% dst/
+ 14.2% rearranged/
+EOF
+
+cat <<EOF >expect_diff_dirstat_CC
+ 16.6% changed/
+ 16.6% dst/copy/changed/
+ 16.6% dst/copy/rearranged/
+ 33.3% dst/copy/
+ 16.6% dst/move/changed/
+ 16.6% dst/move/rearranged/
+ 33.3% dst/move/
+ 66.6% dst/
+ 16.6% rearranged/
+EOF
+
+test_expect_success '--dirstat-by-file --cumulative' '
+ git diff --dirstat-by-file --cumulative HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat-by-file --cumulative -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat-by-file --cumulative -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success '--dirstat=files,cumulative' '
+ git diff --dirstat=files,cumulative HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat=files,cumulative -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat=files,cumulative -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success 'diff.dirstat=cumulative,files' '
+ git -c diff.dirstat=cumulative,files diff --dirstat HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git -c diff.dirstat=cumulative,files diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git -c diff.dirstat=cumulative,files diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+cat <<EOF >expect_diff_dirstat
+ 27.2% dst/copy/
+ 27.2% dst/move/
+ 54.5% dst/
+ 27.2% src/move/
+EOF
+
+cat <<EOF >expect_diff_dirstat_M
+ 14.2% changed/
+ 14.2% dst/copy/changed/
+ 14.2% dst/copy/rearranged/
+ 14.2% dst/copy/unchanged/
+ 42.8% dst/copy/
+ 14.2% dst/move/changed/
+ 14.2% dst/move/rearranged/
+ 28.5% dst/move/
+ 71.4% dst/
+ 14.2% rearranged/
+EOF
+
+cat <<EOF >expect_diff_dirstat_CC
+ 16.6% changed/
+ 16.6% dst/copy/changed/
+ 16.6% dst/copy/rearranged/
+ 33.3% dst/copy/
+ 16.6% dst/move/changed/
+ 16.6% dst/move/rearranged/
+ 33.3% dst/move/
+ 66.6% dst/
+ 16.6% rearranged/
+EOF
+
+test_expect_success '--dirstat=files,cumulative,10' '
+ git diff --dirstat=files,cumulative,10 HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat=files,cumulative,10 -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat=files,cumulative,10 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success 'diff.dirstat=10,cumulative,files' '
+ git -c diff.dirstat=10,cumulative,files diff --dirstat HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git -c diff.dirstat=10,cumulative,files diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git -c diff.dirstat=10,cumulative,files diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+cat <<EOF >expect_diff_dirstat
+ 27.2% dst/copy/
+ 27.2% dst/move/
+ 54.5% dst/
+ 27.2% src/move/
+EOF
+
+cat <<EOF >expect_diff_dirstat_M
+ 42.8% dst/copy/
+ 28.5% dst/move/
+ 71.4% dst/
+EOF
+
+cat <<EOF >expect_diff_dirstat_CC
+ 33.3% dst/copy/
+ 33.3% dst/move/
+ 66.6% dst/
+EOF
+
+test_expect_success '--dirstat=files,cumulative,16.7' '
+ git diff --dirstat=files,cumulative,16.7 HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat=files,cumulative,16.7 -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat=files,cumulative,16.7 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success 'diff.dirstat=16.7,cumulative,files' '
+ git -c diff.dirstat=16.7,cumulative,files diff --dirstat HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git -c diff.dirstat=16.7,cumulative,files diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git -c diff.dirstat=16.7,cumulative,files diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success 'diff.dirstat=16.70,cumulative,files' '
+ git -c diff.dirstat=16.70,cumulative,files diff --dirstat HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git -c diff.dirstat=16.70,cumulative,files diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git -c diff.dirstat=16.70,cumulative,files diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success '--dirstat=files,cumulative,27.2' '
+ git diff --dirstat=files,cumulative,27.2 HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat=files,cumulative,27.2 -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat=files,cumulative,27.2 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success '--dirstat=files,cumulative,27.09' '
+ git diff --dirstat=files,cumulative,27.09 HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat=files,cumulative,27.09 -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat=files,cumulative,27.09 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+cat <<EOF >expect_diff_dirstat
+ 10.6% dst/copy/changed/
+ 10.6% dst/copy/rearranged/
+ 10.6% dst/copy/unchanged/
+ 10.6% dst/move/changed/
+ 10.6% dst/move/rearranged/
+ 10.6% dst/move/unchanged/
+ 10.6% src/move/changed/
+ 10.6% src/move/rearranged/
+ 10.6% src/move/unchanged/
+EOF
+
+cat <<EOF >expect_diff_dirstat_M
+ 5.2% changed/
+ 26.3% dst/copy/changed/
+ 26.3% dst/copy/rearranged/
+ 26.3% dst/copy/unchanged/
+ 5.2% dst/move/changed/
+ 5.2% dst/move/rearranged/
+ 5.2% rearranged/
+EOF
+
+cat <<EOF >expect_diff_dirstat_CC
+ 16.6% changed/
+ 16.6% dst/copy/changed/
+ 16.6% dst/copy/rearranged/
+ 16.6% dst/move/changed/
+ 16.6% dst/move/rearranged/
+ 16.6% rearranged/
+EOF
+
+test_expect_success '--dirstat=lines' '
+ git diff --dirstat=lines HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat=lines -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat=lines -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success 'diff.dirstat=lines' '
+ git -c diff.dirstat=lines diff --dirstat HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git -c diff.dirstat=lines diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git -c diff.dirstat=lines diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+cat <<EOF >expect_diff_dirstat
+ 2.1% changed/
+ 10.6% dst/copy/changed/
+ 10.6% dst/copy/rearranged/
+ 10.6% dst/copy/unchanged/
+ 10.6% dst/move/changed/
+ 10.6% dst/move/rearranged/
+ 10.6% dst/move/unchanged/
+ 2.1% rearranged/
+ 10.6% src/move/changed/
+ 10.6% src/move/rearranged/
+ 10.6% src/move/unchanged/
+EOF
+
+cat <<EOF >expect_diff_dirstat_M
+ 5.2% changed/
+ 26.3% dst/copy/changed/
+ 26.3% dst/copy/rearranged/
+ 26.3% dst/copy/unchanged/
+ 5.2% dst/move/changed/
+ 5.2% dst/move/rearranged/
+ 5.2% rearranged/
+EOF
+
+cat <<EOF >expect_diff_dirstat_CC
+ 16.6% changed/
+ 16.6% dst/copy/changed/
+ 16.6% dst/copy/rearranged/
+ 16.6% dst/move/changed/
+ 16.6% dst/move/rearranged/
+ 16.6% rearranged/
+EOF
+
+test_expect_success '--dirstat=lines,0' '
+ git diff --dirstat=lines,0 HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git diff --dirstat=lines,0 -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git diff --dirstat=lines,0 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success 'diff.dirstat=0,lines' '
+ git -c diff.dirstat=0,lines diff --dirstat HEAD^..HEAD >actual_diff_dirstat &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ git -c diff.dirstat=0,lines diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ git -c diff.dirstat=0,lines diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
+'
+
+test_expect_success '--dirstat=future_param,lines,0 should fail loudly' '
+ test_must_fail git diff --dirstat=future_param,lines,0 HEAD^..HEAD >actual_diff_dirstat 2>actual_error &&
+ test_debug "cat actual_error" &&
+ test_cmp /dev/null actual_diff_dirstat &&
+ test_i18ngrep -q "future_param" actual_error &&
+ test_i18ngrep -q "\--dirstat" actual_error
+'
+
+test_expect_success '--dirstat=dummy1,cumulative,2dummy should report both unrecognized parameters' '
+ test_must_fail git diff --dirstat=dummy1,cumulative,2dummy HEAD^..HEAD >actual_diff_dirstat 2>actual_error &&
+ test_debug "cat actual_error" &&
+ test_cmp /dev/null actual_diff_dirstat &&
+ test_i18ngrep -q "dummy1" actual_error &&
+ test_i18ngrep -q "2dummy" actual_error &&
+ test_i18ngrep -q "\--dirstat" actual_error
+'
+
+test_expect_success 'diff.dirstat=future_param,0,lines should warn, but still work' '
+ git -c diff.dirstat=future_param,0,lines diff --dirstat HEAD^..HEAD >actual_diff_dirstat 2>actual_error &&
+ test_debug "cat actual_error" &&
+ test_cmp expect_diff_dirstat actual_diff_dirstat &&
+ test_i18ngrep -q "future_param" actual_error &&
+ test_i18ngrep -q "diff\\.dirstat" actual_error &&
+
+ git -c diff.dirstat=future_param,0,lines diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M 2>actual_error &&
+ test_debug "cat actual_error" &&
+ test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
+ test_i18ngrep -q "future_param" actual_error &&
+ test_i18ngrep -q "diff\\.dirstat" actual_error &&
+
+ git -c diff.dirstat=future_param,0,lines diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC 2>actual_error &&
+ test_debug "cat actual_error" &&
+ test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC &&
+ test_i18ngrep -q "future_param" actual_error &&
+ test_i18ngrep -q "diff\\.dirstat" actual_error
+'
+
+test_done
diff --git a/t/t4048-diff-combined-binary.sh b/t/t4048-diff-combined-binary.sh
new file mode 100755
index 0000000000..87a8949500
--- /dev/null
+++ b/t/t4048-diff-combined-binary.sh
@@ -0,0 +1,212 @@
+#!/bin/sh
+
+test_description='combined and merge diff handle binary files and textconv'
+. ./test-lib.sh
+
+test_expect_success 'setup binary merge conflict' '
+ echo oneQ1 | q_to_nul >binary &&
+ git add binary &&
+ git commit -m one &&
+ echo twoQ2 | q_to_nul >binary &&
+ git commit -a -m two &&
+ git checkout -b branch-binary HEAD^ &&
+ echo threeQ3 | q_to_nul >binary &&
+ git commit -a -m three &&
+ test_must_fail git merge master &&
+ echo resolvedQhooray | q_to_nul >binary &&
+ git commit -a -m resolved
+'
+
+cat >expect <<'EOF'
+resolved
+
+diff --git a/binary b/binary
+index 7ea6ded..9563691 100644
+Binary files a/binary and b/binary differ
+resolved
+
+diff --git a/binary b/binary
+index 6197570..9563691 100644
+Binary files a/binary and b/binary differ
+EOF
+test_expect_success 'diff -m indicates binary-ness' '
+ git show --format=%s -m >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+resolved
+
+diff --combined binary
+index 7ea6ded,6197570..9563691
+Binary files differ
+EOF
+test_expect_success 'diff -c indicates binary-ness' '
+ git show --format=%s -c >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+resolved
+
+diff --cc binary
+index 7ea6ded,6197570..9563691
+Binary files differ
+EOF
+test_expect_success 'diff --cc indicates binary-ness' '
+ git show --format=%s --cc >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'setup non-binary with binary attribute' '
+ git checkout master &&
+ test_commit one text &&
+ test_commit two text &&
+ git checkout -b branch-text HEAD^ &&
+ test_commit three text &&
+ test_must_fail git merge master &&
+ test_commit resolved text &&
+ echo text -diff >.gitattributes
+'
+
+cat >expect <<'EOF'
+resolved
+
+diff --git a/text b/text
+index 2bdf67a..2ab19ae 100644
+Binary files a/text and b/text differ
+resolved
+
+diff --git a/text b/text
+index f719efd..2ab19ae 100644
+Binary files a/text and b/text differ
+EOF
+test_expect_success 'diff -m respects binary attribute' '
+ git show --format=%s -m >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+resolved
+
+diff --combined text
+index 2bdf67a,f719efd..2ab19ae
+Binary files differ
+EOF
+test_expect_success 'diff -c respects binary attribute' '
+ git show --format=%s -c >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+resolved
+
+diff --cc text
+index 2bdf67a,f719efd..2ab19ae
+Binary files differ
+EOF
+test_expect_success 'diff --cc respects binary attribute' '
+ git show --format=%s --cc >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'setup textconv attribute' '
+ echo "text diff=upcase" >.gitattributes &&
+ git config diff.upcase.textconv "tr a-z A-Z <"
+'
+
+cat >expect <<'EOF'
+resolved
+
+diff --git a/text b/text
+index 2bdf67a..2ab19ae 100644
+--- a/text
++++ b/text
+@@ -1 +1 @@
+-THREE
++RESOLVED
+resolved
+
+diff --git a/text b/text
+index f719efd..2ab19ae 100644
+--- a/text
++++ b/text
+@@ -1 +1 @@
+-TWO
++RESOLVED
+EOF
+test_expect_success 'diff -m respects textconv attribute' '
+ git show --format=%s -m >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+resolved
+
+diff --combined text
+index 2bdf67a,f719efd..2ab19ae
+--- a/text
++++ b/text
+@@@ -1,1 -1,1 +1,1 @@@
+- THREE
+ -TWO
+++RESOLVED
+EOF
+test_expect_success 'diff -c respects textconv attribute' '
+ git show --format=%s -c >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+resolved
+
+diff --cc text
+index 2bdf67a,f719efd..2ab19ae
+--- a/text
++++ b/text
+@@@ -1,1 -1,1 +1,1 @@@
+- THREE
+ -TWO
+++RESOLVED
+EOF
+test_expect_success 'diff --cc respects textconv attribute' '
+ git show --format=%s --cc >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+diff --combined text
+index 2bdf67a,f719efd..2ab19ae
+--- a/text
++++ b/text
+@@@ -1,1 -1,1 +1,1 @@@
+- three
+ -two
+++resolved
+EOF
+test_expect_success 'diff-tree plumbing does not respect textconv' '
+ git diff-tree HEAD -c -p >full &&
+ tail -n +2 full >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+diff --cc text
+index 2bdf67a,f719efd..0000000
+--- a/text
++++ b/text
+@@@ -1,1 -1,1 +1,5 @@@
+++<<<<<<< HEAD
+ +THREE
+++=======
++ TWO
+++>>>>>>> MASTER
+EOF
+test_expect_success 'diff --cc respects textconv on worktree file' '
+ git reset --hard HEAD^ &&
+ test_must_fail git merge master &&
+ git diff >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t4049-diff-stat-count.sh b/t/t4049-diff-stat-count.sh
new file mode 100755
index 0000000000..641e70d14d
--- /dev/null
+++ b/t/t4049-diff-stat-count.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+# Copyright (c) 2011, Google Inc.
+
+test_description='diff --stat-count'
+. ./test-lib.sh
+
+test_expect_success setup '
+ >a &&
+ >b &&
+ >c &&
+ >d &&
+ git add a b c d &&
+ chmod +x c d &&
+ echo a >a &&
+ echo b >b &&
+ cat >expect <<-\EOF
+ a | 1 +
+ b | 1 +
+ 2 files changed, 2 insertions(+), 0 deletions(-)
+ EOF
+ git diff --stat --stat-count=2 >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t4050-diff-histogram.sh b/t/t4050-diff-histogram.sh
new file mode 100755
index 0000000000..fd3e86a74f
--- /dev/null
+++ b/t/t4050-diff-histogram.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+test_description='histogram diff algorithm'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-diff-alternative.sh
+
+test_diff_frobnitz "histogram"
+
+test_diff_unique "histogram"
+
+test_done
diff --git a/t/t4051-diff-function-context.sh b/t/t4051-diff-function-context.sh
new file mode 100755
index 0000000000..001d678e09
--- /dev/null
+++ b/t/t4051-diff-function-context.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+
+test_description='diff function context'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/diff-lib.sh
+
+
+cat <<\EOF >hello.c
+#include <stdio.h>
+
+static int a(void)
+{
+ /*
+ * Dummy.
+ */
+}
+
+static int hello_world(void)
+{
+ /* Classic. */
+ printf("Hello world.\n");
+
+ /* Success! */
+ return 0;
+}
+static int b(void)
+{
+ /*
+ * Dummy, too.
+ */
+}
+
+int main(int argc, char **argv)
+{
+ a();
+ b();
+ return hello_world();
+}
+EOF
+
+test_expect_success 'setup' '
+ git add hello.c &&
+ test_tick &&
+ git commit -m initial &&
+
+ grep -v Classic <hello.c >hello.c.new &&
+ mv hello.c.new hello.c
+'
+
+cat <<\EOF >expected
+diff --git a/hello.c b/hello.c
+--- a/hello.c
++++ b/hello.c
+@@ -10,8 +10,7 @@ static int a(void)
+ static int hello_world(void)
+ {
+- /* Classic. */
+ printf("Hello world.\n");
+
+ /* Success! */
+ return 0;
+ }
+EOF
+
+test_expect_success 'diff -U0 -W' '
+ git diff -U0 -W >actual &&
+ compare_diff_patch actual expected
+'
+
+cat <<\EOF >expected
+diff --git a/hello.c b/hello.c
+--- a/hello.c
++++ b/hello.c
+@@ -9,9 +9,8 @@ static int a(void)
+
+ static int hello_world(void)
+ {
+- /* Classic. */
+ printf("Hello world.\n");
+
+ /* Success! */
+ return 0;
+ }
+EOF
+
+test_expect_success 'diff -W' '
+ git diff -W >actual &&
+ compare_diff_patch actual expected
+'
+
+test_done
diff --git a/t/t4120-apply-popt.sh b/t/t4120-apply-popt.sh
index 579c9e6105..a33d510bf6 100755
--- a/t/t4120-apply-popt.sh
+++ b/t/t4120-apply-popt.sh
@@ -6,6 +6,7 @@
test_description='git apply -p handling.'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-prereq-FILEMODE.sh
test_expect_success setup '
mkdir sub &&
@@ -62,8 +63,12 @@ test_expect_success 'apply (-p2) diff, mode change only' '
old mode 100644
new mode 100755
EOF
- chmod 644 file1 &&
- git apply -p2 patch.chmod &&
+ test_chmod -x file1 &&
+ git apply --index -p2 patch.chmod &&
+ case $(git ls-files -s file1) in 100755*) : good;; *) false;; esac
+'
+
+test_expect_success FILEMODE 'file mode was changed' '
test -x file1
'
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 850fc96d1f..d7d9ccc1c8 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -96,6 +96,13 @@ test_expect_success setup '
echo "X-Fake-Field: Line Three" &&
git format-patch --stdout first | sed -e "1d"
} | append_cr >patch1-crlf.eml &&
+ {
+ printf "%255s\\n" ""
+ echo "X-Fake-Field: Line One" &&
+ echo "X-Fake-Field: Line Two" &&
+ echo "X-Fake-Field: Line Three" &&
+ git format-patch --stdout first | sed -e "1d"
+ } > patch1-ws.eml &&
sed -n -e "3,\$p" msg >file &&
git add file &&
@@ -167,6 +174,17 @@ test_expect_success 'am applies patch e-mail not in a mbox with CRLF' '
test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
'
+test_expect_success 'am applies patch e-mail with preceding whitespace' '
+ rm -fr .git/rebase-apply &&
+ git reset --hard &&
+ git checkout first &&
+ git am patch1-ws.eml &&
+ ! test -d .git/rebase-apply &&
+ git diff --exit-code second &&
+ test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
+ test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
+'
+
test_expect_success 'setup: new author and committer' '
GIT_AUTHOR_NAME="Another Thor" &&
GIT_AUTHOR_EMAIL="a.thor@example.com" &&
@@ -465,7 +483,7 @@ test_expect_success 'am newline in subject' '
test_tick &&
sed -e "s/second/second \\\n foo/" patch1 >patchnl &&
git am <patchnl >output.out 2>&1 &&
- grep "^Applying: second \\\n foo$" output.out
+ test_i18ngrep "^Applying: second \\\n foo$" output.out
'
test_expect_success 'am -q is quiet' '
diff --git a/t/t4151-am-abort.sh b/t/t4151-am-abort.sh
index c95c4ccc39..1176bcccf3 100755
--- a/t/t4151-am-abort.sh
+++ b/t/t4151-am-abort.sh
@@ -45,8 +45,9 @@ do
test_expect_success "am$with3 --skip continue after failed am$with3" '
test_must_fail git am$with3 --skip >output &&
- test "$(grep "^Applying" output)" = "Applying: 6" &&
- test_cmp file-2-expect file-2 &&
+ test_i18ngrep "^Applying" output >output.applying &&
+ test_i18ngrep "^Applying: 6$" output.applying &&
+ test_i18ncmp file-2-expect file-2 &&
test ! -f .git/MERGE_RR
'
diff --git a/t/t4152-am-subjects.sh b/t/t4152-am-subjects.sh
new file mode 100755
index 0000000000..4c68245aca
--- /dev/null
+++ b/t/t4152-am-subjects.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+test_description='test subject preservation with format-patch | am'
+. ./test-lib.sh
+
+make_patches() {
+ type=$1
+ subject=$2
+ test_expect_success "create patches with $type subject" '
+ git reset --hard baseline &&
+ echo $type >file &&
+ git commit -a -m "$subject" &&
+ git format-patch -1 --stdout >$type.patch &&
+ git format-patch -1 --stdout -k >$type-k.patch
+ '
+}
+
+check_subject() {
+ git reset --hard baseline &&
+ git am $2 $1.patch &&
+ git log -1 --pretty=format:%B >actual &&
+ test_cmp expect actual
+}
+
+test_expect_success 'setup baseline commit' '
+ test_commit baseline file
+'
+
+SHORT_SUBJECT='short subject'
+make_patches short "$SHORT_SUBJECT"
+
+LONG_SUBJECT1='this is a long subject that is virtually guaranteed'
+LONG_SUBJECT2='to require wrapping via format-patch if it is all'
+LONG_SUBJECT3='going to appear on a single line'
+LONG_SUBJECT="$LONG_SUBJECT1 $LONG_SUBJECT2 $LONG_SUBJECT3"
+make_patches long "$LONG_SUBJECT"
+
+MULTILINE_SUBJECT="$LONG_SUBJECT1
+$LONG_SUBJECT2
+$LONG_SUBJECT3"
+make_patches multiline "$MULTILINE_SUBJECT"
+
+echo "$SHORT_SUBJECT" >expect
+test_expect_success 'short subject preserved (format-patch | am)' '
+ check_subject short
+'
+test_expect_success 'short subject preserved (format-patch -k | am)' '
+ check_subject short-k
+'
+test_expect_success 'short subject preserved (format-patch -k | am -k)' '
+ check_subject short-k -k
+'
+
+echo "$LONG_SUBJECT" >expect
+test_expect_success 'long subject preserved (format-patch | am)' '
+ check_subject long
+'
+test_expect_success 'long subject preserved (format-patch -k | am)' '
+ check_subject long-k
+'
+test_expect_success 'long subject preserved (format-patch -k | am -k)' '
+ check_subject long-k -k
+'
+
+echo "$LONG_SUBJECT" >expect
+test_expect_success 'multiline subject unwrapped (format-patch | am)' '
+ check_subject multiline
+'
+test_expect_success 'multiline subject unwrapped (format-patch -k | am)' '
+ check_subject multiline-k
+'
+echo "$MULTILINE_SUBJECT" >expect
+test_expect_success 'multiline subject preserved (format-patch -k | am -k)' '
+ check_subject multiline-k -k
+'
+
+test_done
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index 2fcc31a6f3..983e34bec6 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -448,6 +448,59 @@ test_expect_success 'log.decorate configuration' '
git log --oneline --decorate >actual &&
test_cmp expect.short actual
+ git config --unset-all log.decorate &&
+ git log --pretty=raw >expect.raw &&
+ git config log.decorate full &&
+ git log --pretty=raw >actual &&
+ test_cmp expect.raw actual
+
+'
+
+test_expect_success 'reflog is expected format' '
+ test_might_fail git config --remove-section log &&
+ git log -g --abbrev-commit --pretty=oneline >expect &&
+ git reflog >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'whatchanged is expected format' '
+ git log --no-merges --raw >expect &&
+ git whatchanged >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log.abbrevCommit configuration' '
+ test_when_finished "git config --unset log.abbrevCommit" &&
+
+ test_might_fail git config --unset log.abbrevCommit &&
+
+ git log --abbrev-commit >expect.log.abbrev &&
+ git log --no-abbrev-commit >expect.log.full &&
+ git log --pretty=raw >expect.log.raw &&
+ git reflog --abbrev-commit >expect.reflog.abbrev &&
+ git reflog --no-abbrev-commit >expect.reflog.full &&
+ git whatchanged --abbrev-commit >expect.whatchanged.abbrev &&
+ git whatchanged --no-abbrev-commit >expect.whatchanged.full &&
+
+ git config log.abbrevCommit true &&
+
+ git log >actual &&
+ test_cmp expect.log.abbrev actual &&
+ git log --no-abbrev-commit >actual &&
+ test_cmp expect.log.full actual &&
+
+ git log --pretty=raw >actual &&
+ test_cmp expect.log.raw actual &&
+
+ git reflog >actual &&
+ test_cmp expect.reflog.abbrev actual &&
+ git reflog --no-abbrev-commit >actual &&
+ test_cmp expect.reflog.full actual &&
+
+ git whatchanged >actual &&
+ test_cmp expect.whatchanged.abbrev actual &&
+ git whatchanged --no-abbrev-commit >actual &&
+ test_cmp expect.whatchanged.full actual
'
test_expect_success 'show added path under "--follow -M"' '
diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh
index e818de6ddd..1f182f612c 100755
--- a/t/t4203-mailmap.sh
+++ b/t/t4203-mailmap.sh
@@ -94,7 +94,7 @@ nick1 (1):
EOF
-test_expect_success 'mailmap.file non-existant' '
+test_expect_success 'mailmap.file non-existent' '
rm internal_mailmap/.mailmap &&
rmdir internal_mailmap &&
git shortlog HEAD >actual &&
diff --git a/t/t4204-patch-id.sh b/t/t4204-patch-id.sh
index 68e2652814..d2c930de87 100755
--- a/t/t4204-patch-id.sh
+++ b/t/t4204-patch-id.sh
@@ -63,4 +63,40 @@ test_expect_success 'patch-id supports git-format-patch MIME output' '
test_cmp patch-id_master patch-id_same
'
+cat >nonl <<\EOF
+diff --git i/a w/a
+index e69de29..2e65efe 100644
+--- i/a
++++ w/a
+@@ -0,0 +1 @@
++a
+\ No newline at end of file
+diff --git i/b w/b
+index e69de29..6178079 100644
+--- i/b
++++ w/b
+@@ -0,0 +1 @@
++b
+EOF
+
+cat >withnl <<\EOF
+diff --git i/a w/a
+index e69de29..7898192 100644
+--- i/a
++++ w/a
+@@ -0,0 +1 @@
++a
+diff --git i/b w/b
+index e69de29..6178079 100644
+--- i/b
++++ w/b
+@@ -0,0 +1 @@
++b
+EOF
+
+test_expect_success 'patch-id handles no-nl-at-eof markers' '
+ cat nonl | calc_patch_id nonl &&
+ cat withnl | calc_patch_id withnl &&
+ test_cmp patch-id_nonl patch-id_withnl
+'
test_done
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index cb9f2bdd29..2ae9faa8b3 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -45,7 +45,7 @@ test_expect_success 'alias user-defined tformat' '
test_cmp expected actual
'
-test_expect_success 'alias non-existant format' '
+test_expect_success 'alias non-existent format' '
git config pretty.test-alias format-that-will-never-exist &&
test_must_fail git log --pretty=test-alias
'
diff --git a/t/t4208-log-magic-pathspec.sh b/t/t4208-log-magic-pathspec.sh
new file mode 100755
index 0000000000..2c482b622b
--- /dev/null
+++ b/t/t4208-log-magic-pathspec.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+test_description='magic pathspec tests using git-log'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ test_commit initial &&
+ test_tick &&
+ git commit --allow-empty -m empty &&
+ mkdir sub
+'
+
+test_expect_success '"git log :/" should be ambiguous' '
+ test_must_fail git log :/ 2>error &&
+ grep ambiguous error
+'
+
+test_expect_success '"git log :" should be ambiguous' '
+ test_must_fail git log : 2>error &&
+ grep ambiguous error
+'
+
+test_expect_success 'git log -- :' '
+ git log -- :
+'
+
+test_expect_success 'git log HEAD -- :/' '
+ cat >expected <<-EOF &&
+ 24b24cf initial
+ EOF
+ (cd sub && git log --oneline HEAD -- :/ >../actual) &&
+ test_cmp expected actual
+'
+
+test_done
diff --git a/t/t4254-am-corrupt.sh b/t/t4254-am-corrupt.sh
new file mode 100755
index 0000000000..b7da95fac5
--- /dev/null
+++ b/t/t4254-am-corrupt.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+test_description='git am with corrupt input'
+. ./test-lib.sh
+
+# Note the missing "+++" line:
+cat > bad-patch.diff <<'EOF'
+From: A U Thor <au.thor@example.com>
+diff --git a/f b/f
+index 7898192..6178079 100644
+--- a/f
+@@ -1 +1 @@
+-a
++b
+EOF
+
+test_expect_success setup '
+ test $? = 0 &&
+ echo a > f &&
+ git add f &&
+ test_tick &&
+ git commit -m initial
+'
+
+# This used to fail before, too, but with a different diagnostic.
+# fatal: unable to write file '(null)' mode 100644: Bad address
+# Also, it had the unwanted side-effect of deleting f.
+test_expect_success 'try to apply corrupted patch' '
+ git am bad-patch.diff 2> actual
+ test $? = 1
+'
+
+cat > expected <<EOF
+fatal: git diff header lacks filename information (line 4)
+EOF
+
+test_expect_success 'compare diagnostic; ensure file is still here' '
+ test $? = 0 &&
+ test -f f &&
+ test_cmp expected actual
+'
+
+test_done
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index cff1b3e050..d9068981f8 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -26,6 +26,8 @@ commit id embedding:
. ./test-lib.sh
UNZIP=${UNZIP:-unzip}
+GZIP=${GZIP:-gzip}
+GUNZIP=${GUNZIP:-gzip -d}
SUBSTFORMAT=%H%n
@@ -252,4 +254,102 @@ test_expect_success 'git-archive --prefix=olde-' '
test -f h/olde-a/bin/sh
'
+test_expect_success 'setup tar filters' '
+ git config tar.tar.foo.command "tr ab ba" &&
+ git config tar.bar.command "tr ab ba" &&
+ git config tar.bar.remote true
+'
+
+test_expect_success 'archive --list mentions user filter' '
+ git archive --list >output &&
+ grep "^tar\.foo\$" output &&
+ grep "^bar\$" output
+'
+
+test_expect_success NOT_MINGW 'archive --list shows only enabled remote filters' '
+ git archive --list --remote=. >output &&
+ ! grep "^tar\.foo\$" output &&
+ grep "^bar\$" output
+'
+
+test_expect_success 'invoke tar filter by format' '
+ git archive --format=tar.foo HEAD >config.tar.foo &&
+ tr ab ba <config.tar.foo >config.tar &&
+ test_cmp b.tar config.tar &&
+ git archive --format=bar HEAD >config.bar &&
+ tr ab ba <config.bar >config.tar &&
+ test_cmp b.tar config.tar
+'
+
+test_expect_success 'invoke tar filter by extension' '
+ git archive -o config-implicit.tar.foo HEAD &&
+ test_cmp config.tar.foo config-implicit.tar.foo &&
+ git archive -o config-implicit.bar HEAD &&
+ test_cmp config.tar.foo config-implicit.bar
+'
+
+test_expect_success 'default output format remains tar' '
+ git archive -o config-implicit.baz HEAD &&
+ test_cmp b.tar config-implicit.baz
+'
+
+test_expect_success 'extension matching requires dot' '
+ git archive -o config-implicittar.foo HEAD &&
+ test_cmp b.tar config-implicittar.foo
+'
+
+test_expect_success NOT_MINGW 'only enabled filters are available remotely' '
+ test_must_fail git archive --remote=. --format=tar.foo HEAD \
+ >remote.tar.foo &&
+ git archive --remote=. --format=bar >remote.bar HEAD &&
+ test_cmp remote.bar config.bar
+'
+
+if $GZIP --version >/dev/null 2>&1; then
+ test_set_prereq GZIP
+else
+ say "Skipping some tar.gz tests because gzip not found"
+fi
+
+test_expect_success GZIP 'git archive --format=tgz' '
+ git archive --format=tgz HEAD >j.tgz
+'
+
+test_expect_success GZIP 'git archive --format=tar.gz' '
+ git archive --format=tar.gz HEAD >j1.tar.gz &&
+ test_cmp j.tgz j1.tar.gz
+'
+
+test_expect_success GZIP 'infer tgz from .tgz filename' '
+ git archive --output=j2.tgz HEAD &&
+ test_cmp j.tgz j2.tgz
+'
+
+test_expect_success GZIP 'infer tgz from .tar.gz filename' '
+ git archive --output=j3.tar.gz HEAD &&
+ test_cmp j.tgz j3.tar.gz
+'
+
+if $GUNZIP --version >/dev/null 2>&1; then
+ test_set_prereq GUNZIP
+else
+ say "Skipping some tar.gz tests because gunzip was not found"
+fi
+
+test_expect_success GZIP,GUNZIP 'extract tgz file' '
+ $GUNZIP -c <j.tgz >j.tar &&
+ test_cmp b.tar j.tar
+'
+
+test_expect_success GZIP,NOT_MINGW 'remote tar.gz is allowed by default' '
+ git archive --remote=. --format=tar.gz HEAD >remote.tar.gz &&
+ test_cmp j.tgz remote.tar.gz
+'
+
+test_expect_success GZIP,NOT_MINGW 'remote tar.gz can be disabled' '
+ git config tar.tar.gz.remote false &&
+ test_must_fail git archive --remote=. --format=tar.gz HEAD \
+ >remote.tar.gz
+'
+
test_done
diff --git a/t/t5001-archive-attr.sh b/t/t5001-archive-attr.sh
index 02d4d2284d..f47d8717fd 100755
--- a/t/t5001-archive-attr.sh
+++ b/t/t5001-archive-attr.sh
@@ -57,6 +57,15 @@ test_expect_missing worktree/ignored
test_expect_exists worktree/ignored-by-tree
test_expect_missing worktree/ignored-by-worktree
+test_expect_success 'git archive --worktree-attributes option' '
+ git archive --worktree-attributes --worktree-attributes HEAD >worktree.tar &&
+ (mkdir worktree2 && cd worktree2 && "$TAR" xf -) <worktree.tar
+'
+
+test_expect_missing worktree2/ignored
+test_expect_exists worktree2/ignored-by-tree
+test_expect_missing worktree2/ignored-by-worktree
+
test_expect_success 'git archive vs. bare' '
(cd bare && git archive HEAD) >bare-archive.tar &&
test_cmp archive.tar bare-archive.tar
diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh
index b34ea93a80..f8fa92446c 100755
--- a/t/t5302-pack-index.sh
+++ b/t/t5302-pack-index.sh
@@ -65,6 +65,14 @@ test_expect_success \
'cmp "test-1-${pack1}.idx" "1.idx" &&
cmp "test-2-${pack2}.idx" "2.idx"'
+test_expect_success 'index-pack --verify on index version 1' '
+ git index-pack --verify "test-1-${pack1}.pack"
+'
+
+test_expect_success 'index-pack --verify on index version 2' '
+ git index-pack --verify "test-2-${pack2}.pack"
+'
+
test_expect_success \
'index v2: force some 64-bit offsets with pack-objects' \
'pack3=$(git pack-objects --index-version=2,0x40000 test-3 <obj-list)'
@@ -93,6 +101,16 @@ test_expect_success OFF64_T \
'64-bit offsets: index-pack result should match pack-objects one' \
'cmp "test-3-${pack3}.idx" "3.idx"'
+test_expect_success OFF64_T 'index-pack --verify on 64-bit offset v2 (cheat)' '
+ # This cheats by knowing which lower offset should still be encoded
+ # in 64-bit representation.
+ git index-pack --verify --index-version=2,0x40000 "test-3-${pack3}.pack"
+'
+
+test_expect_success OFF64_T 'index-pack --verify on 64-bit offset v2' '
+ git index-pack --verify "test-3-${pack3}.pack"
+'
+
# returns the object number for given object in given pack index
index_obj_nr()
{
@@ -208,9 +226,8 @@ test_expect_success \
( while read obj
do git cat-file -p $obj >/dev/null || exit 1
done <obj-list ) &&
- err=$(test_must_fail git verify-pack \
- ".git/objects/pack/pack-${pack1}.pack" 2>&1) &&
- echo "$err" | grep "CRC mismatch"'
+ test_must_fail git verify-pack ".git/objects/pack/pack-${pack1}.pack"
+'
test_expect_success 'running index-pack in the object store' '
rm -f .git/objects/pack/* &&
diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh
index e2ed13dba2..d645328609 100755
--- a/t/t5304-prune.sh
+++ b/t/t5304-prune.sh
@@ -14,7 +14,8 @@ add_blob() {
BLOB=$(echo aleph_0 | git hash-object -w --stdin) &&
BLOB_FILE=.git/objects/$(echo $BLOB | sed "s/^../&\//") &&
test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
- test -f $BLOB_FILE
+ test -f $BLOB_FILE &&
+ test-chmtime =+0 $BLOB_FILE
}
test_expect_success setup '
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index b0b2684a1f..0eace37a03 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -190,7 +190,7 @@ test_expect_success 'pushing explicit refspecs respects forcing' '
+refs/heads/master:refs/heads/master
) &&
parent_head=$(cd parent && git rev-parse --verify master) &&
- child_head=$(cd parent && git rev-parse --verify master) &&
+ child_head=$(cd child && git rev-parse --verify master) &&
test "$parent_head" = "$child_head"
'
@@ -210,7 +210,7 @@ test_expect_success 'pushing wildcard refspecs respects forcing' '
"+refs/heads/*:refs/heads/*"
) &&
parent_head=$(cd parent && git rev-parse --verify master) &&
- child_head=$(cd parent && git rev-parse --verify master) &&
+ child_head=$(cd child && git rev-parse --verify master) &&
test "$parent_head" = "$child_head"
'
diff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh
index d05a9138b4..1753ef2b91 100755
--- a/t/t5403-post-checkout-hook.sh
+++ b/t/t5403-post-checkout-hook.sh
@@ -31,44 +31,44 @@ EOF
done
test_expect_success 'post-checkout runs as expected ' '
- GIT_DIR=clone1/.git git checkout master &&
- test -e clone1/.git/post-checkout.args
+ GIT_DIR=clone1/.git git checkout master &&
+ test -e clone1/.git/post-checkout.args
'
test_expect_success 'post-checkout receives the right arguments with HEAD unchanged ' '
- old=$(awk "{print \$1}" clone1/.git/post-checkout.args) &&
- new=$(awk "{print \$2}" clone1/.git/post-checkout.args) &&
- flag=$(awk "{print \$3}" clone1/.git/post-checkout.args) &&
- test $old = $new -a $flag = 1
+ old=$(awk "{print \$1}" clone1/.git/post-checkout.args) &&
+ new=$(awk "{print \$2}" clone1/.git/post-checkout.args) &&
+ flag=$(awk "{print \$3}" clone1/.git/post-checkout.args) &&
+ test $old = $new -a $flag = 1
'
test_expect_success 'post-checkout runs as expected ' '
- GIT_DIR=clone1/.git git checkout master &&
- test -e clone1/.git/post-checkout.args
+ GIT_DIR=clone1/.git git checkout master &&
+ test -e clone1/.git/post-checkout.args
'
test_expect_success 'post-checkout args are correct with git checkout -b ' '
- GIT_DIR=clone1/.git git checkout -b new1 &&
- old=$(awk "{print \$1}" clone1/.git/post-checkout.args) &&
- new=$(awk "{print \$2}" clone1/.git/post-checkout.args) &&
- flag=$(awk "{print \$3}" clone1/.git/post-checkout.args) &&
- test $old = $new -a $flag = 1
+ GIT_DIR=clone1/.git git checkout -b new1 &&
+ old=$(awk "{print \$1}" clone1/.git/post-checkout.args) &&
+ new=$(awk "{print \$2}" clone1/.git/post-checkout.args) &&
+ flag=$(awk "{print \$3}" clone1/.git/post-checkout.args) &&
+ test $old = $new -a $flag = 1
'
test_expect_success 'post-checkout receives the right args with HEAD changed ' '
- GIT_DIR=clone2/.git git checkout new2 &&
- old=$(awk "{print \$1}" clone2/.git/post-checkout.args) &&
- new=$(awk "{print \$2}" clone2/.git/post-checkout.args) &&
- flag=$(awk "{print \$3}" clone2/.git/post-checkout.args) &&
- test $old != $new -a $flag = 1
+ GIT_DIR=clone2/.git git checkout new2 &&
+ old=$(awk "{print \$1}" clone2/.git/post-checkout.args) &&
+ new=$(awk "{print \$2}" clone2/.git/post-checkout.args) &&
+ flag=$(awk "{print \$3}" clone2/.git/post-checkout.args) &&
+ test $old != $new -a $flag = 1
'
test_expect_success 'post-checkout receives the right args when not switching branches ' '
- GIT_DIR=clone2/.git git checkout master b &&
- old=$(awk "{print \$1}" clone2/.git/post-checkout.args) &&
- new=$(awk "{print \$2}" clone2/.git/post-checkout.args) &&
- flag=$(awk "{print \$3}" clone2/.git/post-checkout.args) &&
- test $old = $new -a $flag = 0
+ GIT_DIR=clone2/.git git checkout master b &&
+ old=$(awk "{print \$1}" clone2/.git/post-checkout.args) &&
+ new=$(awk "{print \$2}" clone2/.git/post-checkout.args) &&
+ flag=$(awk "{print \$3}" clone2/.git/post-checkout.args) &&
+ test $old = $new -a $flag = 0
'
if test "$(git config --bool core.filemode)" = true; then
diff --git a/t/t5501-fetch-push-alternates.sh b/t/t5501-fetch-push-alternates.sh
new file mode 100755
index 0000000000..b5ced8483a
--- /dev/null
+++ b/t/t5501-fetch-push-alternates.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+test_description='fetch/push involving alternates'
+. ./test-lib.sh
+
+count_objects () {
+ loose=0 inpack=0
+ eval "$(
+ git count-objects -v |
+ sed -n -e 's/^count: \(.*\)/loose=\1/p' \
+ -e 's/^in-pack: \(.*\)/inpack=\1/p'
+ )" &&
+ echo $(( $loose + $inpack ))
+}
+
+
+test_expect_success setup '
+ (
+ git init original &&
+ cd original &&
+ i=0 &&
+ while test $i -le 100
+ do
+ echo "$i" >count &&
+ git add count &&
+ git commit -m "$i" || exit
+ i=$(($i + 1))
+ done
+ ) &&
+ (
+ git clone --reference=original "file:///$(pwd)/original" one &&
+ cd one &&
+ echo Z >count &&
+ git add count &&
+ git commit -m Z &&
+ count_objects >../one.count
+ ) &&
+ A=$(pwd)/original/.git/objects &&
+ git init receiver &&
+ echo "$A" >receiver/.git/objects/info/alternates &&
+ git init fetcher &&
+ echo "$A" >fetcher/.git/objects/info/alternates
+'
+
+test_expect_success 'pushing into a repository with the same alternate' '
+ (
+ cd one &&
+ git push ../receiver master:refs/heads/it
+ ) &&
+ (
+ cd receiver &&
+ count_objects >../receiver.count
+ ) &&
+ test_cmp one.count receiver.count
+'
+
+test_expect_success 'fetching from a repository with the same alternate' '
+ (
+ cd fetcher &&
+ git fetch ../one master:refs/heads/it &&
+ count_objects >../fetcher.count
+ ) &&
+ test_cmp one.count fetcher.count
+'
+
+test_done
diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh
new file mode 100755
index 0000000000..8341fc4d15
--- /dev/null
+++ b/t/t5504-fetch-receive-strict.sh
@@ -0,0 +1,104 @@
+#!/bin/sh
+
+test_description='fetch/receive strict mode'
+. ./test-lib.sh
+
+test_expect_success setup '
+ echo hello >greetings &&
+ git add greetings &&
+ git commit -m greetings &&
+
+ S=$(git rev-parse :greetings | sed -e "s|^..|&/|") &&
+ X=$(echo bye | git hash-object -w --stdin | sed -e "s|^..|&/|") &&
+ mv -f .git/objects/$X .git/objects/$S &&
+
+ test_must_fail git fsck
+'
+
+test_expect_success 'fetch without strict' '
+ rm -rf dst &&
+ git init dst &&
+ (
+ cd dst &&
+ git config fetch.fsckobjects false &&
+ git config transfer.fsckobjects false &&
+ test_must_fail git fetch ../.git master
+ )
+'
+
+test_expect_success 'fetch with !fetch.fsckobjects' '
+ rm -rf dst &&
+ git init dst &&
+ (
+ cd dst &&
+ git config fetch.fsckobjects false &&
+ git config transfer.fsckobjects true &&
+ test_must_fail git fetch ../.git master
+ )
+'
+
+test_expect_success 'fetch with fetch.fsckobjects' '
+ rm -rf dst &&
+ git init dst &&
+ (
+ cd dst &&
+ git config fetch.fsckobjects true &&
+ git config transfer.fsckobjects false &&
+ test_must_fail git fetch ../.git master
+ )
+'
+
+test_expect_success 'fetch with transfer.fsckobjects' '
+ rm -rf dst &&
+ git init dst &&
+ (
+ cd dst &&
+ git config transfer.fsckobjects true &&
+ test_must_fail git fetch ../.git master
+ )
+'
+
+test_expect_success 'push without strict' '
+ rm -rf dst &&
+ git init dst &&
+ (
+ cd dst &&
+ git config fetch.fsckobjects false &&
+ git config transfer.fsckobjects false
+ ) &&
+ git push dst master:refs/heads/test
+'
+
+test_expect_success 'push with !receive.fsckobjects' '
+ rm -rf dst &&
+ git init dst &&
+ (
+ cd dst &&
+ git config receive.fsckobjects false &&
+ git config transfer.fsckobjects true
+ ) &&
+ git push dst master:refs/heads/test
+'
+
+test_expect_success 'push with receive.fsckobjects' '
+ rm -rf dst &&
+ git init dst &&
+ (
+ cd dst &&
+ git config receive.fsckobjects true &&
+ git config transfer.fsckobjects false
+ ) &&
+ test_must_fail git push dst master:refs/heads/test
+'
+
+test_expect_success 'push with transfer.fsckobjects' '
+ rm -rf dst &&
+ git init dst &&
+ (
+ cd dst &&
+ git config transfer.fsckobjects true
+ ) &&
+ test_must_fail git push dst master:refs/heads/test
+'
+
+test_done
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index d189add2d0..e8af615e6d 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -304,6 +304,106 @@ test_expect_success 'add --mirror && prune' '
git rev-parse --verify refs/heads/side)
'
+test_expect_success 'add --mirror=fetch' '
+ mkdir mirror-fetch &&
+ git init mirror-fetch/parent &&
+ (cd mirror-fetch/parent &&
+ test_commit one) &&
+ git init --bare mirror-fetch/child &&
+ (cd mirror-fetch/child &&
+ git remote add --mirror=fetch -f parent ../parent)
+'
+
+test_expect_success 'fetch mirrors act as mirrors during fetch' '
+ (cd mirror-fetch/parent &&
+ git branch new &&
+ git branch -m master renamed
+ ) &&
+ (cd mirror-fetch/child &&
+ git fetch parent &&
+ git rev-parse --verify refs/heads/new &&
+ git rev-parse --verify refs/heads/renamed
+ )
+'
+
+test_expect_success 'fetch mirrors can prune' '
+ (cd mirror-fetch/child &&
+ git remote prune parent &&
+ test_must_fail git rev-parse --verify refs/heads/master
+ )
+'
+
+test_expect_success 'fetch mirrors do not act as mirrors during push' '
+ (cd mirror-fetch/parent &&
+ git checkout HEAD^0
+ ) &&
+ (cd mirror-fetch/child &&
+ git branch -m renamed renamed2 &&
+ git push parent
+ ) &&
+ (cd mirror-fetch/parent &&
+ git rev-parse --verify renamed &&
+ test_must_fail git rev-parse --verify refs/heads/renamed2
+ )
+'
+
+test_expect_success 'add fetch mirror with specific branches' '
+ git init --bare mirror-fetch/track &&
+ (cd mirror-fetch/track &&
+ git remote add --mirror=fetch -t heads/new parent ../parent
+ )
+'
+
+test_expect_success 'fetch mirror respects specific branches' '
+ (cd mirror-fetch/track &&
+ git fetch parent &&
+ git rev-parse --verify refs/heads/new &&
+ test_must_fail git rev-parse --verify refs/heads/renamed
+ )
+'
+
+test_expect_success 'add --mirror=push' '
+ mkdir mirror-push &&
+ git init --bare mirror-push/public &&
+ git init mirror-push/private &&
+ (cd mirror-push/private &&
+ test_commit one &&
+ git remote add --mirror=push public ../public
+ )
+'
+
+test_expect_success 'push mirrors act as mirrors during push' '
+ (cd mirror-push/private &&
+ git branch new &&
+ git branch -m master renamed &&
+ git push public
+ ) &&
+ (cd mirror-push/private &&
+ git rev-parse --verify refs/heads/new &&
+ git rev-parse --verify refs/heads/renamed &&
+ test_must_fail git rev-parse --verify refs/heads/master
+ )
+'
+
+test_expect_success 'push mirrors do not act as mirrors during fetch' '
+ (cd mirror-push/public &&
+ git branch -m renamed renamed2 &&
+ git symbolic-ref HEAD refs/heads/renamed2
+ ) &&
+ (cd mirror-push/private &&
+ git fetch public &&
+ git rev-parse --verify refs/heads/renamed &&
+ test_must_fail git rev-parse --verify refs/heads/renamed2
+ )
+'
+
+test_expect_success 'push mirrors do not allow you to specify refs' '
+ git init mirror-push/track &&
+ (cd mirror-push/track &&
+ test_must_fail git remote add --mirror=push -t new public ../public
+ )
+'
+
test_expect_success 'add alt && prune' '
(mkdir alttst &&
cd alttst &&
@@ -531,6 +631,37 @@ test_expect_success 'rename a remote' '
'
+test_expect_success 'rename does not update a non-default fetch refspec' '
+
+ git clone one four.one &&
+ (cd four.one &&
+ git config remote.origin.fetch +refs/heads/*:refs/heads/origin/* &&
+ git remote rename origin upstream &&
+ test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/heads/origin/*" &&
+ git rev-parse -q origin/master)
+
+'
+
+test_expect_success 'rename a remote with name part of fetch spec' '
+
+ git clone one four.two &&
+ (cd four.two &&
+ git remote rename origin remote &&
+ git remote rename remote upstream &&
+ test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/remotes/upstream/*")
+
+'
+
+test_expect_success 'rename a remote with name prefix of other remote' '
+
+ git clone one four.three &&
+ (cd four.three &&
+ git remote add o git://example.com/repo.git &&
+ git remote rename o upstream &&
+ test "$(git rev-parse origin/master)" = "$(git rev-parse master)")
+
+'
+
cat > remotes_origin << EOF
URL: $(pwd)/one
Push: refs/heads/master:refs/heads/upstream
diff --git a/t/t5506-remote-groups.sh b/t/t5506-remote-groups.sh
index b7b7ddaa40..530b01678e 100755
--- a/t/t5506-remote-groups.sh
+++ b/t/t5506-remote-groups.sh
@@ -43,10 +43,10 @@ test_expect_success 'no group updates all' '
repo_fetched two
'
-test_expect_success 'nonexistant group produces error' '
- mark nonexistant &&
+test_expect_success 'nonexistent group produces error' '
+ mark nonexistent &&
update_repos &&
- test_must_fail git remote update nonexistant &&
+ test_must_fail git remote update nonexistent &&
! repo_fetched one &&
! repo_fetched two
'
diff --git a/t/t5509-fetch-push-namespaces.sh b/t/t5509-fetch-push-namespaces.sh
new file mode 100755
index 0000000000..cc0b31f6b0
--- /dev/null
+++ b/t/t5509-fetch-push-namespaces.sh
@@ -0,0 +1,85 @@
+#!/bin/sh
+
+test_description='fetch/push involving ref namespaces'
+. ./test-lib.sh
+
+test_expect_success setup '
+ test_tick &&
+ git init original &&
+ (
+ cd original &&
+ echo 0 >count &&
+ git add count &&
+ test_commit 0 &&
+ echo 1 >count &&
+ git add count &&
+ test_commit 1 &&
+ git remote add pushee-namespaced "ext::git --namespace=namespace %s ../pushee" &&
+ git remote add pushee-unnamespaced ../pushee
+ ) &&
+ commit0=$(cd original && git rev-parse HEAD^) &&
+ commit1=$(cd original && git rev-parse HEAD) &&
+ git init pushee &&
+ git init puller
+'
+
+test_expect_success 'pushing into a repository using a ref namespace' '
+ (
+ cd original &&
+ git push pushee-namespaced master &&
+ git ls-remote pushee-namespaced >actual &&
+ printf "$commit1\trefs/heads/master\n" >expected &&
+ test_cmp expected actual &&
+ git push pushee-namespaced --tags &&
+ git ls-remote pushee-namespaced >actual &&
+ printf "$commit0\trefs/tags/0\n" >>expected &&
+ printf "$commit1\trefs/tags/1\n" >>expected &&
+ test_cmp expected actual &&
+ # Verify that the GIT_NAMESPACE environment variable works as well
+ GIT_NAMESPACE=namespace git ls-remote "ext::git %s ../pushee" >actual &&
+ test_cmp expected actual &&
+ # Verify that --namespace overrides GIT_NAMESPACE
+ GIT_NAMESPACE=garbage git ls-remote pushee-namespaced >actual &&
+ test_cmp expected actual &&
+ # Try a namespace with no content
+ git ls-remote "ext::git --namespace=garbage %s ../pushee" >actual &&
+ test_cmp /dev/null actual &&
+ git ls-remote pushee-unnamespaced >actual &&
+ sed -e "s|refs/|refs/namespaces/namespace/refs/|" expected >expected.unnamespaced &&
+ test_cmp expected.unnamespaced actual
+ )
+'
+
+test_expect_success 'pulling from a repository using a ref namespace' '
+ (
+ cd puller &&
+ git remote add -f pushee-namespaced "ext::git --namespace=namespace %s ../pushee" &&
+ git for-each-ref refs/ >actual &&
+ printf "$commit1 commit\trefs/remotes/pushee-namespaced/master\n" >expected &&
+ printf "$commit0 commit\trefs/tags/0\n" >>expected &&
+ printf "$commit1 commit\trefs/tags/1\n" >>expected &&
+ test_cmp expected actual
+ )
+'
+
+# This test with clone --mirror checks for possible regressions in clone
+# or the machinery underneath it. It ensures that no future change
+# causes clone to ignore refs in refs/namespaces/*. In particular, it
+# protects against a regression caused by any future change to the refs
+# machinery that might cause it to ignore refs outside of refs/heads/*
+# or refs/tags/*. More generally, this test also checks the high-level
+# functionality of using clone --mirror to back up a set of repos hosted
+# in the namespaces of a single repo.
+test_expect_success 'mirroring a repository using a ref namespace' '
+ git clone --mirror pushee mirror &&
+ (
+ cd mirror &&
+ git for-each-ref refs/ >actual &&
+ printf "$commit1 commit\trefs/namespaces/namespace/refs/heads/master\n" >expected &&
+ printf "$commit0 commit\trefs/namespaces/namespace/refs/tags/0\n" >>expected &&
+ printf "$commit1 commit\trefs/namespaces/namespace/refs/tags/1\n" >>expected &&
+ test_cmp expected actual
+ )
+'
+
+test_done
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 7e433b179f..e0af4c4e62 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -76,6 +76,56 @@ test_expect_success "fetch test for-merge" '
cut -f -2 .git/FETCH_HEAD >actual &&
test_cmp expected actual'
+test_expect_success 'fetch --prune on its own works as expected' '
+ cd "$D" &&
+ git clone . prune &&
+ cd prune &&
+ git fetch origin refs/heads/master:refs/remotes/origin/extrabranch &&
+
+ git fetch --prune origin &&
+ test_must_fail git rev-parse origin/extrabranch
+'
+
+test_expect_success 'fetch --prune with a branch name keeps branches' '
+ cd "$D" &&
+ git clone . prune-branch &&
+ cd prune-branch &&
+ git fetch origin refs/heads/master:refs/remotes/origin/extrabranch &&
+
+ git fetch --prune origin master &&
+ git rev-parse origin/extrabranch
+'
+
+test_expect_success 'fetch --prune with a namespace keeps other namespaces' '
+ cd "$D" &&
+ git clone . prune-namespace &&
+ cd prune-namespace &&
+
+ git fetch --prune origin refs/heads/a/*:refs/remotes/origin/a/* &&
+ git rev-parse origin/master
+'
+
+test_expect_success 'fetch --prune --tags does not delete the remote-tracking branches' '
+ cd "$D" &&
+ git clone . prune-tags &&
+ cd prune-tags &&
+ git fetch origin refs/heads/master:refs/tags/sometag &&
+
+ git fetch --prune --tags origin &&
+ git rev-parse origin/master &&
+ test_must_fail git rev-parse somebranch
+'
+
+test_expect_success 'fetch --prune --tags with branch does not delete other remote-tracking branches' '
+ cd "$D" &&
+ git clone . prune-tags-branch &&
+ cd prune-tags-branch &&
+ git fetch origin refs/heads/master:refs/remotes/origin/extrabranch &&
+
+ git fetch --prune --tags origin master &&
+ git rev-parse origin/extrabranch
+'
+
test_expect_success 'fetch tags when there is no tags' '
cd "$D" &&
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index d1912351db..5c546c99a5 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -123,4 +123,28 @@ test_expect_success 'confuses pattern as remote when no remote specified' '
'
+test_expect_success 'die with non-2 for wrong repository even with --exit-code' '
+ git ls-remote --exit-code ./no-such-repository ;# not &&
+ status=$? &&
+ test $status != 2 && test $status != 0
+'
+
+test_expect_success 'Report success even when nothing matches' '
+ git ls-remote other.git "refs/nsn/*" >actual &&
+ >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'Report no-match with --exit-code' '
+ test_expect_code 2 git ls-remote --exit-code other.git "refs/nsn/*" >actual &&
+ >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'Report match with --exit-code' '
+ git ls-remote --exit-code other.git "refs/tags/*" >actual &&
+ git ls-remote . tags/mark >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index d73731e644..b69cf574d7 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -40,6 +40,40 @@ mk_test () {
)
}
+mk_test_with_hooks() {
+ mk_test "$@" &&
+ (
+ cd testrepo &&
+ mkdir .git/hooks &&
+ cd .git/hooks &&
+
+ cat >pre-receive <<-'EOF' &&
+ #!/bin/sh
+ cat - >>pre-receive.actual
+ EOF
+
+ cat >update <<-'EOF' &&
+ #!/bin/sh
+ printf "%s %s %s\n" "$@" >>update.actual
+ EOF
+
+ cat >post-receive <<-'EOF' &&
+ #!/bin/sh
+ cat - >>post-receive.actual
+ EOF
+
+ cat >post-update <<-'EOF' &&
+ #!/bin/sh
+ for ref in "$@"
+ do
+ printf "%s\n" "$ref" >>post-update.actual
+ done
+ EOF
+
+ chmod +x pre-receive update post-receive post-update
+ )
+}
+
mk_child() {
rm -rf "$1" &&
git clone testrepo "$1"
@@ -367,7 +401,7 @@ test_expect_success 'push with colon-less refspec (4)' '
'
-test_expect_success 'push head with non-existant, incomplete dest' '
+test_expect_success 'push head with non-existent, incomplete dest' '
mk_test &&
git push testrepo master:branch &&
@@ -375,7 +409,7 @@ test_expect_success 'push head with non-existant, incomplete dest' '
'
-test_expect_success 'push tag with non-existant, incomplete dest' '
+test_expect_success 'push tag with non-existent, incomplete dest' '
mk_test &&
git tag -f v1.0 &&
@@ -384,14 +418,14 @@ test_expect_success 'push tag with non-existant, incomplete dest' '
'
-test_expect_success 'push sha1 with non-existant, incomplete dest' '
+test_expect_success 'push sha1 with non-existent, incomplete dest' '
mk_test &&
test_must_fail git push testrepo `git rev-parse master`:foo
'
-test_expect_success 'push ref expression with non-existant, incomplete dest' '
+test_expect_success 'push ref expression with non-existent, incomplete dest' '
mk_test &&
test_must_fail git push testrepo master^:branch
@@ -436,7 +470,7 @@ test_expect_success 'push with +HEAD' '
'
-test_expect_success 'push HEAD with non-existant, incomplete dest' '
+test_expect_success 'push HEAD with non-existent, incomplete dest' '
mk_test &&
git checkout master &&
@@ -559,6 +593,169 @@ test_expect_success 'allow deleting an invalid remote ref' '
'
+test_expect_success 'pushing valid refs triggers post-receive and post-update hooks' '
+ mk_test_with_hooks heads/master heads/next &&
+ orgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) &&
+ newmaster=$(git show-ref -s --verify refs/heads/master) &&
+ orgnext=$(cd testrepo && git show-ref -s --verify refs/heads/next) &&
+ newnext=$_z40 &&
+ git push testrepo refs/heads/master:refs/heads/master :refs/heads/next &&
+ (
+ cd testrepo/.git &&
+ cat >pre-receive.expect <<-EOF &&
+ $orgmaster $newmaster refs/heads/master
+ $orgnext $newnext refs/heads/next
+ EOF
+
+ cat >update.expect <<-EOF &&
+ refs/heads/master $orgmaster $newmaster
+ refs/heads/next $orgnext $newnext
+ EOF
+
+ cat >post-receive.expect <<-EOF &&
+ $orgmaster $newmaster refs/heads/master
+ $orgnext $newnext refs/heads/next
+ EOF
+
+ cat >post-update.expect <<-EOF &&
+ refs/heads/master
+ refs/heads/next
+ EOF
+
+ test_cmp pre-receive.expect pre-receive.actual &&
+ test_cmp update.expect update.actual &&
+ test_cmp post-receive.expect post-receive.actual &&
+ test_cmp post-update.expect post-update.actual
+ )
+'
+
+test_expect_success 'deleting dangling ref triggers hooks with correct args' '
+ mk_test_with_hooks heads/master &&
+ rm -f testrepo/.git/objects/??/* &&
+ git push testrepo :refs/heads/master &&
+ (
+ cd testrepo/.git &&
+ cat >pre-receive.expect <<-EOF &&
+ $_z40 $_z40 refs/heads/master
+ EOF
+
+ cat >update.expect <<-EOF &&
+ refs/heads/master $_z40 $_z40
+ EOF
+
+ cat >post-receive.expect <<-EOF &&
+ $_z40 $_z40 refs/heads/master
+ EOF
+
+ cat >post-update.expect <<-EOF &&
+ refs/heads/master
+ EOF
+
+ test_cmp pre-receive.expect pre-receive.actual &&
+ test_cmp update.expect update.actual &&
+ test_cmp post-receive.expect post-receive.actual &&
+ test_cmp post-update.expect post-update.actual
+ )
+'
+
+test_expect_success 'deletion of a non-existent ref is not fed to post-receive and post-update hooks' '
+ mk_test_with_hooks heads/master &&
+ orgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) &&
+ newmaster=$(git show-ref -s --verify refs/heads/master) &&
+ git push testrepo master :refs/heads/nonexistent &&
+ (
+ cd testrepo/.git &&
+ cat >pre-receive.expect <<-EOF &&
+ $orgmaster $newmaster refs/heads/master
+ $_z40 $_z40 refs/heads/nonexistent
+ EOF
+
+ cat >update.expect <<-EOF &&
+ refs/heads/master $orgmaster $newmaster
+ refs/heads/nonexistent $_z40 $_z40
+ EOF
+
+ cat >post-receive.expect <<-EOF &&
+ $orgmaster $newmaster refs/heads/master
+ EOF
+
+ cat >post-update.expect <<-EOF &&
+ refs/heads/master
+ EOF
+
+ test_cmp pre-receive.expect pre-receive.actual &&
+ test_cmp update.expect update.actual &&
+ test_cmp post-receive.expect post-receive.actual &&
+ test_cmp post-update.expect post-update.actual
+ )
+'
+
+test_expect_success 'deletion of a non-existent ref alone does trigger post-receive and post-update hooks' '
+ mk_test_with_hooks heads/master &&
+ git push testrepo :refs/heads/nonexistent &&
+ (
+ cd testrepo/.git &&
+ cat >pre-receive.expect <<-EOF &&
+ $_z40 $_z40 refs/heads/nonexistent
+ EOF
+
+ cat >update.expect <<-EOF &&
+ refs/heads/nonexistent $_z40 $_z40
+ EOF
+
+ test_cmp pre-receive.expect pre-receive.actual &&
+ test_cmp update.expect update.actual &&
+ test_path_is_missing post-receive.actual &&
+ test_path_is_missing post-update.actual
+ )
+'
+
+test_expect_success 'mixed ref updates, deletes, invalid deletes trigger hooks with correct input' '
+ mk_test_with_hooks heads/master heads/next heads/pu &&
+ orgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) &&
+ newmaster=$(git show-ref -s --verify refs/heads/master) &&
+ orgnext=$(cd testrepo && git show-ref -s --verify refs/heads/next) &&
+ newnext=$_z40 &&
+ orgpu=$(cd testrepo && git show-ref -s --verify refs/heads/pu) &&
+ newpu=$(git show-ref -s --verify refs/heads/master) &&
+ git push testrepo refs/heads/master:refs/heads/master \
+ refs/heads/master:refs/heads/pu :refs/heads/next \
+ :refs/heads/nonexistent &&
+ (
+ cd testrepo/.git &&
+ cat >pre-receive.expect <<-EOF &&
+ $orgmaster $newmaster refs/heads/master
+ $orgnext $newnext refs/heads/next
+ $orgpu $newpu refs/heads/pu
+ $_z40 $_z40 refs/heads/nonexistent
+ EOF
+
+ cat >update.expect <<-EOF &&
+ refs/heads/master $orgmaster $newmaster
+ refs/heads/next $orgnext $newnext
+ refs/heads/pu $orgpu $newpu
+ refs/heads/nonexistent $_z40 $_z40
+ EOF
+
+ cat >post-receive.expect <<-EOF &&
+ $orgmaster $newmaster refs/heads/master
+ $orgnext $newnext refs/heads/next
+ $orgpu $newpu refs/heads/pu
+ EOF
+
+ cat >post-update.expect <<-EOF &&
+ refs/heads/master
+ refs/heads/next
+ refs/heads/pu
+ EOF
+
+ test_cmp pre-receive.expect pre-receive.actual &&
+ test_cmp update.expect update.actual &&
+ test_cmp post-receive.expect post-receive.actual &&
+ test_cmp post-update.expect post-update.actual
+ )
+'
+
test_expect_success 'allow deleting a ref using --delete' '
mk_test heads/master &&
(cd testrepo && git config receive.denyDeleteCurrent warn) &&
diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh
index 0470a81be0..0e5eb678ce 100755
--- a/t/t5520-pull.sh
+++ b/t/t5520-pull.sh
@@ -46,6 +46,17 @@ test_expect_success 'pulling into void using master:master' '
test_cmp file cloned-uho/file
'
+test_expect_success 'pulling into void does not overwrite untracked files' '
+ git init cloned-untracked &&
+ (
+ cd cloned-untracked &&
+ echo untracked >file &&
+ test_must_fail git pull .. master &&
+ echo untracked >expect &&
+ test_cmp expect file
+ )
+'
+
test_expect_success 'test . as a remote' '
git branch copy master &&
diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh
index 884a5e567c..ca5b027c55 100755
--- a/t/t5526-fetch-submodules.sh
+++ b/t/t5526-fetch-submodules.sh
@@ -47,7 +47,7 @@ test_expect_success setup '
git init &&
echo subcontent > subfile &&
git add subfile &&
- git submodule add "$pwd/deepsubmodule" deepsubmodule &&
+ git submodule add "$pwd/deepsubmodule" subdir/deepsubmodule &&
git commit -a -m new
) &&
git submodule add "$pwd/submodule" submodule &&
@@ -58,7 +58,7 @@ test_expect_success setup '
git submodule update --init --recursive
) &&
echo "Fetching submodule submodule" > expect.out &&
- echo "Fetching submodule submodule/deepsubmodule" >> expect.out
+ echo "Fetching submodule submodule/subdir/deepsubmodule" >> expect.out
'
test_expect_success "fetch --recurse-submodules recurses into submodules" '
@@ -67,8 +67,8 @@ test_expect_success "fetch --recurse-submodules recurses into submodules" '
cd downstream &&
git fetch --recurse-submodules >../actual.out 2>../actual.err
) &&
- test_cmp expect.out actual.out &&
- test_cmp expect.err actual.err
+ test_i18ncmp expect.out actual.out &&
+ test_i18ncmp expect.err actual.err
'
test_expect_success "fetch alone only fetches superproject" '
@@ -96,8 +96,8 @@ test_expect_success "using fetchRecurseSubmodules=true in .gitmodules recurses i
git config -f .gitmodules submodule.submodule.fetchRecurseSubmodules true &&
git fetch >../actual.out 2>../actual.err
) &&
- test_cmp expect.out actual.out &&
- test_cmp expect.err actual.err
+ test_i18ncmp expect.out actual.out &&
+ test_i18ncmp expect.err actual.err
'
test_expect_success "--no-recurse-submodules overrides .gitmodules config" '
@@ -124,11 +124,11 @@ test_expect_success "--recurse-submodules overrides fetchRecurseSubmodules setti
(
cd downstream &&
git fetch --recurse-submodules >../actual.out 2>../actual.err &&
- git config -f --unset .gitmodules submodule.submodule.fetchRecurseSubmodules true &&
+ git config --unset -f .gitmodules submodule.submodule.fetchRecurseSubmodules &&
git config --unset submodule.submodule.fetchRecurseSubmodules
) &&
- test_cmp expect.out actual.out &&
- test_cmp expect.err actual.err
+ test_i18ncmp expect.out actual.out &&
+ test_i18ncmp expect.err actual.err
'
test_expect_success "--quiet propagates to submodules" '
@@ -146,14 +146,17 @@ test_expect_success "--dry-run propagates to submodules" '
cd downstream &&
git fetch --recurse-submodules --dry-run >../actual.out 2>../actual.err
) &&
- test_cmp expect.out actual.out &&
- test_cmp expect.err actual.err &&
+ test_i18ncmp expect.out actual.out &&
+ test_i18ncmp expect.err actual.err
+'
+
+test_expect_success "Without --dry-run propagates to submodules" '
(
cd downstream &&
git fetch --recurse-submodules >../actual.out 2>../actual.err
) &&
- test_cmp expect.out actual.out &&
- test_cmp expect.err actual.err
+ test_i18ncmp expect.out actual.out &&
+ test_i18ncmp expect.err actual.err
'
test_expect_success "recurseSubmodules=true propagates into submodules" '
@@ -163,8 +166,8 @@ test_expect_success "recurseSubmodules=true propagates into submodules" '
git config fetch.recurseSubmodules true
git fetch >../actual.out 2>../actual.err
) &&
- test_cmp expect.out actual.out &&
- test_cmp expect.err actual.err
+ test_i18ncmp expect.out actual.out &&
+ test_i18ncmp expect.err actual.err
'
test_expect_success "--recurse-submodules overrides config in submodule" '
@@ -177,8 +180,8 @@ test_expect_success "--recurse-submodules overrides config in submodule" '
) &&
git fetch --recurse-submodules >../actual.out 2>../actual.err
) &&
- test_cmp expect.out actual.out &&
- test_cmp expect.err actual.err
+ test_i18ncmp expect.out actual.out &&
+ test_i18ncmp expect.err actual.err
'
test_expect_success "--no-recurse-submodules overrides config setting" '
@@ -192,4 +195,259 @@ test_expect_success "--no-recurse-submodules overrides config setting" '
! test -s actual.err
'
+test_expect_success "Recursion doesn't happen when no new commits are fetched in the superproject" '
+ (
+ cd downstream &&
+ (
+ cd submodule &&
+ git config --unset fetch.recurseSubmodules
+ ) &&
+ git config --unset fetch.recurseSubmodules
+ git fetch >../actual.out 2>../actual.err
+ ) &&
+ ! test -s actual.out &&
+ ! test -s actual.err
+'
+
+test_expect_success "Recursion stops when no new submodule commits are fetched" '
+ head1=$(git rev-parse --short HEAD) &&
+ git add submodule &&
+ git commit -m "new submodule" &&
+ head2=$(git rev-parse --short HEAD) &&
+ echo "Fetching submodule submodule" > expect.out.sub &&
+ echo "From $pwd/." > expect.err.sub &&
+ echo " $head1..$head2 master -> origin/master" >> expect.err.sub
+ head -2 expect.err >> expect.err.sub &&
+ (
+ cd downstream &&
+ git fetch >../actual.out 2>../actual.err
+ ) &&
+ test_i18ncmp expect.err.sub actual.err &&
+ test_i18ncmp expect.out.sub actual.out
+'
+
+test_expect_success "Recursion doesn't happen when new superproject commits don't change any submodules" '
+ add_upstream_commit &&
+ head1=$(git rev-parse --short HEAD) &&
+ echo a > file &&
+ git add file &&
+ git commit -m "new file" &&
+ head2=$(git rev-parse --short HEAD) &&
+ echo "From $pwd/." > expect.err.file &&
+ echo " $head1..$head2 master -> origin/master" >> expect.err.file &&
+ (
+ cd downstream &&
+ git fetch >../actual.out 2>../actual.err
+ ) &&
+ ! test -s actual.out &&
+ test_i18ncmp expect.err.file actual.err
+'
+
+test_expect_success "Recursion picks up config in submodule" '
+ (
+ cd downstream &&
+ git fetch --recurse-submodules &&
+ (
+ cd submodule &&
+ git config fetch.recurseSubmodules true
+ )
+ ) &&
+ add_upstream_commit &&
+ head1=$(git rev-parse --short HEAD) &&
+ git add submodule &&
+ git commit -m "new submodule" &&
+ head2=$(git rev-parse --short HEAD) &&
+ echo "From $pwd/." > expect.err.sub &&
+ echo " $head1..$head2 master -> origin/master" >> expect.err.sub &&
+ cat expect.err >> expect.err.sub &&
+ (
+ cd downstream &&
+ git fetch >../actual.out 2>../actual.err &&
+ (
+ cd submodule &&
+ git config --unset fetch.recurseSubmodules
+ )
+ ) &&
+ test_i18ncmp expect.err.sub actual.err &&
+ test_i18ncmp expect.out actual.out
+'
+
+test_expect_success "Recursion picks up all submodules when necessary" '
+ add_upstream_commit &&
+ (
+ cd submodule &&
+ (
+ cd subdir/deepsubmodule &&
+ git fetch &&
+ git checkout -q FETCH_HEAD
+ ) &&
+ head1=$(git rev-parse --short HEAD^) &&
+ git add subdir/deepsubmodule &&
+ git commit -m "new deepsubmodule"
+ head2=$(git rev-parse --short HEAD) &&
+ echo "From $pwd/submodule" > ../expect.err.sub &&
+ echo " $head1..$head2 master -> origin/master" >> ../expect.err.sub
+ ) &&
+ head1=$(git rev-parse --short HEAD) &&
+ git add submodule &&
+ git commit -m "new submodule" &&
+ head2=$(git rev-parse --short HEAD) &&
+ echo "From $pwd/." > expect.err.2 &&
+ echo " $head1..$head2 master -> origin/master" >> expect.err.2 &&
+ cat expect.err.sub >> expect.err.2 &&
+ tail -2 expect.err >> expect.err.2 &&
+ (
+ cd downstream &&
+ git fetch >../actual.out 2>../actual.err
+ ) &&
+ test_i18ncmp expect.err.2 actual.err &&
+ test_i18ncmp expect.out actual.out
+'
+
+test_expect_success "'--recurse-submodules=on-demand' doesn't recurse when no new commits are fetched in the superproject (and ignores config)" '
+ add_upstream_commit &&
+ (
+ cd submodule &&
+ (
+ cd subdir/deepsubmodule &&
+ git fetch &&
+ git checkout -q FETCH_HEAD
+ ) &&
+ head1=$(git rev-parse --short HEAD^) &&
+ git add subdir/deepsubmodule &&
+ git commit -m "new deepsubmodule"
+ head2=$(git rev-parse --short HEAD) &&
+ echo "From $pwd/submodule" > ../expect.err.sub &&
+ echo " $head1..$head2 master -> origin/master" >> ../expect.err.sub
+ ) &&
+ (
+ cd downstream &&
+ git config fetch.recurseSubmodules true &&
+ git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err &&
+ git config --unset fetch.recurseSubmodules
+ ) &&
+ ! test -s actual.out &&
+ ! test -s actual.err
+'
+
+test_expect_success "'--recurse-submodules=on-demand' recurses as deep as necessary (and ignores config)" '
+ head1=$(git rev-parse --short HEAD) &&
+ git add submodule &&
+ git commit -m "new submodule" &&
+ head2=$(git rev-parse --short HEAD) &&
+ tail -2 expect.err > expect.err.deepsub &&
+ echo "From $pwd/." > expect.err &&
+ echo " $head1..$head2 master -> origin/master" >> expect.err
+ cat expect.err.sub >> expect.err &&
+ cat expect.err.deepsub >> expect.err &&
+ (
+ cd downstream &&
+ git config fetch.recurseSubmodules false &&
+ (
+ cd submodule &&
+ git config -f .gitmodules submodule.subdir/deepsubmodule.fetchRecursive false
+ ) &&
+ git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err &&
+ git config --unset fetch.recurseSubmodules
+ (
+ cd submodule &&
+ git config --unset -f .gitmodules submodule.subdir/deepsubmodule.fetchRecursive
+ )
+ ) &&
+ test_i18ncmp expect.out actual.out &&
+ test_i18ncmp expect.err actual.err
+'
+
+test_expect_success "'--recurse-submodules=on-demand' stops when no new submodule commits are found in the superproject (and ignores config)" '
+ add_upstream_commit &&
+ head1=$(git rev-parse --short HEAD) &&
+ echo a >> file &&
+ git add file &&
+ git commit -m "new file" &&
+ head2=$(git rev-parse --short HEAD) &&
+ echo "From $pwd/." > expect.err.file &&
+ echo " $head1..$head2 master -> origin/master" >> expect.err.file &&
+ (
+ cd downstream &&
+ git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err
+ ) &&
+ ! test -s actual.out &&
+ test_i18ncmp expect.err.file actual.err
+'
+
+test_expect_success "'fetch.recurseSubmodules=on-demand' overrides global config" '
+ (
+ cd downstream &&
+ git fetch --recurse-submodules
+ ) &&
+ add_upstream_commit &&
+ git config --global fetch.recurseSubmodules false &&
+ head1=$(git rev-parse --short HEAD) &&
+ git add submodule &&
+ git commit -m "new submodule" &&
+ head2=$(git rev-parse --short HEAD) &&
+ echo "From $pwd/." > expect.err.2 &&
+ echo " $head1..$head2 master -> origin/master" >> expect.err.2
+ head -2 expect.err >> expect.err.2 &&
+ (
+ cd downstream &&
+ git config fetch.recurseSubmodules on-demand &&
+ git fetch >../actual.out 2>../actual.err
+ ) &&
+ git config --global --unset fetch.recurseSubmodules &&
+ (
+ cd downstream &&
+ git config --unset fetch.recurseSubmodules
+ ) &&
+ test_i18ncmp expect.out.sub actual.out &&
+ test_i18ncmp expect.err.2 actual.err
+'
+
+test_expect_success "'submodule.<sub>.fetchRecurseSubmodules=on-demand' overrides fetch.recurseSubmodules" '
+ (
+ cd downstream &&
+ git fetch --recurse-submodules
+ ) &&
+ add_upstream_commit &&
+ git config fetch.recurseSubmodules false &&
+ head1=$(git rev-parse --short HEAD) &&
+ git add submodule &&
+ git commit -m "new submodule" &&
+ head2=$(git rev-parse --short HEAD) &&
+ echo "From $pwd/." > expect.err.2 &&
+ echo " $head1..$head2 master -> origin/master" >> expect.err.2
+ head -2 expect.err >> expect.err.2 &&
+ (
+ cd downstream &&
+ git config submodule.submodule.fetchRecurseSubmodules on-demand &&
+ git fetch >../actual.out 2>../actual.err
+ ) &&
+ git config --unset fetch.recurseSubmodules &&
+ (
+ cd downstream &&
+ git config --unset submodule.submodule.fetchRecurseSubmodules
+ ) &&
+ test_i18ncmp expect.out.sub actual.out &&
+ test_i18ncmp expect.err.2 actual.err
+'
+
+test_expect_success "don't fetch submodule when newly recorded commits are already present" '
+ (
+ cd submodule &&
+ git checkout -q HEAD^^
+ ) &&
+ head1=$(git rev-parse --short HEAD) &&
+ git add submodule &&
+ git commit -m "submodule rewound" &&
+ head2=$(git rev-parse --short HEAD) &&
+ echo "From $pwd/." > expect.err &&
+ echo " $head1..$head2 master -> origin/master" >> expect.err &&
+ (
+ cd downstream &&
+ git fetch >../actual.out 2>../actual.err
+ ) &&
+ ! test -s actual.out &&
+ test_i18ncmp expect.err actual.err
+'
+
test_done
diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh
index faa2e96337..30bec4b5f9 100755
--- a/t/t5531-deep-submodule-push.sh
+++ b/t/t5531-deep-submodule-push.sh
@@ -32,4 +32,91 @@ test_expect_success push '
)
'
+test_expect_success 'push if submodule has no remote' '
+ (
+ cd work/gar/bage &&
+ >junk2 &&
+ git add junk2 &&
+ git commit -m "Second junk"
+ ) &&
+ (
+ cd work &&
+ git add gar/bage &&
+ git commit -m "Second commit for gar/bage" &&
+ git push --recurse-submodules=check ../pub.git master
+ )
+'
+
+test_expect_success 'push fails if submodule commit not on remote' '
+ (
+ cd work/gar &&
+ git clone --bare bage ../../submodule.git &&
+ cd bage &&
+ git remote add origin ../../../submodule.git &&
+ git fetch &&
+ >junk3 &&
+ git add junk3 &&
+ git commit -m "Third junk"
+ ) &&
+ (
+ cd work &&
+ git add gar/bage &&
+ git commit -m "Third commit for gar/bage" &&
+ test_must_fail git push --recurse-submodules=check ../pub.git master
+ )
+'
+
+test_expect_success 'push succeeds after commit was pushed to remote' '
+ (
+ cd work/gar/bage &&
+ git push origin master
+ ) &&
+ (
+ cd work &&
+ git push --recurse-submodules=check ../pub.git master
+ )
+'
+
+test_expect_success 'push fails when commit on multiple branches if one branch has no remote' '
+ (
+ cd work/gar/bage &&
+ >junk4 &&
+ git add junk4 &&
+ git commit -m "Fourth junk"
+ ) &&
+ (
+ cd work &&
+ git branch branch2 &&
+ git add gar/bage &&
+ git commit -m "Fourth commit for gar/bage" &&
+ git checkout branch2 &&
+ (
+ cd gar/bage &&
+ git checkout HEAD~1
+ ) &&
+ >junk1 &&
+ git add junk1 &&
+ git commit -m "First junk" &&
+ test_must_fail git push --recurse-submodules=check ../pub.git
+ )
+'
+
+test_expect_success 'push succeeds if submodule has no remote and is on the first superproject commit' '
+ git init --bare a
+ git clone a a1 &&
+ (
+ cd a1 &&
+ git init b
+ (
+ cd b &&
+ >junk &&
+ git add junk &&
+ git commit -m "initial"
+ ) &&
+ git add b &&
+ git commit -m "added submodule" &&
+ git push --recurse-submodule=check origin master
+ )
+'
+
test_done
diff --git a/t/t5532-fetch-proxy.sh b/t/t5532-fetch-proxy.sh
new file mode 100755
index 0000000000..62f2460047
--- /dev/null
+++ b/t/t5532-fetch-proxy.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+test_description='fetching via git:// using core.gitproxy'
+. ./test-lib.sh
+
+test_expect_success 'setup remote repo' '
+ git init remote &&
+ (cd remote &&
+ echo content >file &&
+ git add file &&
+ git commit -m one
+ )
+'
+
+cat >proxy <<'EOF'
+#!/bin/sh
+echo >&2 "proxying for $*"
+cmd=`perl -e '
+ read(STDIN, $buf, 4);
+ my $n = hex($buf) - 4;
+ read(STDIN, $buf, $n);
+ my ($cmd, $other) = split /\0/, $buf;
+ # drop absolute-path on repo name
+ $cmd =~ s{ /}{ };
+ print $cmd;
+'`
+echo >&2 "Running '$cmd'"
+exec $cmd
+EOF
+chmod +x proxy
+test_expect_success 'setup local repo' '
+ git remote add fake git://example.com/remote &&
+ git config core.gitproxy ./proxy
+'
+
+test_expect_success 'fetch through proxy works' '
+ git fetch fake &&
+ echo one >expect &&
+ git log -1 --format=%s FETCH_HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t5540-http-push.sh b/t/t5540-http-push.sh
index a266ca5636..64767d8705 100755
--- a/t/t5540-http-push.sh
+++ b/t/t5540-http-push.sh
@@ -132,8 +132,12 @@ x38="$x5$x5$x5$x5$x5$x5$x5$x1$x1$x1"
x40="$x38$x2"
test_expect_success 'PUT and MOVE sends object to URLs with SHA-1 hash suffix' '
- sed -e "s/PUT /OP /" -e "s/MOVE /OP /" "$HTTPD_ROOT_PATH"/access.log |
- grep -e "\"OP .*/objects/$x2/${x38}_$x40 HTTP/[.0-9]*\" 20[0-9] "
+ sed \
+ -e "s/PUT /OP /" \
+ -e "s/MOVE /OP /" \
+ -e "s|/objects/$x2/${x38}_$x40|WANTED_PATH_REQUEST|" \
+ "$HTTPD_ROOT_PATH"/access.log |
+ grep -e "\"OP .*WANTED_PATH_REQUEST HTTP/[.0-9]*\" 20[0-9] "
'
diff --git a/t/t5541-http-push.sh b/t/t5541-http-push.sh
index b0c2a2c3ae..a73c82635f 100755
--- a/t/t5541-http-push.sh
+++ b/t/t5541-http-push.sh
@@ -65,14 +65,16 @@ test_expect_success 'clone remote repository' '
git clone $HTTPD_URL/smart/test_repo.git test_repo_clone
'
-test_expect_success 'push to remote repository' '
+test_expect_success 'push to remote repository (standard)' '
cd "$ROOT_PATH"/test_repo_clone &&
: >path2 &&
git add path2 &&
test_tick &&
git commit -m path2 &&
HEAD=$(git rev-parse --verify HEAD) &&
- git push &&
+ GIT_CURL_VERBOSE=1 git push -v -v 2>err &&
+ ! grep "Expect: 100-continue" err &&
+ grep "POST git-receive-pack ([0-9]* bytes)" err &&
(cd "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git &&
test $HEAD = $(git rev-parse --verify HEAD))
'
@@ -128,14 +130,29 @@ test_expect_success 'push fails for non-fast-forward refs unmatched by remote he
# push master too; this ensures there is at least one '"'push'"' command to
# the remote helper and triggers interaction with the helper.
- test_must_fail git push -v origin +master master:retsam >output 2>&1 &&
+ test_must_fail git push -v origin +master master:retsam >output 2>&1'
+test_expect_success 'push fails for non-fast-forward refs unmatched by remote helper: remote output' '
grep "^ + [a-f0-9]*\.\.\.[a-f0-9]* *master -> master (forced update)$" output &&
- grep "^ ! \[rejected\] *master -> retsam (non-fast-forward)$" output &&
+ grep "^ ! \[rejected\] *master -> retsam (non-fast-forward)$" output
+'
- grep "To prevent you from losing history, non-fast-forward updates were rejected" \
+test_expect_success 'push fails for non-fast-forward refs unmatched by remote helper: our output' '
+ test_i18ngrep "To prevent you from losing history, non-fast-forward updates were rejected" \
output
'
+test_expect_success 'push (chunked)' '
+ git checkout master &&
+ test_commit commit path3 &&
+ HEAD=$(git rev-parse --verify HEAD) &&
+ git config http.postbuffer 4 &&
+ test_when_finished "git config --unset http.postbuffer" &&
+ git push -v -v origin $BRANCH 2>err &&
+ grep "POST git-receive-pack (chunked)" err &&
+ (cd "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git &&
+ test $HEAD = $(git rev-parse --verify HEAD))
+'
+
stop_httpd
test_done
diff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch.sh
index a1883ca6b6..311a33ca84 100755
--- a/t/t5550-http-fetch.sh
+++ b/t/t5550-http-fetch.sh
@@ -8,8 +8,8 @@ if test -n "$NO_CURL"; then
test_done
fi
-. "$TEST_DIRECTORY"/lib-httpd.sh
LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5550'}
+. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
test_expect_success 'setup repository' '
@@ -35,11 +35,54 @@ test_expect_success 'clone http repository' '
test_cmp file clone/file
'
-test_expect_success 'clone http repository with authentication' '
+test_expect_success 'create password-protected repository' '
mkdir "$HTTPD_DOCUMENT_ROOT_PATH/auth/" &&
- cp -Rf "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" "$HTTPD_DOCUMENT_ROOT_PATH/auth/repo.git" &&
- git clone $AUTH_HTTPD_URL/auth/repo.git clone-auth &&
- test_cmp file clone-auth/file
+ cp -Rf "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
+ "$HTTPD_DOCUMENT_ROOT_PATH/auth/repo.git"
+'
+
+test_expect_success 'setup askpass helpers' '
+ cat >askpass <<-EOF &&
+ #!/bin/sh
+ echo >>"$PWD/askpass-query" "askpass: \$*" &&
+ cat "$PWD/askpass-response"
+ EOF
+ chmod +x askpass &&
+ GIT_ASKPASS="$PWD/askpass" &&
+ export GIT_ASKPASS &&
+ >askpass-expect-none &&
+ echo "askpass: Password for '\''$HTTPD_DEST'\'': " >askpass-expect-pass &&
+ { echo "askpass: Username for '\''$HTTPD_DEST'\'': " &&
+ cat askpass-expect-pass
+ } >askpass-expect-both
+'
+
+test_expect_success 'cloning password-protected repository can fail' '
+ >askpass-query &&
+ echo wrong >askpass-response &&
+ test_must_fail git clone "$HTTPD_URL/auth/repo.git" clone-auth-fail &&
+ test_cmp askpass-expect-both askpass-query
+'
+
+test_expect_success 'http auth can use user/pass in URL' '
+ >askpass-query &&
+ echo wrong >askpass-reponse &&
+ git clone "$HTTPD_URL_USER_PASS/auth/repo.git" clone-auth-none &&
+ test_cmp askpass-expect-none askpass-query
+'
+
+test_expect_success 'http auth can use just user in URL' '
+ >askpass-query &&
+ echo user@host >askpass-response &&
+ git clone "$HTTPD_URL_USER/auth/repo.git" clone-auth-pass &&
+ test_cmp askpass-expect-pass askpass-query
+'
+
+test_expect_success 'http auth can request both user and pass' '
+ >askpass-query &&
+ echo user@host >askpass-response &&
+ git clone "$HTTPD_URL/auth/repo.git" clone-auth-both &&
+ test_cmp askpass-expect-both askpass-query
'
test_expect_success 'fetch changes via http' '
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 987e0c8463..87ee01662c 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -31,7 +31,7 @@ test_expect_success 'clone with excess parameters (2)' '
'
-test_expect_success 'output from clone' '
+test_expect_success C_LOCALE_OUTPUT 'output from clone' '
rm -fr dst &&
git clone -n "file://$(pwd)/src" dst >output &&
test $(grep Clon output | wc -l) = 1
@@ -164,7 +164,6 @@ test_expect_success 'clone a void' '
test_expect_success 'clone respects global branch.autosetuprebase' '
(
test_config="$HOME/.gitconfig" &&
- unset GIT_CONFIG_NOGLOBAL &&
git config -f "$test_config" branch.autosetuprebase remote &&
rm -fr dst &&
git clone src dst &&
@@ -192,4 +191,61 @@ test_expect_success 'do not respect url-encoding of non-url path' '
git clone x+y xy-regular
'
+test_expect_success 'clone separate gitdir' '
+ rm -rf dst &&
+ git clone --separate-git-dir realgitdir src dst &&
+ test -d realgitdir/refs
+'
+
+test_expect_success 'clone separate gitdir: output' '
+ echo "gitdir: `pwd`/realgitdir" >expected &&
+ test_cmp expected dst/.git
+'
+
+test_expect_success 'clone from .git file' '
+ git clone dst/.git dst2
+'
+
+test_expect_success 'fetch from .git gitfile' '
+ (
+ cd dst2 &&
+ git fetch ../dst/.git
+ )
+'
+
+test_expect_success 'fetch from gitfile parent' '
+ (
+ cd dst2 &&
+ git fetch ../dst
+ )
+'
+
+test_expect_success 'clone separate gitdir where target already exists' '
+ rm -rf dst &&
+ test_must_fail git clone --separate-git-dir realgitdir src dst
+'
+
+test_expect_success 'clone --reference from original' '
+ git clone --shared --bare src src-1 &&
+ git clone --bare src src-2 &&
+ git clone --reference=src-2 --bare src-1 target-8 &&
+ grep /src-2/ target-8/objects/info/alternates
+'
+
+test_expect_success 'clone with more than one --reference' '
+ git clone --bare src src-3 &&
+ git clone --bare src src-4 &&
+ git clone --reference=src-3 --reference=src-4 src target-9 &&
+ grep /src-3/ target-9/.git/objects/info/alternates &&
+ grep /src-4/ target-9/.git/objects/info/alternates
+'
+
+test_expect_success 'clone from original with relative alternate' '
+ mkdir nest &&
+ git clone --bare src nest/src-5 &&
+ echo ../../../src/.git/objects >nest/src-5/objects/info/alternates &&
+ git clone --bare nest/src-5 target-10 &&
+ grep /src/\\.git/objects target-10/objects/info/alternates
+'
+
test_done
diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh
index 0f4d487be3..6972258b27 100755
--- a/t/t5701-clone-local.sh
+++ b/t/t5701-clone-local.sh
@@ -144,4 +144,17 @@ test_expect_success 'clone empty repository, and then push should not segfault.'
test_must_fail git push)
'
+test_expect_success 'cloning non-existent directory fails' '
+ cd "$D" &&
+ rm -rf does-not-exist &&
+ test_must_fail git clone does-not-exist
+'
+
+test_expect_success 'cloning non-git directory fails' '
+ cd "$D" &&
+ rm -rf not-a-git-repo not-a-git-repo-clone &&
+ mkdir not-a-git-repo &&
+ test_must_fail git clone not-a-git-repo not-a-git-repo-clone
+'
+
test_done
diff --git a/t/t5707-clone-detached.sh b/t/t5707-clone-detached.sh
new file mode 100755
index 0000000000..8b0d607df1
--- /dev/null
+++ b/t/t5707-clone-detached.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+
+test_description='test cloning a repository with detached HEAD'
+. ./test-lib.sh
+
+head_is_detached() {
+ git --git-dir=$1/.git rev-parse --verify HEAD &&
+ test_must_fail git --git-dir=$1/.git symbolic-ref HEAD
+}
+
+test_expect_success 'setup' '
+ echo one >file &&
+ git add file &&
+ git commit -m one &&
+ echo two >file &&
+ git commit -a -m two &&
+ git tag two &&
+ echo three >file &&
+ git commit -a -m three
+'
+
+test_expect_success 'clone repo (detached HEAD points to branch)' '
+ git checkout master^0 &&
+ git clone "file://$PWD" detached-branch
+'
+test_expect_success 'cloned HEAD matches' '
+ echo three >expect &&
+ git --git-dir=detached-branch/.git log -1 --format=%s >actual &&
+ test_cmp expect actual
+'
+test_expect_failure 'cloned HEAD is detached' '
+ head_is_detached detached-branch
+'
+
+test_expect_success 'clone repo (detached HEAD points to tag)' '
+ git checkout two^0 &&
+ git clone "file://$PWD" detached-tag
+'
+test_expect_success 'cloned HEAD matches' '
+ echo two >expect &&
+ git --git-dir=detached-tag/.git log -1 --format=%s >actual &&
+ test_cmp expect actual
+'
+test_expect_success 'cloned HEAD is detached' '
+ head_is_detached detached-tag
+'
+
+test_expect_success 'clone repo (detached HEAD points to history)' '
+ git checkout two^ &&
+ git clone "file://$PWD" detached-history
+'
+test_expect_success 'cloned HEAD matches' '
+ echo one >expect &&
+ git --git-dir=detached-history/.git log -1 --format=%s >actual &&
+ test_cmp expect actual
+'
+test_expect_success 'cloned HEAD is detached' '
+ head_is_detached detached-history
+'
+
+test_expect_success 'clone repo (orphan detached HEAD)' '
+ git checkout master^0 &&
+ echo four >file &&
+ git commit -a -m four &&
+ git clone "file://$PWD" detached-orphan
+'
+test_expect_success 'cloned HEAD matches' '
+ echo four >expect &&
+ git --git-dir=detached-orphan/.git log -1 --format=%s >actual &&
+ test_cmp expect actual
+'
+test_expect_success 'cloned HEAD is detached' '
+ head_is_detached detached-orphan
+'
+
+test_done
diff --git a/t/t5708-clone-config.sh b/t/t5708-clone-config.sh
new file mode 100755
index 0000000000..27d730c0a7
--- /dev/null
+++ b/t/t5708-clone-config.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+test_description='tests for git clone -c key=value'
+. ./test-lib.sh
+
+test_expect_success 'clone -c sets config in cloned repo' '
+ rm -rf child &&
+ git clone -c core.foo=bar . child &&
+ echo bar >expect &&
+ git --git-dir=child/.git config core.foo >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'clone -c can set multi-keys' '
+ rm -rf child &&
+ git clone -c core.foo=bar -c core.foo=baz . child &&
+ { echo bar; echo baz; } >expect &&
+ git --git-dir=child/.git config --get-all core.foo >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'clone -c without a value is boolean true' '
+ rm -rf child &&
+ git clone -c core.foo . child &&
+ echo true >expect &&
+ git --git-dir=child/.git config --bool core.foo >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'clone -c config is available during clone' '
+ echo content >file &&
+ git add file &&
+ git commit -m one &&
+ rm -rf child &&
+ git clone -c core.autocrlf . child &&
+ printf "content\\r\\n" >expect &&
+ test_cmp expect child/file
+'
+
+test_done
diff --git a/t/t5800-remote-helpers.sh b/t/t5800-remote-helpers.sh
index 1fb6380fce..1c62001fce 100755
--- a/t/t5800-remote-helpers.sh
+++ b/t/t5800-remote-helpers.sh
@@ -7,17 +7,27 @@ test_description='Test remote-helper import and export commands'
. ./test-lib.sh
-if test_have_prereq PYTHON && "$PYTHON_PATH" -c '
+if ! test_have_prereq PYTHON ; then
+ skip_all='skipping git-remote-hg tests, python not available'
+ test_done
+fi
+
+"$PYTHON_PATH" -c '
import sys
if sys.hexversion < 0x02040000:
sys.exit(1)
-'
-then
- # Requires Python 2.4 or newer
- test_set_prereq PYTHON_24
-fi
+' || {
+ skip_all='skipping git-remote-hg tests, python version < 2.4'
+ test_done
+}
+
+compare_refs() {
+ git --git-dir="$1/.git" rev-parse --verify $2 >expect &&
+ git --git-dir="$3/.git" rev-parse --verify $4 >actual &&
+ test_cmp expect actual
+}
-test_expect_success PYTHON_24 'setup repository' '
+test_expect_success 'setup repository' '
git init --bare server/.git &&
git clone server public &&
(cd public &&
@@ -27,54 +37,99 @@ test_expect_success PYTHON_24 'setup repository' '
git push origin master)
'
-test_expect_success PYTHON_24 'cloning from local repo' '
+test_expect_success 'cloning from local repo' '
git clone "testgit::${PWD}/server" localclone &&
test_cmp public/file localclone/file
'
-test_expect_success PYTHON_24 'cloning from remote repo' '
+test_expect_success 'cloning from remote repo' '
git clone "testgit::file://${PWD}/server" clone &&
test_cmp public/file clone/file
'
-test_expect_success PYTHON_24 'create new commit on remote' '
+test_expect_success 'create new commit on remote' '
(cd public &&
echo content >>file &&
git commit -a -m two &&
git push)
'
-test_expect_success PYTHON_24 'pulling from local repo' '
+test_expect_success 'pulling from local repo' '
(cd localclone && git pull) &&
test_cmp public/file localclone/file
'
-test_expect_success PYTHON_24 'pulling from remote remote' '
+test_expect_success 'pulling from remote remote' '
(cd clone && git pull) &&
test_cmp public/file clone/file
'
-test_expect_success PYTHON_24 'pushing to local repo' '
+test_expect_success 'pushing to local repo' '
(cd localclone &&
echo content >>file &&
git commit -a -m three &&
git push) &&
- HEAD=$(git --git-dir=localclone/.git rev-parse --verify HEAD) &&
- test $HEAD = $(git --git-dir=server/.git rev-parse --verify HEAD)
+ compare_refs localclone HEAD server HEAD
'
-test_expect_success PYTHON_24 'synch with changes from localclone' '
+test_expect_success 'synch with changes from localclone' '
(cd clone &&
git pull)
'
-test_expect_success PYTHON_24 'pushing remote local repo' '
+test_expect_success 'pushing remote local repo' '
(cd clone &&
echo content >>file &&
git commit -a -m four &&
git push) &&
- HEAD=$(git --git-dir=clone/.git rev-parse --verify HEAD) &&
- test $HEAD = $(git --git-dir=server/.git rev-parse --verify HEAD)
+ compare_refs clone HEAD server HEAD
+'
+
+test_expect_success 'fetch new branch' '
+ (cd public &&
+ git checkout -b new &&
+ echo content >>file &&
+ git commit -a -m five &&
+ git push origin new
+ ) &&
+ (cd localclone &&
+ git fetch origin new
+ ) &&
+ compare_refs public HEAD localclone FETCH_HEAD
+'
+
+test_expect_success 'fetch multiple branches' '
+ (cd localclone &&
+ git fetch
+ ) &&
+ compare_refs server master localclone refs/remotes/origin/master &&
+ compare_refs server new localclone refs/remotes/origin/new
+'
+
+test_expect_success 'push when remote has extra refs' '
+ (cd clone &&
+ echo content >>file &&
+ git commit -a -m six &&
+ git push
+ ) &&
+ compare_refs clone master server master
+'
+
+test_expect_success 'push new branch by name' '
+ (cd clone &&
+ git checkout -b new-name &&
+ echo content >>file &&
+ git commit -a -m seven &&
+ git push origin new-name
+ ) &&
+ compare_refs clone HEAD server refs/heads/new-name
+'
+
+test_expect_failure 'push new branch with old:new refspec' '
+ (cd clone &&
+ git push origin new-name:new-refspec
+ ) &&
+ compare_refs clone HEAD server refs/heads/new-refspec
'
test_done
diff --git a/t/t6000-rev-list-misc.sh b/t/t6000-rev-list-misc.sh
new file mode 100755
index 0000000000..b10685af4e
--- /dev/null
+++ b/t/t6000-rev-list-misc.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+test_description='miscellaneous rev-list tests'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+ echo content1 >wanted_file &&
+ echo content2 >unwanted_file &&
+ git add wanted_file unwanted_file &&
+ git commit -m one
+'
+
+test_expect_success 'rev-list --objects heeds pathspecs' '
+ git rev-list --objects HEAD -- wanted_file >output &&
+ grep wanted_file output &&
+ ! grep unwanted_file output
+'
+
+test_expect_success 'rev-list --objects with pathspecs and deeper paths' '
+ mkdir foo &&
+ >foo/file &&
+ git add foo/file &&
+ git commit -m two &&
+
+ git rev-list --objects HEAD -- foo >output &&
+ grep foo/file output &&
+
+ git rev-list --objects HEAD -- foo/file >output &&
+ grep foo/file output &&
+ ! grep unwanted_file output
+'
+
+test_expect_success 'rev-list --objects with pathspecs and copied files' '
+ git checkout --orphan junio-testcase &&
+ git rm -rf . &&
+
+ mkdir two &&
+ echo frotz >one &&
+ cp one two/three &&
+ git add one two/three &&
+ test_tick &&
+ git commit -m that &&
+
+ ONE=$(git rev-parse HEAD:one)
+ git rev-list --objects HEAD two >output &&
+ grep "$ONE two/three" output &&
+ ! grep one output
+'
+
+test_done
diff --git a/t/t6004-rev-list-path-optim.sh b/t/t6004-rev-list-path-optim.sh
index 5dabf1c5e3..3e8c42ee0b 100755
--- a/t/t6004-rev-list-path-optim.sh
+++ b/t/t6004-rev-list-path-optim.sh
@@ -1,51 +1,96 @@
#!/bin/sh
-test_description='git rev-list trivial path optimization test'
+test_description='git rev-list trivial path optimization test
+
+ d/z1
+ b0 b1
+ o------------------------*----o master
+ / /
+ o---------o----o----o----o side
+ a0 c0 c1 a1 c2
+ d/f0 d/f1
+ d/z0
+
+'
. ./test-lib.sh
test_expect_success setup '
-echo Hello > a &&
-git add a &&
-git commit -m "Initial commit" a &&
-initial=$(git rev-parse --verify HEAD)
+ echo Hello >a &&
+ mkdir d &&
+ echo World >d/f &&
+ echo World >d/z &&
+ git add a d &&
+ test_tick &&
+ git commit -m "Initial commit" &&
+ git rev-parse --verify HEAD &&
+ git tag initial
'
test_expect_success path-optimization '
- commit=$(echo "Unchanged tree" | git commit-tree "HEAD^{tree}" -p HEAD) &&
- test $(git rev-list $commit | wc -l) = 2 &&
- test $(git rev-list $commit -- . | wc -l) = 1
+ test_tick &&
+ commit=$(echo "Unchanged tree" | git commit-tree "HEAD^{tree}" -p HEAD) &&
+ test $(git rev-list $commit | wc -l) = 2 &&
+ test $(git rev-list $commit -- . | wc -l) = 1
'
test_expect_success 'further setup' '
git checkout -b side &&
echo Irrelevant >c &&
- git add c &&
+ echo Irrelevant >d/f &&
+ git add c d/f &&
+ test_tick &&
git commit -m "Side makes an irrelevant commit" &&
+ git tag side_c0 &&
echo "More Irrelevancy" >c &&
git add c &&
+ test_tick &&
git commit -m "Side makes another irrelevant commit" &&
echo Bye >a &&
git add a &&
+ test_tick &&
git commit -m "Side touches a" &&
- side=$(git rev-parse --verify HEAD) &&
+ git tag side_a1 &&
echo "Yet more Irrelevancy" >c &&
git add c &&
+ test_tick &&
git commit -m "Side makes yet another irrelevant commit" &&
git checkout master &&
echo Another >b &&
- git add b &&
+ echo Munged >d/z &&
+ git add b d/z &&
+ test_tick &&
git commit -m "Master touches b" &&
+ git tag master_b0 &&
git merge side &&
echo Touched >b &&
git add b &&
+ test_tick &&
git commit -m "Master touches b again"
'
test_expect_success 'path optimization 2' '
- ( echo "$side"; echo "$initial" ) >expected &&
+ git rev-parse side_a1 initial >expected &&
git rev-list HEAD -- a >actual &&
test_cmp expected actual
'
+test_expect_success 'pathspec with leading path' '
+ git rev-parse master^ master_b0 side_c0 initial >expected &&
+ git rev-list HEAD -- d >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'pathspec with glob (1)' '
+ git rev-parse master^ master_b0 side_c0 initial >expected &&
+ git rev-list HEAD -- "d/*" >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'pathspec with glob (2)' '
+ git rev-parse side_c0 initial >expected &&
+ git rev-list HEAD -- "d/[a-m]*" >actual &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh
index b565638e92..28d4f6b259 100755
--- a/t/t6007-rev-list-cherry-pick-file.sh
+++ b/t/t6007-rev-list-cherry-pick-file.sh
@@ -4,13 +4,14 @@ test_description='test git rev-list --cherry-pick -- file'
. ./test-lib.sh
-# A---B
+# A---B---D---F
# \
# \
-# C
+# C---E
#
# B changes a file foo.c, adding a line of text. C changes foo.c as
# well as bar.c, but the change in foo.c was identical to change B.
+# D and C change bar in the same way, E and F differently.
test_expect_success setup '
echo Hallo > foo &&
@@ -25,11 +26,26 @@ test_expect_success setup '
test_tick &&
git commit -m "C" &&
git tag C &&
+ echo Dello > bar &&
+ git add bar &&
+ test_tick &&
+ git commit -m "E" &&
+ git tag E &&
git checkout master &&
git checkout branch foo &&
test_tick &&
git commit -m "B" &&
- git tag B
+ git tag B &&
+ echo Cello > bar &&
+ git add bar &&
+ test_tick &&
+ git commit -m "D" &&
+ git tag D &&
+ echo Nello > bar &&
+ git add bar &&
+ test_tick &&
+ git commit -m "F" &&
+ git tag F
'
cat >expect <<EOF
@@ -53,8 +69,119 @@ test_expect_success '--cherry-pick foo comes up empty' '
test -z "$(git rev-list --left-right --cherry-pick B...C -- foo)"
'
+cat >expect <<EOF
+>tags/C
+EOF
+
test_expect_success '--cherry-pick bar does not come up empty' '
- ! test -z "$(git rev-list --left-right --cherry-pick B...C -- bar)"
+ git rev-list --left-right --cherry-pick B...C -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+test_expect_success 'bar does not come up empty' '
+ git rev-list --left-right B...C -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+<tags/F
+>tags/E
+EOF
+
+test_expect_success '--cherry-pick bar does not come up empty (II)' '
+ git rev-list --left-right --cherry-pick F...E -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
++tags/F
+=tags/D
++tags/E
+=tags/C
+EOF
+
+test_expect_success '--cherry-mark' '
+ git rev-list --cherry-mark F...E -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+<tags/F
+=tags/D
+>tags/E
+=tags/C
+EOF
+
+test_expect_success '--cherry-mark --left-right' '
+ git rev-list --cherry-mark --left-right F...E -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+tags/E
+EOF
+
+test_expect_success '--cherry-pick --right-only' '
+ git rev-list --cherry-pick --right-only F...E -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+test_expect_success '--cherry-pick --left-only' '
+ git rev-list --cherry-pick --left-only E...F -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
++tags/E
+=tags/C
+EOF
+
+test_expect_success '--cherry' '
+ git rev-list --cherry F...E -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+1 1
+EOF
+
+test_expect_success '--cherry --count' '
+ git rev-list --cherry --count F...E -- bar > actual &&
+ test_cmp actual expect
+'
+
+cat >expect <<EOF
+2 2
+EOF
+
+test_expect_success '--cherry-mark --count' '
+ git rev-list --cherry-mark --count F...E -- bar > actual &&
+ test_cmp actual expect
+'
+
+cat >expect <<EOF
+1 1 2
+EOF
+
+test_expect_success '--cherry-mark --left-right --count' '
+ git rev-list --cherry-mark --left-right --count F...E -- bar > actual &&
+ test_cmp actual expect
'
test_expect_success '--cherry-pick with independent, but identical branches' '
@@ -75,11 +202,8 @@ cat >expect <<EOF
1 2
EOF
-# Insert an extra commit to break the symmetry
test_expect_success '--count --left-right' '
- git checkout branch &&
- test_commit D &&
- git rev-list --count --left-right B...D > actual &&
+ git rev-list --count --left-right C...D > actual &&
test_cmp expect actual
'
diff --git a/t/t6009-rev-list-parent.sh b/t/t6009-rev-list-parent.sh
index 52f7b277ce..30507407ff 100755
--- a/t/t6009-rev-list-parent.sh
+++ b/t/t6009-rev-list-parent.sh
@@ -1,14 +1,15 @@
#!/bin/sh
-test_description='properly cull all ancestors'
+test_description='ancestor culling and limiting by parent number'
. ./test-lib.sh
-commit () {
- test_tick &&
- echo $1 >file &&
- git commit -a -m $1 &&
- git tag $1
+check_revlist () {
+ rev_list_args="$1" &&
+ shift &&
+ git rev-parse "$@" >expect &&
+ git rev-list $rev_list_args --all >actual &&
+ test_cmp expect actual
}
test_expect_success setup '
@@ -16,13 +17,13 @@ test_expect_success setup '
touch file &&
git add file &&
- commit one &&
+ test_commit one &&
test_tick=$(($test_tick - 2400)) &&
- commit two &&
- commit three &&
- commit four &&
+ test_commit two &&
+ test_commit three &&
+ test_commit four &&
git log --pretty=oneline --abbrev-commit
'
@@ -35,4 +36,101 @@ test_expect_success 'one is ancestor of others and should not be shown' '
'
+test_expect_success 'setup roots, merges and octopuses' '
+
+ git checkout --orphan newroot &&
+ test_commit five &&
+ git checkout -b sidebranch two &&
+ test_commit six &&
+ git checkout -b anotherbranch three &&
+ test_commit seven &&
+ git checkout -b yetanotherbranch four &&
+ test_commit eight &&
+ git checkout master &&
+ test_merge normalmerge newroot &&
+ test_tick &&
+ git merge -m tripus sidebranch anotherbranch &&
+ git tag tripus &&
+ git checkout -b tetrabranch normalmerge &&
+ test_tick &&
+ git merge -m tetrapus sidebranch anotherbranch yetanotherbranch &&
+ git tag tetrapus &&
+ git checkout master
+'
+
+test_expect_success 'rev-list roots' '
+
+ check_revlist "--max-parents=0" one five
+'
+
+test_expect_success 'rev-list no merges' '
+
+ check_revlist "--max-parents=1" one eight seven six five four three two &&
+ check_revlist "--no-merges" one eight seven six five four three two
+'
+
+test_expect_success 'rev-list no octopuses' '
+
+ check_revlist "--max-parents=2" one normalmerge eight seven six five four three two
+'
+
+test_expect_success 'rev-list no roots' '
+
+ check_revlist "--min-parents=1" tetrapus tripus normalmerge eight seven six four three two
+'
+
+test_expect_success 'rev-list merges' '
+
+ check_revlist "--min-parents=2" tetrapus tripus normalmerge &&
+ check_revlist "--merges" tetrapus tripus normalmerge
+'
+
+test_expect_success 'rev-list octopus' '
+
+ check_revlist "--min-parents=3" tetrapus tripus
+'
+
+test_expect_success 'rev-list ordinary commits' '
+
+ check_revlist "--min-parents=1 --max-parents=1" eight seven six four three two
+'
+
+test_expect_success 'rev-list --merges --no-merges yields empty set' '
+
+ check_revlist "--min-parents=2 --no-merges" &&
+ check_revlist "--merges --no-merges" &&
+ check_revlist "--no-merges --merges"
+'
+
+test_expect_success 'rev-list override and infinities' '
+
+ check_revlist "--min-parents=2 --max-parents=1 --max-parents=3" tripus normalmerge &&
+ check_revlist "--min-parents=1 --min-parents=2 --max-parents=7" tetrapus tripus normalmerge &&
+ check_revlist "--min-parents=2 --max-parents=8" tetrapus tripus normalmerge &&
+ check_revlist "--min-parents=2 --max-parents=-1" tetrapus tripus normalmerge &&
+ check_revlist "--min-parents=2 --no-max-parents" tetrapus tripus normalmerge &&
+ check_revlist "--max-parents=0 --min-parents=1 --no-min-parents" one five
+'
+
+test_expect_success 'dodecapus' '
+
+ roots= &&
+ for i in 1 2 3 4 5 6 7 8 9 10 11
+ do
+ git checkout -b root$i five &&
+ test_commit $i &&
+ roots="$roots root$i" ||
+ return
+ done &&
+ git checkout master &&
+ test_tick &&
+ git merge -m dodecapus $roots &&
+ git tag dodecapus &&
+
+ check_revlist "--min-parents=4" dodecapus tetrapus &&
+ check_revlist "--min-parents=8" dodecapus &&
+ check_revlist "--min-parents=12" dodecapus &&
+ check_revlist "--min-parents=13" &&
+ check_revlist "--min-parents=4 --max-parents=11" tetrapus
+'
test_done
diff --git a/t/t6010-merge-base.sh b/t/t6010-merge-base.sh
index 082032edc3..f80bba871c 100755
--- a/t/t6010-merge-base.sh
+++ b/t/t6010-merge-base.sh
@@ -8,38 +8,38 @@ test_description='Merge base and parent list computation.
. ./test-lib.sh
-test_expect_success 'setup' '
- T=$(git write-tree) &&
+M=1130000000
+Z=+0000
- M=1130000000 &&
- Z=+0000 &&
+GIT_COMMITTER_EMAIL=git@comm.iter.xz
+GIT_COMMITTER_NAME='C O Mmiter'
+GIT_AUTHOR_NAME='A U Thor'
+GIT_AUTHOR_EMAIL=git@au.thor.xz
+export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
- GIT_COMMITTER_EMAIL=git@comm.iter.xz &&
- GIT_COMMITTER_NAME="C O Mmiter" &&
- GIT_AUTHOR_NAME="A U Thor" &&
- GIT_AUTHOR_EMAIL=git@au.thor.xz &&
- export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL &&
+doit () {
+ OFFSET=$1 &&
+ NAME=$2 &&
+ shift 2 &&
- doit() {
- OFFSET=$1 &&
- NAME=$2 &&
- shift 2 &&
+ PARENTS= &&
+ for P
+ do
+ PARENTS="${PARENTS}-p $P "
+ done &&
- PARENTS= &&
- for P
- do
- PARENTS="${PARENTS}-p $P "
- done &&
+ GIT_COMMITTER_DATE="$(($M + $OFFSET)) $Z" &&
+ GIT_AUTHOR_DATE=$GIT_COMMITTER_DATE &&
+ export GIT_COMMITTER_DATE GIT_AUTHOR_DATE &&
- GIT_COMMITTER_DATE="$(($M + $OFFSET)) $Z" &&
- GIT_AUTHOR_DATE=$GIT_COMMITTER_DATE &&
- export GIT_COMMITTER_DATE GIT_AUTHOR_DATE &&
+ commit=$(echo $NAME | git commit-tree $T $PARENTS) &&
- commit=$(echo $NAME | git commit-tree $T $PARENTS) &&
+ echo $commit >.git/refs/tags/$NAME &&
+ echo $commit
+}
- echo $commit >.git/refs/tags/$NAME &&
- echo $commit
- }
+test_expect_success 'setup' '
+ T=$(git mktree </dev/null)
'
test_expect_success 'set up G and H' '
diff --git a/t/t6017-rev-list-stdin.sh b/t/t6017-rev-list-stdin.sh
index f1c32dba42..667b37564e 100755
--- a/t/t6017-rev-list-stdin.sh
+++ b/t/t6017-rev-list-stdin.sh
@@ -58,4 +58,21 @@ check side-3 ^side-4 -- file-3
check side-3 ^side-2
check side-3 ^side-2 -- file-1
+test_expect_success 'not only --stdin' '
+ cat >expect <<-EOF &&
+ 7
+
+ file-1
+ file-2
+ EOF
+ cat >input <<-EOF &&
+ ^master^
+ --
+ file-2
+ EOF
+ git log --pretty=tformat:%s --name-only --stdin master -- file-1 \
+ <input >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t6018-rev-list-glob.sh b/t/t6018-rev-list-glob.sh
index fb8291c812..f00cebff3e 100755
--- a/t/t6018-rev-list-glob.sh
+++ b/t/t6018-rev-list-glob.sh
@@ -69,6 +69,18 @@ test_expect_success 'rev-parse --glob=heads/subspace' '
'
+test_expect_failure 'rev-parse accepts --glob as detached option' '
+
+ compare rev-parse "subspace/one subspace/two" "--glob heads/subspace"
+
+'
+
+test_expect_failure 'rev-parse is not confused by option-like glob' '
+
+ compare rev-parse "master" "--glob --symbolic master"
+
+'
+
test_expect_success 'rev-parse --branches=subspace/*' '
compare rev-parse "subspace/one subspace/two" "--branches=subspace/*"
@@ -129,6 +141,12 @@ test_expect_success 'rev-list --glob refs/heads/subspace/*' '
'
+test_expect_success 'rev-list not confused by option-like --glob arg' '
+
+ compare rev-list "master" "--glob -0 master"
+
+'
+
test_expect_success 'rev-list --glob=heads/subspace/*' '
compare rev-list "subspace/one subspace/two" "--glob=heads/subspace/*"
@@ -213,4 +231,36 @@ test_expect_success 'rev-list --remotes=foo' '
'
+test_expect_success 'shortlog accepts --glob/--tags/--remotes' '
+
+ compare shortlog "subspace/one subspace/two" --branches=subspace &&
+ compare shortlog \
+ "master subspace-x someref other/three subspace/one subspace/two" \
+ --branches &&
+ compare shortlog master "--glob=heads/someref/* master" &&
+ compare shortlog "subspace/one subspace/two other/three" \
+ "--glob=heads/subspace/* --glob=heads/other/*" &&
+ compare shortlog \
+ "master other/three someref subspace-x subspace/one subspace/two" \
+ "--glob=heads/*" &&
+ compare shortlog foo/bar --tags=foo &&
+ compare shortlog foo/bar --tags &&
+ compare shortlog foo/baz --remotes=foo
+
+'
+
+test_expect_failure 'shortlog accepts --glob as detached option' '
+
+ compare shortlog \
+ "master other/three someref subspace-x subspace/one subspace/two" \
+ "--glob heads/*"
+
+'
+
+test_expect_failure 'shortlog --glob is not confused by option-like argument' '
+
+ compare shortlog master "--glob -e master"
+
+'
+
test_done
diff --git a/t/t6019-rev-list-ancestry-path.sh b/t/t6019-rev-list-ancestry-path.sh
index 76410293b3..39b4cb0ecd 100755
--- a/t/t6019-rev-list-ancestry-path.sh
+++ b/t/t6019-rev-list-ancestry-path.sh
@@ -70,4 +70,42 @@ test_expect_success 'rev-list --ancestry-patch D..M -- M.t' '
test_cmp expect actual
'
+# b---bc
+# / \ /
+# a X
+# \ / \
+# c---cb
+#
+# All refnames prefixed with 'x' to avoid confusion with the tags
+# generated by test_commit on case-insensitive systems.
+test_expect_success 'setup criss-cross' '
+ mkdir criss-cross &&
+ (cd criss-cross &&
+ git init &&
+ test_commit A &&
+ git checkout -b xb master &&
+ test_commit B &&
+ git checkout -b xc master &&
+ test_commit C &&
+ git checkout -b xbc xb -- &&
+ git merge xc &&
+ git checkout -b xcb xc -- &&
+ git merge xb &&
+ git checkout master)
+'
+
+# no commits in bc descend from cb
+test_expect_success 'criss-cross: rev-list --ancestry-path cb..bc' '
+ (cd criss-cross &&
+ git rev-list --ancestry-path xcb..xbc > actual &&
+ test -z "$(cat actual)")
+'
+
+# no commits in repository descend from cb
+test_expect_success 'criss-cross: rev-list --ancestry-path --all ^cb' '
+ (cd criss-cross &&
+ git rev-list --ancestry-path --all ^xcb > actual &&
+ test -z "$(cat actual)")
+'
+
test_done
diff --git a/t/t6020-merge-df.sh b/t/t6020-merge-df.sh
index eec8f4e3ed..27c3d73961 100755
--- a/t/t6020-merge-df.sh
+++ b/t/t6020-merge-df.sh
@@ -59,15 +59,19 @@ test_expect_success 'setup modify/delete + directory/file conflict' '
git add letters &&
git commit -m initial &&
+ # Throw in letters.txt for sorting order fun
+ # ("letters.txt" sorts between "letters" and "letters/file")
echo i >>letters &&
- git add letters &&
+ echo "version 2" >letters.txt &&
+ git add letters letters.txt &&
git commit -m modified &&
git checkout -b delete HEAD^ &&
git rm letters &&
mkdir letters &&
>letters/file &&
- git add letters &&
+ echo "version 1" >letters.txt &&
+ git add letters letters.txt &&
git commit -m deleted
'
@@ -75,25 +79,31 @@ test_expect_success 'modify/delete + directory/file conflict' '
git checkout delete^0 &&
test_must_fail git merge modify &&
- test 3 = $(git ls-files -s | wc -l) &&
- test 2 = $(git ls-files -u | wc -l) &&
- test 1 = $(git ls-files -o | wc -l) &&
+ test 5 -eq $(git ls-files -s | wc -l) &&
+ test 4 -eq $(git ls-files -u | wc -l) &&
+ test 1 -eq $(git ls-files -o | wc -l) &&
test -f letters/file &&
+ test -f letters.txt &&
test -f letters~modify
'
test_expect_success 'modify/delete + directory/file conflict; other way' '
+ # Yes, we really need the double reset since "letters" appears as
+ # both a file and a directory.
+ git reset --hard &&
git reset --hard &&
git clean -f &&
git checkout modify^0 &&
+
test_must_fail git merge delete &&
- test 3 = $(git ls-files -s | wc -l) &&
- test 2 = $(git ls-files -u | wc -l) &&
- test 1 = $(git ls-files -o | wc -l) &&
+ test 5 -eq $(git ls-files -s | wc -l) &&
+ test 4 -eq $(git ls-files -u | wc -l) &&
+ test 1 -eq $(git ls-files -o | wc -l) &&
test -f letters/file &&
+ test -f letters.txt &&
test -f letters~HEAD
'
diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh
index 1ed259d864..9d8584e957 100755
--- a/t/t6022-merge-rename.sh
+++ b/t/t6022-merge-rename.sh
@@ -252,6 +252,7 @@ test_expect_success 'setup for rename + d/f conflicts' '
git reset --hard &&
git checkout --orphan dir-in-way &&
git rm -rf . &&
+ git clean -fdqx &&
mkdir sub &&
mkdir dir &&
@@ -302,11 +303,11 @@ test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '
git checkout -q renamed-file-has-no-conflicts^0 &&
test_must_fail git merge --strategy=recursive dir-in-way >output &&
- grep "CONFLICT (delete/modify): dir/file-in-the-way" output &&
+ grep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
grep "Auto-merging dir" output &&
grep "Adding as dir~HEAD instead" output &&
- test 2 -eq "$(git ls-files -u | wc -l)" &&
+ test 3 -eq "$(git ls-files -u | wc -l)" &&
test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
test_must_fail git diff --quiet &&
@@ -324,11 +325,11 @@ test_expect_success 'Same as previous, but merged other way' '
test_must_fail git merge --strategy=recursive renamed-file-has-no-conflicts >output 2>errors &&
! grep "error: refusing to lose untracked file at" errors &&
- grep "CONFLICT (delete/modify): dir/file-in-the-way" output &&
+ grep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
grep "Auto-merging dir" output &&
grep "Adding as dir~renamed-file-has-no-conflicts instead" output &&
- test 2 -eq "$(git ls-files -u | wc -l)" &&
+ test 3 -eq "$(git ls-files -u | wc -l)" &&
test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
test_must_fail git diff --quiet &&
@@ -350,11 +351,11 @@ cat >expected <<\EOF &&
8
9
10
-<<<<<<< HEAD
+<<<<<<< HEAD:dir
12
=======
11
->>>>>>> dir-not-in-way
+>>>>>>> dir-not-in-way:sub/file
EOF
test_expect_success 'Rename+D/F conflict; renamed file cannot merge, dir not in way' '
@@ -404,11 +405,11 @@ cat >expected <<\EOF &&
8
9
10
-<<<<<<< HEAD
+<<<<<<< HEAD:sub/file
11
=======
12
->>>>>>> renamed-file-has-conflicts
+>>>>>>> renamed-file-has-conflicts:dir
EOF
test_expect_success 'Same as previous, but merged other way' '
@@ -609,4 +610,278 @@ test_expect_success 'check handling of differently renamed file with D/F conflic
! test -f original
'
+test_expect_success 'setup avoid unnecessary update, normal rename' '
+ git reset --hard &&
+ git checkout --orphan avoid-unnecessary-update-1 &&
+ git rm -rf . &&
+ git clean -fdqx &&
+
+ printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >original &&
+ git add -A &&
+ git commit -m "Common commmit" &&
+
+ git mv original rename &&
+ echo 11 >>rename &&
+ git add -u &&
+ git commit -m "Renamed and modified" &&
+
+ git checkout -b merge-branch-1 HEAD~1 &&
+ echo "random content" >random-file &&
+ git add -A &&
+ git commit -m "Random, unrelated changes"
+'
+
+test_expect_success 'avoid unnecessary update, normal rename' '
+ git checkout -q avoid-unnecessary-update-1^0 &&
+ test-chmtime =1000000000 rename &&
+ test-chmtime -v +0 rename >expect &&
+ git merge merge-branch-1 &&
+ test-chmtime -v +0 rename >actual &&
+ test_cmp expect actual # "rename" should have stayed intact
+'
+
+test_expect_success 'setup to test avoiding unnecessary update, with D/F conflict' '
+ git reset --hard &&
+ git checkout --orphan avoid-unnecessary-update-2 &&
+ git rm -rf . &&
+ git clean -fdqx &&
+
+ mkdir df &&
+ printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >df/file &&
+ git add -A &&
+ git commit -m "Common commmit" &&
+
+ git mv df/file temp &&
+ rm -rf df &&
+ git mv temp df &&
+ echo 11 >>df &&
+ git add -u &&
+ git commit -m "Renamed and modified" &&
+
+ git checkout -b merge-branch-2 HEAD~1 &&
+ >unrelated-change &&
+ git add unrelated-change &&
+ git commit -m "Only unrelated changes"
+'
+
+test_expect_success 'avoid unnecessary update, with D/F conflict' '
+ git checkout -q avoid-unnecessary-update-2^0 &&
+ test-chmtime =1000000000 df &&
+ test-chmtime -v +0 df >expect &&
+ git merge merge-branch-2 &&
+ test-chmtime -v +0 df >actual &&
+ test_cmp expect actual # "df" should have stayed intact
+'
+
+test_expect_success 'setup avoid unnecessary update, dir->(file,nothing)' '
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ >irrelevant &&
+ mkdir df &&
+ >df/file &&
+ git add -A &&
+ git commit -mA &&
+
+ git checkout -b side
+ git rm -rf df &&
+ git commit -mB &&
+
+ git checkout master &&
+ git rm -rf df &&
+ echo bla >df &&
+ git add -A &&
+ git commit -m "Add a newfile"
+'
+
+test_expect_success 'avoid unnecessary update, dir->(file,nothing)' '
+ git checkout -q master^0 &&
+ test-chmtime =1000000000 df &&
+ test-chmtime -v +0 df >expect &&
+ git merge side &&
+ test-chmtime -v +0 df >actual &&
+ test_cmp expect actual # "df" should have stayed intact
+'
+
+test_expect_success 'setup avoid unnecessary update, modify/delete' '
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ >irrelevant &&
+ >file &&
+ git add -A &&
+ git commit -mA &&
+
+ git checkout -b side
+ git rm -f file &&
+ git commit -m "Delete file" &&
+
+ git checkout master &&
+ echo bla >file &&
+ git add -A &&
+ git commit -m "Modify file"
+'
+
+test_expect_success 'avoid unnecessary update, modify/delete' '
+ git checkout -q master^0 &&
+ test-chmtime =1000000000 file &&
+ test-chmtime -v +0 file >expect &&
+ test_must_fail git merge side &&
+ test-chmtime -v +0 file >actual &&
+ test_cmp expect actual # "file" should have stayed intact
+'
+
+test_expect_success 'setup avoid unnecessary update, rename/add-dest' '
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ printf "1\n2\n3\n4\n5\n6\n7\n8\n" >file &&
+ git add -A &&
+ git commit -mA &&
+
+ git checkout -b side
+ cp file newfile &&
+ git add -A &&
+ git commit -m "Add file copy" &&
+
+ git checkout master &&
+ git mv file newfile &&
+ git commit -m "Rename file"
+'
+
+test_expect_success 'avoid unnecessary update, rename/add-dest' '
+ git checkout -q master^0 &&
+ test-chmtime =1000000000 newfile &&
+ test-chmtime -v +0 newfile >expect &&
+ git merge side &&
+ test-chmtime -v +0 newfile >actual &&
+ test_cmp expect actual # "file" should have stayed intact
+'
+
+test_expect_success 'setup merge of rename + small change' '
+ git reset --hard &&
+ git checkout --orphan rename-plus-small-change &&
+ git rm -rf . &&
+ git clean -fdqx &&
+
+ echo ORIGINAL >file &&
+ git add file &&
+
+ test_tick &&
+ git commit -m Initial &&
+ git checkout -b rename_branch &&
+ git mv file renamed_file &&
+ git commit -m Rename &&
+ git checkout rename-plus-small-change &&
+ echo NEW-VERSION >file &&
+ git commit -a -m Reformat
+'
+
+test_expect_success 'merge rename + small change' '
+ git merge rename_branch &&
+
+ test 1 -eq $(git ls-files -s | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+ test $(git rev-parse HEAD:renamed_file) = $(git rev-parse HEAD~1:file)
+'
+
+test_expect_success 'setup for use of extended merge markers' '
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ printf "1\n2\n3\n4\n5\n6\n7\n8\n" >original_file &&
+ git add original_file &&
+ git commit -mA &&
+
+ git checkout -b rename &&
+ echo 9 >>original_file &&
+ git add original_file &&
+ git mv original_file renamed_file &&
+ git commit -mB &&
+
+ git checkout master &&
+ echo 8.5 >>original_file &&
+ git add original_file &&
+ git commit -mC
+'
+
+cat >expected <<\EOF &&
+1
+2
+3
+4
+5
+6
+7
+8
+<<<<<<< HEAD:renamed_file
+9
+=======
+8.5
+>>>>>>> master^0:original_file
+EOF
+
+test_expect_success 'merge master into rename has correct extended markers' '
+ git checkout rename^0 &&
+ test_must_fail git merge -s recursive master^0 &&
+ test_cmp expected renamed_file
+'
+
+cat >expected <<\EOF &&
+1
+2
+3
+4
+5
+6
+7
+8
+<<<<<<< HEAD:original_file
+8.5
+=======
+9
+>>>>>>> rename^0:renamed_file
+EOF
+
+test_expect_success 'merge rename into master has correct extended markers' '
+ git reset --hard &&
+ git checkout master^0 &&
+ test_must_fail git merge -s recursive rename^0 &&
+ test_cmp expected renamed_file
+'
+
+test_expect_success 'setup spurious "refusing to lose untracked" message' '
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ > irrelevant_file &&
+ printf "1\n2\n3\n4\n5\n6\n7\n8\n" >original_file &&
+ git add irrelevant_file original_file &&
+ git commit -mA &&
+
+ git checkout -b rename &&
+ git mv original_file renamed_file &&
+ git commit -mB &&
+
+ git checkout master &&
+ git rm original_file &&
+ git commit -mC
+'
+
+test_expect_success 'no spurious "refusing to lose untracked" message' '
+ git checkout master^0 &&
+ test_must_fail git merge rename^0 2>errors.txt &&
+ ! grep "refusing to lose untracked file" errors.txt
+'
+
test_done
diff --git a/t/t6023-merge-file.sh b/t/t6023-merge-file.sh
index d9f343942c..432f086c06 100755
--- a/t/t6023-merge-file.sh
+++ b/t/t6023-merge-file.sh
@@ -154,7 +154,7 @@ test_expect_success "expected conflict markers" "test_cmp expect out"
test_expect_success 'binary files cannot be merged' '
test_must_fail git merge-file -p \
- orig.txt "$TEST_DIRECTORY"/test4012.png new1.txt 2> merge.err &&
+ orig.txt "$TEST_DIRECTORY"/test-binary-1.png new1.txt 2> merge.err &&
grep "Cannot merge binary files" merge.err
'
diff --git a/t/t6027-merge-binary.sh b/t/t6027-merge-binary.sh
index b519626ca0..07735410b9 100755
--- a/t/t6027-merge-binary.sh
+++ b/t/t6027-merge-binary.sh
@@ -6,7 +6,7 @@ test_description='ask merge-recursive to merge binary files'
test_expect_success setup '
- cat "$TEST_DIRECTORY"/test4012.png >m &&
+ cat "$TEST_DIRECTORY"/test-binary-1.png >m &&
git add m &&
git ls-files -s | sed -e "s/ 0 / 1 /" >E1 &&
test_tick &&
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index b5063b6fe6..c6f1f9f8ab 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -126,6 +126,18 @@ test_expect_success 'bisect reset removes packed refs' '
test -z "$(git for-each-ref "refs/heads/bisect")"
'
+test_expect_success 'bisect reset removes bisect state after --no-checkout' '
+ git bisect reset &&
+ git bisect start --no-checkout &&
+ git bisect good $HASH1 &&
+ git bisect bad $HASH3 &&
+ git bisect next &&
+ git bisect reset &&
+ test -z "$(git for-each-ref "refs/bisect/*")" &&
+ test -z "$(git for-each-ref "refs/heads/bisect")" &&
+ test -z "$(git for-each-ref "BISECT_HEAD")"
+'
+
test_expect_success 'bisect start: back in good branch' '
git branch > branch.output &&
grep "* other" branch.output > /dev/null &&
@@ -138,15 +150,23 @@ test_expect_success 'bisect start: back in good branch' '
grep "* other" branch.output > /dev/null
'
-test_expect_success 'bisect start: no ".git/BISECT_START" if junk rev' '
- git bisect start $HASH4 $HASH1 -- &&
- git bisect good &&
+test_expect_success 'bisect start: no ".git/BISECT_START" created if junk rev' '
+ git bisect reset &&
test_must_fail git bisect start $HASH4 foo -- &&
git branch > branch.output &&
grep "* other" branch.output > /dev/null &&
test_must_fail test -e .git/BISECT_START
'
+test_expect_success 'bisect start: existing ".git/BISECT_START" not modified if junk rev' '
+ git bisect start $HASH4 $HASH1 -- &&
+ git bisect good &&
+ cp .git/BISECT_START saved &&
+ test_must_fail git bisect start $HASH4 foo -- &&
+ git branch > branch.output &&
+ grep "* (no branch)" branch.output > /dev/null &&
+ test_cmp saved .git/BISECT_START
+'
test_expect_success 'bisect start: no ".git/BISECT_START" if mistaken rev' '
git bisect start $HASH4 $HASH1 -- &&
git bisect good &&
@@ -572,6 +592,155 @@ test_expect_success 'erroring out when using bad path parameters' '
grep "bad path parameters" error.txt
'
+test_expect_success 'test bisection on bare repo - --no-checkout specified' '
+ git clone --bare . bare.nocheckout &&
+ (
+ cd bare.nocheckout &&
+ git bisect start --no-checkout &&
+ git bisect good $HASH1 &&
+ git bisect bad $HASH4 &&
+ git bisect run eval \
+ "test \$(git rev-list BISECT_HEAD ^$HASH2 --max-count=1 | wc -l) = 0" \
+ >../nocheckout.log &&
+ git bisect reset
+ ) &&
+ grep "$HASH3 is the first bad commit" nocheckout.log
+'
+
+
+test_expect_success 'test bisection on bare repo - --no-checkout defaulted' '
+ git clone --bare . bare.defaulted &&
+ (
+ cd bare.defaulted &&
+ git bisect start &&
+ git bisect good $HASH1 &&
+ git bisect bad $HASH4 &&
+ git bisect run eval \
+ "test \$(git rev-list BISECT_HEAD ^$HASH2 --max-count=1 | wc -l) = 0" \
+ >../defaulted.log &&
+ git bisect reset
+ ) &&
+ grep "$HASH3 is the first bad commit" defaulted.log
+'
+
#
+# This creates a broken branch which cannot be checked out because
+# the tree created has been deleted.
#
+# H1-H2-H3-H4-H5-H6-H7 <--other
+# \
+# S5-S6'-S7'-S8'-S9 <--broken
+#
+# Commits marked with ' have a missing tree.
+#
+test_expect_success 'broken branch creation' '
+ git bisect reset &&
+ git checkout -b broken $HASH4 &&
+ git tag BROKEN_HASH4 $HASH4 &&
+ add_line_into_file "5(broken): first line on a broken branch" hello2 &&
+ git tag BROKEN_HASH5 &&
+ mkdir missing &&
+ :> missing/MISSING &&
+ git add missing/MISSING &&
+ git commit -m "6(broken): Added file that will be deleted"
+ git tag BROKEN_HASH6 &&
+ add_line_into_file "7(broken): second line on a broken branch" hello2 &&
+ git tag BROKEN_HASH7 &&
+ add_line_into_file "8(broken): third line on a broken branch" hello2 &&
+ git tag BROKEN_HASH8 &&
+ git rm missing/MISSING &&
+ git commit -m "9(broken): Remove missing file"
+ git tag BROKEN_HASH9 &&
+ rm .git/objects/39/f7e61a724187ab767d2e08442d9b6b9dab587d
+'
+
+echo "" > expected.ok
+cat > expected.missing-tree.default <<EOF
+fatal: unable to read tree 39f7e61a724187ab767d2e08442d9b6b9dab587d
+EOF
+
+test_expect_success 'bisect fails if tree is broken on start commit' '
+ git bisect reset &&
+ test_must_fail git bisect start BROKEN_HASH7 BROKEN_HASH4 2>error.txt &&
+ test_cmp expected.missing-tree.default error.txt
+'
+
+test_expect_success 'bisect fails if tree is broken on trial commit' '
+ git bisect reset &&
+ test_must_fail git bisect start BROKEN_HASH9 BROKEN_HASH4 2>error.txt &&
+ git reset --hard broken &&
+ git checkout broken &&
+ test_cmp expected.missing-tree.default error.txt
+'
+
+check_same()
+{
+ echo "Checking $1 is the same as $2" &&
+ git rev-parse "$1" > expected.same &&
+ git rev-parse "$2" > expected.actual &&
+ test_cmp expected.same expected.actual
+}
+
+test_expect_success 'bisect: --no-checkout - start commit bad' '
+ git bisect reset &&
+ git bisect start BROKEN_HASH7 BROKEN_HASH4 --no-checkout &&
+ check_same BROKEN_HASH6 BISECT_HEAD &&
+ git bisect reset
+'
+
+test_expect_success 'bisect: --no-checkout - trial commit bad' '
+ git bisect reset &&
+ git bisect start broken BROKEN_HASH4 --no-checkout &&
+ check_same BROKEN_HASH6 BISECT_HEAD &&
+ git bisect reset
+'
+
+test_expect_success 'bisect: --no-checkout - target before breakage' '
+ git bisect reset &&
+ git bisect start broken BROKEN_HASH4 --no-checkout &&
+ check_same BROKEN_HASH6 BISECT_HEAD &&
+ git bisect bad BISECT_HEAD &&
+ check_same BROKEN_HASH5 BISECT_HEAD &&
+ git bisect bad BISECT_HEAD &&
+ check_same BROKEN_HASH5 bisect/bad &&
+ git bisect reset
+'
+
+test_expect_success 'bisect: --no-checkout - target in breakage' '
+ git bisect reset &&
+ git bisect start broken BROKEN_HASH4 --no-checkout &&
+ check_same BROKEN_HASH6 BISECT_HEAD &&
+ git bisect bad BISECT_HEAD &&
+ check_same BROKEN_HASH5 BISECT_HEAD &&
+ git bisect good BISECT_HEAD &&
+ check_same BROKEN_HASH6 bisect/bad &&
+ git bisect reset
+'
+
+test_expect_success 'bisect: --no-checkout - target after breakage' '
+ git bisect reset &&
+ git bisect start broken BROKEN_HASH4 --no-checkout &&
+ check_same BROKEN_HASH6 BISECT_HEAD &&
+ git bisect good BISECT_HEAD &&
+ check_same BROKEN_HASH8 BISECT_HEAD &&
+ git bisect good BISECT_HEAD &&
+ check_same BROKEN_HASH9 bisect/bad &&
+ git bisect reset
+'
+
+test_expect_success 'bisect: demonstrate identification of damage boundary' "
+ git bisect reset &&
+ git checkout broken &&
+ git bisect start broken master --no-checkout &&
+ git bisect run \"\$SHELL_PATH\" -c '
+ GOOD=\$(git for-each-ref \"--format=%(objectname)\" refs/bisect/good-*) &&
+ git rev-list --objects BISECT_HEAD --not \$GOOD >tmp.\$\$ &&
+ git pack-objects --stdout >/dev/null < tmp.\$\$
+ rc=\$?
+ rm -f tmp.\$\$
+ test \$rc = 0' &&
+ check_same BROKEN_HASH6 bisect/bad &&
+ git bisect reset
+"
+
test_done
diff --git a/t/t6035-merge-dir-to-symlink.sh b/t/t6035-merge-dir-to-symlink.sh
index 92e02d5d77..2599ae50eb 100755
--- a/t/t6035-merge-dir-to-symlink.sh
+++ b/t/t6035-merge-dir-to-symlink.sh
@@ -17,13 +17,21 @@ test_expect_success SYMLINKS 'create a commit where dir a/b changed to symlink'
git commit -m "dir to symlink"
'
-test_expect_success SYMLINKS 'keep a/b-2/c/d across checkout' '
+test_expect_success SYMLINKS 'checkout does not clobber untracked symlink' '
git checkout HEAD^0 &&
git reset --hard master &&
git rm --cached a/b &&
git commit -m "untracked symlink remains" &&
- git checkout start^0 &&
- test -f a/b-2/c/d
+ test_must_fail git checkout start^0
+'
+
+test_expect_success SYMLINKS 'a/b-2/c/d is kept when clobbering symlink b' '
+ git checkout HEAD^0 &&
+ git reset --hard master &&
+ git rm --cached a/b &&
+ git commit -m "untracked symlink remains" &&
+ git checkout -f start^0 &&
+ test -f a/b-2/c/d
'
test_expect_success SYMLINKS 'checkout should not have deleted a/b-2/c/d' '
diff --git a/t/t6036-recursive-corner-cases.sh b/t/t6036-recursive-corner-cases.sh
index 871577d90c..dfee7d159b 100755
--- a/t/t6036-recursive-corner-cases.sh
+++ b/t/t6036-recursive-corner-cases.sh
@@ -1,9 +1,15 @@
#!/bin/sh
-test_description='recursive merge corner cases'
+test_description='recursive merge corner cases involving criss-cross merges'
. ./test-lib.sh
+get_clean_checkout () {
+ git reset --hard &&
+ git clean -fdqx &&
+ git checkout "$1"
+}
+
#
# L1 L2
# o---o
@@ -51,23 +57,15 @@ test_expect_success 'merge simple rename+criss-cross with no modifications' '
test_must_fail git merge -s recursive R2^0 &&
- test 5 = $(git ls-files -s | wc -l) &&
- test 3 = $(git ls-files -u | wc -l) &&
- test 0 = $(git ls-files -o | wc -l) &&
+ test 2 = $(git ls-files -s | wc -l) &&
+ test 2 = $(git ls-files -u | wc -l) &&
+ test 2 = $(git ls-files -o | wc -l) &&
- test $(git rev-parse :0:one) = $(git rev-parse L2:one) &&
- test $(git rev-parse :0:two) = $(git rev-parse R2:two) &&
test $(git rev-parse :2:three) = $(git rev-parse L2:three) &&
test $(git rev-parse :3:three) = $(git rev-parse R2:three) &&
- cp two merged &&
- >empty &&
- test_must_fail git merge-file \
- -L "Temporary merge branch 2" \
- -L "" \
- -L "Temporary merge branch 1" \
- merged empty one &&
- test $(git rev-parse :1:three) = $(git hash-object merged)
+ test $(git rev-parse L2:three) = $(git hash-object three~HEAD) &&
+ test $(git rev-parse R2:three) = $(git hash-object three~R2^0)
'
#
@@ -126,24 +124,15 @@ test_expect_success 'merge criss-cross + rename merges with basic modification'
test_must_fail git merge -s recursive R2^0 &&
- test 5 = $(git ls-files -s | wc -l) &&
- test 3 = $(git ls-files -u | wc -l) &&
- test 0 = $(git ls-files -o | wc -l) &&
+ test 2 = $(git ls-files -s | wc -l) &&
+ test 2 = $(git ls-files -u | wc -l) &&
+ test 2 = $(git ls-files -o | wc -l) &&
- test $(git rev-parse :0:one) = $(git rev-parse L2:one) &&
- test $(git rev-parse :0:two) = $(git rev-parse R2:two) &&
test $(git rev-parse :2:three) = $(git rev-parse L2:three) &&
test $(git rev-parse :3:three) = $(git rev-parse R2:three) &&
- head -n 10 two >merged &&
- cp one merge-me &&
- >empty &&
- test_must_fail git merge-file \
- -L "Temporary merge branch 2" \
- -L "" \
- -L "Temporary merge branch 1" \
- merged empty merge-me &&
- test $(git rev-parse :1:three) = $(git hash-object merged)
+ test $(git rev-parse L2:three) = $(git hash-object three~HEAD) &&
+ test $(git rev-parse R2:three) = $(git hash-object three~R2^0)
'
#
@@ -231,4 +220,557 @@ test_expect_success 'git detects differently handled merges conflict' '
test $(git rev-parse :1:new_a) = $(git hash-object merged)
'
+#
+# criss-cross + modify/delete:
+#
+# B D
+# o---o
+# / \ / \
+# A o X ? F
+# \ / \ /
+# o---o
+# C E
+#
+# Commit A: file with contents 'A\n'
+# Commit B: file with contents 'B\n'
+# Commit C: file not present
+# Commit D: file with contents 'B\n'
+# Commit E: file not present
+#
+# Merging commits D & E should result in modify/delete conflict.
+
+test_expect_success 'setup criss-cross + modify/delete resolved differently' '
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ echo A >file &&
+ git add file &&
+ test_tick &&
+ git commit -m A &&
+
+ git branch B &&
+ git checkout -b C &&
+ git rm file &&
+ test_tick &&
+ git commit -m C &&
+
+ git checkout B &&
+ echo B >file &&
+ git add file &&
+ test_tick &&
+ git commit -m B &&
+
+ git checkout B^0 &&
+ test_must_fail git merge C &&
+ echo B >file &&
+ git add file &&
+ test_tick &&
+ git commit -m D &&
+ git tag D &&
+
+ git checkout C^0 &&
+ test_must_fail git merge B &&
+ git rm file &&
+ test_tick &&
+ git commit -m E &&
+ git tag E
+'
+
+test_expect_success 'git detects conflict merging criss-cross+modify/delete' '
+ git checkout D^0 &&
+
+ test_must_fail git merge -s recursive E^0 &&
+
+ test 2 -eq $(git ls-files -s | wc -l) &&
+ test 2 -eq $(git ls-files -u | wc -l) &&
+
+ test $(git rev-parse :1:file) = $(git rev-parse master:file) &&
+ test $(git rev-parse :2:file) = $(git rev-parse B:file)
+'
+
+test_expect_success 'git detects conflict merging criss-cross+modify/delete, reverse direction' '
+ git reset --hard &&
+ git checkout E^0 &&
+
+ test_must_fail git merge -s recursive D^0 &&
+
+ test 2 -eq $(git ls-files -s | wc -l) &&
+ test 2 -eq $(git ls-files -u | wc -l) &&
+
+ test $(git rev-parse :1:file) = $(git rev-parse master:file) &&
+ test $(git rev-parse :3:file) = $(git rev-parse B:file)
+'
+
+#
+# criss-cross + modify/modify with very contrived file contents:
+#
+# B D
+# o---o
+# / \ / \
+# A o X ? F
+# \ / \ /
+# o---o
+# C E
+#
+# Commit A: file with contents 'A\n'
+# Commit B: file with contents 'B\n'
+# Commit C: file with contents 'C\n'
+# Commit D: file with contents 'D\n'
+# Commit E: file with contents:
+# <<<<<<< Temporary merge branch 1
+# C
+# =======
+# B
+# >>>>>>> Temporary merge branch 2
+#
+# Now, when we merge commits D & E, does git detect the conflict?
+
+test_expect_success 'setup differently handled merges of content conflict' '
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ echo A >file &&
+ git add file &&
+ test_tick &&
+ git commit -m A &&
+
+ git branch B &&
+ git checkout -b C &&
+ echo C >file &&
+ git add file &&
+ test_tick &&
+ git commit -m C &&
+
+ git checkout B &&
+ echo B >file &&
+ git add file &&
+ test_tick &&
+ git commit -m B &&
+
+ git checkout B^0 &&
+ test_must_fail git merge C &&
+ echo D >file &&
+ git add file &&
+ test_tick &&
+ git commit -m D &&
+ git tag D &&
+
+ git checkout C^0 &&
+ test_must_fail git merge B &&
+ cat <<EOF >file &&
+<<<<<<< Temporary merge branch 1
+C
+=======
+B
+>>>>>>> Temporary merge branch 2
+EOF
+ git add file &&
+ test_tick &&
+ git commit -m E &&
+ git tag E
+'
+
+test_expect_failure 'git detects conflict w/ criss-cross+contrived resolution' '
+ git checkout D^0 &&
+
+ test_must_fail git merge -s recursive E^0 &&
+
+ test 3 -eq $(git ls-files -s | wc -l) &&
+ test 3 -eq $(git ls-files -u | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+
+ test $(git rev-parse :2:file) = $(git rev-parse D:file) &&
+ test $(git rev-parse :3:file) = $(git rev-parse E:file)
+'
+
+#
+# criss-cross + d/f conflict via add/add:
+# Commit A: Neither file 'a' nor directory 'a/' exist.
+# Commit B: Introduce 'a'
+# Commit C: Introduce 'a/file'
+# Commit D: Merge B & C, keeping 'a' and deleting 'a/'
+#
+# Two different later cases:
+# Commit E1: Merge B & C, deleting 'a' but keeping 'a/file'
+# Commit E2: Merge B & C, deleting 'a' but keeping a slightly modified 'a/file'
+#
+# B D
+# o---o
+# / \ / \
+# A o X ? F
+# \ / \ /
+# o---o
+# C E1 or E2
+#
+# Merging D & E1 requires we first create a virtual merge base X from
+# merging A & B in memory. Now, if X could keep both 'a' and 'a/file' in
+# the index, then the merge of D & E1 could be resolved cleanly with both
+# 'a' and 'a/file' removed. Since git does not currently allow creating
+# such a tree, the best we can do is have X contain both 'a~<unique>' and
+# 'a/file' resulting in the merge of D and E1 having a rename/delete
+# conflict for 'a'. (Although this merge appears to be unsolvable with git
+# currently, git could do a lot better than it currently does with these
+# d/f conflicts, which is the purpose of this test.)
+#
+# Merge of D & E2 has similar issues for path 'a', but should always result
+# in a modify/delete conflict for path 'a/file'.
+#
+# We run each merge in both directions, to check for directional issues
+# with D/F conflict handling.
+#
+
+test_expect_success 'setup differently handled merges of directory/file conflict' '
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ >ignore-me &&
+ git add ignore-me &&
+ test_tick &&
+ git commit -m A &&
+ git tag A &&
+
+ git branch B &&
+ git checkout -b C &&
+ mkdir a &&
+ echo 10 >a/file &&
+ git add a/file &&
+ test_tick &&
+ git commit -m C &&
+
+ git checkout B &&
+ echo 5 >a &&
+ git add a &&
+ test_tick &&
+ git commit -m B &&
+
+ git checkout B^0 &&
+ test_must_fail git merge C &&
+ git clean -f &&
+ rm -rf a/ &&
+ echo 5 >a &&
+ git add a &&
+ test_tick &&
+ git commit -m D &&
+ git tag D &&
+
+ git checkout C^0 &&
+ test_must_fail git merge B &&
+ git clean -f &&
+ git rm --cached a &&
+ echo 10 >a/file &&
+ git add a/file &&
+ test_tick &&
+ git commit -m E1 &&
+ git tag E1 &&
+
+ git checkout C^0 &&
+ test_must_fail git merge B &&
+ git clean -f &&
+ git rm --cached a &&
+ printf "10\n11\n" >a/file &&
+ git add a/file &&
+ test_tick &&
+ git commit -m E2 &&
+ git tag E2
+'
+
+test_expect_success 'merge of D & E1 fails but has appropriate contents' '
+ get_clean_checkout D^0 &&
+
+ test_must_fail git merge -s recursive E1^0 &&
+
+ test 2 -eq $(git ls-files -s | wc -l) &&
+ test 1 -eq $(git ls-files -u | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+
+ test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) &&
+ test $(git rev-parse :2:a) = $(git rev-parse B:a)
+'
+
+test_expect_success 'merge of E1 & D fails but has appropriate contents' '
+ get_clean_checkout E1^0 &&
+
+ test_must_fail git merge -s recursive D^0 &&
+
+ test 2 -eq $(git ls-files -s | wc -l) &&
+ test 1 -eq $(git ls-files -u | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+
+ test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) &&
+ test $(git rev-parse :3:a) = $(git rev-parse B:a)
+'
+
+test_expect_success 'merge of D & E2 fails but has appropriate contents' '
+ get_clean_checkout D^0 &&
+
+ test_must_fail git merge -s recursive E2^0 &&
+
+ test 4 -eq $(git ls-files -s | wc -l) &&
+ test 3 -eq $(git ls-files -u | wc -l) &&
+ test 1 -eq $(git ls-files -o | wc -l) &&
+
+ test $(git rev-parse :2:a) = $(git rev-parse B:a) &&
+ test $(git rev-parse :3:a/file) = $(git rev-parse E2:a/file) &&
+ test $(git rev-parse :1:a/file) = $(git rev-parse C:a/file) &&
+ test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) &&
+
+ test -f a~HEAD
+'
+
+test_expect_success 'merge of E2 & D fails but has appropriate contents' '
+ get_clean_checkout E2^0 &&
+
+ test_must_fail git merge -s recursive D^0 &&
+
+ test 4 -eq $(git ls-files -s | wc -l) &&
+ test 3 -eq $(git ls-files -u | wc -l) &&
+ test 1 -eq $(git ls-files -o | wc -l) &&
+
+ test $(git rev-parse :3:a) = $(git rev-parse B:a) &&
+ test $(git rev-parse :2:a/file) = $(git rev-parse E2:a/file) &&
+ test $(git rev-parse :1:a/file) = $(git rev-parse C:a/file)
+ test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) &&
+
+ test -f a~D^0
+'
+
+#
+# criss-cross with rename/rename(1to2)/modify followed by
+# rename/rename(2to1)/modify:
+#
+# B D
+# o---o
+# / \ / \
+# A o X ? F
+# \ / \ /
+# o---o
+# C E
+#
+# Commit A: new file: a
+# Commit B: rename a->b, modifying by adding a line
+# Commit C: rename a->c
+# Commit D: merge B&C, resolving conflict by keeping contents in newname
+# Commit E: merge B&C, resolving conflict similar to D but adding another line
+#
+# There is a conflict merging B & C, but one of filename not of file
+# content. Whoever created D and E chose specific resolutions for that
+# conflict resolution. Now, since: (1) there is no content conflict
+# merging B & C, (2) D does not modify that merged content further, and (3)
+# both D & E resolve the name conflict in the same way, the modification to
+# newname in E should not cause any conflicts when it is merged with D.
+# (Note that this can be accomplished by having the virtual merge base have
+# the merged contents of b and c stored in a file named a, which seems like
+# the most logical choice anyway.)
+#
+# Comment from Junio: I do not necessarily agree with the choice "a", but
+# it feels sound to say "B and C do not agree what the final pathname
+# should be, but we know this content was derived from the common A:a so we
+# use one path whose name is arbitrary in the virtual merge base X between
+# D and E" and then further let the rename detection to notice that that
+# arbitrary path gets renamed between X-D to "newname" and X-E also to
+# "newname" to resolve it as both sides renaming it to the same new
+# name. It is akin to what we do at the content level, i.e. "B and C do not
+# agree what the final contents should be, so we leave the conflict marker
+# but that may cancel out at the final merge stage".
+
+test_expect_success 'setup rename/rename(1to2)/modify followed by what looks like rename/rename(2to1)/modify' '
+ git reset --hard &&
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ printf "1\n2\n3\n4\n5\n6\n" >a &&
+ git add a &&
+ git commit -m A &&
+ git tag A &&
+
+ git checkout -b B A &&
+ git mv a b &&
+ echo 7 >>b &&
+ git add -u &&
+ git commit -m B &&
+
+ git checkout -b C A &&
+ git mv a c &&
+ git commit -m C &&
+
+ git checkout -q B^0 &&
+ git merge --no-commit -s ours C^0 &&
+ git mv b newname &&
+ git commit -m "Merge commit C^0 into HEAD" &&
+ git tag D &&
+
+ git checkout -q C^0 &&
+ git merge --no-commit -s ours B^0 &&
+ git mv c newname &&
+ printf "7\n8\n" >>newname &&
+ git add -u &&
+ git commit -m "Merge commit B^0 into HEAD" &&
+ git tag E
+'
+
+test_expect_success 'handle rename/rename(1to2)/modify followed by what looks like rename/rename(2to1)/modify' '
+ git checkout D^0 &&
+
+ git merge -s recursive E^0 &&
+
+ test 1 -eq $(git ls-files -s | wc -l) &&
+ test 0 -eq $(git ls-files -u | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+
+ test $(git rev-parse HEAD:newname) = $(git rev-parse E:newname)
+'
+
+#
+# criss-cross with rename/rename(1to2)/add-source + resolvable modify/modify:
+#
+# B D
+# o---o
+# / \ / \
+# A o X ? F
+# \ / \ /
+# o---o
+# C E
+#
+# Commit A: new file: a
+# Commit B: rename a->b
+# Commit C: rename a->c, add different a
+# Commit D: merge B&C, keeping b&c and (new) a modified at beginning
+# Commit E: merge B&C, keeping b&c and (new) a modified at end
+#
+# Merging commits D & E should result in no conflict; doing so correctly
+# requires getting the virtual merge base (from merging B&C) right, handling
+# renaming carefully (both in the virtual merge base and later), and getting
+# content merge handled.
+
+test_expect_success 'setup criss-cross + rename/rename/add + modify/modify' '
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ printf "lots\nof\nwords\nand\ncontent\n" >a &&
+ git add a &&
+ git commit -m A &&
+ git tag A &&
+
+ git checkout -b B A &&
+ git mv a b &&
+ git commit -m B &&
+
+ git checkout -b C A &&
+ git mv a c &&
+ printf "2\n3\n4\n5\n6\n7\n" >a &&
+ git add a &&
+ git commit -m C &&
+
+ git checkout B^0 &&
+ git merge --no-commit -s ours C^0 &&
+ git checkout C -- a c &&
+ mv a old_a &&
+ echo 1 >a &&
+ cat old_a >>a &&
+ rm old_a &&
+ git add -u &&
+ git commit -m "Merge commit C^0 into HEAD" &&
+ git tag D &&
+
+ git checkout C^0 &&
+ git merge --no-commit -s ours B^0 &&
+ git checkout B -- b &&
+ echo 8 >>a &&
+ git add -u &&
+ git commit -m "Merge commit B^0 into HEAD" &&
+ git tag E
+'
+
+test_expect_failure 'detect rename/rename/add-source for virtual merge-base' '
+ git checkout D^0 &&
+
+ git merge -s recursive E^0 &&
+
+ test 3 -eq $(git ls-files -s | wc -l) &&
+ test 0 -eq $(git ls-files -u | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+
+ test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
+ test $(git rev-parse HEAD:c) = $(git rev-parse A:a) &&
+ test "$(cat a)" = "$(printf "1\n2\n3\n4\n5\n6\n7\n8\n")"
+'
+
+#
+# criss-cross with rename/rename(1to2)/add-dest + simple modify:
+#
+# B D
+# o---o
+# / \ / \
+# A o X ? F
+# \ / \ /
+# o---o
+# C E
+#
+# Commit A: new file: a
+# Commit B: rename a->b, add c
+# Commit C: rename a->c
+# Commit D: merge B&C, keeping A:a and B:c
+# Commit E: merge B&C, keeping A:a and slightly modified c from B
+#
+# Merging commits D & E should result in no conflict. The virtual merge
+# base of B & C needs to not delete B:c for that to work, though...
+
+test_expect_success 'setup criss-cross+rename/rename/add-dest + simple modify' '
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ >a &&
+ git add a &&
+ git commit -m A &&
+ git tag A &&
+
+ git checkout -b B A &&
+ git mv a b &&
+ printf "1\n2\n3\n4\n5\n6\n7\n" >c &&
+ git add c &&
+ git commit -m B &&
+
+ git checkout -b C A &&
+ git mv a c &&
+ git commit -m C &&
+
+ git checkout B^0 &&
+ git merge --no-commit -s ours C^0 &&
+ git mv b a &&
+ git commit -m "D is like B but renames b back to a" &&
+ git tag D &&
+
+ git checkout B^0 &&
+ git merge --no-commit -s ours C^0 &&
+ git mv b a &&
+ echo 8 >>c &&
+ git add c &&
+ git commit -m "E like D but has mod in c" &&
+ git tag E
+'
+
+test_expect_success 'virtual merge base handles rename/rename(1to2)/add-dest' '
+ git checkout D^0 &&
+
+ git merge -s recursive E^0 &&
+
+ test 2 -eq $(git ls-files -s | wc -l) &&
+ test 0 -eq $(git ls-files -u | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+
+ test $(git rev-parse HEAD:a) = $(git rev-parse A:a) &&
+ test $(git rev-parse HEAD:c) = $(git rev-parse E:c)
+'
+
test_done
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index 1e0447f615..19272bc551 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -48,7 +48,23 @@ test_expect_success 'branch -v' '
git branch -v
) |
sed -n -e "$script" >actual &&
- test_cmp expect actual
+ test_i18ncmp expect actual
+'
+
+cat >expect <<\EOF
+b1 origin/master: ahead 1, behind 1
+b2 origin/master: ahead 1, behind 1
+b3 origin/master: behind 1
+b4 origin/master: ahead 2
+EOF
+
+test_expect_success 'branch -vv' '
+ (
+ cd test &&
+ git branch -vv
+ ) |
+ sed -n -e "$script" >actual &&
+ test_i18ncmp expect actual
'
test_expect_success 'checkout' '
@@ -74,20 +90,20 @@ test_expect_success 'status' '
grep "have 1 and 1 different" actual
'
-test_expect_success 'status when tracking lightweight tags' '
+test_expect_success 'fail to track lightweight tags' '
git checkout master &&
git tag light &&
- git branch --track lighttrack light >actual &&
- grep "set up to track" actual &&
- git checkout lighttrack
+ test_must_fail git branch --track lighttrack light >actual &&
+ test_must_fail grep "set up to track" actual &&
+ test_must_fail git checkout lighttrack
'
-test_expect_success 'status when tracking annotated tags' '
+test_expect_success 'fail to track annotated tags' '
git checkout master &&
git tag -m heavy heavy &&
- git branch --track heavytrack heavy >actual &&
- grep "set up to track" actual &&
- git checkout heavytrack
+ test_must_fail git branch --track heavytrack heavy >actual &&
+ test_must_fail grep "set up to track" actual &&
+ test_must_fail git checkout heavytrack
'
test_expect_success 'setup tracking with branch --set-upstream on existing branch' '
@@ -110,4 +126,18 @@ test_expect_success '--set-upstream does not change branch' '
grep -q "^refs/heads/master$" actual &&
cmp expect2 actual2
'
+
+test_expect_success '--set-upstream @{-1}' '
+ git checkout from-master &&
+ git checkout from-master2 &&
+ git config branch.from-master2.merge > expect2 &&
+ git branch --set-upstream @{-1} follower &&
+ git config branch.from-master.merge > actual &&
+ git config branch.from-master2.merge > actual2 &&
+ git branch --set-upstream from-master follower &&
+ git config branch.from-master.merge > expect &&
+ test_cmp expect2 actual2 &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t6042-merge-rename-corner-cases.sh b/t/t6042-merge-rename-corner-cases.sh
new file mode 100755
index 0000000000..32591f9413
--- /dev/null
+++ b/t/t6042-merge-rename-corner-cases.sh
@@ -0,0 +1,578 @@
+#!/bin/sh
+
+test_description="recursive merge corner cases w/ renames but not criss-crosses"
+# t6036 has corner cases that involve both criss-cross merges and renames
+
+. ./test-lib.sh
+
+test_expect_success 'setup rename/delete + untracked file' '
+ echo "A pretty inscription" >ring &&
+ git add ring &&
+ test_tick &&
+ git commit -m beginning &&
+
+ git branch people &&
+ git checkout -b rename-the-ring &&
+ git mv ring one-ring-to-rule-them-all &&
+ test_tick &&
+ git commit -m fullname &&
+
+ git checkout people &&
+ git rm ring &&
+ echo gollum >owner &&
+ git add owner &&
+ test_tick &&
+ git commit -m track-people-instead-of-objects &&
+ echo "Myyy PRECIOUSSS" >ring
+'
+
+test_expect_success "Does git preserve Gollum's precious artifact?" '
+ test_must_fail git merge -s recursive rename-the-ring &&
+
+ # Make sure git did not delete an untracked file
+ test -f ring
+'
+
+# Testcase setup for rename/modify/add-source:
+# Commit A: new file: a
+# Commit B: modify a slightly
+# Commit C: rename a->b, add completely different a
+#
+# We should be able to merge B & C cleanly
+
+test_expect_success 'setup rename/modify/add-source conflict' '
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
+ git add a &&
+ git commit -m A &&
+ git tag A &&
+
+ git checkout -b B A &&
+ echo 8 >>a &&
+ git add a &&
+ git commit -m B &&
+
+ git checkout -b C A &&
+ git mv a b &&
+ echo something completely different >a &&
+ git add a &&
+ git commit -m C
+'
+
+test_expect_failure 'rename/modify/add-source conflict resolvable' '
+ git checkout B^0 &&
+
+ git merge -s recursive C^0 &&
+
+ test $(git rev-parse B:a) = $(git rev-parse b) &&
+ test $(git rev-parse C:a) = $(git rev-parse a)
+'
+
+test_expect_success 'setup resolvable conflict missed if rename missed' '
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ printf "1\n2\n3\n4\n5\n" >a &&
+ echo foo >b &&
+ git add a b &&
+ git commit -m A &&
+ git tag A &&
+
+ git checkout -b B A &&
+ git mv a c &&
+ echo "Completely different content" >a &&
+ git add a &&
+ git commit -m B &&
+
+ git checkout -b C A &&
+ echo 6 >>a &&
+ git add a &&
+ git commit -m C
+'
+
+test_expect_failure 'conflict caused if rename not detected' '
+ git checkout -q C^0 &&
+ git merge -s recursive B^0 &&
+
+ test 3 -eq $(git ls-files -s | wc -l) &&
+ test 0 -eq $(git ls-files -u | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+
+ test 6 -eq $(wc -l < c) &&
+ test $(git rev-parse HEAD:a) = $(git rev-parse B:a) &&
+ test $(git rev-parse HEAD:b) = $(git rev-parse A:b)
+'
+
+test_expect_success 'setup conflict resolved wrong if rename missed' '
+ git reset --hard &&
+ git clean -f &&
+
+ git checkout -b D A &&
+ echo 7 >>a &&
+ git add a &&
+ git mv a c &&
+ echo "Completely different content" >a &&
+ git add a &&
+ git commit -m D &&
+
+ git checkout -b E A &&
+ git rm a &&
+ echo "Completely different content" >>a &&
+ git add a &&
+ git commit -m E
+'
+
+test_expect_failure 'missed conflict if rename not detected' '
+ git checkout -q E^0 &&
+ test_must_fail git merge -s recursive D^0
+'
+
+# Tests for undetected rename/add-source causing a file to erroneously be
+# deleted (and for mishandled rename/rename(1to1) causing the same issue).
+#
+# This test uses a rename/rename(1to1)+add-source conflict (1to1 means the
+# same file is renamed on both sides to the same thing; it should trigger
+# the 1to2 logic, which it would do if the add-source didn't cause issues
+# for git's rename detection):
+# Commit A: new file: a
+# Commit B: rename a->b
+# Commit C: rename a->b, add unrelated a
+
+test_expect_success 'setup undetected rename/add-source causes data loss' '
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ printf "1\n2\n3\n4\n5\n" >a &&
+ git add a &&
+ git commit -m A &&
+ git tag A &&
+
+ git checkout -b B A &&
+ git mv a b &&
+ git commit -m B &&
+
+ git checkout -b C A &&
+ git mv a b &&
+ echo foobar >a &&
+ git add a &&
+ git commit -m C
+'
+
+test_expect_failure 'detect rename/add-source and preserve all data' '
+ git checkout B^0 &&
+
+ git merge -s recursive C^0 &&
+
+ test 2 -eq $(git ls-files -s | wc -l) &&
+ test 2 -eq $(git ls-files -u | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+
+ test -f a &&
+ test -f b &&
+
+ test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
+ test $(git rev-parse HEAD:a) = $(git rev-parse C:a)
+'
+
+test_expect_failure 'detect rename/add-source and preserve all data, merge other way' '
+ git checkout C^0 &&
+
+ git merge -s recursive B^0 &&
+
+ test 2 -eq $(git ls-files -s | wc -l) &&
+ test 2 -eq $(git ls-files -u | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+
+ test -f a &&
+ test -f b &&
+
+ test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
+ test $(git rev-parse HEAD:a) = $(git rev-parse C:a)
+'
+
+test_expect_success 'setup content merge + rename/directory conflict' '
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ printf "1\n2\n3\n4\n5\n6\n" >file &&
+ git add file &&
+ test_tick &&
+ git commit -m base &&
+ git tag base &&
+
+ git checkout -b right &&
+ echo 7 >>file &&
+ mkdir newfile &&
+ echo junk >newfile/realfile &&
+ git add file newfile/realfile &&
+ test_tick &&
+ git commit -m right &&
+
+ git checkout -b left-conflict base &&
+ echo 8 >>file &&
+ git add file &&
+ git mv file newfile &&
+ test_tick &&
+ git commit -m left &&
+
+ git checkout -b left-clean base &&
+ echo 0 >newfile &&
+ cat file >>newfile &&
+ git add newfile &&
+ git rm file &&
+ test_tick &&
+ git commit -m left
+'
+
+test_expect_success 'rename/directory conflict + clean content merge' '
+ git reset --hard &&
+ git reset --hard &&
+ git clean -fdqx &&
+
+ git checkout left-clean^0 &&
+
+ test_must_fail git merge -s recursive right^0 &&
+
+ test 2 -eq $(git ls-files -s | wc -l) &&
+ test 1 -eq $(git ls-files -u | wc -l) &&
+ test 1 -eq $(git ls-files -o | wc -l) &&
+
+ echo 0 >expect &&
+ git cat-file -p base:file >>expect &&
+ echo 7 >>expect &&
+ test_cmp expect newfile~HEAD &&
+
+ test $(git rev-parse :2:newfile) = $(git hash-object expect) &&
+
+ test -f newfile/realfile &&
+ test -f newfile~HEAD
+'
+
+test_expect_success 'rename/directory conflict + content merge conflict' '
+ git reset --hard &&
+ git reset --hard &&
+ git clean -fdqx &&
+
+ git checkout left-conflict^0 &&
+
+ test_must_fail git merge -s recursive right^0 &&
+
+ test 4 -eq $(git ls-files -s | wc -l) &&
+ test 3 -eq $(git ls-files -u | wc -l) &&
+ test 1 -eq $(git ls-files -o | wc -l) &&
+
+ git cat-file -p left-conflict:newfile >left &&
+ git cat-file -p base:file >base &&
+ git cat-file -p right:file >right &&
+ test_must_fail git merge-file \
+ -L "HEAD:newfile" \
+ -L "" \
+ -L "right^0:file" \
+ left base right &&
+ test_cmp left newfile~HEAD &&
+
+ test $(git rev-parse :1:newfile) = $(git rev-parse base:file) &&
+ test $(git rev-parse :2:newfile) = $(git rev-parse left-conflict:newfile) &&
+ test $(git rev-parse :3:newfile) = $(git rev-parse right:file) &&
+
+ test -f newfile/realfile &&
+ test -f newfile~HEAD
+'
+
+test_expect_success 'setup content merge + rename/directory conflict w/ disappearing dir' '
+ git reset --hard &&
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ mkdir sub &&
+ printf "1\n2\n3\n4\n5\n6\n" >sub/file &&
+ git add sub/file &&
+ test_tick &&
+ git commit -m base &&
+ git tag base &&
+
+ git checkout -b right &&
+ echo 7 >>sub/file &&
+ git add sub/file &&
+ test_tick &&
+ git commit -m right &&
+
+ git checkout -b left base &&
+ echo 0 >newfile &&
+ cat sub/file >>newfile &&
+ git rm sub/file &&
+ mv newfile sub &&
+ git add sub &&
+ test_tick &&
+ git commit -m left
+'
+
+test_expect_success 'disappearing dir in rename/directory conflict handled' '
+ git reset --hard &&
+ git clean -fdqx &&
+
+ git checkout left^0 &&
+
+ git merge -s recursive right^0 &&
+
+ test 1 -eq $(git ls-files -s | wc -l) &&
+ test 0 -eq $(git ls-files -u | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+
+ echo 0 >expect &&
+ git cat-file -p base:sub/file >>expect &&
+ echo 7 >>expect &&
+ test_cmp expect sub &&
+
+ test -f sub
+'
+
+# Test for all kinds of things that can go wrong with rename/rename (2to1):
+# Commit A: new files: a & b
+# Commit B: rename a->c, modify b
+# Commit C: rename b->c, modify a
+#
+# Merging of B & C should NOT be clean. Questions:
+# * Both a & b should be removed by the merge; are they?
+# * The two c's should contain modifications to a & b; do they?
+# * The index should contain two files, both for c; does it?
+# * The working copy should have two files, both of form c~<unique>; does it?
+# * Nothing else should be present. Is anything?
+
+test_expect_success 'setup rename/rename (2to1) + modify/modify' '
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ printf "1\n2\n3\n4\n5\n" >a &&
+ printf "5\n4\n3\n2\n1\n" >b &&
+ git add a b &&
+ git commit -m A &&
+ git tag A &&
+
+ git checkout -b B A &&
+ git mv a c &&
+ echo 0 >>b &&
+ git add b &&
+ git commit -m B &&
+
+ git checkout -b C A &&
+ git mv b c &&
+ echo 6 >>a &&
+ git add a &&
+ git commit -m C
+'
+
+test_expect_success 'handle rename/rename (2to1) conflict correctly' '
+ git checkout B^0 &&
+
+ test_must_fail git merge -s recursive C^0 >out &&
+ grep "CONFLICT (rename/rename)" out &&
+
+ test 2 -eq $(git ls-files -s | wc -l) &&
+ test 2 -eq $(git ls-files -u | wc -l) &&
+ test 2 -eq $(git ls-files -u c | wc -l) &&
+ test 3 -eq $(git ls-files -o | wc -l) &&
+
+ test ! -f a &&
+ test ! -f b &&
+ test -f c~HEAD &&
+ test -f c~C^0 &&
+
+ test $(git hash-object c~HEAD) = $(git rev-parse C:a) &&
+ test $(git hash-object c~C^0) = $(git rev-parse B:b)
+'
+
+# Testcase setup for simple rename/rename (1to2) conflict:
+# Commit A: new file: a
+# Commit B: rename a->b
+# Commit C: rename a->c
+test_expect_success 'setup simple rename/rename (1to2) conflict' '
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ echo stuff >a &&
+ git add a &&
+ test_tick &&
+ git commit -m A &&
+ git tag A &&
+
+ git checkout -b B A &&
+ git mv a b &&
+ test_tick &&
+ git commit -m B &&
+
+ git checkout -b C A &&
+ git mv a c &&
+ test_tick &&
+ git commit -m C
+'
+
+test_expect_success 'merge has correct working tree contents' '
+ git checkout C^0 &&
+
+ test_must_fail git merge -s recursive B^0 &&
+
+ test 3 -eq $(git ls-files -s | wc -l) &&
+ test 3 -eq $(git ls-files -u | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+
+ test $(git rev-parse :1:a) = $(git rev-parse A:a) &&
+ test $(git rev-parse :3:b) = $(git rev-parse A:a) &&
+ test $(git rev-parse :2:c) = $(git rev-parse A:a) &&
+
+ test ! -f a &&
+ test $(git hash-object b) = $(git rev-parse A:a) &&
+ test $(git hash-object c) = $(git rev-parse A:a)
+'
+
+# Testcase setup for rename/rename(1to2)/add-source conflict:
+# Commit A: new file: a
+# Commit B: rename a->b
+# Commit C: rename a->c, add completely different a
+#
+# Merging of B & C should NOT be clean; there's a rename/rename conflict
+
+test_expect_success 'setup rename/rename(1to2)/add-source conflict' '
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
+ git add a &&
+ git commit -m A &&
+ git tag A &&
+
+ git checkout -b B A &&
+ git mv a b &&
+ git commit -m B &&
+
+ git checkout -b C A &&
+ git mv a c &&
+ echo something completely different >a &&
+ git add a &&
+ git commit -m C
+'
+
+test_expect_failure 'detect conflict with rename/rename(1to2)/add-source merge' '
+ git checkout B^0 &&
+
+ test_must_fail git merge -s recursive C^0 &&
+
+ test 4 -eq $(git ls-files -s | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+
+ test $(git rev-parse 3:a) = $(git rev-parse C:a) &&
+ test $(git rev-parse 1:a) = $(git rev-parse A:a) &&
+ test $(git rev-parse 2:b) = $(git rev-parse B:b) &&
+ test $(git rev-parse 3:c) = $(git rev-parse C:c) &&
+
+ test -f a &&
+ test -f b &&
+ test -f c
+'
+
+test_expect_success 'setup rename/rename(1to2)/add-source resolvable conflict' '
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ >a &&
+ git add a &&
+ test_tick &&
+ git commit -m base &&
+ git tag A &&
+
+ git checkout -b B A &&
+ git mv a b &&
+ test_tick &&
+ git commit -m one &&
+
+ git checkout -b C A &&
+ git mv a b &&
+ echo important-info >a &&
+ git add a &&
+ test_tick &&
+ git commit -m two
+'
+
+test_expect_failure 'rename/rename/add-source still tracks new a file' '
+ git checkout C^0 &&
+ git merge -s recursive B^0 &&
+
+ test 2 -eq $(git ls-files -s | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+
+ test $(git rev-parse HEAD:a) = $(git rev-parse C:a) &&
+ test $(git rev-parse HEAD:b) = $(git rev-parse A:a)
+'
+
+test_expect_success 'setup rename/rename(1to2)/add-dest conflict' '
+ git rm -rf . &&
+ git clean -fdqx &&
+ rm -rf .git &&
+ git init &&
+
+ echo stuff >a &&
+ git add a &&
+ test_tick &&
+ git commit -m base &&
+ git tag A &&
+
+ git checkout -b B A &&
+ git mv a b &&
+ echo precious-data >c &&
+ git add c &&
+ test_tick &&
+ git commit -m one &&
+
+ git checkout -b C A &&
+ git mv a c &&
+ echo important-info >b &&
+ git add b &&
+ test_tick &&
+ git commit -m two
+'
+
+test_expect_success 'rename/rename/add-dest merge still knows about conflicting file versions' '
+ git checkout C^0 &&
+ test_must_fail git merge -s recursive B^0 &&
+
+ test 5 -eq $(git ls-files -s | wc -l) &&
+ test 2 -eq $(git ls-files -u b | wc -l) &&
+ test 2 -eq $(git ls-files -u c | wc -l) &&
+ test 4 -eq $(git ls-files -o | wc -l) &&
+
+ test $(git rev-parse :1:a) = $(git rev-parse A:a) &&
+ test $(git rev-parse :2:b) = $(git rev-parse C:b) &&
+ test $(git rev-parse :3:b) = $(git rev-parse B:b) &&
+ test $(git rev-parse :2:c) = $(git rev-parse C:c) &&
+ test $(git rev-parse :3:c) = $(git rev-parse B:c) &&
+
+ test $(git hash-object c~HEAD) = $(git rev-parse C:c) &&
+ test $(git hash-object c~B\^0) = $(git rev-parse B:c) &&
+ test $(git hash-object b~HEAD) = $(git rev-parse C:b) &&
+ test $(git hash-object b~B\^0) = $(git rev-parse B:b) &&
+
+ test ! -f b &&
+ test ! -f c
+'
+
+test_done
diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh
index ae2194e07d..5c87f28e4e 100755
--- a/t/t6050-replace.sh
+++ b/t/t6050-replace.sh
@@ -236,6 +236,20 @@ test_expect_success 'index-pack and replacements' '
git index-pack test-*.pack
'
-#
-#
+test_expect_success 'not just commits' '
+ echo replaced >file &&
+ git add file &&
+ REPLACED=$(git rev-parse :file) &&
+ mv file file.replaced &&
+
+ echo original >file &&
+ git add file &&
+ ORIGINAL=$(git rev-parse :file) &&
+ git update-ref refs/replace/$ORIGINAL $REPLACED &&
+ mv file file.original &&
+
+ git checkout file &&
+ test_cmp file.replaced file
+'
+
test_done
diff --git a/t/t6060-merge-index.sh b/t/t6060-merge-index.sh
new file mode 100755
index 0000000000..debadbd299
--- /dev/null
+++ b/t/t6060-merge-index.sh
@@ -0,0 +1,100 @@
+#!/bin/sh
+
+test_description='basic git merge-index / git-merge-one-file tests'
+. ./test-lib.sh
+
+test_expect_success 'setup diverging branches' '
+ for i in 1 2 3 4 5 6 7 8 9 10; do
+ echo $i
+ done >file &&
+ git add file &&
+ git commit -m base &&
+ git tag base &&
+ sed s/2/two/ <file >tmp &&
+ mv tmp file &&
+ git commit -a -m two &&
+ git tag two &&
+ git checkout -b other HEAD^ &&
+ sed s/10/ten/ <file >tmp &&
+ mv tmp file &&
+ git commit -a -m ten &&
+ git tag ten
+'
+
+cat >expect-merged <<'EOF'
+1
+two
+3
+4
+5
+6
+7
+8
+9
+ten
+EOF
+
+test_expect_success 'read-tree does not resolve content merge' '
+ git read-tree -i -m base ten two &&
+ echo file >expect &&
+ git diff-files --name-only --diff-filter=U >unmerged &&
+ test_cmp expect unmerged
+'
+
+test_expect_success 'git merge-index git-merge-one-file resolves' '
+ git merge-index git-merge-one-file -a &&
+ git diff-files --name-only --diff-filter=U >unmerged &&
+ >expect &&
+ test_cmp expect unmerged &&
+ test_cmp expect-merged file &&
+ git cat-file blob :file >file-index &&
+ test_cmp expect-merged file-index
+'
+
+test_expect_success 'setup bare merge' '
+ git clone --bare . bare.git &&
+ (cd bare.git &&
+ GIT_INDEX_FILE=$PWD/merge.index &&
+ export GIT_INDEX_FILE &&
+ git read-tree -i -m base ten two
+ )
+'
+
+test_expect_success 'merge-one-file fails without a work tree' '
+ (cd bare.git &&
+ GIT_INDEX_FILE=$PWD/merge.index &&
+ export GIT_INDEX_FILE &&
+ test_must_fail git merge-index git-merge-one-file -a
+ )
+'
+
+test_expect_success 'merge-one-file respects GIT_WORK_TREE' '
+ (cd bare.git &&
+ mkdir work &&
+ GIT_WORK_TREE=$PWD/work &&
+ export GIT_WORK_TREE &&
+ GIT_INDEX_FILE=$PWD/merge.index &&
+ export GIT_INDEX_FILE &&
+ git merge-index git-merge-one-file -a &&
+ git cat-file blob :file >work/file-index
+ ) &&
+ test_cmp expect-merged bare.git/work/file &&
+ test_cmp expect-merged bare.git/work/file-index
+'
+
+test_expect_success 'merge-one-file respects core.worktree' '
+ mkdir subdir &&
+ git clone . subdir/child &&
+ (cd subdir &&
+ GIT_DIR=$PWD/child/.git &&
+ export GIT_DIR &&
+ git config core.worktree "$PWD/child" &&
+ git read-tree -i -m base ten two &&
+ git merge-index git-merge-one-file -a &&
+ git cat-file blob :file >file-index
+ ) &&
+ test_cmp expect-merged subdir/child/file &&
+ test_cmp expect-merged subdir/file-index
+'
+
+test_done
diff --git a/t/t6110-rev-list-sparse.sh b/t/t6110-rev-list-sparse.sh
new file mode 100755
index 0000000000..656ac7fe9d
--- /dev/null
+++ b/t/t6110-rev-list-sparse.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+test_description='operations that cull histories in unusual ways'
+. ./test-lib.sh
+
+test_expect_success setup '
+ test_commit A &&
+ test_commit B &&
+ test_commit C &&
+ git checkout -b side HEAD^ &&
+ test_commit D &&
+ test_commit E &&
+ git merge master
+'
+
+test_expect_success 'rev-list --first-parent --boundary' '
+ git rev-list --first-parent --boundary HEAD^..
+'
+
+test_done
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 876d1ab743..f67aa6ff6a 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -124,7 +124,7 @@ warning: tag 'A' is really 'Q' here
EOF
check_describe A-* HEAD
test_expect_success 'warning was displayed for Q' '
- test_cmp err.expect err.actual
+ test_i18ncmp err.expect err.actual
'
test_expect_success 'rename tag Q back to A' '
mv .git/refs/tags/Q .git/refs/tags/A
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 7dc8a510c7..172178490a 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -6,6 +6,7 @@
test_description='for-each-ref test'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-gpg.sh
# Mon Jul 3 15:18:43 2006 +0000
datestamp=1151939923
@@ -37,11 +38,13 @@ test_atom() {
case "$1" in
head) ref=refs/heads/master ;;
tag) ref=refs/tags/testtag ;;
+ *) ref=$1 ;;
esac
printf '%s\n' "$3" >expected
- test_expect_${4:-success} "basic atom: $1 $2" "
+ test_expect_${4:-success} $PREREQ "basic atom: $1 $2" "
git for-each-ref --format='%($2)' $ref >actual &&
- test_cmp expected actual
+ sanitize_pgp <actual >actual.clean &&
+ test_cmp expected actual.clean
"
}
@@ -71,7 +74,10 @@ test_atom head taggerdate ''
test_atom head creator 'C O Mitter <committer@example.com> 1151939923 +0200'
test_atom head creatordate 'Mon Jul 3 17:18:43 2006 +0200'
test_atom head subject 'Initial'
+test_atom head contents:subject 'Initial'
test_atom head body ''
+test_atom head contents:body ''
+test_atom head contents:signature ''
test_atom head contents 'Initial
'
@@ -101,7 +107,10 @@ test_atom tag taggerdate 'Mon Jul 3 17:18:45 2006 +0200'
test_atom tag creator 'C O Mitter <committer@example.com> 1151939925 +0200'
test_atom tag creatordate 'Mon Jul 3 17:18:45 2006 +0200'
test_atom tag subject 'Tagging at 1151939927'
+test_atom tag contents:subject 'Tagging at 1151939927'
test_atom tag body ''
+test_atom tag contents:body ''
+test_atom tag contents:signature ''
test_atom tag contents 'Tagging at 1151939927
'
@@ -359,4 +368,92 @@ test_expect_success 'an unusual tag with an incomplete line' '
'
+test_expect_success 'create tag with subject and body content' '
+ cat >>msg <<-\EOF &&
+ the subject line
+
+ first body line
+ second body line
+ EOF
+ git tag -F msg subject-body
+'
+test_atom refs/tags/subject-body subject 'the subject line'
+test_atom refs/tags/subject-body body 'first body line
+second body line
+'
+test_atom refs/tags/subject-body contents 'the subject line
+
+first body line
+second body line
+'
+
+test_expect_success 'create tag with multiline subject' '
+ cat >msg <<-\EOF &&
+ first subject line
+ second subject line
+
+ first body line
+ second body line
+ EOF
+ git tag -F msg multiline
+'
+test_atom refs/tags/multiline subject 'first subject line second subject line'
+test_atom refs/tags/multiline contents:subject 'first subject line second subject line'
+test_atom refs/tags/multiline body 'first body line
+second body line
+'
+test_atom refs/tags/multiline contents:body 'first body line
+second body line
+'
+test_atom refs/tags/multiline contents:signature ''
+test_atom refs/tags/multiline contents 'first subject line
+second subject line
+
+first body line
+second body line
+'
+
+test_expect_success GPG 'create signed tags' '
+ git tag -s -m "" signed-empty &&
+ git tag -s -m "subject line" signed-short &&
+ cat >msg <<-\EOF &&
+ subject line
+
+ body contents
+ EOF
+ git tag -s -F msg signed-long
+'
+
+sig='-----BEGIN PGP SIGNATURE-----
+-----END PGP SIGNATURE-----
+'
+
+PREREQ=GPG
+test_atom refs/tags/signed-empty subject ''
+test_atom refs/tags/signed-empty contents:subject ''
+test_atom refs/tags/signed-empty body "$sig"
+test_atom refs/tags/signed-empty contents:body ''
+test_atom refs/tags/signed-empty contents:signature "$sig"
+test_atom refs/tags/signed-empty contents "$sig"
+
+test_atom refs/tags/signed-short subject 'subject line'
+test_atom refs/tags/signed-short contents:subject 'subject line'
+test_atom refs/tags/signed-short body "$sig"
+test_atom refs/tags/signed-short contents:body ''
+test_atom refs/tags/signed-short contents:signature "$sig"
+test_atom refs/tags/signed-short contents "subject line
+$sig"
+
+test_atom refs/tags/signed-long subject 'subject line'
+test_atom refs/tags/signed-long contents:subject 'subject line'
+test_atom refs/tags/signed-long body "body contents
+$sig"
+test_atom refs/tags/signed-long contents:body 'body contents
+'
+test_atom refs/tags/signed-long contents:signature "$sig"
+test_atom refs/tags/signed-long contents "subject line
+
+body contents
+$sig"
+
test_done
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 3e7baaf89f..e93ac73829 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -8,6 +8,7 @@ test_description='git tag
Tests for operations with tags.'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-gpg.sh
# creating and listing lightweight tags:
@@ -257,6 +258,11 @@ test_expect_success \
test_cmp expect actual
'
+test_expect_success 'tag -l can accept multiple patterns' '
+ git tag -l "v1*" "v0*" >actual &&
+ test_cmp expect actual
+'
+
# creating and verifying lightweight tags:
test_expect_success \
@@ -580,24 +586,6 @@ test_expect_success \
test_cmp expect actual
'
-# subsequent tests require gpg; check if it is available
-gpg --version >/dev/null 2>/dev/null
-if [ $? -eq 127 ]; then
- say "# gpg not found - skipping tag signing and verification tests"
-else
- # As said here: http://www.gnupg.org/documentation/faqs.html#q6.19
- # the gpg version 1.0.6 didn't parse trust packets correctly, so for
- # that version, creation of signed tags using the generated key fails.
- case "$(gpg --version)" in
- 'gpg (GnuPG) 1.0.6'*)
- say "Skipping signed tag tests, because a bug in 1.0.6 version"
- ;;
- *)
- test_set_prereq GPG
- ;;
- esac
-fi
-
# trying to verify annotated non-signed tags:
test_expect_success GPG \
@@ -620,16 +608,6 @@ test_expect_success GPG \
# creating and verifying signed tags:
-# key generation info: gpg --homedir t/t7004 --gen-key
-# Type DSA and Elgamal, size 2048 bits, no expiration date.
-# Name and email: C O Mitter <committer@example.com>
-# No password given, to enable non-interactive operation.
-
-cp -R "$TEST_DIRECTORY"/t7004 ./gpghome
-chmod 0700 gpghome
-GNUPGHOME="$(pwd)/gpghome"
-export GNUPGHOME
-
get_tag_header signed-tag $commit commit $time >expect
echo 'A signed tag message' >>expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
@@ -1120,12 +1098,11 @@ test_expect_success \
! (GIT_EDITOR=cat git tag -a initial-comment > actual)
'
-test_expect_success \
- 'message in editor has initial comment: first line' '
+test_expect_success 'message in editor has initial comment: first line' '
# check the first line --- should be empty
echo >first.expect &&
sed -e 1q <actual >first.actual &&
- test_cmp first.expect first.actual
+ test_i18ncmp first.expect first.actual
'
test_expect_success \
diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh
index ed7575d0fd..320e1d1dbe 100755
--- a/t/t7006-pager.sh
+++ b/t/t7006-pager.sh
@@ -13,7 +13,7 @@ cleanup_fail() {
test_expect_success 'setup' '
sane_unset GIT_PAGER GIT_PAGER_IN_USE &&
- test_might_fail git config --unset core.pager &&
+ test_unconfig core.pager &&
PAGER="cat >paginated.out" &&
export PAGER &&
@@ -94,21 +94,19 @@ test_expect_success TTY 'no pager with --no-pager' '
test_expect_success TTY 'configuration can disable pager' '
rm -f paginated.out &&
- test_might_fail git config --unset pager.grep &&
+ test_unconfig pager.grep &&
test_terminal git grep initial &&
test -e paginated.out &&
rm -f paginated.out &&
- git config pager.grep false &&
- test_when_finished "git config --unset pager.grep" &&
+ test_config pager.grep false &&
test_terminal git grep initial &&
! test -e paginated.out
'
test_expect_success TTY 'git config uses a pager if configured to' '
rm -f paginated.out &&
- git config pager.config true &&
- test_when_finished "git config --unset pager.config" &&
+ test_config pager.config true &&
test_terminal git config --list &&
test -e paginated.out
'
@@ -116,8 +114,7 @@ test_expect_success TTY 'git config uses a pager if configured to' '
test_expect_success TTY 'configuration can enable pager (from subdir)' '
rm -f paginated.out &&
mkdir -p subdir &&
- git config pager.bundle true &&
- test_when_finished "git config --unset pager.bundle" &&
+ test_config pager.bundle true &&
git bundle create test.bundle --all &&
rm -f paginated.out subdir/paginated.out &&
@@ -150,7 +147,7 @@ test_expect_success 'tests can detect color' '
test_expect_success 'no color when stdout is a regular file' '
rm -f colorless.log &&
- git config color.ui auto ||
+ test_config color.ui auto ||
cleanup_fail &&
git log >colorless.log &&
@@ -159,7 +156,7 @@ test_expect_success 'no color when stdout is a regular file' '
test_expect_success TTY 'color when writing to a pager' '
rm -f paginated.out &&
- git config color.ui auto ||
+ test_config color.ui auto ||
cleanup_fail &&
(
@@ -170,9 +167,21 @@ test_expect_success TTY 'color when writing to a pager' '
colorful paginated.out
'
+test_expect_success TTY 'colors are suppressed by color.pager' '
+ rm -f paginated.out &&
+ test_config color.ui auto &&
+ test_config color.pager false &&
+ (
+ TERM=vt100 &&
+ export TERM &&
+ test_terminal git log
+ ) &&
+ ! colorful paginated.out
+'
+
test_expect_success 'color when writing to a file intended for a pager' '
rm -f colorful.log &&
- git config color.ui auto ||
+ test_config color.ui auto ||
cleanup_fail &&
(
@@ -184,6 +193,17 @@ test_expect_success 'color when writing to a file intended for a pager' '
colorful colorful.log
'
+test_expect_success TTY 'colors are sent to pager for external commands' '
+ test_config alias.externallog "!git log" &&
+ test_config color.ui auto &&
+ (
+ TERM=vt100 &&
+ export TERM &&
+ test_terminal git -p externallog
+ ) &&
+ colorful paginated.out
+'
+
# Use this helper to make it easy for the caller of your
# terminal-using function to specify whether it should fail.
# If you write
@@ -221,7 +241,7 @@ test_default_pager() {
$test_expectation SIMPLEPAGER,TTY "$cmd - default pager is used by default" "
sane_unset PAGER GIT_PAGER &&
- test_might_fail git config --unset core.pager &&
+ test_unconfig core.pager &&
rm -f default_pager_used ||
cleanup_fail &&
@@ -244,7 +264,7 @@ test_PAGER_overrides() {
$test_expectation TTY "$cmd - PAGER overrides default pager" "
sane_unset GIT_PAGER &&
- test_might_fail git config --unset core.pager &&
+ test_unconfig core.pager &&
rm -f PAGER_used ||
cleanup_fail &&
@@ -277,7 +297,7 @@ test_core_pager() {
PAGER=wc &&
export PAGER &&
- git config core.pager 'wc >core.pager_used' &&
+ test_config core.pager 'wc >core.pager_used' &&
$full_command &&
${if_local_config}test -e core.pager_used
"
@@ -307,7 +327,7 @@ test_pager_subdir_helper() {
PAGER=wc &&
stampname=\$(pwd)/core.pager_used &&
export PAGER stampname &&
- git config core.pager 'wc >\"\$stampname\"' &&
+ test_config core.pager 'wc >\"\$stampname\"' &&
mkdir sub &&
(
cd sub &&
@@ -324,7 +344,7 @@ test_GIT_PAGER_overrides() {
rm -f GIT_PAGER_used ||
cleanup_fail &&
- git config core.pager wc &&
+ test_config core.pager wc &&
GIT_PAGER='wc >GIT_PAGER_used' &&
export GIT_PAGER &&
$full_command &&
@@ -402,21 +422,21 @@ test_core_pager_subdir expect_success test_must_fail \
'git -p apply </dev/null'
test_expect_success TTY 'command-specific pager' '
- unset PAGER GIT_PAGER;
+ sane_unset PAGER GIT_PAGER &&
echo "foo:initial" >expect &&
>actual &&
- git config --unset core.pager &&
- git config pager.log "sed s/^/foo:/ >actual" &&
+ test_unconfig core.pager &&
+ test_config pager.log "sed s/^/foo:/ >actual" &&
test_terminal git log --format=%s -1 &&
test_cmp expect actual
'
test_expect_success TTY 'command-specific pager overrides core.pager' '
- unset PAGER GIT_PAGER;
+ sane_unset PAGER GIT_PAGER &&
echo "foo:initial" >expect &&
>actual &&
- git config core.pager "exit 1"
- git config pager.log "sed s/^/foo:/ >actual" &&
+ test_config core.pager "exit 1"
+ test_config pager.log "sed s/^/foo:/ >actual" &&
test_terminal git log --format=%s -1 &&
test_cmp expect actual
'
@@ -425,9 +445,45 @@ test_expect_success TTY 'command-specific pager overridden by environment' '
GIT_PAGER="sed s/^/foo:/ >actual" && export GIT_PAGER &&
>actual &&
echo "foo:initial" >expect &&
- git config pager.log "exit 1" &&
+ test_config pager.log "exit 1" &&
test_terminal git log --format=%s -1 &&
test_cmp expect actual
'
+test_expect_success 'setup external command' '
+ cat >git-external <<-\EOF &&
+ #!/bin/sh
+ git "$@"
+ EOF
+ chmod +x git-external
+'
+
+test_expect_success TTY 'command-specific pager works for external commands' '
+ sane_unset PAGER GIT_PAGER &&
+ echo "foo:initial" >expect &&
+ >actual &&
+ test_config pager.external "sed s/^/foo:/ >actual" &&
+ test_terminal git --exec-path="`pwd`" external log --format=%s -1 &&
+ test_cmp expect actual
+'
+
+test_expect_success TTY 'sub-commands of externals use their own pager' '
+ sane_unset PAGER GIT_PAGER &&
+ echo "foo:initial" >expect &&
+ >actual &&
+ test_config pager.log "sed s/^/foo:/ >actual" &&
+ test_terminal git --exec-path=. external log --format=%s -1 &&
+ test_cmp expect actual
+'
+
+test_expect_success TTY 'external command pagers override sub-commands' '
+ sane_unset PAGER GIT_PAGER &&
+ >expect &&
+ >actual &&
+ test_config pager.external false &&
+ test_config pager.log "sed s/^/log:/ >actual" &&
+ test_terminal git --exec-path=. external log --format=%s -1 &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t7008-grep-binary.sh b/t/t7008-grep-binary.sh
index e058d184d1..917a264eea 100755
--- a/t/t7008-grep-binary.sh
+++ b/t/t7008-grep-binary.sh
@@ -84,7 +84,7 @@ test_expect_success 'git grep -Fi Y<NUL>f a' "
git grep -f f -Fi a
"
-test_expect_failure 'git grep -Fi Y<NUL>x a' "
+test_expect_success 'git grep -Fi Y<NUL>x a' "
printf 'YQx' | q_to_nul >f &&
test_must_fail git grep -f f -Fi a
"
@@ -94,7 +94,7 @@ test_expect_success 'git grep y<NUL>f a' "
git grep -f f a
"
-test_expect_failure 'git grep y<NUL>x a' "
+test_expect_success 'git grep y<NUL>x a' "
printf 'yQx' | q_to_nul >f &&
test_must_fail git grep -f f a
"
diff --git a/t/t7011-skip-worktree-reading.sh b/t/t7011-skip-worktree-reading.sh
index bb4066f767..8f3b54d826 100755
--- a/t/t7011-skip-worktree-reading.sh
+++ b/t/t7011-skip-worktree-reading.sh
@@ -24,7 +24,7 @@ H sub/2
EOF
NULL_SHA1=e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
-ZERO_SHA0=0000000000000000000000000000000000000000
+
setup_absent() {
test -f 1 && rm 1
git update-index --remove 1 &&
@@ -120,7 +120,7 @@ test_expect_success 'grep with skip-worktree file' '
test "$(git grep --no-ext-grep test)" = "1:test"
'
-echo ":000000 100644 $ZERO_SHA0 $NULL_SHA1 A 1" > expected
+echo ":000000 100644 $_z40 $NULL_SHA1 A 1" > expected
test_expect_success 'diff-index does not examine skip-worktree absent entries' '
setup_absent &&
git diff-index HEAD -- 1 > result &&
diff --git a/t/t7012-skip-worktree-writing.sh b/t/t7012-skip-worktree-writing.sh
index 582d0b54f1..9ceaa4049f 100755
--- a/t/t7012-skip-worktree-writing.sh
+++ b/t/t7012-skip-worktree-writing.sh
@@ -54,7 +54,7 @@ test_expect_success 'read-tree removes worktree, dirty case' '
'
NULL_SHA1=e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
-ZERO_SHA0=0000000000000000000000000000000000000000
+
setup_absent() {
test -f 1 && rm 1
git update-index --remove 1 &&
@@ -127,13 +127,13 @@ EOF
test_expect_success 'git-clean, absent case' '
setup_absent &&
git clean -n > result &&
- test_cmp expected result
+ test_i18ncmp expected result
'
test_expect_success 'git-clean, dirty case' '
setup_dirty &&
git clean -n > result &&
- test_cmp expected result
+ test_i18ncmp expected result
'
#TODO test_expect_failure 'git-apply adds file' false
diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh
index fcac472598..b8cb4906aa 100755
--- a/t/t7060-wtstatus.sh
+++ b/t/t7060-wtstatus.sh
@@ -50,10 +50,72 @@ test_expect_success 'M/D conflict does not segfault' '
git commit -m delete &&
test_must_fail git merge master &&
test_must_fail git commit --dry-run >../actual &&
- test_cmp ../expect ../actual &&
+ test_i18ncmp ../expect ../actual &&
git status >../actual &&
- test_cmp ../expect ../actual
+ test_i18ncmp ../expect ../actual
)
'
+test_expect_success 'rename & unmerged setup' '
+ git rm -f -r . &&
+ cat "$TEST_DIRECTORY/README" >ONE &&
+ git add ONE &&
+ test_tick &&
+ git commit -m "One commit with ONE" &&
+
+ echo Modified >TWO &&
+ cat ONE >>TWO &&
+ cat ONE >>THREE &&
+ git add TWO THREE &&
+ sha1=$(git rev-parse :ONE) &&
+ git rm --cached ONE &&
+ (
+ echo "100644 $sha1 1 ONE" &&
+ echo "100644 $sha1 2 ONE" &&
+ echo "100644 $sha1 3 ONE"
+ ) | git update-index --index-info &&
+ echo Further >>THREE
+'
+
+test_expect_success 'rename & unmerged status' '
+ git status -suno >actual &&
+ cat >expect <<-EOF &&
+ UU ONE
+ AM THREE
+ A TWO
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'git diff-index --cached shows 2 added + 1 unmerged' '
+ cat >expected <<-EOF &&
+ U ONE
+ A THREE
+ A TWO
+ EOF
+ git diff-index --cached --name-status HEAD >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'git diff-index --cached -M shows 2 added + 1 unmerged' '
+ cat >expected <<-EOF &&
+ U ONE
+ A THREE
+ A TWO
+ EOF
+ git diff-index --cached --name-status HEAD >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'git diff-index --cached -C shows 2 copies + 1 unmerged' '
+ cat >expected <<-EOF &&
+ U ONE
+ C ONE THREE
+ C ONE TWO
+ EOF
+ git diff-index --cached -C --name-status HEAD |
+ sed "s/^C[0-9]*/C/g" >actual &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh
index b8cf2603a1..b096dc88c2 100755
--- a/t/t7102-reset.sh
+++ b/t/t7102-reset.sh
@@ -426,7 +426,22 @@ EOF
test_expect_success '--mixed refreshes the index' '
echo 123 >> file2 &&
git reset --mixed HEAD > output &&
- test_cmp expect output
+ test_i18ncmp expect output
+'
+
+test_expect_success 'resetting specific path that is unmerged' '
+ git rm --cached file2 &&
+ F1=$(git rev-parse HEAD:file1) &&
+ F2=$(git rev-parse HEAD:file2) &&
+ F3=$(git rev-parse HEAD:secondfile) &&
+ {
+ echo "100644 $F1 1 file2" &&
+ echo "100644 $F2 2 file2" &&
+ echo "100644 $F3 3 file2"
+ } | git update-index --index-info &&
+ git ls-files -u &&
+ test_must_fail git reset HEAD file2 &&
+ git diff-index --exit-code --cached HEAD
'
test_expect_success 'disambiguation (1)' '
diff --git a/t/t7106-reset-sequence.sh b/t/t7106-reset-sequence.sh
new file mode 100755
index 0000000000..4956caaf82
--- /dev/null
+++ b/t/t7106-reset-sequence.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+test_description='Test interaction of reset --hard with sequencer
+
+ + anotherpick: rewrites foo to d
+ + picked: rewrites foo to c
+ + unrelatedpick: rewrites unrelated to reallyunrelated
+ + base: rewrites foo to b
+ + initial: writes foo as a, unrelated as unrelated
+'
+
+. ./test-lib.sh
+
+pristine_detach () {
+ git cherry-pick --reset &&
+ git checkout -f "$1^0" &&
+ git read-tree -u --reset HEAD &&
+ git clean -d -f -f -q -x
+}
+
+test_expect_success setup '
+ echo unrelated >unrelated &&
+ git add unrelated &&
+ test_commit initial foo a &&
+ test_commit base foo b &&
+ test_commit unrelatedpick unrelated reallyunrelated &&
+ test_commit picked foo c &&
+ test_commit anotherpick foo d &&
+ git config advice.detachedhead false
+
+'
+
+test_expect_success 'reset --hard cleans up sequencer state, providing one-level undo' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick base..anotherpick &&
+ test_path_is_dir .git/sequencer &&
+ git reset --hard &&
+ test_path_is_missing .git/sequencer &&
+ test_path_is_dir .git/sequencer-old &&
+ git reset --hard &&
+ test_path_is_missing .git/sequencer-old
+'
+
+test_done
diff --git a/t/t7110-reset-merge.sh b/t/t7110-reset-merge.sh
index 70cdd8e618..a82a07a04a 100755
--- a/t/t7110-reset-merge.sh
+++ b/t/t7110-reset-merge.sh
@@ -237,7 +237,7 @@ test_expect_success '"reset --keep HEAD^" fails with pending merge' '
git reset --hard third &&
test_must_fail git merge branch1 &&
test_must_fail git reset --keep HEAD^ 2>err.log &&
- grep "middle of a merge" err.log
+ test_i18ngrep "middle of a merge" err.log
'
# The next test will test the following:
@@ -263,7 +263,7 @@ test_expect_success '"reset --keep HEAD" fails with pending merge' '
git reset --hard third &&
test_must_fail git merge branch1 &&
test_must_fail git reset --keep HEAD 2>err.log &&
- grep "middle of a merge" err.log
+ test_i18ngrep "middle of a merge" err.log
'
test_expect_success '--merge is ok with added/deleted merge' '
@@ -289,7 +289,7 @@ test_expect_success '--keep fails with added/deleted merge' '
git diff --exit-code file3 &&
git diff --exit-code branch3 file3 &&
test_must_fail git reset --keep HEAD 2>err.log &&
- grep "middle of a merge" err.log
+ test_i18ngrep "middle of a merge" err.log
'
test_done
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index 1337fa5a22..07fb53adcb 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -228,7 +228,7 @@ test_expect_success 'checkout to detach HEAD (with advice declined)' '
git config advice.detachedHead false &&
git checkout -f renamer && git clean -f &&
git checkout renamer^ 2>messages &&
- grep "HEAD is now at 7329388" messages &&
+ test_i18ngrep "HEAD is now at 7329388" messages &&
test 1 -eq $(wc -l <messages) &&
H=$(git rev-parse --verify HEAD) &&
M=$(git show-ref -s --verify refs/heads/master) &&
@@ -246,7 +246,7 @@ test_expect_success 'checkout to detach HEAD' '
git config advice.detachedHead true &&
git checkout -f renamer && git clean -f &&
git checkout renamer^ 2>messages &&
- grep "HEAD is now at 7329388" messages &&
+ test_i18ngrep "HEAD is now at 7329388" messages &&
test 1 -lt $(wc -l <messages) &&
H=$(git rev-parse --verify HEAD) &&
M=$(git show-ref -s --verify refs/heads/master) &&
@@ -408,6 +408,15 @@ test_expect_success 'checkout w/--track from non-branch HEAD fails' '
test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)"
'
+test_expect_success 'checkout w/--track from tag fails' '
+ git checkout master^0 &&
+ test_must_fail git symbolic-ref HEAD &&
+ test_must_fail git checkout --track -b track frotz &&
+ test_must_fail git rev-parse --verify track &&
+ test_must_fail git symbolic-ref HEAD &&
+ test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)"
+'
+
test_expect_success 'detach a symbolic link HEAD' '
git checkout master &&
git config --bool core.prefersymlinkrefs yes &&
@@ -423,7 +432,6 @@ test_expect_success 'detach a symbolic link HEAD' '
test_expect_success \
'checkout with --track fakes a sensible -b <name>' '
git update-ref refs/remotes/origin/koala/bear renamer &&
- git update-ref refs/new/koala/bear renamer &&
git checkout --track origin/koala/bear &&
test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
@@ -439,12 +447,6 @@ test_expect_success \
git checkout --track remotes/origin/koala/bear &&
test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
- test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
-
- git checkout master && git branch -D koala/bear &&
-
- git checkout --track refs/new/koala/bear &&
- test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)"
'
diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index 02f67b73b7..800b5368a5 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -110,7 +110,7 @@ test_expect_success 'git clean with prefix' '
'
-test_expect_success 'git clean with relative prefix' '
+test_expect_success C_LOCALE_OUTPUT 'git clean with relative prefix' '
mkdir -p build docs &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
@@ -125,7 +125,7 @@ test_expect_success 'git clean with relative prefix' '
}
'
-test_expect_success 'git clean with absolute path' '
+test_expect_success C_LOCALE_OUTPUT 'git clean with absolute path' '
mkdir -p build docs &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
@@ -377,7 +377,7 @@ test_expect_success 'clean.requireForce and -f' '
'
-test_expect_success 'core.excludesfile' '
+test_expect_success C_LOCALE_OUTPUT 'core.excludesfile' '
echo excludes >excludes &&
echo included >included &&
@@ -453,4 +453,11 @@ test_expect_success 'git clean -e' '
)
'
+test_expect_success SANITY 'git clean -d with an unreadable empty directory' '
+ mkdir foo &&
+ chmod a= foo &&
+ git clean -dfx foo &&
+ ! test -d foo
+'
+
test_done
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 874279e32d..695f7afdf3 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -47,8 +47,10 @@ test_expect_success 'setup - repository to add submodules to' '
'
# The 'submodule add' tests need some repository to add as a submodule.
-# The trash directory is a good one as any.
-submodurl=$TRASH_DIRECTORY
+# The trash directory is a good one as any. We need to canonicalize
+# the name, though, as some tests compare it to the absolute path git
+# generates, which will expand symbolic links.
+submodurl=$(pwd -P)
listbranches() {
git for-each-ref --format='%(refname)' 'refs/heads/*'
@@ -75,7 +77,8 @@ test_expect_success 'submodule add' '
(
cd addtest &&
- git submodule add "$submodurl" submod &&
+ git submodule add -q "$submodurl" submod >actual &&
+ test ! -s actual &&
git submodule init
) &&
@@ -99,7 +102,7 @@ test_expect_success 'submodule add to .gitignored path fails' '
git add --force .gitignore &&
git commit -m"Ignore everything" &&
! git submodule add "$submodurl" submod >actual 2>&1 &&
- test_cmp expect actual
+ test_i18ncmp expect actual
)
'
@@ -273,7 +276,8 @@ test_expect_success 'update should work when path is an empty dir' '
echo "$rev1" >expect &&
mkdir init &&
- git submodule update &&
+ git submodule update -q >update.out &&
+ test ! -s update.out &&
inspect init &&
test_cmp expect head-sha1
@@ -357,11 +361,11 @@ test_expect_success 'update --init' '
git submodule update init > update.out &&
cat update.out &&
- grep "not initialized" update.out &&
- ! test -d init/.git &&
+ test_i18ngrep "not initialized" update.out &&
+ test_must_fail git rev-parse --resolve-git-dir init/.git &&
git submodule update --init init &&
- test -d init/.git
+ git rev-parse --resolve-git-dir init/.git
'
test_expect_success 'do not add files from a submodule' '
@@ -446,6 +450,16 @@ test_expect_success 'add should fail when path is used by an existing directory'
)
'
+test_expect_success 'use superproject as upstream when path is relative and no url is set there' '
+ (
+ cd addtest &&
+ git submodule add ../repo relative &&
+ test "$(git config -f .gitmodules submodule.relative.url)" = ../repo &&
+ git submodule sync relative &&
+ test "$(git config submodule.relative.url)" = "$submodurl/repo"
+ )
+'
+
test_expect_success 'set up for relative path tests' '
mkdir reltest &&
(
diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh
index 7d7fde057b..30b429e7dc 100755
--- a/t/t7401-submodule-summary.sh
+++ b/t/t7401-submodule-summary.sh
@@ -128,7 +128,7 @@ test_expect_success 'typechanged submodule(submodule->blob), --cached' "
< Add foo5
EOF
- test_cmp actual expected
+ test_i18ncmp actual expected
"
test_expect_success 'typechanged submodule(submodule->blob), --files' "
@@ -138,7 +138,7 @@ test_expect_success 'typechanged submodule(submodule->blob), --files' "
> Add foo5
EOF
- test_cmp actual expected
+ test_i18ncmp actual expected
"
rm -rf sm1 &&
@@ -149,7 +149,7 @@ test_expect_success 'typechanged submodule(submodule->blob)' "
* sm1 $head4(submodule)->$head5(blob):
EOF
- test_cmp actual expected
+ test_i18ncmp actual expected
"
rm -f sm1 &&
@@ -162,7 +162,7 @@ test_expect_success 'nonexistent commit' "
Warn: sm1 doesn't contain commit $head4_full
EOF
- test_cmp actual expected
+ test_i18ncmp actual expected
"
commit_file
@@ -173,7 +173,7 @@ test_expect_success 'typechanged submodule(blob->submodule)' "
> Add foo7
EOF
- test_cmp expected actual
+ test_i18ncmp expected actual
"
commit_file sm1 &&
@@ -228,7 +228,7 @@ EOF
test_expect_success '--for-status' "
git submodule summary --for-status HEAD^ >actual &&
- test_cmp actual - <<EOF
+ test_i18ncmp actual - <<EOF
# Submodule changes to be committed:
#
# * sm1 $head6...0000000:
diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh
index e5b19538b0..3620215c1f 100755
--- a/t/t7403-submodule-sync.sh
+++ b/t/t7403-submodule-sync.sh
@@ -25,7 +25,8 @@ test_expect_success setup '
git clone super super-clone &&
(cd super-clone && git submodule update --init) &&
git clone super empty-clone &&
- (cd empty-clone && git submodule init)
+ (cd empty-clone && git submodule init) &&
+ git clone super top-only-clone
'
test_expect_success 'change submodule' '
@@ -52,11 +53,12 @@ test_expect_success 'change submodule url' '
test_expect_success '"git submodule sync" should update submodule URLs' '
(cd super-clone &&
- git pull &&
+ git pull --no-recurse-submodules &&
git submodule sync
) &&
- test -d "$(git config -f super-clone/submodule/.git/config \
- remote.origin.url)" &&
+ test -d "$(cd super-clone/submodule &&
+ git config remote.origin.url
+ )" &&
(cd super-clone/submodule &&
git checkout master &&
git pull
@@ -66,7 +68,7 @@ test_expect_success '"git submodule sync" should update submodule URLs' '
)
'
-test_expect_success '"git submodule sync" should update submodule URLs if not yet cloned' '
+test_expect_success '"git submodule sync" should update known submodule URLs' '
(cd empty-clone &&
git pull &&
git submodule sync &&
@@ -74,4 +76,14 @@ test_expect_success '"git submodule sync" should update submodule URLs if not ye
)
'
+test_expect_success '"git submodule sync" should not vivify uninteresting submodule' '
+ (cd top-only-clone &&
+ git pull &&
+ git submodule sync &&
+ test -z "$(git config submodule.submodule.url)" &&
+ git submodule sync submodule &&
+ test -z "$(git config submodule.submodule.url)"
+ )
+'
+
test_done
diff --git a/t/t7405-submodule-merge.sh b/t/t7405-submodule-merge.sh
index 7e2e258950..0d5b42a25b 100755
--- a/t/t7405-submodule-merge.sh
+++ b/t/t7405-submodule-merge.sh
@@ -56,11 +56,11 @@ test_expect_success setup '
# History setup
#
-# b
-# / \
-# a d
-# \ /
-# c
+# b
+# / \
+# init -- a d
+# \ \ /
+# g c
#
# a in the main repository records to sub-a in the submodule and
# analogous b and c. d should be automatically found by merging c into
@@ -76,6 +76,8 @@ test_expect_success 'setup for merge search' '
git add file-a &&
git commit -m "sub-a" &&
git branch sub-a) &&
+ git commit --allow-empty -m init &&
+ git branch init &&
git add sub &&
git commit -m "a" &&
git branch a &&
@@ -101,7 +103,13 @@ test_expect_success 'setup for merge search' '
git checkout -b sub-d sub-b &&
git merge sub-c) &&
git commit -a -m "d" &&
- git branch test b)
+ git branch test b &&
+
+ git checkout -b g init &&
+ (cd sub &&
+ git checkout -b sub-g sub-c) &&
+ git add sub &&
+ git commit -a -m "g")
'
test_expect_success 'merge with one side as a fast-forward of the other' '
@@ -176,10 +184,99 @@ test_expect_success 'merging should fail for changes that are backwards' '
test_must_fail git merge f)
'
+
+# Check that the conflicting submodule is detected when it is
+# in the common ancestor. status should be 'U00...00"
+test_expect_success 'git submodule status should display the merge conflict properly with merge base' '
+ (cd merge-search &&
+ cat >.gitmodules <<EOF &&
+[submodule "sub"]
+ path = sub
+ url = $TRASH_DIRECTORY/sub
+EOF
+ cat >expect <<EOF &&
+U0000000000000000000000000000000000000000 sub
+EOF
+ git submodule status > actual &&
+ test_cmp expect actual &&
+ git reset --hard)
+'
+
+# Check that the conflicting submodule is detected when it is
+# not in the common ancestor. status should be 'U00...00"
+test_expect_success 'git submodule status should display the merge conflict properly without merge-base' '
+ (cd merge-search &&
+ git checkout -b test-no-merge-base g &&
+ test_must_fail git merge b &&
+ cat >.gitmodules <<EOF &&
+[submodule "sub"]
+ path = sub
+ url = $TRASH_DIRECTORY/sub
+EOF
+ cat >expect <<EOF &&
+U0000000000000000000000000000000000000000 sub
+EOF
+ git submodule status > actual &&
+ test_cmp expect actual &&
+ git reset --hard)
+'
+
+
test_expect_success 'merging with a modify/modify conflict between merge bases' '
git reset --hard HEAD &&
git checkout -b test2 c &&
git merge d
'
+# canonical criss-cross history in top and submodule
+test_expect_success 'setup for recursive merge with submodule' '
+ mkdir merge-recursive &&
+ (cd merge-recursive &&
+ git init &&
+ mkdir sub &&
+ (cd sub &&
+ git init &&
+ test_commit a &&
+ git checkout -b sub-b master &&
+ test_commit b &&
+ git checkout -b sub-c master &&
+ test_commit c &&
+ git checkout -b sub-bc sub-b &&
+ git merge sub-c &&
+ git checkout -b sub-cb sub-c &&
+ git merge sub-b &&
+ git checkout master) &&
+ git add sub &&
+ git commit -m a &&
+ git checkout -b top-b master &&
+ (cd sub && git checkout sub-b) &&
+ git add sub &&
+ git commit -m b &&
+ git checkout -b top-c master &&
+ (cd sub && git checkout sub-c) &&
+ git add sub &&
+ git commit -m c &&
+ git checkout -b top-bc top-b &&
+ git merge -s ours --no-commit top-c &&
+ (cd sub && git checkout sub-bc) &&
+ git add sub &&
+ git commit -m bc &&
+ git checkout -b top-cb top-c &&
+ git merge -s ours --no-commit top-b &&
+ (cd sub && git checkout sub-cb) &&
+ git add sub &&
+ git commit -m cb)
+'
+
+# merge should leave submodule unmerged in index
+test_expect_success 'recursive merge with submodule' '
+ (cd merge-recursive &&
+ test_must_fail git merge top-bc &&
+ echo "160000 $(git rev-parse top-cb:sub) 2 sub" > expect2 &&
+ echo "160000 $(git rev-parse top-bc:sub) 3 sub" > expect3 &&
+ git ls-files -u > actual &&
+ grep "$(cat expect2)" actual > /dev/null &&
+ grep "$(cat expect3)" actual > /dev/null)
+'
+
test_done
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index bfb4975e94..33b292b8a8 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -30,6 +30,7 @@ test_expect_success 'setup a submodule tree' '
git clone super submodule &&
git clone super rebasing &&
git clone super merging &&
+ git clone super none &&
(cd super &&
git submodule add ../submodule submodule &&
test_tick &&
@@ -58,6 +59,11 @@ test_expect_success 'setup a submodule tree' '
test_tick &&
git commit -m "rebasing"
)
+ (cd super &&
+ git submodule add ../none none &&
+ test_tick &&
+ git commit -m "none"
+ )
'
test_expect_success 'submodule update detaching the HEAD ' '
@@ -74,6 +80,49 @@ test_expect_success 'submodule update detaching the HEAD ' '
)
'
+apos="'";
+test_expect_success 'submodule update does not fetch already present commits' '
+ (cd submodule &&
+ echo line3 >> file &&
+ git add file &&
+ test_tick &&
+ git commit -m "upstream line3"
+ ) &&
+ (cd super/submodule &&
+ head=$(git rev-parse --verify HEAD) &&
+ echo "Submodule path ${apos}submodule$apos: checked out $apos$head$apos" > ../../expected &&
+ git reset --hard HEAD~1
+ ) &&
+ (cd super &&
+ git submodule update > ../actual 2> ../actual.err
+ ) &&
+ test_i18ncmp expected actual &&
+ ! test -s actual.err
+'
+
+test_expect_success 'submodule update should fail due to local changes' '
+ (cd super/submodule &&
+ git reset --hard HEAD~1 &&
+ echo "local change" > file
+ ) &&
+ (cd super &&
+ (cd submodule &&
+ compare_head
+ ) &&
+ test_must_fail git submodule update submodule
+ )
+'
+test_expect_success 'submodule update should throw away changes with --force ' '
+ (cd super &&
+ (cd submodule &&
+ compare_head
+ ) &&
+ git submodule update --force submodule &&
+ cd submodule &&
+ ! compare_head
+ )
+'
+
test_expect_success 'submodule update --rebase staying on master' '
(cd super/submodule &&
git checkout master
@@ -203,4 +252,363 @@ test_expect_success 'submodule init picks up merge' '
)
'
+test_expect_success 'submodule update --merge - ignores --merge for new submodules' '
+ (cd super &&
+ rm -rf submodule &&
+ git submodule update submodule &&
+ git status -s submodule >expect &&
+ rm -rf submodule &&
+ git submodule update --merge submodule &&
+ git status -s submodule >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'submodule update --rebase - ignores --rebase for new submodules' '
+ (cd super &&
+ rm -rf submodule &&
+ git submodule update submodule &&
+ git status -s submodule >expect &&
+ rm -rf submodule &&
+ git submodule update --rebase submodule &&
+ git status -s submodule >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'submodule update ignores update=merge config for new submodules' '
+ (cd super &&
+ rm -rf submodule &&
+ git submodule update submodule &&
+ git status -s submodule >expect &&
+ rm -rf submodule &&
+ git config submodule.submodule.update merge &&
+ git submodule update submodule &&
+ git status -s submodule >actual &&
+ git config --unset submodule.submodule.update &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'submodule update ignores update=rebase config for new submodules' '
+ (cd super &&
+ rm -rf submodule &&
+ git submodule update submodule &&
+ git status -s submodule >expect &&
+ rm -rf submodule &&
+ git config submodule.submodule.update rebase &&
+ git submodule update submodule &&
+ git status -s submodule >actual &&
+ git config --unset submodule.submodule.update &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'submodule init picks up update=none' '
+ (cd super &&
+ git config -f .gitmodules submodule.none.update none &&
+ git submodule init none &&
+ test "none" = "$(git config submodule.none.update)"
+ )
+'
+
+test_expect_success 'submodule update - update=none in .git/config' '
+ (cd super &&
+ git config submodule.submodule.update none &&
+ (cd submodule &&
+ git checkout master &&
+ compare_head
+ ) &&
+ git diff --raw | grep " submodule" &&
+ git submodule update &&
+ git diff --raw | grep " submodule" &&
+ (cd submodule &&
+ compare_head
+ ) &&
+ git config --unset submodule.submodule.update &&
+ git submodule update submodule
+ )
+'
+
+test_expect_success 'submodule update - update=none in .git/config but --checkout given' '
+ (cd super &&
+ git config submodule.submodule.update none &&
+ (cd submodule &&
+ git checkout master &&
+ compare_head
+ ) &&
+ git diff --raw | grep " submodule" &&
+ git submodule update --checkout &&
+ test_must_fail git diff --raw \| grep " submodule" &&
+ (cd submodule &&
+ test_must_fail compare_head
+ ) &&
+ git config --unset submodule.submodule.update
+ )
+'
+
+test_expect_success 'submodule update --init skips submodule with update=none' '
+ (cd super &&
+ git add .gitmodules &&
+ git commit -m ".gitmodules"
+ ) &&
+ git clone super cloned &&
+ (cd cloned &&
+ git submodule update --init &&
+ test -e submodule/.git &&
+ test_must_fail test -e none/.git
+ )
+'
+
+test_expect_success 'submodule update continues after checkout error' '
+ (cd super &&
+ git reset --hard HEAD &&
+ git submodule add ../submodule submodule2 &&
+ git submodule init &&
+ git commit -am "new_submodule" &&
+ (cd submodule2 &&
+ git rev-parse --max-count=1 HEAD > ../expect
+ ) &&
+ (cd submodule &&
+ test_commit "update_submodule" file
+ ) &&
+ (cd submodule2 &&
+ test_commit "update_submodule2" file
+ ) &&
+ git add submodule &&
+ git add submodule2 &&
+ git commit -m "two_new_submodule_commits" &&
+ (cd submodule &&
+ echo "" > file
+ ) &&
+ git checkout HEAD^ &&
+ test_must_fail git submodule update &&
+ (cd submodule2 &&
+ git rev-parse --max-count=1 HEAD > ../actual
+ ) &&
+ test_cmp expect actual
+ )
+'
+test_expect_success 'submodule update continues after recursive checkout error' '
+ (cd super &&
+ git reset --hard HEAD &&
+ git checkout master &&
+ git submodule update &&
+ (cd submodule &&
+ git submodule add ../submodule subsubmodule &&
+ git submodule init &&
+ git commit -m "new_subsubmodule"
+ ) &&
+ git add submodule &&
+ git commit -m "update_submodule" &&
+ (cd submodule &&
+ (cd subsubmodule &&
+ test_commit "update_subsubmodule" file
+ ) &&
+ git add subsubmodule &&
+ test_commit "update_submodule_again" file &&
+ (cd subsubmodule &&
+ test_commit "update_subsubmodule_again" file
+ ) &&
+ test_commit "update_submodule_again_again" file
+ ) &&
+ (cd submodule2 &&
+ git rev-parse --max-count=1 HEAD > ../expect &&
+ test_commit "update_submodule2_again" file
+ ) &&
+ git add submodule &&
+ git add submodule2 &&
+ git commit -m "new_commits" &&
+ git checkout HEAD^ &&
+ (cd submodule &&
+ git checkout HEAD^ &&
+ (cd subsubmodule &&
+ echo "" > file
+ )
+ ) &&
+ test_must_fail git submodule update --recursive &&
+ (cd submodule2 &&
+ git rev-parse --max-count=1 HEAD > ../actual
+ ) &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'submodule update exit immediately in case of merge conflict' '
+ (cd super &&
+ git checkout master &&
+ git reset --hard HEAD &&
+ (cd submodule &&
+ (cd subsubmodule &&
+ git reset --hard HEAD
+ )
+ ) &&
+ git submodule update --recursive &&
+ (cd submodule &&
+ test_commit "update_submodule_2" file
+ ) &&
+ (cd submodule2 &&
+ test_commit "update_submodule2_2" file
+ ) &&
+ git add submodule &&
+ git add submodule2 &&
+ git commit -m "two_new_submodule_commits" &&
+ (cd submodule &&
+ git checkout master &&
+ test_commit "conflict" file &&
+ echo "conflict" > file
+ ) &&
+ git checkout HEAD^ &&
+ (cd submodule2 &&
+ git rev-parse --max-count=1 HEAD > ../expect
+ ) &&
+ git config submodule.submodule.update merge &&
+ test_must_fail git submodule update &&
+ (cd submodule2 &&
+ git rev-parse --max-count=1 HEAD > ../actual
+ ) &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'submodule update exit immediately after recursive rebase error' '
+ (cd super &&
+ git checkout master &&
+ git reset --hard HEAD &&
+ (cd submodule &&
+ git reset --hard HEAD &&
+ git submodule update --recursive
+ ) &&
+ (cd submodule &&
+ test_commit "update_submodule_3" file
+ ) &&
+ (cd submodule2 &&
+ test_commit "update_submodule2_3" file
+ ) &&
+ git add submodule &&
+ git add submodule2 &&
+ git commit -m "two_new_submodule_commits" &&
+ (cd submodule &&
+ git checkout master &&
+ test_commit "conflict2" file &&
+ echo "conflict" > file
+ ) &&
+ git checkout HEAD^ &&
+ (cd submodule2 &&
+ git rev-parse --max-count=1 HEAD > ../expect
+ ) &&
+ git config submodule.submodule.update rebase &&
+ test_must_fail git submodule update &&
+ (cd submodule2 &&
+ git rev-parse --max-count=1 HEAD > ../actual
+ ) &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'add different submodules to the same path' '
+ (cd super &&
+ git submodule add ../submodule s1 &&
+ test_must_fail git submodule add ../merging s1
+ )
+'
+
+test_expect_success 'submodule add places git-dir in superprojects git-dir' '
+ (cd super &&
+ mkdir deeper &&
+ git submodule add ../submodule deeper/submodule &&
+ (cd deeper/submodule &&
+ git log > ../../expected
+ ) &&
+ (cd .git/modules/deeper/submodule &&
+ git log > ../../../../actual
+ ) &&
+ test_cmp actual expected
+ )
+'
+
+test_expect_success 'submodule update places git-dir in superprojects git-dir' '
+ (cd super &&
+ git commit -m "added submodule"
+ ) &&
+ git clone super super2 &&
+ (cd super2 &&
+ git submodule init deeper/submodule &&
+ git submodule update &&
+ (cd deeper/submodule &&
+ git log > ../../expected
+ ) &&
+ (cd .git/modules/deeper/submodule &&
+ git log > ../../../../actual
+ ) &&
+ test_cmp actual expected
+ )
+'
+
+test_expect_success 'submodule add places git-dir in superprojects git-dir recursive' '
+ (cd super2 &&
+ (cd deeper/submodule &&
+ git submodule add ../submodule subsubmodule &&
+ (cd subsubmodule &&
+ git log > ../../../expected
+ ) &&
+ git commit -m "added subsubmodule" &&
+ git push
+ ) &&
+ (cd .git/modules/deeper/submodule/modules/subsubmodule &&
+ git log > ../../../../../actual
+ ) &&
+ git add deeper/submodule &&
+ git commit -m "update submodule" &&
+ git push &&
+ test_cmp actual expected
+ )
+'
+
+test_expect_success 'submodule update places git-dir in superprojects git-dir recursive' '
+ mkdir super_update_r &&
+ (cd super_update_r &&
+ git init --bare
+ ) &&
+ mkdir subsuper_update_r &&
+ (cd subsuper_update_r &&
+ git init --bare
+ ) &&
+ mkdir subsubsuper_update_r &&
+ (cd subsubsuper_update_r &&
+ git init --bare
+ ) &&
+ git clone subsubsuper_update_r subsubsuper_update_r2 &&
+ (cd subsubsuper_update_r2 &&
+ test_commit "update_subsubsuper" file &&
+ git push origin master
+ ) &&
+ git clone subsuper_update_r subsuper_update_r2 &&
+ (cd subsuper_update_r2 &&
+ test_commit "update_subsuper" file &&
+ git submodule add ../subsubsuper_update_r subsubmodule &&
+ git commit -am "subsubmodule" &&
+ git push origin master
+ ) &&
+ git clone super_update_r super_update_r2 &&
+ (cd super_update_r2 &&
+ test_commit "update_super" file &&
+ git submodule add ../subsuper_update_r submodule &&
+ git commit -am "submodule" &&
+ git push origin master
+ ) &&
+ rm -rf super_update_r2 &&
+ git clone super_update_r super_update_r2 &&
+ (cd super_update_r2 &&
+ git submodule update --init --recursive &&
+ (cd submodule/subsubmodule &&
+ git log > ../../expected
+ ) &&
+ (cd .git/modules/submodule/modules/subsubmodule
+ git log > ../../../../../actual
+ )
+ test_cmp actual expected
+ )
+'
+
test_done
diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index d8ad25036f..9b69fe2e14 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,7 +77,7 @@ test_expect_success 'test basic "submodule foreach" usage' '
git config foo.bar zar &&
git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
) &&
- test_cmp expect actual
+ test_i18ncmp expect actual
'
test_expect_success 'setup nested submodules' '
@@ -118,19 +118,19 @@ test_expect_success 'use "submodule foreach" to checkout 2nd level submodule' '
git clone super clone2 &&
(
cd clone2 &&
- test ! -d sub1/.git &&
- test ! -d sub2/.git &&
- test ! -d sub3/.git &&
- test ! -d nested1/.git &&
+ test_must_fail git rev-parse --resolve-git-dir sub1/.git &&
+ test_must_fail git rev-parse --resolve-git-dir sub2/.git &&
+ test_must_fail git rev-parse --resolve-git-dir sub3/.git &&
+ test_must_fail git rev-parse --resolve-git-dir nested1/.git &&
git submodule update --init &&
- test -d sub1/.git &&
- test -d sub2/.git &&
- test -d sub3/.git &&
- test -d nested1/.git &&
- test ! -d nested1/nested2/.git &&
+ git rev-parse --resolve-git-dir sub1/.git &&
+ git rev-parse --resolve-git-dir sub2/.git &&
+ git rev-parse --resolve-git-dir sub3/.git &&
+ git rev-parse --resolve-git-dir nested1/.git &&
+ test_must_fail git rev-parse --resolve-git-dir nested1/nested2/.git &&
git submodule foreach "git submodule update --init" &&
- test -d nested1/nested2/.git &&
- test ! -d nested1/nested2/nested3/.git
+ git rev-parse --resolve-git-dir nested1/nested1/nested2/.git
+ test_must_fail git rev-parse --resolve-git-dir nested1/nested2/nested3/.git
)
'
@@ -138,8 +138,8 @@ test_expect_success 'use "foreach --recursive" to checkout all submodules' '
(
cd clone2 &&
git submodule foreach --recursive "git submodule update --init" &&
- test -d nested1/nested2/nested3/.git &&
- test -d nested1/nested2/nested3/submodule/.git
+ git rev-parse --resolve-git-dir nested1/nested2/nested3/.git &&
+ git rev-parse --resolve-git-dir nested1/nested2/nested3/submodule/.git
)
'
@@ -158,7 +158,7 @@ test_expect_success 'test messages from "foreach --recursive"' '
cd clone2 &&
git submodule foreach --recursive "true" > ../actual
) &&
- test_cmp expect actual
+ test_i18ncmp expect actual
'
cat > expect <<EOF
@@ -183,18 +183,18 @@ test_expect_success 'use "update --recursive" to checkout all submodules' '
git clone super clone3 &&
(
cd clone3 &&
- test ! -d sub1/.git &&
- test ! -d sub2/.git &&
- test ! -d sub3/.git &&
- test ! -d nested1/.git &&
+ test_must_fail git rev-parse --resolve-git-dir sub1/.git &&
+ test_must_fail git rev-parse --resolve-git-dir sub2/.git &&
+ test_must_fail git rev-parse --resolve-git-dir sub3/.git &&
+ test_must_fail git rev-parse --resolve-git-dir nested1/.git &&
git submodule update --init --recursive &&
- test -d sub1/.git &&
- test -d sub2/.git &&
- test -d sub3/.git &&
- test -d nested1/.git &&
- test -d nested1/nested2/.git &&
- test -d nested1/nested2/nested3/.git &&
- test -d nested1/nested2/nested3/submodule/.git
+ git rev-parse --resolve-git-dir sub1/.git &&
+ git rev-parse --resolve-git-dir sub2/.git &&
+ git rev-parse --resolve-git-dir sub3/.git &&
+ git rev-parse --resolve-git-dir nested1/.git &&
+ git rev-parse --resolve-git-dir nested1/nested2/.git &&
+ git rev-parse --resolve-git-dir nested1/nested2/nested3/.git &&
+ git rev-parse --resolve-git-dir nested1/nested2/nested3/submodule/.git
)
'
@@ -238,19 +238,26 @@ test_expect_success 'ensure "status --cached --recursive" preserves the --cached
) &&
git submodule status --cached --recursive -- nested1 > ../actual
) &&
+ if test_have_prereq MINGW
+ then
+ dos2unix actual
+ fi &&
test_cmp expect actual
'
test_expect_success 'use "git clone --recursive" to checkout all submodules' '
git clone --recursive super clone4 &&
- test -d clone4/.git &&
- test -d clone4/sub1/.git &&
- test -d clone4/sub2/.git &&
- test -d clone4/sub3/.git &&
- test -d clone4/nested1/.git &&
- test -d clone4/nested1/nested2/.git &&
- test -d clone4/nested1/nested2/nested3/.git &&
- test -d clone4/nested1/nested2/nested3/submodule/.git
+ (
+ cd clone4 &&
+ git rev-parse --resolve-git-dir .git &&
+ git rev-parse --resolve-git-dir sub1/.git &&
+ git rev-parse --resolve-git-dir sub2/.git &&
+ git rev-parse --resolve-git-dir sub3/.git &&
+ git rev-parse --resolve-git-dir nested1/.git &&
+ git rev-parse --resolve-git-dir nested1/nested2/.git &&
+ git rev-parse --resolve-git-dir nested1/nested2/nested3/.git &&
+ git rev-parse --resolve-git-dir nested1/nested2/nested3/submodule/.git
+ )
'
test_expect_success 'test "update --recursive" with a flag with spaces' '
@@ -258,14 +265,14 @@ test_expect_success 'test "update --recursive" with a flag with spaces' '
git clone super clone5 &&
(
cd clone5 &&
- test ! -d nested1/.git &&
+ test_must_fail git rev-parse --resolve-git-dir d nested1/.git &&
git submodule update --init --recursive --reference="$(dirname "$PWD")/common objects" &&
- test -d nested1/.git &&
- test -d nested1/nested2/.git &&
- test -d nested1/nested2/nested3/.git &&
- test -f nested1/.git/objects/info/alternates &&
- test -f nested1/nested2/.git/objects/info/alternates &&
- test -f nested1/nested2/nested3/.git/objects/info/alternates
+ git rev-parse --resolve-git-dir nested1/.git &&
+ git rev-parse --resolve-git-dir nested1/nested2/.git &&
+ git rev-parse --resolve-git-dir nested1/nested2/nested3/.git &&
+ test -f .git/modules/nested1/objects/info/alternates &&
+ test -f .git/modules/nested1/modules/nested2/objects/info/alternates &&
+ test -f .git/modules/nested1/modules/nested2/modules/nested3/objects/info/alternates
)
'
@@ -273,19 +280,37 @@ test_expect_success 'use "update --recursive nested1" to checkout all submodules
git clone super clone6 &&
(
cd clone6 &&
- test ! -d sub1/.git &&
- test ! -d sub2/.git &&
- test ! -d sub3/.git &&
- test ! -d nested1/.git &&
+ test_must_fail git rev-parse --resolve-git-dir sub1/.git &&
+ test_must_fail git rev-parse --resolve-git-dir sub2/.git &&
+ test_must_fail git rev-parse --resolve-git-dir sub3/.git &&
+ test_must_fail git rev-parse --resolve-git-dir nested1/.git &&
git submodule update --init --recursive -- nested1 &&
- test ! -d sub1/.git &&
- test ! -d sub2/.git &&
- test ! -d sub3/.git &&
- test -d nested1/.git &&
- test -d nested1/nested2/.git &&
- test -d nested1/nested2/nested3/.git &&
- test -d nested1/nested2/nested3/submodule/.git
+ test_must_fail git rev-parse --resolve-git-dir sub1/.git &&
+ test_must_fail git rev-parse --resolve-git-dir sub2/.git &&
+ test_must_fail git rev-parse --resolve-git-dir sub3/.git &&
+ git rev-parse --resolve-git-dir nested1/.git &&
+ git rev-parse --resolve-git-dir nested1/nested2/.git &&
+ git rev-parse --resolve-git-dir nested1/nested2/nested3/.git &&
+ git rev-parse --resolve-git-dir nested1/nested2/nested3/submodule/.git
)
'
+test_expect_success 'command passed to foreach retains notion of stdin' '
+ (
+ cd super &&
+ git submodule foreach echo success >../expected &&
+ yes | git submodule foreach "read y && test \"x\$y\" = xy && echo success" >../actual
+ ) &&
+ test_cmp expected actual
+'
+
+test_expect_success 'command passed to foreach --recursive retains notion of stdin' '
+ (
+ cd clone2 &&
+ git submodule foreach --recursive echo success >../expected &&
+ yes | git submodule foreach --recursive "read y && test \"x\$y\" = xy && echo success" >../actual
+ ) &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t7408-submodule-reference.sh b/t/t7408-submodule-reference.sh
index cc16d3f05d..ab37c368d0 100755
--- a/t/t7408-submodule-reference.sh
+++ b/t/t7408-submodule-reference.sh
@@ -43,7 +43,7 @@ git commit -m B-super-added'
cd "$base_dir"
test_expect_success 'after add: existence of info/alternates' \
-'test `wc -l <super/sub/.git/objects/info/alternates` = 1'
+'test `wc -l <super/.git/modules/sub/objects/info/alternates` = 1'
cd "$base_dir"
@@ -66,7 +66,7 @@ test_expect_success 'update with reference' \
cd "$base_dir"
test_expect_success 'after update: existence of info/alternates' \
-'test `wc -l <super-clone/sub/.git/objects/info/alternates` = 1'
+'test `wc -l <super-clone/.git/modules/sub/objects/info/alternates` = 1'
cd "$base_dir"
diff --git a/t/t7500-commit.sh b/t/t7500-commit.sh
index 162527c211..1c908f4d39 100755
--- a/t/t7500-commit.sh
+++ b/t/t7500-commit.sh
@@ -10,7 +10,12 @@ Tests for selected commit options.'
. ./test-lib.sh
commit_msg_is () {
- test "`git log --pretty=format:%s%b -1`" = "$1"
+ expect=commit_msg_is.expect
+ actual=commit_msg_is.actual
+
+ printf "%s" "$(git log --pretty=format:%s%b -1)" >$expect &&
+ printf "%s" "$1" >$actual &&
+ test_i18ncmp $expect $actual
}
# A sanity check to see if commit is working at all.
@@ -23,13 +28,21 @@ test_expect_success 'a basic commit in an empty tree should succeed' '
test_expect_success 'nonexistent template file should return error' '
echo changes >> foo &&
git add foo &&
- test_must_fail git commit --template "$PWD"/notexist
+ (
+ GIT_EDITOR="echo hello >\"\$1\"" &&
+ export GIT_EDITOR &&
+ test_must_fail git commit --template "$PWD"/notexist
+ )
'
test_expect_success 'nonexistent template file in config should return error' '
git config commit.template "$PWD"/notexist &&
- test_must_fail git commit &&
- git config --unset commit.template
+ test_when_finished "git config --unset commit.template" &&
+ (
+ GIT_EDITOR="echo hello >\"\$1\"" &&
+ export GIT_EDITOR &&
+ test_must_fail git commit
+ )
'
# From now on we'll use a template file that exists.
@@ -110,6 +123,20 @@ test_expect_success 'commit message from file should override template' '
commit_msg_is "standard input msg"
'
+cat >"$TEMPLATE" <<\EOF
+
+
+### template
+
+EOF
+test_expect_success 'commit message from template with whitespace issue' '
+ echo "content galore" >>foo &&
+ git add foo &&
+ GIT_EDITOR="$TEST_DIRECTORY"/t7500/add-whitespaced-content git commit \
+ --template "$TEMPLATE" &&
+ commit_msg_is "commit message"
+'
+
test_expect_success 'using alternate GIT_INDEX_FILE (1)' '
cp .git/index saved-index &&
diff --git a/t/t7500/add-whitespaced-content b/t/t7500/add-whitespaced-content
new file mode 100755
index 0000000000..ccf07c61a4
--- /dev/null
+++ b/t/t7500/add-whitespaced-content
@@ -0,0 +1,8 @@
+#!/bin/sh
+sed -e 's/|$//' >>"$1" <<\EOF
+
+ |
+commit message |
+
+EOF
+exit 0
diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh
index 8980738c75..3ad04363b5 100755
--- a/t/t7501-commit.sh
+++ b/t/t7501-commit.sh
@@ -14,8 +14,12 @@ test_tick
test_expect_success \
"initial status" \
"echo 'bongo bongo' >file &&
- git add file && \
- git status | grep 'Initial commit'"
+ git add file"
+
+test_expect_success "Constructing initial commit" '
+ git status >actual &&
+ test_i18ngrep "Initial commit" actual
+'
test_expect_success \
"fail initial amend" \
@@ -38,10 +42,13 @@ test_expect_success \
"echo King of the bongo >file &&
test_must_fail git commit -m foo -a file"
-test_expect_success PERL \
- "using paths with --interactive" \
- "echo bong-o-bong >file &&
- ! (echo 7 | git commit -m foo --interactive file)"
+test_expect_success PERL 'can use paths with --interactive' '
+ echo bong-o-bong >file &&
+ # 2: update, 1:st path, that is all, 7: quit
+ ( echo 2; echo 1; echo; echo 7 ) |
+ git commit -m foo --interactive file &&
+ git reset --hard HEAD^
+'
test_expect_success \
"using invalid commit with -C" \
@@ -127,6 +134,16 @@ test_expect_success PERL \
"interactive add" \
"echo 7 | git commit --interactive | grep 'What now'"
+test_expect_success PERL \
+ "commit --interactive doesn't change index if editor aborts" \
+ "echo zoo >file &&
+ test_must_fail git diff --exit-code >diff1 &&
+ (echo u ; echo '*' ; echo q) |
+ (EDITOR=: && export EDITOR &&
+ test_must_fail git commit --interactive) &&
+ git diff >diff2 &&
+ test_cmp diff1 diff2"
+
test_expect_success \
"showing committed revisions" \
"git rev-list HEAD >current"
diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh
index 50da034cd3..3f3adc31b9 100755
--- a/t/t7502-commit.sh
+++ b/t/t7502-commit.sh
@@ -22,7 +22,7 @@ check_summary_oneline() {
SUMMARY_POSTFIX="$(git log -1 --pretty='format:%h')"
echo "[$SUMMARY_PREFIX $SUMMARY_POSTFIX] $2" >exp &&
- test_cmp exp act
+ test_i18ncmp exp act
}
test_expect_success 'output summary format' '
@@ -32,7 +32,10 @@ test_expect_success 'output summary format' '
check_summary_oneline "root-commit" "initial" &&
echo change >>file1 &&
- git add file1 &&
+ git add file1
+'
+
+test_expect_success 'output summary format: root-commit' '
check_summary_oneline "" "a change"
'
@@ -215,19 +218,21 @@ test_expect_success 'cleanup commit messages (strip,-F)' '
'
-echo "sample
-
-# Please enter the commit message for your changes. Lines starting
-# with '#' will be ignored, and an empty message aborts the commit." >expect
-
test_expect_success 'cleanup commit messages (strip,-F,-e)' '
echo >>negative &&
{ echo;echo sample;echo; } >text &&
git commit -e -F text -a &&
- head -n 4 .git/COMMIT_EDITMSG >actual &&
- test_cmp expect actual
+ head -n 4 .git/COMMIT_EDITMSG >actual
+'
+
+echo "sample
+# Please enter the commit message for your changes. Lines starting
+# with '#' will be ignored, and an empty message aborts the commit." >expect
+
+test_expect_success 'cleanup commit messages (strip,-F,-e): output' '
+ test_i18ncmp expect actual
'
echo "#
@@ -235,11 +240,10 @@ echo "#
#" >> expect
test_expect_success 'author different from committer' '
-
echo >>negative &&
- git commit -e -m "sample"
+ test_might_fail git commit -e -m "sample" &&
head -n 7 .git/COMMIT_EDITMSG >actual &&
- test_cmp expect actual
+ test_i18ncmp expect actual
'
mv expect expect.tmp
@@ -258,8 +262,8 @@ test_expect_success 'committer is automatic' '
test_must_fail git commit -e -m "sample"
) &&
head -n 8 .git/COMMIT_EDITMSG | \
- sed "s/^# Committer: .*/# Committer:/" >actual &&
- test_cmp expect actual
+ sed "s/^# Committer: .*/# Committer:/" >actual
+ test_i18ncmp expect actual
'
pwd=`pwd`
@@ -362,9 +366,9 @@ try_commit () {
GIT_EDITOR=.git/FAKE_EDITOR git commit -a $* $use_template &&
case "$use_template" in
'')
- ! grep "^## Custom template" .git/COMMIT_EDITMSG ;;
+ test_i18ngrep ! "^## Custom template" .git/COMMIT_EDITMSG ;;
*)
- grep "^## Custom template" .git/COMMIT_EDITMSG ;;
+ test_i18ngrep "^## Custom template" .git/COMMIT_EDITMSG ;;
esac
}
@@ -373,67 +377,67 @@ try_commit_status_combo () {
test_expect_success 'commit' '
clear_config commit.status &&
try_commit "" &&
- grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit' '
clear_config commit.status &&
try_commit "" &&
- grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit --status' '
clear_config commit.status &&
try_commit --status &&
- grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit --no-status' '
clear_config commit.status &&
try_commit --no-status &&
- ! grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit with commit.status = yes' '
clear_config commit.status &&
git config commit.status yes &&
try_commit "" &&
- grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit with commit.status = no' '
clear_config commit.status &&
git config commit.status no &&
try_commit "" &&
- ! grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit --status with commit.status = yes' '
clear_config commit.status &&
git config commit.status yes &&
try_commit --status &&
- grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit --no-status with commit.status = yes' '
clear_config commit.status &&
git config commit.status yes &&
try_commit --no-status &&
- ! grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit --status with commit.status = no' '
clear_config commit.status &&
git config commit.status no &&
try_commit --status &&
- grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit --no-status with commit.status = no' '
clear_config commit.status &&
git config commit.status no &&
try_commit --no-status &&
- ! grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
}
diff --git a/t/t7503-pre-commit-hook.sh b/t/t7503-pre-commit-hook.sh
index 8528f64c8d..ee7f0cd459 100755
--- a/t/t7503-pre-commit-hook.sh
+++ b/t/t7503-pre-commit-hook.sh
@@ -84,5 +84,38 @@ test_expect_success POSIXPERM '--no-verify with non-executable hook' '
git commit --no-verify -m "more content"
'
+chmod +x "$HOOK"
+
+# a hook that checks $GIT_PREFIX and succeeds inside the
+# success/ subdirectory only
+cat > "$HOOK" <<EOF
+#!/bin/sh
+test \$GIT_PREFIX = success/
+EOF
+
+test_expect_success 'with hook requiring GIT_PREFIX' '
+
+ echo "more content" >> file &&
+ git add file &&
+ mkdir success &&
+ (
+ cd success &&
+ git commit -m "hook requires GIT_PREFIX = success/"
+ ) &&
+ rmdir success
+'
+
+test_expect_success 'with failing hook requiring GIT_PREFIX' '
+
+ echo "more content" >> file &&
+ git add file &&
+ mkdir fail &&
+ (
+ cd fail &&
+ test_must_fail git commit -m "hook must fail"
+ ) &&
+ rmdir fail &&
+ git checkout -- file
+'
test_done
diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh
index ff189624d4..5b4b694f18 100755
--- a/t/t7505-prepare-commit-msg-hook.sh
+++ b/t/t7505-prepare-commit-msg-hook.sh
@@ -132,6 +132,18 @@ test_expect_success 'with hook (-c)' '
'
+test_expect_success 'with hook (merge)' '
+
+ head=`git rev-parse HEAD` &&
+ git checkout -b other HEAD@{1} &&
+ echo "more" >> file &&
+ git add file &&
+ git commit -m other &&
+ git checkout - &&
+ git merge other &&
+ test "`git log -1 --pretty=format:%s`" = merge
+'
+
cat > "$HOOK" <<'EOF'
#!/bin/sh
exit 1
diff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh
index 3d4f85d74f..d31b34da83 100755
--- a/t/t7506-status-submodule.sh
+++ b/t/t7506-status-submodule.sh
@@ -4,17 +4,21 @@ test_description='git status for submodule'
. ./test-lib.sh
-test_expect_success 'setup' '
- test_create_repo sub &&
+test_create_repo_with_commit () {
+ test_create_repo "$1" &&
(
- cd sub &&
+ cd "$1" &&
: >bar &&
git add bar &&
git commit -m " Add bar" &&
: >foo &&
git add foo &&
git commit -m " Add foo"
- ) &&
+ )
+}
+
+test_expect_success 'setup' '
+ test_create_repo_with_commit sub &&
echo output > .gitignore &&
git add sub .gitignore &&
git commit -m "Add submodule sub"
@@ -22,19 +26,19 @@ test_expect_success 'setup' '
test_expect_success 'status clean' '
git status >output &&
- grep "nothing to commit" output
+ test_i18ngrep "nothing to commit" output
'
test_expect_success 'commit --dry-run -a clean' '
test_must_fail git commit --dry-run -a >output &&
- grep "nothing to commit" output
+ test_i18ngrep "nothing to commit" output
'
test_expect_success 'status with modified file in submodule' '
(cd sub && git reset --hard) &&
echo "changed" >sub/foo &&
git status >output &&
- grep "modified: sub (modified content)" output
+ test_i18ngrep "modified: sub (modified content)" output
'
test_expect_success 'status with modified file in submodule (porcelain)' '
@@ -49,7 +53,7 @@ test_expect_success 'status with modified file in submodule (porcelain)' '
test_expect_success 'status with added file in submodule' '
(cd sub && git reset --hard && echo >foo && git add foo) &&
git status >output &&
- grep "modified: sub (modified content)" output
+ test_i18ngrep "modified: sub (modified content)" output
'
test_expect_success 'status with added file in submodule (porcelain)' '
@@ -64,12 +68,12 @@ test_expect_success 'status with untracked file in submodule' '
(cd sub && git reset --hard) &&
echo "content" >sub/new-file &&
git status >output &&
- grep "modified: sub (untracked content)" output
+ test_i18ngrep "modified: sub (untracked content)" output
'
test_expect_success 'status -uno with untracked file in submodule' '
git status -uno >output &&
- grep "^nothing to commit" output
+ test_i18ngrep "^nothing to commit" output
'
test_expect_success 'status with untracked file in submodule (porcelain)' '
@@ -83,7 +87,7 @@ test_expect_success 'status with added and untracked file in submodule' '
(cd sub && git reset --hard && echo >foo && git add foo) &&
echo "content" >sub/new-file &&
git status >output &&
- grep "modified: sub (modified content, untracked content)" output
+ test_i18ngrep "modified: sub (modified content, untracked content)" output
'
test_expect_success 'status with added and untracked file in submodule (porcelain)' '
@@ -101,7 +105,7 @@ test_expect_success 'status with modified file in modified submodule' '
(cd sub && echo "next change" >foo && git commit -m "next change" foo) &&
echo "changed" >sub/foo &&
git status >output &&
- grep "modified: sub (new commits, modified content)" output
+ test_i18ngrep "modified: sub (new commits, modified content)" output
'
test_expect_success 'status with modified file in modified submodule (porcelain)' '
@@ -116,7 +120,7 @@ test_expect_success 'status with modified file in modified submodule (porcelain)
test_expect_success 'status with added file in modified submodule' '
(cd sub && git reset --hard && echo >foo && git add foo) &&
git status >output &&
- grep "modified: sub (new commits, modified content)" output
+ test_i18ngrep "modified: sub (new commits, modified content)" output
'
test_expect_success 'status with added file in modified submodule (porcelain)' '
@@ -131,7 +135,7 @@ test_expect_success 'status with untracked file in modified submodule' '
(cd sub && git reset --hard) &&
echo "content" >sub/new-file &&
git status >output &&
- grep "modified: sub (new commits, untracked content)" output
+ test_i18ngrep "modified: sub (new commits, untracked content)" output
'
test_expect_success 'status with untracked file in modified submodule (porcelain)' '
@@ -145,7 +149,7 @@ test_expect_success 'status with added and untracked file in modified submodule'
(cd sub && git reset --hard && echo >foo && git add foo) &&
echo "content" >sub/new-file &&
git status >output &&
- grep "modified: sub (new commits, modified content, untracked content)" output
+ test_i18ngrep "modified: sub (new commits, modified content, untracked content)" output
'
test_expect_success 'status with added and untracked file in modified submodule (porcelain)' '
@@ -170,7 +174,7 @@ test_expect_success 'setup .git file for sub' '
test_expect_success 'status with added file in modified submodule with .git file' '
(cd sub && git reset --hard && echo >foo && git add foo) &&
git status >output &&
- grep "modified: sub (new commits, modified content)" output
+ test_i18ngrep "modified: sub (new commits, modified content)" output
'
test_expect_success 'rm submodule contents' '
@@ -179,12 +183,92 @@ test_expect_success 'rm submodule contents' '
test_expect_success 'status clean (empty submodule dir)' '
git status >output &&
- grep "nothing to commit" output
+ test_i18ngrep "nothing to commit" output
'
test_expect_success 'status -a clean (empty submodule dir)' '
test_must_fail git commit --dry-run -a >output &&
- grep "nothing to commit" output
+ test_i18ngrep "nothing to commit" output
+'
+
+cat >status_expect <<\EOF
+AA .gitmodules
+A sub1
+EOF
+
+test_expect_success 'status with merge conflict in .gitmodules' '
+ git clone . super &&
+ test_create_repo_with_commit sub1 &&
+ test_tick &&
+ test_create_repo_with_commit sub2 &&
+ (
+ cd super &&
+ prev=$(git rev-parse HEAD) &&
+ git checkout -b add_sub1 &&
+ git submodule add ../sub1 &&
+ git commit -m "add sub1" &&
+ git checkout -b add_sub2 $prev &&
+ git submodule add ../sub2 &&
+ git commit -m "add sub2" &&
+ git checkout -b merge_conflict_gitmodules &&
+ test_must_fail git merge add_sub1 &&
+ git status -s >../status_actual 2>&1
+ ) &&
+ test_cmp status_actual status_expect
+'
+
+sha1_merge_sub1=$(cd sub1 && git rev-parse HEAD)
+sha1_merge_sub2=$(cd sub2 && git rev-parse HEAD)
+short_sha1_merge_sub1=$(cd sub1 && git rev-parse --short HEAD)
+short_sha1_merge_sub2=$(cd sub2 && git rev-parse --short HEAD)
+cat >diff_expect <<\EOF
+diff --cc .gitmodules
+index badaa4c,44f999a..0000000
+--- a/.gitmodules
++++ b/.gitmodules
+@@@ -1,3 -1,3 +1,9 @@@
+++<<<<<<< HEAD
+ +[submodule "sub2"]
+ + path = sub2
+ + url = ../sub2
+++=======
++ [submodule "sub1"]
++ path = sub1
++ url = ../sub1
+++>>>>>>> add_sub1
+EOF
+
+cat >diff_submodule_expect <<\EOF
+diff --cc .gitmodules
+index badaa4c,44f999a..0000000
+--- a/.gitmodules
++++ b/.gitmodules
+@@@ -1,3 -1,3 +1,9 @@@
+++<<<<<<< HEAD
+ +[submodule "sub2"]
+ + path = sub2
+ + url = ../sub2
+++=======
++ [submodule "sub1"]
++ path = sub1
++ url = ../sub1
+++>>>>>>> add_sub1
+EOF
+
+test_expect_success 'diff with merge conflict in .gitmodules' '
+ (
+ cd super &&
+ git diff >../diff_actual 2>&1
+ ) &&
+ test_cmp diff_actual diff_expect
+'
+
+test_expect_success 'diff --submodule with merge conflict in .gitmodules' '
+ (
+ cd super &&
+ git diff --submodule >../diff_submodule_actual 2>&1
+ ) &&
+ test_cmp diff_submodule_actual diff_submodule_expect
'
test_done
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index f1dc5c3b6a..905255adf0 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -16,7 +16,7 @@ test_expect_success 'status -h in broken repository' '
echo "[status] showuntrackedfiles = CORRUPT" >>.git/config &&
test_expect_code 129 git status -h >usage 2>&1
) &&
- grep "[Uu]sage" broken/usage
+ test_i18ngrep "[Uu]sage" broken/usage
'
test_expect_success 'commit -h in broken repository' '
@@ -28,7 +28,7 @@ test_expect_success 'commit -h in broken repository' '
echo "[status] showuntrackedfiles = CORRUPT" >>.git/config &&
test_expect_code 129 git commit -h >usage 2>&1
) &&
- grep "[Uu]sage" broken/usage
+ test_i18ngrep "[Uu]sage" broken/usage
'
test_expect_success 'setup' '
@@ -56,9 +56,7 @@ test_expect_success 'setup' '
'
test_expect_success 'status (1)' '
-
- grep "use \"git rm --cached <file>\.\.\.\" to unstage" output
-
+ test_i18ngrep "use \"git rm --cached <file>\.\.\.\" to unstage" output
'
cat >expect <<\EOF
@@ -86,10 +84,8 @@ cat >expect <<\EOF
EOF
test_expect_success 'status (2)' '
-
git status >output &&
- test_cmp expect output
-
+ test_i18ncmp expect output
'
cat >expect <<\EOF
@@ -109,17 +105,14 @@ cat >expect <<\EOF
# untracked
EOF
-git config advice.statusHints false
-
test_expect_success 'status (advice.statusHints false)' '
-
+ test_when_finished "git config --unset advice.statusHints" &&
+ git config advice.statusHints false &&
git status >output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
-git config --unset advice.statusHints
-
cat >expect <<\EOF
M dir1/modified
A dir2/added
@@ -138,6 +131,127 @@ test_expect_success 'status -s' '
'
+test_expect_success 'status with gitignore' '
+ {
+ echo ".gitignore" &&
+ echo "expect" &&
+ echo "output" &&
+ echo "untracked"
+ } >.gitignore &&
+
+ cat >expect <<-\EOF &&
+ M dir1/modified
+ A dir2/added
+ ?? dir2/modified
+ EOF
+ git status -s >output &&
+ test_cmp expect output &&
+
+ cat >expect <<-\EOF &&
+ M dir1/modified
+ A dir2/added
+ ?? dir2/modified
+ !! .gitignore
+ !! dir1/untracked
+ !! dir2/untracked
+ !! expect
+ !! output
+ !! untracked
+ EOF
+ git status -s --ignored >output &&
+ test_cmp expect output &&
+
+ cat >expect <<-\EOF &&
+ # On branch master
+ # Changes to be committed:
+ # (use "git reset HEAD <file>..." to unstage)
+ #
+ # new file: dir2/added
+ #
+ # Changes not staged for commit:
+ # (use "git add <file>..." to update what will be committed)
+ # (use "git checkout -- <file>..." to discard changes in working directory)
+ #
+ # modified: dir1/modified
+ #
+ # Untracked files:
+ # (use "git add <file>..." to include in what will be committed)
+ #
+ # dir2/modified
+ # Ignored files:
+ # (use "git add -f <file>..." to include in what will be committed)
+ #
+ # .gitignore
+ # dir1/untracked
+ # dir2/untracked
+ # expect
+ # output
+ # untracked
+ EOF
+ git status --ignored >output &&
+ test_cmp expect output
+'
+
+test_expect_success 'status with gitignore (nothing untracked)' '
+ {
+ echo ".gitignore" &&
+ echo "expect" &&
+ echo "dir2/modified" &&
+ echo "output" &&
+ echo "untracked"
+ } >.gitignore &&
+
+ cat >expect <<-\EOF &&
+ M dir1/modified
+ A dir2/added
+ EOF
+ git status -s >output &&
+ test_cmp expect output &&
+
+ cat >expect <<-\EOF &&
+ M dir1/modified
+ A dir2/added
+ !! .gitignore
+ !! dir1/untracked
+ !! dir2/modified
+ !! dir2/untracked
+ !! expect
+ !! output
+ !! untracked
+ EOF
+ git status -s --ignored >output &&
+ test_cmp expect output &&
+
+ cat >expect <<-\EOF &&
+ # On branch master
+ # Changes to be committed:
+ # (use "git reset HEAD <file>..." to unstage)
+ #
+ # new file: dir2/added
+ #
+ # Changes not staged for commit:
+ # (use "git add <file>..." to update what will be committed)
+ # (use "git checkout -- <file>..." to discard changes in working directory)
+ #
+ # modified: dir1/modified
+ #
+ # Ignored files:
+ # (use "git add -f <file>..." to include in what will be committed)
+ #
+ # .gitignore
+ # dir1/untracked
+ # dir2/modified
+ # dir2/untracked
+ # expect
+ # output
+ # untracked
+ EOF
+ git status --ignored >output &&
+ test_cmp expect output
+'
+
+rm -f .gitignore
+
cat >expect <<\EOF
## master
M dir1/modified
@@ -157,6 +271,12 @@ test_expect_success 'status -s -b' '
'
+test_expect_success 'setup dir3' '
+ mkdir dir3 &&
+ : >dir3/untracked1 &&
+ : >dir3/untracked2
+'
+
cat >expect <<EOF
# On branch master
# Changes to be committed:
@@ -173,17 +293,15 @@ cat >expect <<EOF
# Untracked files not listed (use -u option to show untracked files)
EOF
test_expect_success 'status -uno' '
- mkdir dir3 &&
- : >dir3/untracked1 &&
- : >dir3/untracked2 &&
git status -uno >output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
test_expect_success 'status (status.showUntrackedFiles no)' '
git config status.showuntrackedfiles no
+ test_when_finished "git config --unset status.showuntrackedfiles" &&
git status >output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
cat >expect <<EOF
@@ -199,7 +317,7 @@ EOF
git config advice.statusHints false
test_expect_success 'status -uno (advice.statusHints false)' '
git status -uno >output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
git config --unset advice.statusHints
@@ -208,7 +326,6 @@ cat >expect << EOF
A dir2/added
EOF
test_expect_success 'status -s -uno' '
- git config --unset status.showuntrackedfiles
git status -s -uno >output &&
test_cmp expect output
'
@@ -245,13 +362,14 @@ cat >expect <<EOF
EOF
test_expect_success 'status -unormal' '
git status -unormal >output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
test_expect_success 'status (status.showUntrackedFiles normal)' '
git config status.showuntrackedfiles normal
+ test_when_finished "git config --unset status.showuntrackedfiles" &&
git status >output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
cat >expect <<EOF
@@ -266,7 +384,6 @@ A dir2/added
?? untracked
EOF
test_expect_success 'status -s -unormal' '
- git config --unset status.showuntrackedfiles
git status -s -unormal >output &&
test_cmp expect output
'
@@ -304,14 +421,18 @@ cat >expect <<EOF
EOF
test_expect_success 'status -uall' '
git status -uall >output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
+
test_expect_success 'status (status.showUntrackedFiles all)' '
git config status.showuntrackedfiles all
+ test_when_finished "git config --unset status.showuntrackedfiles" &&
git status >output &&
- rm -rf dir3 &&
- git config --unset status.showuntrackedfiles &&
- test_cmp expect output
+ test_i18ncmp expect output
+'
+
+test_expect_success 'teardown dir3' '
+ rm -rf dir3
'
cat >expect <<EOF
@@ -362,10 +483,8 @@ cat >expect <<\EOF
EOF
test_expect_success 'status with relative paths' '
-
(cd dir1 && git status) >output &&
- test_cmp expect output
-
+ test_i18ncmp expect output
'
cat >expect <<\EOF
@@ -435,20 +554,17 @@ cat >expect <<\EOF
EOF
test_expect_success 'status with color.ui' '
-
git config color.ui always &&
+ test_when_finished "git config --unset color.ui" &&
git status | test_decode_color >output &&
- test_cmp expect output
-
+ test_i18ncmp expect output
'
test_expect_success 'status with color.status' '
-
- git config --unset color.ui &&
git config color.status always &&
+ test_when_finished "git config --unset color.status" &&
git status | test_decode_color >output &&
- test_cmp expect output
-
+ test_i18ncmp expect output
'
cat >expect <<\EOF
@@ -464,7 +580,6 @@ EOF
test_expect_success 'status -s with color.ui' '
- git config --unset color.status &&
git config color.ui always &&
git status -s | test_decode_color >output &&
test_cmp expect output
@@ -566,9 +681,10 @@ EOF
test_expect_success 'status without relative paths' '
- git config status.relativePaths false
+ git config status.relativePaths false &&
+ test_when_finished "git config --unset status.relativePaths" &&
(cd dir1 && git status) >output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
@@ -585,6 +701,8 @@ EOF
test_expect_success 'status -s without relative paths' '
+ git config status.relativePaths false &&
+ test_when_finished "git config --unset status.relativePaths" &&
(cd dir1 && git status -s) >output &&
test_cmp expect output
@@ -608,7 +726,7 @@ cat <<EOF >expect
EOF
test_expect_success 'dry-run of partial commit excluding new file in index' '
git commit --dry-run dir1/modified >output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
cat >expect <<EOF
@@ -657,13 +775,13 @@ cat >expect <<EOF
EOF
test_expect_success 'status submodule summary is disabled by default' '
git status >output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
# we expect the same as the previous test
test_expect_success 'status --untracked-files=all does not show submodule' '
git status --untracked-files=all >output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
cat >expect <<EOF
@@ -722,7 +840,7 @@ EOF
test_expect_success 'status submodule summary' '
git config status.submodulesummary 10 &&
git status >output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
cat >expect <<EOF
@@ -760,13 +878,13 @@ cat >expect <<EOF
# untracked
no changes added to commit (use "git add" and/or "git commit -a")
EOF
-test_expect_success 'status submodule summary (clean submodule)' '
+test_expect_success 'status submodule summary (clean submodule): commit' '
git commit -m "commit submodule" &&
git config status.submodulesummary 10 &&
test_must_fail git commit --dry-run >output &&
- test_cmp expect output &&
+ test_i18ncmp expect output &&
git status >output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
cat >expect <<EOF
@@ -783,6 +901,13 @@ test_expect_success 'status -s submodule summary (clean submodule)' '
test_cmp expect output
'
+test_expect_success 'status -z implies porcelain' '
+ git status --porcelain |
+ perl -pe "s/\012/\000/g" >expect &&
+ git status -z >output &&
+ test_cmp expect output
+'
+
cat >expect <<EOF
# On branch master
# Changes to be committed:
@@ -815,7 +940,7 @@ EOF
test_expect_success 'commit --dry-run submodule summary (--amend)' '
git config status.submodulesummary 10 &&
git commit --dry-run --amend >output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
test_expect_success POSIXPERM,SANITY 'status succeeds in a read-only repository' '
@@ -868,19 +993,19 @@ cat > expect << EOF
EOF
test_expect_success '--ignore-submodules=untracked suppresses submodules with untracked content' '
- echo modified > sm/untracked &&
- git status --ignore-submodules=untracked > output &&
- test_cmp expect output
+ echo modified sm/untracked &&
+ git status --ignore-submodules=untracked >output &&
+ test_i18ncmp expect output
'
test_expect_success '.gitmodules ignore=untracked suppresses submodules with untracked content' '
git config diff.ignoreSubmodules dirty &&
git status >output &&
- test_cmp expect output &&
+ test_i18ncmp expect output &&
git config --add -f .gitmodules submodule.subname.ignore untracked &&
git config --add -f .gitmodules submodule.subname.path sm &&
- git status > output &&
- test_cmp expect output &&
+ git status >output &&
+ test_i18ncmp expect output &&
git config -f .gitmodules --remove-section submodule.subname &&
git config --unset diff.ignoreSubmodules
'
@@ -890,15 +1015,15 @@ test_expect_success '.git/config ignore=untracked suppresses submodules with unt
git config --add -f .gitmodules submodule.subname.path sm &&
git config --add submodule.subname.ignore untracked &&
git config --add submodule.subname.path sm &&
- git status > output &&
- test_cmp expect output &&
+ git status >output &&
+ test_i18ncmp expect output &&
git config --remove-section submodule.subname &&
git config --remove-section -f .gitmodules submodule.subname
'
test_expect_success '--ignore-submodules=dirty suppresses submodules with untracked content' '
- git status --ignore-submodules=dirty > output &&
- test_cmp expect output
+ git status --ignore-submodules=dirty >output &&
+ test_i18ncmp expect output
'
test_expect_success '.gitmodules ignore=dirty suppresses submodules with untracked content' '
@@ -907,8 +1032,8 @@ test_expect_success '.gitmodules ignore=dirty suppresses submodules with untrack
! test -s actual &&
git config --add -f .gitmodules submodule.subname.ignore dirty &&
git config --add -f .gitmodules submodule.subname.path sm &&
- git status > output &&
- test_cmp expect output &&
+ git status >output &&
+ test_i18ncmp expect output &&
git config -f .gitmodules --remove-section submodule.subname &&
git config --unset diff.ignoreSubmodules
'
@@ -918,23 +1043,23 @@ test_expect_success '.git/config ignore=dirty suppresses submodules with untrack
git config --add -f .gitmodules submodule.subname.path sm &&
git config --add submodule.subname.ignore dirty &&
git config --add submodule.subname.path sm &&
- git status > output &&
- test_cmp expect output &&
+ git status >output &&
+ test_i18ncmp expect output &&
git config --remove-section submodule.subname &&
git config -f .gitmodules --remove-section submodule.subname
'
test_expect_success '--ignore-submodules=dirty suppresses submodules with modified content' '
- echo modified > sm/foo &&
- git status --ignore-submodules=dirty > output &&
- test_cmp expect output
+ echo modified >sm/foo &&
+ git status --ignore-submodules=dirty >output &&
+ test_i18ncmp expect output
'
test_expect_success '.gitmodules ignore=dirty suppresses submodules with modified content' '
git config --add -f .gitmodules submodule.subname.ignore dirty &&
git config --add -f .gitmodules submodule.subname.path sm &&
- git status > output &&
- test_cmp expect output &&
+ git status >output &&
+ test_i18ncmp expect output &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -943,8 +1068,8 @@ test_expect_success '.git/config ignore=dirty suppresses submodules with modifie
git config --add -f .gitmodules submodule.subname.path sm &&
git config --add submodule.subname.ignore dirty &&
git config --add submodule.subname.path sm &&
- git status > output &&
- test_cmp expect output &&
+ git status >output &&
+ test_i18ncmp expect output &&
git config --remove-section submodule.subname &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -983,14 +1108,14 @@ EOF
test_expect_success "--ignore-submodules=untracked doesn't suppress submodules with modified content" '
git status --ignore-submodules=untracked > output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
test_expect_success ".gitmodules ignore=untracked doesn't suppress submodules with modified content" '
git config --add -f .gitmodules submodule.subname.ignore untracked &&
git config --add -f .gitmodules submodule.subname.path sm &&
- git status > output &&
- test_cmp expect output &&
+ git status >output &&
+ test_i18ncmp expect output &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -999,8 +1124,8 @@ test_expect_success ".git/config ignore=untracked doesn't suppress submodules wi
git config --add -f .gitmodules submodule.subname.path sm &&
git config --add submodule.subname.ignore untracked &&
git config --add submodule.subname.path sm &&
- git status > output &&
- test_cmp expect output &&
+ git status >output &&
+ test_i18ncmp expect output &&
git config --remove-section submodule.subname &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -1045,14 +1170,14 @@ EOF
test_expect_success "--ignore-submodules=untracked doesn't suppress submodule summary" '
git status --ignore-submodules=untracked > output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
test_expect_success ".gitmodules ignore=untracked doesn't suppress submodule summary" '
git config --add -f .gitmodules submodule.subname.ignore untracked &&
git config --add -f .gitmodules submodule.subname.path sm &&
- git status > output &&
- test_cmp expect output &&
+ git status >output &&
+ test_i18ncmp expect output &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -1061,21 +1186,21 @@ test_expect_success ".git/config ignore=untracked doesn't suppress submodule sum
git config --add -f .gitmodules submodule.subname.path sm &&
git config --add submodule.subname.ignore untracked &&
git config --add submodule.subname.path sm &&
- git status > output &&
- test_cmp expect output &&
+ git status >output &&
+ test_i18ncmp expect output &&
git config --remove-section submodule.subname &&
git config -f .gitmodules --remove-section submodule.subname
'
test_expect_success "--ignore-submodules=dirty doesn't suppress submodule summary" '
git status --ignore-submodules=dirty > output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
test_expect_success ".gitmodules ignore=dirty doesn't suppress submodule summary" '
git config --add -f .gitmodules submodule.subname.ignore dirty &&
git config --add -f .gitmodules submodule.subname.path sm &&
- git status > output &&
- test_cmp expect output &&
+ git status >output &&
+ test_i18ncmp expect output &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -1084,8 +1209,8 @@ test_expect_success ".git/config ignore=dirty doesn't suppress submodule summary
git config --add -f .gitmodules submodule.subname.path sm &&
git config --add submodule.subname.ignore dirty &&
git config --add submodule.subname.path sm &&
- git status > output &&
- test_cmp expect output &&
+ git status >output &&
+ test_i18ncmp expect output &&
git config --remove-section submodule.subname &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -1113,7 +1238,7 @@ EOF
test_expect_success "--ignore-submodules=all suppresses submodule summary" '
git status --ignore-submodules=all > output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
test_expect_failure '.gitmodules ignore=all suppresses submodule summary' '
diff --git a/t/t7509-commit.sh b/t/t7509-commit.sh
index 77b6920029..b61fd3c3c4 100755
--- a/t/t7509-commit.sh
+++ b/t/t7509-commit.sh
@@ -157,4 +157,33 @@ test_expect_success '--reset-author should be rejected without -c/-C/--amend' '
test_must_fail git commit -a --reset-author -m done
'
+test_expect_success 'commit respects CHERRY_PICK_HEAD and MERGE_MSG' '
+ echo "cherry-pick 1a" >>foo &&
+ test_tick &&
+ git commit -am "cherry-pick 1" --author="Cherry <cherry@pick.er>" &&
+ git tag cherry-pick-head &&
+ git rev-parse cherry-pick-head >.git/CHERRY_PICK_HEAD &&
+ echo "This is a MERGE_MSG" >.git/MERGE_MSG &&
+ echo "cherry-pick 1b" >>foo &&
+ test_tick &&
+ git commit -a &&
+ author_header cherry-pick-head >expect &&
+ author_header HEAD >actual &&
+ test_cmp expect actual &&
+
+ echo "This is a MERGE_MSG" >expect &&
+ message_body HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--reset-author with CHERRY_PICK_HEAD' '
+ git rev-parse cherry-pick-head >.git/CHERRY_PICK_HEAD &&
+ echo "cherry-pick 2" >>foo &&
+ test_tick &&
+ git commit -am "cherry-pick 2" --reset-author &&
+ echo "author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE" >expect &&
+ author_header HEAD >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t7511-status-index.sh b/t/t7511-status-index.sh
new file mode 100755
index 0000000000..bca359dc1e
--- /dev/null
+++ b/t/t7511-status-index.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+test_description='git status with certain file name lengths'
+
+. ./test-lib.sh
+
+files="0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z"
+
+check() {
+ len=$1
+ prefix=$2
+
+ for i in $files
+ do
+ : >$prefix$i
+ done
+
+ test_expect_success "status, filename length $len" "
+ git add $prefix* &&
+ git status
+ "
+ rm $prefix* .git/index
+}
+
+check 1
+check 2 p
+check 3 pr
+check 4 pre
+check 5 pref
+check 6 prefi
+check 7 prefix
+check 8 prefix-
+check 9 prefix-p
+check 10 prefix-pr
+check 11 prefix-pre
+check 12 prefix-pref
+check 13 prefix-prefi
+check 14 prefix-prefix
+check 15 prefix-prefix-
+check 16 prefix-prefix-p
+check 17 prefix-prefix-pr
+check 18 prefix-prefix-pre
+check 19 prefix-prefix-pref
+check 20 prefix-prefix-prefi
+check 21 prefix-prefix-prefix
+check 22 prefix-prefix-prefix-
+check 23 prefix-prefix-prefix-p
+check 24 prefix-prefix-prefix-pr
+
+test_done
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index b147a1bd69..3008e4e121 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -28,80 +28,80 @@ Testing basic merge operations/option parsing.
. ./test-lib.sh
-test_expect_success 'set up test data and helpers' '
- printf "%s\n" 1 2 3 4 5 6 7 8 9 >file &&
- printf "%s\n" "1 X" 2 3 4 5 6 7 8 9 >file.1 &&
- printf "%s\n" 1 2 3 4 "5 X" 6 7 8 9 >file.5 &&
- printf "%s\n" 1 2 3 4 5 6 7 8 "9 X" >file.9 &&
- printf "%s\n" "1 X" 2 3 4 5 6 7 8 9 >result.1 &&
- printf "%s\n" "1 X" 2 3 4 "5 X" 6 7 8 9 >result.1-5 &&
- printf "%s\n" "1 X" 2 3 4 "5 X" 6 7 8 "9 X" >result.1-5-9 &&
-
- create_merge_msgs() {
- echo "Merge commit '\''c2'\''" >msg.1-5 &&
- echo "Merge commit '\''c2'\''; commit '\''c3'\''" >msg.1-5-9 &&
- {
- echo "Squashed commit of the following:" &&
- echo &&
- git log --no-merges ^HEAD c1
- } >squash.1 &&
- {
- echo "Squashed commit of the following:" &&
- echo &&
- git log --no-merges ^HEAD c2
- } >squash.1-5 &&
- {
- echo "Squashed commit of the following:" &&
- echo &&
- git log --no-merges ^HEAD c2 c3
- } >squash.1-5-9 &&
- echo >msg.nolog &&
- {
- echo "* commit '\''c3'\'':" &&
- echo " commit 3" &&
- echo
- } >msg.log
- } &&
-
- verify_merge() {
- test_cmp "$2" "$1" &&
- git update-index --refresh &&
- git diff --exit-code &&
- if test -n "$3"
- then
- git show -s --pretty=format:%s HEAD >msg.act &&
- test_cmp "$3" msg.act
- fi
- } &&
-
- verify_head() {
- echo "$1" >head.expected &&
- git rev-parse HEAD >head.actual &&
- test_cmp head.expected head.actual
- } &&
-
- verify_parents() {
- printf "%s\n" "$@" >parents.expected &&
- >parents.actual &&
- i=1 &&
- while test $i -le $#
- do
- git rev-parse HEAD^$i >>parents.actual &&
- i=$(expr $i + 1) ||
- return 1
- done &&
- test_cmp parents.expected parents.actual
- } &&
-
- verify_mergeheads() {
- printf "%s\n" "$@" >mergehead.expected &&
- test_cmp mergehead.expected .git/MERGE_HEAD
- } &&
-
- verify_no_mergehead() {
- ! test -e .git/MERGE_HEAD
- }
-'
+printf '%s\n' 1 2 3 4 5 6 7 8 9 >file
+printf '%s\n' '1 X' 2 3 4 5 6 7 8 9 >file.1
+printf '%s\n' 1 2 3 4 '5 X' 6 7 8 9 >file.5
+printf '%s\n' 1 2 3 4 5 6 7 8 '9 X' >file.9
+printf '%s\n' '1 X' 2 3 4 5 6 7 8 9 >result.1
+printf '%s\n' '1 X' 2 3 4 '5 X' 6 7 8 9 >result.1-5
+printf '%s\n' '1 X' 2 3 4 '5 X' 6 7 8 '9 X' >result.1-5-9
+>empty
+
+create_merge_msgs () {
+ echo "Merge commit 'c2'" >msg.1-5 &&
+ echo "Merge commit 'c2'; commit 'c3'" >msg.1-5-9 &&
+ {
+ echo "Squashed commit of the following:" &&
+ echo &&
+ git log --no-merges ^HEAD c1
+ } >squash.1 &&
+ {
+ echo "Squashed commit of the following:" &&
+ echo &&
+ git log --no-merges ^HEAD c2
+ } >squash.1-5 &&
+ {
+ echo "Squashed commit of the following:" &&
+ echo &&
+ git log --no-merges ^HEAD c2 c3
+ } >squash.1-5-9 &&
+ echo >msg.nolog &&
+ {
+ echo "* commit 'c3':" &&
+ echo " commit 3" &&
+ echo
+ } >msg.log
+}
+
+verify_merge () {
+ test_cmp "$2" "$1" &&
+ git update-index --refresh &&
+ git diff --exit-code &&
+ if test -n "$3"
+ then
+ git show -s --pretty=format:%s HEAD >msg.act &&
+ test_cmp "$3" msg.act
+ fi
+}
+
+verify_head () {
+ echo "$1" >head.expected &&
+ git rev-parse HEAD >head.actual &&
+ test_cmp head.expected head.actual
+}
+
+verify_parents () {
+ printf '%s\n' "$@" >parents.expected &&
+ >parents.actual &&
+ i=1 &&
+ while test $i -le $#
+ do
+ git rev-parse HEAD^$i >>parents.actual &&
+ i=$(expr $i + 1) ||
+ return 1
+ done &&
+ test_must_fail git rev-parse --verify "HEAD^$i" &&
+ test_cmp parents.expected parents.actual
+}
+
+verify_mergeheads () {
+ printf '%s\n' "$@" >mergehead.expected &&
+ test_cmp mergehead.expected .git/MERGE_HEAD
+}
+
+verify_no_mergehead () {
+ ! test -e .git/MERGE_HEAD
+}
test_expect_success 'setup' '
git add file &&
@@ -225,12 +225,28 @@ test_expect_success 'merge c1 with c2 and c3' '
test_debug 'git log --graph --decorate --oneline --all'
-test_expect_success 'failing merges with --ff-only' '
+test_expect_success 'merges with --ff-only' '
git reset --hard c1 &&
test_tick &&
test_must_fail git merge --ff-only c2 &&
test_must_fail git merge --ff-only c3 &&
- test_must_fail git merge --ff-only c2 c3
+ test_must_fail git merge --ff-only c2 c3 &&
+ git reset --hard c0 &&
+ git merge c3 &&
+ verify_head $c3
+'
+
+test_expect_success 'merges with merge.ff=only' '
+ git reset --hard c1 &&
+ test_tick &&
+ test_when_finished "git config --unset merge.ff" &&
+ git config merge.ff only &&
+ test_must_fail git merge c2 &&
+ test_must_fail git merge c3 &&
+ test_must_fail git merge c2 c3 &&
+ git reset --hard c0 &&
+ git merge c3 &&
+ verify_head $c3
'
test_expect_success 'merge c0 with c1 (no-commit)' '
@@ -324,6 +340,39 @@ test_expect_success 'merge c1 with c2 (no-commit in config)' '
test_debug 'git log --graph --decorate --oneline --all'
+test_expect_success 'merge c1 with c2 (log in config)' '
+ git config branch.master.mergeoptions "" &&
+ git reset --hard c1 &&
+ git merge --log c2 &&
+ git show -s --pretty=tformat:%s%n%b >expect &&
+
+ git config branch.master.mergeoptions --log &&
+ git reset --hard c1 &&
+ git merge c2 &&
+ git show -s --pretty=tformat:%s%n%b >actual &&
+
+ test_cmp expect actual
+'
+
+test_expect_success 'merge c1 with c2 (log in config gets overridden)' '
+ test_when_finished "git config --remove-section branch.master" &&
+ test_when_finished "git config --remove-section merge" &&
+ test_might_fail git config --remove-section branch.master &&
+ test_might_fail git config --remove-section merge &&
+
+ git reset --hard c1 &&
+ git merge c2 &&
+ git show -s --pretty=tformat:%s%n%b >expect &&
+
+ git config branch.master.mergeoptions "--no-log" &&
+ git config merge.log true &&
+ git reset --hard c1 &&
+ git merge c2 &&
+ git show -s --pretty=tformat:%s%n%b >actual &&
+
+ test_cmp expect actual
+'
+
test_expect_success 'merge c1 with c2 (squash in config)' '
git reset --hard c1 &&
git config branch.master.mergeoptions "--squash" &&
@@ -415,7 +464,41 @@ test_expect_success 'merge c0 with c1 (no-ff)' '
test_debug 'git log --graph --decorate --oneline --all'
+test_expect_success 'merge c0 with c1 (merge.ff=false)' '
+ git reset --hard c0 &&
+ git config merge.ff false &&
+ test_tick &&
+ git merge c1 &&
+ git config --remove-section merge &&
+ verify_merge file result.1 &&
+ verify_parents $c0 $c1
+'
+test_debug 'git log --graph --decorate --oneline --all'
+
+test_expect_success 'combine branch.master.mergeoptions with merge.ff' '
+ git reset --hard c0 &&
+ git config branch.master.mergeoptions --ff &&
+ git config merge.ff false &&
+ test_tick &&
+ git merge c1 &&
+ git config --remove-section "branch.master" &&
+ git config --remove-section "merge" &&
+ verify_merge file result.1 &&
+ verify_parents "$c0"
+'
+
+test_expect_success 'tolerate unknown values for merge.ff' '
+ git reset --hard c0 &&
+ git config merge.ff something-new &&
+ test_tick &&
+ git merge c1 2>message &&
+ git config --remove-section "merge" &&
+ verify_head "$c1" &&
+ test_cmp empty message
+'
+
test_expect_success 'combining --squash and --no-ff is refused' '
+ git reset --hard c0 &&
test_must_fail git merge --squash --no-ff c1 &&
test_must_fail git merge --no-ff --squash c1
'
@@ -498,7 +581,7 @@ test_debug 'git log --graph --decorate --oneline --all'
test_expect_success 'in-index merge' '
git reset --hard c0 &&
git merge --no-ff -s resolve c1 >out &&
- grep "Wonderful." out &&
+ test_i18ngrep "Wonderful." out &&
verify_parents $c0 $c1
'
@@ -560,4 +643,27 @@ test_expect_success 'amending no-ff merge commit' '
test_debug 'git log --graph --decorate --oneline --all'
+cat >editor <<\EOF
+#!/bin/sh
+# Add a new message string that was not in the template
+(
+ echo "Merge work done on the side branch c1"
+ echo
+ cat <"$1"
+) >"$1.tmp" && mv "$1.tmp" "$1"
+# strip comments and blank lines from end of message
+sed -e '/^#/d' < "$1" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' > expected
+EOF
+chmod 755 editor
+
+test_expect_success 'merge --no-ff --edit' '
+ git reset --hard c0 &&
+ EDITOR=./editor git merge --no-ff --edit c1 &&
+ verify_parents $c0 $c1 &&
+ git cat-file commit HEAD >raw &&
+ grep "work done on the side branch" raw &&
+ sed "1,/^$/d" >actual raw &&
+ test_cmp actual expected
+'
+
test_done
diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index 0a46795ae7..61f36baa1f 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -53,7 +53,7 @@ cat >expected <<\EOF
Trying simple merge with c2
Trying simple merge with c3
Trying simple merge with c4
-Merge made by octopus.
+Merge made by the 'octopus' strategy.
c2.c | 1 +
c3.c | 1 +
c4.c | 1 +
@@ -72,7 +72,7 @@ test_expect_success 'merge output uses pretty names' '
cat >expected <<\EOF
Already up-to-date with c4
Trying simple merge with c5
-Merge made by octopus.
+Merge made by the 'octopus' strategy.
c5.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 c5.c
@@ -86,7 +86,7 @@ test_expect_success 'merge up-to-date output uses pretty names' '
cat >expected <<\EOF
Fast-forwarding to: c1
Trying simple merge with c2
-Merge made by octopus.
+Merge made by the 'octopus' strategy.
c1.c | 1 +
c2.c | 1 +
2 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/t/t7607-merge-overwrite.sh b/t/t7607-merge-overwrite.sh
index 4d5ce4e682..aa74184c31 100755
--- a/t/t7607-merge-overwrite.sh
+++ b/t/t7607-merge-overwrite.sh
@@ -107,6 +107,7 @@ error: The following untracked working tree files would be overwritten by merge:
sub
sub2
Please move or remove them before you can merge.
+Aborting
EOF
test_expect_success 'will not overwrite untracked file in leading path' '
@@ -122,7 +123,7 @@ test_expect_success 'will not overwrite untracked file in leading path' '
rm -f sub sub2
'
-test_expect_failure SYMLINKS 'will not overwrite untracked symlink in leading path' '
+test_expect_success SYMLINKS 'will not overwrite untracked symlink in leading path' '
git reset --hard c0 &&
rm -rf sub &&
mkdir sub2 &&
@@ -151,9 +152,33 @@ test_expect_success 'will not overwrite untracked file on unborn branch' '
git checkout --orphan new &&
cp important c0.c &&
test_must_fail git merge c0 2>out &&
- test_cmp out expect &&
+ test_i18ncmp out expect
+'
+
+test_expect_success 'will not overwrite untracked file on unborn branch .git/MERGE_HEAD sanity etc.' '
+ test_when_finished "rm c0.c" &&
test_path_is_missing .git/MERGE_HEAD &&
test_cmp important c0.c
'
+test_expect_success 'failed merge leaves unborn branch in the womb' '
+ test_must_fail git rev-parse --verify HEAD
+'
+
+test_expect_success 'set up unborn branch and content' '
+ git symbolic-ref HEAD refs/heads/unborn &&
+ rm -f .git/index &&
+ echo foo > tracked-file &&
+ git add tracked-file &&
+ echo bar > untracked-file
+'
+
+test_expect_success 'will not clobber WT/index when merging into unborn' '
+ git merge master &&
+ grep foo tracked-file &&
+ git show :tracked-file >expect &&
+ grep foo expect &&
+ grep bar untracked-file
+'
+
test_done
diff --git a/t/t7609-merge-co-error-msgs.sh b/t/t7609-merge-co-error-msgs.sh
index c994836c53..0e4a682c64 100755
--- a/t/t7609-merge-co-error-msgs.sh
+++ b/t/t7609-merge-co-error-msgs.sh
@@ -32,6 +32,7 @@ error: The following untracked working tree files would be overwritten by merge:
three
two
Please move or remove them before you can merge.
+Aborting
EOF
test_expect_success 'untracked files overwritten by merge (fast and non-fast forward)' '
@@ -56,6 +57,7 @@ Please, commit your changes or stash them before you can merge.
error: The following untracked working tree files would be overwritten by merge:
five
Please move or remove them before you can merge.
+Aborting
EOF
test_expect_success 'untracked files or local changes ovewritten by merge' '
@@ -71,6 +73,7 @@ error: Your local changes to the following files would be overwritten by checkou
rep/one
rep/two
Please, commit your changes or stash them before you can switch branches.
+Aborting
EOF
test_expect_success 'cannot switch branches because of local changes' '
@@ -92,6 +95,7 @@ error: Your local changes to the following files would be overwritten by checkou
rep/one
rep/two
Please, commit your changes or stash them before you can switch branches.
+Aborting
EOF
test_expect_success 'not uptodate file porcelain checkout error' '
@@ -105,6 +109,7 @@ error: Updating the following directories would lose untracked files in it:
rep
rep2
+Aborting
EOF
test_expect_success 'not_uptodate_dir porcelain checkout error' '
diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh
index d78bdec330..4aab2a75b8 100755
--- a/t/t7610-mergetool.sh
+++ b/t/t7610-mergetool.sh
@@ -16,23 +16,60 @@ Testing basic merge tool invocation'
test_expect_success 'setup' '
git config rerere.enabled true &&
echo master >file1 &&
+ echo master spaced >"spaced name" &&
+ echo master file11 >file11 &&
+ echo master file12 >file12 &&
+ echo master file13 >file13 &&
+ echo master file14 >file14 &&
mkdir subdir &&
echo master sub >subdir/file3 &&
- git add file1 subdir/file3 &&
- git commit -m "added file1" &&
+ test_create_repo submod &&
+ (
+ cd submod &&
+ : >foo &&
+ git add foo &&
+ git commit -m "Add foo"
+ ) &&
+ git submodule add git://example.com/submod submod &&
+ git add file1 "spaced name" file1[1-4] subdir/file3 .gitmodules submod &&
+ git commit -m "add initial versions" &&
git checkout -b branch1 master &&
+ git submodule update -N &&
echo branch1 change >file1 &&
echo branch1 newfile >file2 &&
+ echo branch1 spaced >"spaced name" &&
+ echo branch1 change file11 >file11 &&
+ echo branch1 change file13 >file13 &&
echo branch1 sub >subdir/file3 &&
- git add file1 file2 subdir/file3 &&
+ (
+ cd submod &&
+ echo branch1 submodule >bar &&
+ git add bar &&
+ git commit -m "Add bar on branch1" &&
+ git checkout -b submod-branch1
+ ) &&
+ git add file1 "spaced name" file11 file13 file2 subdir/file3 submod &&
+ git rm file12 &&
git commit -m "branch1 changes" &&
git checkout master &&
+ git submodule update -N &&
echo master updated >file1 &&
echo master new >file2 &&
+ echo master updated spaced >"spaced name" &&
+ echo master updated file12 >file12 &&
+ echo master updated file14 >file14 &&
echo master new sub >subdir/file3 &&
- git add file1 file2 subdir/file3 &&
+ (
+ cd submod &&
+ echo master submodule >bar &&
+ git add bar &&
+ git commit -m "Add bar on master" &&
+ git checkout -b submod-master
+ ) &&
+ git add file1 "spaced name" file12 file14 file2 subdir/file3 submod &&
+ git rm file11 &&
git commit -m "master updates" &&
git config merge.tool mytool &&
@@ -42,13 +79,18 @@ test_expect_success 'setup' '
test_expect_success 'custom mergetool' '
git checkout -b test1 branch1 &&
+ git submodule update -N &&
test_must_fail git merge master >/dev/null 2>&1 &&
- ( yes "" | git mergetool file1 >/dev/null 2>&1 ) &&
- ( yes "" | git mergetool file2 >/dev/null 2>&1 ) &&
+ ( yes "" | git mergetool file1 file1 ) &&
+ ( yes "" | git mergetool file2 "spaced name" >/dev/null 2>&1 ) &&
( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) &&
+ ( yes "l" | git mergetool submod >/dev/null 2>&1 ) &&
test "$(cat file1)" = "master updated" &&
test "$(cat file2)" = "master new" &&
test "$(cat subdir/file3)" = "master new sub" &&
+ test "$(cat submod/bar)" = "branch1 submodule" &&
git commit -m "branch1 resolved with mergetool"
'
@@ -58,10 +100,16 @@ test_expect_success 'mergetool crlf' '
test_must_fail git merge master >/dev/null 2>&1 &&
( yes "" | git mergetool file1 >/dev/null 2>&1 ) &&
( yes "" | git mergetool file2 >/dev/null 2>&1 ) &&
+ ( yes "" | git mergetool "spaced name" >/dev/null 2>&1 ) &&
( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) &&
+ ( yes "r" | git mergetool submod >/dev/null 2>&1 ) &&
test "$(printf x | cat file1 -)" = "$(printf "master updated\r\nx")" &&
test "$(printf x | cat file2 -)" = "$(printf "master new\r\nx")" &&
test "$(printf x | cat subdir/file3 -)" = "$(printf "master new sub\r\nx")" &&
+ git submodule update -N &&
+ test "$(cat submod/bar)" = "master submodule" &&
git commit -m "branch1 resolved with mergetool - autocrlf" &&
git config core.autocrlf false &&
git reset --hard
@@ -69,6 +117,7 @@ test_expect_success 'mergetool crlf' '
test_expect_success 'mergetool in subdir' '
git checkout -b test3 branch1 &&
+ git submodule update -N &&
(
cd subdir &&
test_must_fail git merge master >/dev/null 2>&1 &&
@@ -81,17 +130,25 @@ test_expect_success 'mergetool on file in parent dir' '
(
cd subdir &&
( yes "" | git mergetool ../file1 >/dev/null 2>&1 ) &&
- ( yes "" | git mergetool ../file2 >/dev/null 2>&1 ) &&
+ ( yes "" | git mergetool ../file2 ../spaced\ name >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool ../file11 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool ../file12 >/dev/null 2>&1 ) &&
+ ( yes "l" | git mergetool ../submod >/dev/null 2>&1 ) &&
test "$(cat ../file1)" = "master updated" &&
test "$(cat ../file2)" = "master new" &&
+ test "$(cat ../submod/bar)" = "branch1 submodule" &&
git commit -m "branch1 resolved with mergetool - subdir"
)
'
test_expect_success 'mergetool skips autoresolved' '
git checkout -b test4 branch1 &&
+ git submodule update -N &&
test_must_fail git merge master &&
test -n "$(git ls-files -u)" &&
+ ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) &&
+ ( yes "l" | git mergetool submod >/dev/null 2>&1 ) &&
output="$(git mergetool --no-prompt)" &&
test "$output" = "No files need merging" &&
git reset --hard
@@ -102,13 +159,290 @@ test_expect_success 'mergetool merges all from subdir' '
cd subdir &&
git config rerere.enabled false &&
test_must_fail git merge master &&
- git mergetool --no-prompt &&
+ ( yes "r" | git mergetool ../submod ) &&
+ ( yes "d" "d" | git mergetool --no-prompt ) &&
test "$(cat ../file1)" = "master updated" &&
test "$(cat ../file2)" = "master new" &&
test "$(cat file3)" = "master new sub" &&
- git add ../file1 ../file2 file3 &&
+ ( cd .. && git submodule update -N ) &&
+ test "$(cat ../submod/bar)" = "master submodule" &&
git commit -m "branch2 resolved by mergetool from subdir"
)
'
+test_expect_success 'mergetool skips resolved paths when rerere is active' '
+ git config rerere.enabled true &&
+ rm -rf .git/rr-cache &&
+ git checkout -b test5 branch1
+ git submodule update -N &&
+ test_must_fail git merge master >/dev/null 2>&1 &&
+ ( yes "l" | git mergetool --no-prompt submod >/dev/null 2>&1 ) &&
+ ( yes "d" "d" | git mergetool --no-prompt >/dev/null 2>&1 ) &&
+ git submodule update -N &&
+ output="$(yes "n" | git mergetool --no-prompt)" &&
+ test "$output" = "No files need merging" &&
+ git reset --hard
+'
+
+test_expect_success 'mergetool takes partial path' '
+ git config rerere.enabled false &&
+ git checkout -b test12 branch1 &&
+ git submodule update -N &&
+ test_must_fail git merge master &&
+
+ #shouldnt need these lines
+ #( yes "d" | git mergetool file11 >/dev/null 2>&1 ) &&
+ #( yes "d" | git mergetool file12 >/dev/null 2>&1 ) &&
+ #( yes "l" | git mergetool submod >/dev/null 2>&1 ) &&
+ #( yes "" | git mergetool file1 file2 >/dev/null 2>&1 ) &&
+
+ ( yes "" | git mergetool subdir ) &&
+
+ test "$(cat subdir/file3)" = "master new sub" &&
+ git reset --hard
+'
+
+test_expect_success 'deleted vs modified submodule' '
+ git checkout -b test6 branch1 &&
+ git submodule update -N &&
+ mv submod submod-movedaside &&
+ git rm submod &&
+ git commit -m "Submodule deleted from branch" &&
+ git checkout -b test6.a test6 &&
+ test_must_fail git merge master &&
+ test -n "$(git ls-files -u)" &&
+ ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
+ ( yes "r" | git mergetool submod ) &&
+ rmdir submod && mv submod-movedaside submod &&
+ test "$(cat submod/bar)" = "branch1 submodule" &&
+ git submodule update -N &&
+ test "$(cat submod/bar)" = "master submodule" &&
+ output="$(git mergetool --no-prompt)" &&
+ test "$output" = "No files need merging" &&
+ git commit -m "Merge resolved by keeping module" &&
+
+ mv submod submod-movedaside &&
+ git checkout -b test6.b test6 &&
+ git submodule update -N &&
+ test_must_fail git merge master &&
+ test -n "$(git ls-files -u)" &&
+ ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
+ ( yes "l" | git mergetool submod ) &&
+ test ! -e submod &&
+ output="$(git mergetool --no-prompt)" &&
+ test "$output" = "No files need merging" &&
+ git commit -m "Merge resolved by deleting module" &&
+
+ mv submod-movedaside submod &&
+ git checkout -b test6.c master &&
+ git submodule update -N &&
+ test_must_fail git merge test6 &&
+ test -n "$(git ls-files -u)" &&
+ ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
+ ( yes "r" | git mergetool submod ) &&
+ test ! -e submod &&
+ test -d submod.orig &&
+ git submodule update -N &&
+ output="$(git mergetool --no-prompt)" &&
+ test "$output" = "No files need merging" &&
+ git commit -m "Merge resolved by deleting module" &&
+ mv submod.orig submod &&
+
+ git checkout -b test6.d master &&
+ git submodule update -N &&
+ test_must_fail git merge test6 &&
+ test -n "$(git ls-files -u)" &&
+ ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
+ ( yes "l" | git mergetool submod ) &&
+ test "$(cat submod/bar)" = "master submodule" &&
+ git submodule update -N &&
+ test "$(cat submod/bar)" = "master submodule" &&
+ output="$(git mergetool --no-prompt)" &&
+ test "$output" = "No files need merging" &&
+ git commit -m "Merge resolved by keeping module" &&
+ git reset --hard HEAD
+'
+
+test_expect_success 'file vs modified submodule' '
+ git checkout -b test7 branch1 &&
+ git submodule update -N &&
+ mv submod submod-movedaside &&
+ git rm submod &&
+ echo not a submodule >submod &&
+ git add submod &&
+ git commit -m "Submodule path becomes file" &&
+ git checkout -b test7.a branch1 &&
+ test_must_fail git merge master &&
+ test -n "$(git ls-files -u)" &&
+ ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
+ ( yes "r" | git mergetool submod ) &&
+ rmdir submod && mv submod-movedaside submod &&
+ test "$(cat submod/bar)" = "branch1 submodule" &&
+ git submodule update -N &&
+ test "$(cat submod/bar)" = "master submodule" &&
+ output="$(git mergetool --no-prompt)" &&
+ test "$output" = "No files need merging" &&
+ git commit -m "Merge resolved by keeping module" &&
+
+ mv submod submod-movedaside &&
+ git checkout -b test7.b test7 &&
+ test_must_fail git merge master &&
+ test -n "$(git ls-files -u)" &&
+ ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
+ ( yes "l" | git mergetool submod ) &&
+ git submodule update -N &&
+ test "$(cat submod)" = "not a submodule" &&
+ output="$(git mergetool --no-prompt)" &&
+ test "$output" = "No files need merging" &&
+ git commit -m "Merge resolved by keeping file" &&
+
+ git checkout -b test7.c master &&
+ rmdir submod && mv submod-movedaside submod &&
+ test ! -e submod.orig &&
+ git submodule update -N &&
+ test_must_fail git merge test7 &&
+ test -n "$(git ls-files -u)" &&
+ ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
+ ( yes "r" | git mergetool submod ) &&
+ test -d submod.orig &&
+ git submodule update -N &&
+ test "$(cat submod)" = "not a submodule" &&
+ output="$(git mergetool --no-prompt)" &&
+ test "$output" = "No files need merging" &&
+ git commit -m "Merge resolved by keeping file" &&
+
+ git checkout -b test7.d master &&
+ rmdir submod && mv submod.orig submod &&
+ git submodule update -N &&
+ test_must_fail git merge test7 &&
+ test -n "$(git ls-files -u)" &&
+ ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
+ ( yes "l" | git mergetool submod ) &&
+ test "$(cat submod/bar)" = "master submodule" &&
+ git submodule update -N &&
+ test "$(cat submod/bar)" = "master submodule" &&
+ output="$(git mergetool --no-prompt)" &&
+ test "$output" = "No files need merging" &&
+ git commit -m "Merge resolved by keeping module"
+'
+
+test_expect_success 'submodule in subdirectory' '
+ git checkout -b test10 branch1 &&
+ git submodule update -N &&
+ (
+ cd subdir &&
+ test_create_repo subdir_module &&
+ (
+ cd subdir_module &&
+ : >file15 &&
+ git add file15 &&
+ git commit -m "add initial versions"
+ )
+ ) &&
+ git submodule add git://example.com/subsubmodule subdir/subdir_module &&
+ git add subdir/subdir_module &&
+ git commit -m "add submodule in subdirectory" &&
+
+ git checkout -b test10.a test10 &&
+ git submodule update -N &&
+ (
+ cd subdir/subdir_module &&
+ git checkout -b super10.a &&
+ echo test10.a >file15 &&
+ git add file15 &&
+ git commit -m "on branch 10.a"
+ ) &&
+ git add subdir/subdir_module &&
+ git commit -m "change submodule in subdirectory on test10.a" &&
+
+ git checkout -b test10.b test10 &&
+ git submodule update -N &&
+ (
+ cd subdir/subdir_module &&
+ git checkout -b super10.b &&
+ echo test10.b >file15 &&
+ git add file15 &&
+ git commit -m "on branch 10.b"
+ ) &&
+ git add subdir/subdir_module &&
+ git commit -m "change submodule in subdirectory on test10.b" &&
+
+ test_must_fail git merge test10.a >/dev/null 2>&1 &&
+ (
+ cd subdir &&
+ ( yes "l" | git mergetool subdir_module )
+ ) &&
+ test "$(cat subdir/subdir_module/file15)" = "test10.b" &&
+ git submodule update -N &&
+ test "$(cat subdir/subdir_module/file15)" = "test10.b" &&
+ git reset --hard &&
+ git submodule update -N &&
+
+ test_must_fail git merge test10.a >/dev/null 2>&1 &&
+ ( yes "r" | git mergetool subdir/subdir_module ) &&
+ test "$(cat subdir/subdir_module/file15)" = "test10.b" &&
+ git submodule update -N &&
+ test "$(cat subdir/subdir_module/file15)" = "test10.a" &&
+ git commit -m "branch1 resolved with mergetool" &&
+ rm -rf subdir/subdir_module
+'
+
+test_expect_success 'directory vs modified submodule' '
+ git checkout -b test11 branch1 &&
+ mv submod submod-movedaside &&
+ git rm submod &&
+ mkdir submod &&
+ echo not a submodule >submod/file16 &&
+ git add submod/file16 &&
+ git commit -m "Submodule path becomes directory" &&
+
+ test_must_fail git merge master &&
+ test -n "$(git ls-files -u)" &&
+ ( yes "l" | git mergetool submod ) &&
+ test "$(cat submod/file16)" = "not a submodule" &&
+ rm -rf submod.orig &&
+
+ git reset --hard >/dev/null 2>&1 &&
+ test_must_fail git merge master &&
+ test -n "$(git ls-files -u)" &&
+ test ! -e submod.orig &&
+ ( yes "r" | git mergetool submod ) &&
+ test -d submod.orig &&
+ test "$(cat submod.orig/file16)" = "not a submodule" &&
+ rm -r submod.orig &&
+ mv submod-movedaside/.git submod &&
+ ( cd submod && git clean -f && git reset --hard ) &&
+ git submodule update -N &&
+ test "$(cat submod/bar)" = "master submodule" &&
+ git reset --hard >/dev/null 2>&1 && rm -rf submod-movedaside &&
+
+ git checkout -b test11.c master &&
+ git submodule update -N &&
+ test_must_fail git merge test11 &&
+ test -n "$(git ls-files -u)" &&
+ ( yes "l" | git mergetool submod ) &&
+ git submodule update -N &&
+ test "$(cat submod/bar)" = "master submodule" &&
+
+ git reset --hard >/dev/null 2>&1 &&
+ git submodule update -N &&
+ test_must_fail git merge test11 &&
+ test -n "$(git ls-files -u)" &&
+ test ! -e submod.orig &&
+ ( yes "r" | git mergetool submod ) &&
+ test "$(cat submod/file16)" = "not a submodule" &&
+
+ git reset --hard master >/dev/null 2>&1 &&
+ ( cd submod && git clean -f && git reset --hard ) &&
+ git submodule update -N
+'
+
test_done
diff --git a/t/t7611-merge-abort.sh b/t/t7611-merge-abort.sh
index 61890bc892..7b4798e8e4 100755
--- a/t/t7611-merge-abort.sh
+++ b/t/t7611-merge-abort.sh
@@ -47,7 +47,10 @@ pre_merge_head="$(git rev-parse HEAD)"
test_expect_success 'fails without MERGE_HEAD (unstarted merge)' '
test_must_fail git merge --abort 2>output &&
- grep -q MERGE_HEAD output &&
+ test_i18ngrep MERGE_HEAD output
+'
+
+test_expect_success 'fails without MERGE_HEAD (unstarted merge): .git/MERGE_HEAD sanity' '
test ! -f .git/MERGE_HEAD &&
test "$pre_merge_head" = "$(git rev-parse HEAD)"
'
@@ -58,7 +61,10 @@ test_expect_success 'fails without MERGE_HEAD (completed merge)' '
# Merge successfully completed
post_merge_head="$(git rev-parse HEAD)" &&
test_must_fail git merge --abort 2>output &&
- grep -q MERGE_HEAD output &&
+ test_i18ngrep MERGE_HEAD output
+'
+
+test_expect_success 'fails without MERGE_HEAD (completed merge): .git/MERGE_HEAD sanity' '
test ! -f .git/MERGE_HEAD &&
test "$post_merge_head" = "$(git rev-parse HEAD)"
'
diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
index 4048d106d4..4fb4c9384a 100755
--- a/t/t7800-difftool.sh
+++ b/t/t7800-difftool.sh
@@ -10,9 +10,6 @@ Testing basic diff tool invocation
. ./test-lib.sh
-LF='
-'
-
remove_config_vars()
{
# Unset all config variables used by git-difftool
@@ -41,7 +38,17 @@ restore_test_defaults()
prompt_given()
{
prompt="$1"
- test "$prompt" = "Hit return to launch 'test-tool': branch"
+ test "$prompt" = "Launch 'test-tool' [Y/n]: branch"
+}
+
+stdin_contains()
+{
+ grep >/dev/null "$1"
+}
+
+stdin_doesnot_contain()
+{
+ ! stdin_contains "$1"
}
# Create a file on master and change it on branch
@@ -268,4 +275,35 @@ test_expect_success PERL 'difftool --extcmd cat arg2' '
test "$diff" = branch
'
+# Create a second file on master and a different version on branch
+test_expect_success PERL 'setup with 2 files different' '
+ echo m2 >file2 &&
+ git add file2 &&
+ git commit -m "added file2" &&
+
+ git checkout branch &&
+ echo br2 >file2 &&
+ git add file2 &&
+ git commit -a -m "branch changed file2" &&
+ git checkout master
+'
+
+test_expect_success PERL 'say no to the first file' '
+ diff=$( (echo n; echo) | git difftool -x cat branch ) &&
+
+ echo "$diff" | stdin_contains m2 &&
+ echo "$diff" | stdin_contains br2 &&
+ echo "$diff" | stdin_doesnot_contain master &&
+ echo "$diff" | stdin_doesnot_contain branch
+'
+
+test_expect_success PERL 'say no to the second file' '
+ diff=$( (echo; echo n) | git difftool -x cat branch ) &&
+
+ echo "$diff" | stdin_contains master &&
+ echo "$diff" | stdin_contains branch &&
+ echo "$diff" | stdin_doesnot_contain m2 &&
+ echo "$diff" | stdin_doesnot_contain br2
+'
+
test_done
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index c8777589ca..81263b7851 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -26,6 +26,17 @@ test_expect_success setup '
echo foo mmap bar_mmap
echo foo_mmap bar mmap baz
} >file &&
+ {
+ echo Hello world
+ echo HeLLo world
+ echo Hello_world
+ echo HeLLo_world
+ } >hello_world &&
+ {
+ echo "a+b*c"
+ echo "a+bc"
+ echo "abc"
+ } >ab &&
echo vvv >v &&
echo ww w >w &&
echo x x xx x >x &&
@@ -59,7 +70,29 @@ do
echo ${HC}file:4:foo mmap bar_mmap
echo ${HC}file:5:foo_mmap bar mmap baz
} >expected &&
- git grep -n -w -e mmap $H >actual &&
+ git -c grep.linenumber=false grep -n -w -e mmap $H >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success "grep -w $L" '
+ {
+ echo ${HC}file:1:foo mmap bar
+ echo ${HC}file:3:foo_mmap bar mmap
+ echo ${HC}file:4:foo mmap bar_mmap
+ echo ${HC}file:5:foo_mmap bar mmap baz
+ } >expected &&
+ git -c grep.linenumber=true grep -w -e mmap $H >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success "grep -w $L" '
+ {
+ echo ${HC}file:foo mmap bar
+ echo ${HC}file:foo_mmap bar mmap
+ echo ${HC}file:foo mmap bar_mmap
+ echo ${HC}file:foo_mmap bar mmap baz
+ } >expected &&
+ git -c grep.linenumber=true grep --no-line-number -w -e mmap $H >actual &&
test_cmp expected actual
'
@@ -182,6 +215,34 @@ do
test_cmp expected actual
'
+ test_expect_success "grep --max-depth 0 -- . t $L" '
+ {
+ echo ${HC}t/v:1:vvv
+ echo ${HC}v:1:vvv
+ } >expected &&
+ git grep --max-depth 0 -n -e vvv $H -- . t >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success "grep --max-depth 0 -- t . $L" '
+ {
+ echo ${HC}t/v:1:vvv
+ echo ${HC}v:1:vvv
+ } >expected &&
+ git grep --max-depth 0 -n -e vvv $H -- t . >actual &&
+ test_cmp expected actual
+ '
+ test_expect_success "grep $L with grep.extendedRegexp=false" '
+ echo "ab:a+bc" >expected &&
+ git -c grep.extendedRegexp=false grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success "grep $L with grep.extendedRegexp=true" '
+ echo "ab:abc" >expected &&
+ git -c grep.extendedRegexp=true grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
done
cat >expected <<EOF
@@ -285,6 +346,11 @@ test_expect_success 'grep -f, ignore empty lines' '
test_cmp expected actual
'
+test_expect_success 'grep -f, ignore empty lines, read patterns from stdin' '
+ git grep -f - <patterns >actual &&
+ test_cmp expected actual
+'
+
cat >expected <<EOF
y:y yy
--
@@ -443,6 +509,20 @@ test_expect_success 'grep -p -B5' '
test_cmp expected actual
'
+cat >expected <<EOF
+hello.c=int main(int argc, const char **argv)
+hello.c-{
+hello.c- printf("Hello world.\n");
+hello.c: return 0;
+hello.c- /* char ?? */
+hello.c-}
+EOF
+
+test_expect_success 'grep -W' '
+ git grep -W return >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'grep from a subdirectory to search wider area (1)' '
mkdir -p s &&
(
@@ -474,7 +554,6 @@ test_expect_success 'outside of git repository' '
mkdir -p non/git/sub &&
echo hello >non/git/file1 &&
echo world >non/git/sub/file2 &&
- echo ".*o*" >non/git/.gitignore &&
{
echo file1:hello &&
echo sub/file2:world
@@ -491,6 +570,23 @@ test_expect_success 'outside of git repository' '
test_must_fail git grep o &&
git grep --no-index o >../../actual.sub &&
test_cmp ../../expect.sub ../../actual.sub
+ ) &&
+
+ echo ".*o*" >non/git/.gitignore &&
+ (
+ GIT_CEILING_DIRECTORIES="$(pwd)/non/git" &&
+ export GIT_CEILING_DIRECTORIES &&
+ cd non/git &&
+ test_must_fail git grep o &&
+ git grep --no-index --exclude-standard o >../actual.full &&
+ test_cmp ../expect.full ../actual.full &&
+
+ {
+ echo ".gitignore:.*o*"
+ cat ../expect.full
+ } >../expect.with.ignored &&
+ git grep --no-index --no-exclude o >../actual.full &&
+ test_cmp ../expect.with.ignored ../actual.full
)
'
@@ -503,6 +599,10 @@ test_expect_success 'inside git repository but with --no-index' '
{
echo file1:hello &&
echo sub/file2:world
+ } >is/expect.unignored &&
+ {
+ echo ".gitignore:.*o*" &&
+ cat is/expect.unignored
} >is/expect.full &&
: >is/expect.empty &&
echo file2:world >is/expect.sub &&
@@ -511,12 +611,24 @@ test_expect_success 'inside git repository but with --no-index' '
git init &&
test_must_fail git grep o >../actual.full &&
test_cmp ../expect.empty ../actual.full &&
+
+ git grep --untracked o >../actual.unignored &&
+ test_cmp ../expect.unignored ../actual.unignored &&
+
git grep --no-index o >../actual.full &&
test_cmp ../expect.full ../actual.full &&
+
+ git grep --no-index --exclude-standard o >../actual.unignored &&
+ test_cmp ../expect.unignored ../actual.unignored &&
+
cd sub &&
test_must_fail git grep o >../../actual.sub &&
test_cmp ../../expect.empty ../../actual.sub &&
+
git grep --no-index o >../../actual.sub &&
+ test_cmp ../../expect.sub ../../actual.sub &&
+
+ git grep --untracked o >../../actual.sub &&
test_cmp ../../expect.sub ../../actual.sub
)
'
@@ -554,4 +666,195 @@ test_expect_success 'grep -e -- -- path' '
test_cmp expected actual
'
+cat >expected <<EOF
+hello.c:int main(int argc, const char **argv)
+hello.c: printf("Hello world.\n");
+EOF
+
+test_expect_success LIBPCRE 'grep --perl-regexp pattern' '
+ git grep --perl-regexp "\p{Ps}.*?\p{Pe}" hello.c >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success LIBPCRE 'grep -P pattern' '
+ git grep -P "\p{Ps}.*?\p{Pe}" hello.c >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'grep pattern with grep.extendedRegexp=true' '
+ >empty &&
+ test_must_fail git -c grep.extendedregexp=true \
+ grep "\p{Ps}.*?\p{Pe}" hello.c >actual &&
+ test_cmp empty actual
+'
+
+test_expect_success LIBPCRE 'grep -P pattern with grep.extendedRegexp=true' '
+ git -c grep.extendedregexp=true \
+ grep -P "\p{Ps}.*?\p{Pe}" hello.c >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success LIBPCRE 'grep -P -v pattern' '
+ {
+ echo "ab:a+b*c"
+ echo "ab:a+bc"
+ } >expected &&
+ git grep -P -v "abc" ab >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success LIBPCRE 'grep -P -i pattern' '
+ cat >expected <<-EOF &&
+ hello.c: printf("Hello world.\n");
+ EOF
+ git grep -P -i "PRINTF\([^\d]+\)" hello.c >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success LIBPCRE 'grep -P -w pattern' '
+ {
+ echo "hello_world:Hello world"
+ echo "hello_world:HeLLo world"
+ } >expected &&
+ git grep -P -w "He((?i)ll)o" hello_world >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'grep -G invalidpattern properly dies ' '
+ test_must_fail git grep -G "a["
+'
+
+test_expect_success 'grep -E invalidpattern properly dies ' '
+ test_must_fail git grep -E "a["
+'
+
+test_expect_success LIBPCRE 'grep -P invalidpattern properly dies ' '
+ test_must_fail git grep -P "a["
+'
+
+test_expect_success 'grep -G -E -F pattern' '
+ echo "ab:a+b*c" >expected &&
+ git grep -G -E -F "a+b*c" ab >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'grep -E -F -G pattern' '
+ echo "ab:a+bc" >expected &&
+ git grep -E -F -G "a+b*c" ab >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'grep -F -G -E pattern' '
+ echo "ab:abc" >expected &&
+ git grep -F -G -E "a+b*c" ab >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'grep -G -F -P -E pattern' '
+ >empty &&
+ test_must_fail git grep -G -F -P -E "a\x{2b}b\x{2a}c" ab >actual &&
+ test_cmp empty actual
+'
+
+test_expect_success LIBPCRE 'grep -G -F -E -P pattern' '
+ echo "ab:a+b*c" >expected &&
+ git grep -G -F -E -P "a\x{2b}b\x{2a}c" ab >actual &&
+ test_cmp expected actual
+'
+
+test_config() {
+ git config "$1" "$2" &&
+ test_when_finished "git config --unset $1"
+}
+
+cat >expected <<EOF
+hello.c<RED>:<RESET>int main(int argc, const char **argv)
+hello.c<RED>-<RESET>{
+<RED>--<RESET>
+hello.c<RED>:<RESET> /* char ?? */
+hello.c<RED>-<RESET>}
+<RED>--<RESET>
+hello_world<RED>:<RESET>Hello_world
+hello_world<RED>-<RESET>HeLLo_world
+EOF
+
+test_expect_success 'grep --color, separator' '
+ test_config color.grep.context normal &&
+ test_config color.grep.filename normal &&
+ test_config color.grep.function normal &&
+ test_config color.grep.linenumber normal &&
+ test_config color.grep.match normal &&
+ test_config color.grep.selected normal &&
+ test_config color.grep.separator red &&
+
+ git grep --color=always -A1 -e char -e lo_w hello.c hello_world |
+ test_decode_color >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+hello.c:int main(int argc, const char **argv)
+hello.c: /* char ?? */
+
+hello_world:Hello_world
+EOF
+
+test_expect_success 'grep --break' '
+ git grep --break -e char -e lo_w hello.c hello_world >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+hello.c:int main(int argc, const char **argv)
+hello.c-{
+--
+hello.c: /* char ?? */
+hello.c-}
+
+hello_world:Hello_world
+hello_world-HeLLo_world
+EOF
+
+test_expect_success 'grep --break with context' '
+ git grep --break -A1 -e char -e lo_w hello.c hello_world >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+hello.c
+int main(int argc, const char **argv)
+ /* char ?? */
+hello_world
+Hello_world
+EOF
+
+test_expect_success 'grep --heading' '
+ git grep --heading -e char -e lo_w hello.c hello_world >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+<BOLD;GREEN>hello.c<RESET>
+2:int main(int argc, const <BLACK;BYELLOW>char<RESET> **argv)
+6: /* <BLACK;BYELLOW>char<RESET> ?? */
+
+<BOLD;GREEN>hello_world<RESET>
+3:Hel<BLACK;BYELLOW>lo_w<RESET>orld
+EOF
+
+test_expect_success 'mimic ack-grep --group' '
+ test_config color.grep.context normal &&
+ test_config color.grep.filename "bold green" &&
+ test_config color.grep.function normal &&
+ test_config color.grep.linenumber normal &&
+ test_config color.grep.match "black yellow" &&
+ test_config color.grep.selected normal &&
+ test_config color.grep.separator normal &&
+
+ git grep --break --heading -n --color \
+ -e char -e lo_w hello.c hello_world |
+ test_decode_color >actual &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t7811-grep-open.sh b/t/t7811-grep-open.sh
index 568a6f2b69..a8957782cf 100755
--- a/t/t7811-grep-open.sh
+++ b/t/t7811-grep-open.sh
@@ -63,7 +63,7 @@ test_expect_success SIMPLEPAGER 'git grep -O' '
test_expect_success 'git grep -O --cached' '
test_must_fail git grep --cached -O GREP_PATTERN >out 2>msg &&
- grep open-files-in-pager msg
+ test_i18ngrep open-files-in-pager msg
'
test_expect_success 'git grep -O --no-index' '
diff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh
index 45cb60ea4b..41962f04a7 100755
--- a/t/t8001-annotate.sh
+++ b/t/t8001-annotate.sh
@@ -6,10 +6,11 @@ test_description='git annotate'
PROG='git annotate'
. "$TEST_DIRECTORY"/annotate-tests.sh
-test_expect_success \
- 'Annotating an old revision works' \
- '[ $(git annotate file master | awk "{print \$3}" | grep -c "^A$") -eq 2 ] && \
- [ $(git annotate file master | awk "{print \$3}" | grep -c "^B$") -eq 2 ]'
-
+test_expect_success 'Annotating an old revision works' '
+ git annotate file master >result &&
+ awk "{ print \$3; }" <result >authors &&
+ test 2 = $(grep A <authors | wc -l) &&
+ test 2 = $(grep B <authors | wc -l)
+'
test_done
diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh
index d3a51e1269..e2896cffc1 100755
--- a/t/t8002-blame.sh
+++ b/t/t8002-blame.sh
@@ -8,7 +8,7 @@ PROG='git blame -c'
PROG='git blame -c -e'
test_expect_success 'Blame --show-email works' '
- check_count "<A@test.git>" 1 "<B@test.git>" 1 "<B1@test.git>" 1 "<B2@test.git>" 1 "<author@example.com>" 1 "<C@test.git>" 1 "<D@test.git>" 1
+ check_count "<A@test.git>" 1 "<B@test.git>" 1 "<B1@test.git>" 1 "<B2@test.git>" 1 "<author@example.com>" 1 "<C@test.git>" 1 "<D@test.git>" 1 "<E at test dot git>" 1
'
test_done
diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh
index ea64cd8d0f..32ec82ad67 100755
--- a/t/t8006-blame-textconv.sh
+++ b/t/t8006-blame-textconv.sh
@@ -25,7 +25,8 @@ test_expect_success 'setup ' '
echo "bin: test 1 version 2" >one.bin &&
echo "bin: test number 2 version 2" >>two.bin &&
if test_have_prereq SYMLINKS; then
- ln -sf two.bin symlink.bin
+ rm symlink.bin &&
+ ln -s two.bin symlink.bin
fi &&
GIT_AUTHOR_NAME=Number2 git commit -a -m Second --date="2010-01-01 20:00:00"
'
diff --git a/t/t8008-blame-formats.sh b/t/t8008-blame-formats.sh
new file mode 100755
index 0000000000..d15f8b3d47
--- /dev/null
+++ b/t/t8008-blame-formats.sh
@@ -0,0 +1,90 @@
+#!/bin/sh
+
+test_description='blame output in various formats on a simple case'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ echo a >file &&
+ git add file
+ test_tick &&
+ git commit -m one &&
+ echo b >>file &&
+ echo c >>file &&
+ echo d >>file &&
+ test_tick &&
+ git commit -a -m two
+'
+
+cat >expect <<'EOF'
+^baf5e0b (A U Thor 2005-04-07 15:13:13 -0700 1) a
+8825379d (A U Thor 2005-04-07 15:14:13 -0700 2) b
+8825379d (A U Thor 2005-04-07 15:14:13 -0700 3) c
+8825379d (A U Thor 2005-04-07 15:14:13 -0700 4) d
+EOF
+test_expect_success 'normal blame output' '
+ git blame file >actual &&
+ test_cmp expect actual
+'
+
+ID1=baf5e0b3869e0b2b2beb395a3720c7b51eac94fc
+COMMIT1='author A U Thor
+author-mail <author@example.com>
+author-time 1112911993
+author-tz -0700
+committer C O Mitter
+committer-mail <committer@example.com>
+committer-time 1112911993
+committer-tz -0700
+summary one
+boundary
+filename file'
+ID2=8825379dfb8a1267b58e8e5bcf69eec838f685ec
+COMMIT2='author A U Thor
+author-mail <author@example.com>
+author-time 1112912053
+author-tz -0700
+committer C O Mitter
+committer-mail <committer@example.com>
+committer-time 1112912053
+committer-tz -0700
+summary two
+previous baf5e0b3869e0b2b2beb395a3720c7b51eac94fc file
+filename file'
+
+cat >expect <<EOF
+$ID1 1 1 1
+$COMMIT1
+ a
+$ID2 2 2 3
+$COMMIT2
+ b
+$ID2 3 3
+ c
+$ID2 4 4
+ d
+EOF
+test_expect_success 'blame --porcelain output' '
+ git blame --porcelain file >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<EOF
+$ID1 1 1 1
+$COMMIT1
+ a
+$ID2 2 2 3
+$COMMIT2
+ b
+$ID2 3 3
+$COMMIT2
+ c
+$ID2 4 4
+$COMMIT2
+ d
+EOF
+test_expect_success 'blame --line-porcelain output' '
+ git blame --line-porcelain file >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 579ddb7572..8c12c65c72 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -23,6 +23,7 @@ test_expect_success $PREREQ \
echo do
echo " echo \"!\$a!\""
echo "done >commandline\$output"
+ test_have_prereq MINGW && echo "dos2unix commandline\$output"
echo "cat > msgtxt\$output"
) >fake.sendmail &&
chmod +x ./fake.sendmail &&
@@ -1168,4 +1169,32 @@ test_expect_success $PREREQ '--force sends cover letter template anyway' '
test -n "$(ls msgtxt*)"
'
+test_expect_success $PREREQ 'sendemail.aliasfiletype=mailrc' '
+ clean_fake_sendmail &&
+ echo "alias sbd somebody@example.org" >.mailrc &&
+ git config --replace-all sendemail.aliasesfile "$(pwd)/.mailrc" &&
+ git config sendemail.aliasfiletype mailrc &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --to=sbd \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ outdir/0001-*.patch \
+ 2>errors >out &&
+ grep "^!somebody@example\.org!$" commandline1
+'
+
+test_expect_success $PREREQ 'sendemail.aliasfile=~/.mailrc' '
+ clean_fake_sendmail &&
+ echo "alias sbd someone@example.org" >~/.mailrc &&
+ git config --replace-all sendemail.aliasesfile "~/.mailrc" &&
+ git config sendemail.aliasfiletype mailrc &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --to=sbd \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ outdir/0001-*.patch \
+ 2>errors >out &&
+ grep "^!someone@example\.org!$" commandline1
+'
+
test_done
diff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh
index 88a9751dd3..6f6175a8f7 100755
--- a/t/t9010-svn-fe.sh
+++ b/t/t9010-svn-fe.sh
@@ -9,6 +9,30 @@ reinit_git () {
git init
}
+properties () {
+ while test "$#" -ne 0
+ do
+ property="$1" &&
+ value="$2" &&
+ printf "%s\n" "K ${#property}" &&
+ printf "%s\n" "$property" &&
+ printf "%s\n" "V ${#value}" &&
+ printf "%s\n" "$value" &&
+ shift 2 ||
+ return 1
+ done
+}
+
+text_no_props () {
+ text="$1
+" &&
+ printf "%s\n" "Prop-content-length: 10" &&
+ printf "%s\n" "Text-content-length: ${#text}" &&
+ printf "%s\n" "Content-length: $((${#text} + 10))" &&
+ printf "%s\n" "" "PROPS-END" &&
+ printf "%s\n" "$text"
+}
+
>empty
test_expect_success 'empty dump' '
@@ -18,13 +42,794 @@ test_expect_success 'empty dump' '
git fast-import <stream
'
-test_expect_success 'v3 dumps not supported' '
+test_expect_success 'v4 dumps not supported' '
reinit_git &&
- echo "SVN-fs-dump-format-version: 3" >input &&
- test_must_fail test-svn-fe input >stream &&
+ echo "SVN-fs-dump-format-version: 4" >v4.dump &&
+ test_must_fail test-svn-fe v4.dump >stream &&
test_cmp empty stream
'
+test_expect_failure 'empty revision' '
+ reinit_git &&
+ printf "rev <nobody, nobody@local>: %s\n" "" "" >expect &&
+ cat >emptyrev.dump <<-\EOF &&
+ SVN-fs-dump-format-version: 3
+
+ Revision-number: 1
+ Prop-content-length: 0
+ Content-length: 0
+
+ Revision-number: 2
+ Prop-content-length: 0
+ Content-length: 0
+
+ EOF
+ test-svn-fe emptyrev.dump >stream &&
+ git fast-import <stream &&
+ git log -p --format="rev <%an, %ae>: %s" HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'empty properties' '
+ reinit_git &&
+ printf "rev <nobody, nobody@local>: %s\n" "" "" >expect &&
+ cat >emptyprop.dump <<-\EOF &&
+ SVN-fs-dump-format-version: 3
+
+ Revision-number: 1
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Revision-number: 2
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+ EOF
+ test-svn-fe emptyprop.dump >stream &&
+ git fast-import <stream &&
+ git log -p --format="rev <%an, %ae>: %s" HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'author name and commit message' '
+ reinit_git &&
+ echo "<author@example.com, author@example.com@local>" >expect.author &&
+ cat >message <<-\EOF &&
+ A concise summary of the change
+
+ A detailed description of the change, why it is needed, what
+ was broken and why applying this is the best course of action.
+
+ * file.c
+ Details pertaining to an individual file.
+ EOF
+ {
+ properties \
+ svn:author author@example.com \
+ svn:log "$(cat message)" &&
+ echo PROPS-END
+ } >props &&
+ {
+ echo "SVN-fs-dump-format-version: 3" &&
+ echo &&
+ echo "Revision-number: 1" &&
+ echo Prop-content-length: $(wc -c <props) &&
+ echo Content-length: $(wc -c <props) &&
+ echo &&
+ cat props
+ } >log.dump &&
+ test-svn-fe log.dump >stream &&
+ git fast-import <stream &&
+ git log -p --format="%B" HEAD >actual.log &&
+ git log --format="<%an, %ae>" >actual.author &&
+ test_cmp message actual.log &&
+ test_cmp expect.author actual.author
+'
+
+test_expect_success 'unsupported properties are ignored' '
+ reinit_git &&
+ echo author >expect &&
+ cat >extraprop.dump <<-\EOF &&
+ SVN-fs-dump-format-version: 3
+
+ Revision-number: 1
+ Prop-content-length: 56
+ Content-length: 56
+
+ K 8
+ nonsense
+ V 1
+ y
+ K 10
+ svn:author
+ V 6
+ author
+ PROPS-END
+ EOF
+ test-svn-fe extraprop.dump >stream &&
+ git fast-import <stream &&
+ git log -p --format=%an HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_failure 'timestamp and empty file' '
+ echo author@example.com >expect.author &&
+ echo 1999-01-01 >expect.date &&
+ echo file >expect.files &&
+ reinit_git &&
+ {
+ properties \
+ svn:author author@example.com \
+ svn:date "1999-01-01T00:01:002.000000Z" \
+ svn:log "add empty file" &&
+ echo PROPS-END
+ } >props &&
+ {
+ cat <<-EOF &&
+ SVN-fs-dump-format-version: 3
+
+ Revision-number: 1
+ EOF
+ echo Prop-content-length: $(wc -c <props) &&
+ echo Content-length: $(wc -c <props) &&
+ echo &&
+ cat props &&
+ cat <<-\EOF
+
+ Node-path: empty-file
+ Node-kind: file
+ Node-action: add
+ Content-length: 0
+
+ EOF
+ } >emptyfile.dump &&
+ test-svn-fe emptyfile.dump >stream &&
+ git fast-import <stream &&
+ git log --format=%an HEAD >actual.author &&
+ git log --date=short --format=%ad HEAD >actual.date &&
+ git ls-tree -r --name-only HEAD >actual.files &&
+ test_cmp expect.author actual.author &&
+ test_cmp expect.date actual.date &&
+ test_cmp expect.files actual.files &&
+ git checkout HEAD empty-file &&
+ test_cmp empty file
+'
+
+test_expect_success 'directory with files' '
+ reinit_git &&
+ printf "%s\n" directory/file1 directory/file2 >expect.files &&
+ echo hi >hi &&
+ echo hello >hello &&
+ {
+ properties \
+ svn:author author@example.com \
+ svn:date "1999-02-01T00:01:002.000000Z" \
+ svn:log "add directory with some files in it" &&
+ echo PROPS-END
+ } >props &&
+ {
+ cat <<-EOF &&
+ SVN-fs-dump-format-version: 3
+
+ Revision-number: 1
+ EOF
+ echo Prop-content-length: $(wc -c <props) &&
+ echo Content-length: $(wc -c <props) &&
+ echo &&
+ cat props &&
+ cat <<-\EOF &&
+
+ Node-path: directory
+ Node-kind: dir
+ Node-action: add
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: directory/file1
+ Node-kind: file
+ Node-action: add
+ EOF
+ text_no_props hello &&
+ cat <<-\EOF &&
+ Node-path: directory/file2
+ Node-kind: file
+ Node-action: add
+ EOF
+ text_no_props hi
+ } >directory.dump &&
+ test-svn-fe directory.dump >stream &&
+ git fast-import <stream &&
+
+ git ls-tree -r --name-only HEAD >actual.files &&
+ git checkout HEAD directory &&
+ test_cmp expect.files actual.files &&
+ test_cmp hello directory/file1 &&
+ test_cmp hi directory/file2
+'
+
+test_expect_success 'node without action' '
+ cat >inaction.dump <<-\EOF &&
+ SVN-fs-dump-format-version: 3
+
+ Revision-number: 1
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: directory
+ Node-kind: dir
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+ EOF
+ test_must_fail test-svn-fe inaction.dump
+'
+
+test_expect_success 'action: add node without text' '
+ cat >textless.dump <<-\EOF &&
+ SVN-fs-dump-format-version: 3
+
+ Revision-number: 1
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: textless
+ Node-kind: file
+ Node-action: add
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+ EOF
+ test_must_fail test-svn-fe textless.dump
+'
+
+test_expect_failure 'change file mode but keep old content' '
+ reinit_git &&
+ cat >expect <<-\EOF &&
+ OBJID
+ :120000 100644 OBJID OBJID T greeting
+ OBJID
+ :100644 120000 OBJID OBJID T greeting
+ OBJID
+ :000000 100644 OBJID OBJID A greeting
+ EOF
+ echo "link hello" >expect.blob &&
+ echo hello >hello &&
+ cat >filemode.dump <<-\EOF &&
+ SVN-fs-dump-format-version: 3
+
+ Revision-number: 1
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: greeting
+ Node-kind: file
+ Node-action: add
+ Prop-content-length: 10
+ Text-content-length: 11
+ Content-length: 21
+
+ PROPS-END
+ link hello
+
+ Revision-number: 2
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: greeting
+ Node-kind: file
+ Node-action: change
+ Prop-content-length: 33
+ Content-length: 33
+
+ K 11
+ svn:special
+ V 1
+ *
+ PROPS-END
+
+ Revision-number: 3
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: greeting
+ Node-kind: file
+ Node-action: change
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+ EOF
+ test-svn-fe filemode.dump >stream &&
+ git fast-import <stream &&
+ {
+ git rev-list HEAD |
+ git diff-tree --root --stdin |
+ sed "s/$_x40/OBJID/g"
+ } >actual &&
+ git show HEAD:greeting >actual.blob &&
+ git show HEAD^:greeting >actual.target &&
+ test_cmp expect actual &&
+ test_cmp expect.blob actual.blob &&
+ test_cmp hello actual.target
+'
+
+test_expect_success 'NUL in property value' '
+ reinit_git &&
+ echo "commit message" >expect.message &&
+ {
+ properties \
+ unimportant "something with a NUL (Q)" \
+ svn:log "commit message"&&
+ echo PROPS-END
+ } |
+ q_to_nul >props &&
+ {
+ cat <<-\EOF &&
+ SVN-fs-dump-format-version: 3
+
+ Revision-number: 1
+ EOF
+ echo Prop-content-length: $(wc -c <props) &&
+ echo Content-length: $(wc -c <props) &&
+ echo &&
+ cat props
+ } >nulprop.dump &&
+ test-svn-fe nulprop.dump >stream &&
+ git fast-import <stream &&
+ git diff-tree --always -s --format=%s HEAD >actual.message &&
+ test_cmp expect.message actual.message
+'
+
+test_expect_success 'NUL in log message, file content, and property name' '
+ # Caveat: svnadmin 1.6.16 (r1073529) truncates at \0 in the
+ # svn:specialQnotreally example.
+ reinit_git &&
+ cat >expect <<-\EOF &&
+ OBJID
+ :100644 100644 OBJID OBJID M greeting
+ OBJID
+ :000000 100644 OBJID OBJID A greeting
+ EOF
+ printf "\n%s\n" "something with an ASCII NUL (Q)" >expect.message &&
+ printf "%s\n" "helQo" >expect.hello1 &&
+ printf "%s\n" "link hello" >expect.hello2 &&
+ {
+ properties svn:log "something with an ASCII NUL (Q)" &&
+ echo PROPS-END
+ } |
+ q_to_nul >props &&
+ {
+ q_to_nul <<-\EOF &&
+ SVN-fs-dump-format-version: 3
+
+ Revision-number: 1
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: greeting
+ Node-kind: file
+ Node-action: add
+ Prop-content-length: 10
+ Text-content-length: 6
+ Content-length: 16
+
+ PROPS-END
+ helQo
+
+ Revision-number: 2
+ EOF
+ echo Prop-content-length: $(wc -c <props) &&
+ echo Content-length: $(wc -c <props) &&
+ echo &&
+ cat props &&
+ q_to_nul <<-\EOF
+
+ Node-path: greeting
+ Node-kind: file
+ Node-action: change
+ Prop-content-length: 43
+ Text-content-length: 11
+ Content-length: 54
+
+ K 21
+ svn:specialQnotreally
+ V 1
+ *
+ PROPS-END
+ link hello
+ EOF
+ } >8bitclean.dump &&
+ test-svn-fe 8bitclean.dump >stream &&
+ git fast-import <stream &&
+ {
+ git rev-list HEAD |
+ git diff-tree --root --stdin |
+ sed "s/$_x40/OBJID/g"
+ } >actual &&
+ {
+ git cat-file commit HEAD | nul_to_q &&
+ echo
+ } |
+ sed -ne "/^\$/,\$ p" >actual.message &&
+ git cat-file blob HEAD^:greeting | nul_to_q >actual.hello1 &&
+ git cat-file blob HEAD:greeting | nul_to_q >actual.hello2 &&
+ test_cmp expect actual &&
+ test_cmp expect.message actual.message &&
+ test_cmp expect.hello1 actual.hello1 &&
+ test_cmp expect.hello2 actual.hello2
+'
+
+test_expect_success 'change file mode and reiterate content' '
+ reinit_git &&
+ cat >expect <<-\EOF &&
+ OBJID
+ :120000 100644 OBJID OBJID T greeting
+ OBJID
+ :100644 120000 OBJID OBJID T greeting
+ OBJID
+ :000000 100644 OBJID OBJID A greeting
+ EOF
+ echo "link hello" >expect.blob &&
+ echo hello >hello &&
+ cat >filemode.dump <<-\EOF &&
+ SVN-fs-dump-format-version: 3
+
+ Revision-number: 1
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: greeting
+ Node-kind: file
+ Node-action: add
+ Prop-content-length: 10
+ Text-content-length: 11
+ Content-length: 21
+
+ PROPS-END
+ link hello
+
+ Revision-number: 2
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: greeting
+ Node-kind: file
+ Node-action: change
+ Prop-content-length: 33
+ Text-content-length: 11
+ Content-length: 44
+
+ K 11
+ svn:special
+ V 1
+ *
+ PROPS-END
+ link hello
+
+ Revision-number: 3
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: greeting
+ Node-kind: file
+ Node-action: change
+ Prop-content-length: 10
+ Text-content-length: 11
+ Content-length: 21
+
+ PROPS-END
+ link hello
+ EOF
+ test-svn-fe filemode.dump >stream &&
+ git fast-import <stream &&
+ {
+ git rev-list HEAD |
+ git diff-tree --root --stdin |
+ sed "s/$_x40/OBJID/g"
+ } >actual &&
+ git show HEAD:greeting >actual.blob &&
+ git show HEAD^:greeting >actual.target &&
+ test_cmp expect actual &&
+ test_cmp expect.blob actual.blob &&
+ test_cmp hello actual.target
+'
+
+test_expect_success 'deltas not supported' '
+ {
+ # (old) h + (inline) ello + (old) \n
+ printf "SVNQ%b%b%s" "Q\003\006\005\004" "\001Q\0204\001\002" "ello" |
+ q_to_nul
+ } >delta &&
+ {
+ properties \
+ svn:author author@example.com \
+ svn:date "1999-01-05T00:01:002.000000Z" \
+ svn:log "add greeting" &&
+ echo PROPS-END
+ } >props &&
+ {
+ properties \
+ svn:author author@example.com \
+ svn:date "1999-01-06T00:01:002.000000Z" \
+ svn:log "change it" &&
+ echo PROPS-END
+ } >props2 &&
+ {
+ echo SVN-fs-dump-format-version: 3 &&
+ echo &&
+ echo Revision-number: 1 &&
+ echo Prop-content-length: $(wc -c <props) &&
+ echo Content-length: $(wc -c <props) &&
+ echo &&
+ cat props &&
+ cat <<-\EOF &&
+
+ Node-path: hello
+ Node-kind: file
+ Node-action: add
+ Prop-content-length: 10
+ Text-content-length: 3
+ Content-length: 13
+
+ PROPS-END
+ hi
+
+ EOF
+ echo Revision-number: 2 &&
+ echo Prop-content-length: $(wc -c <props2) &&
+ echo Content-length: $(wc -c <props2) &&
+ echo &&
+ cat props2 &&
+ cat <<-\EOF &&
+
+ Node-path: hello
+ Node-kind: file
+ Node-action: change
+ Text-delta: true
+ Prop-content-length: 10
+ EOF
+ echo Text-content-length: $(wc -c <delta) &&
+ echo Content-length: $((10 + $(wc -c <delta))) &&
+ echo &&
+ echo PROPS-END &&
+ cat delta
+ } >delta.dump &&
+ test_must_fail test-svn-fe delta.dump
+'
+
+test_expect_success 'property deltas supported' '
+ reinit_git &&
+ cat >expect <<-\EOF &&
+ OBJID
+ :100755 100644 OBJID OBJID M script.sh
+ EOF
+ {
+ properties \
+ svn:author author@example.com \
+ svn:date "1999-03-06T00:01:002.000000Z" \
+ svn:log "make an executable, or chmod -x it" &&
+ echo PROPS-END
+ } >revprops &&
+ {
+ echo SVN-fs-dump-format-version: 3 &&
+ echo &&
+ echo Revision-number: 1 &&
+ echo Prop-content-length: $(wc -c <revprops) &&
+ echo Content-length: $(wc -c <revprops) &&
+ echo &&
+ cat revprops &&
+ echo &&
+ cat <<-\EOF &&
+ Node-path: script.sh
+ Node-kind: file
+ Node-action: add
+ Text-content-length: 0
+ Prop-content-length: 39
+ Content-length: 39
+
+ K 14
+ svn:executable
+ V 4
+ true
+ PROPS-END
+
+ EOF
+ echo Revision-number: 2 &&
+ echo Prop-content-length: $(wc -c <revprops) &&
+ echo Content-length: $(wc -c <revprops) &&
+ echo &&
+ cat revprops &&
+ echo &&
+ cat <<-\EOF
+ Node-path: script.sh
+ Node-kind: file
+ Node-action: change
+ Prop-delta: true
+ Prop-content-length: 30
+ Content-length: 30
+
+ D 14
+ svn:executable
+ PROPS-END
+ EOF
+ } >propdelta.dump &&
+ test-svn-fe propdelta.dump >stream &&
+ git fast-import <stream &&
+ {
+ git rev-list HEAD |
+ git diff-tree --stdin |
+ sed "s/$_x40/OBJID/g"
+ } >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'properties on /' '
+ reinit_git &&
+ cat <<-\EOF >expect &&
+ OBJID
+ OBJID
+ :000000 100644 OBJID OBJID A greeting
+ EOF
+ sed -e "s/X$//" <<-\EOF >changeroot.dump &&
+ SVN-fs-dump-format-version: 3
+
+ Revision-number: 1
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: greeting
+ Node-kind: file
+ Node-action: add
+ Text-content-length: 0
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Revision-number: 2
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: X
+ Node-kind: dir
+ Node-action: change
+ Prop-delta: true
+ Prop-content-length: 43
+ Content-length: 43
+
+ K 10
+ svn:ignore
+ V 11
+ build-area
+
+ PROPS-END
+ EOF
+ test-svn-fe changeroot.dump >stream &&
+ git fast-import <stream &&
+ {
+ git rev-list HEAD |
+ git diff-tree --root --always --stdin |
+ sed "s/$_x40/OBJID/g"
+ } >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'deltas for typechange' '
+ reinit_git &&
+ cat >expect <<-\EOF &&
+ OBJID
+ :120000 100644 OBJID OBJID T test-file
+ OBJID
+ :100755 120000 OBJID OBJID T test-file
+ OBJID
+ :000000 100755 OBJID OBJID A test-file
+ EOF
+ cat >deleteprop.dump <<-\EOF &&
+ SVN-fs-dump-format-version: 3
+
+ Revision-number: 1
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: test-file
+ Node-kind: file
+ Node-action: add
+ Prop-delta: true
+ Prop-content-length: 35
+ Text-content-length: 17
+ Content-length: 52
+
+ K 14
+ svn:executable
+ V 0
+
+ PROPS-END
+ link testing 123
+
+ Revision-number: 2
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: test-file
+ Node-kind: file
+ Node-action: change
+ Prop-delta: true
+ Prop-content-length: 53
+ Text-content-length: 17
+ Content-length: 70
+
+ K 11
+ svn:special
+ V 1
+ *
+ D 14
+ svn:executable
+ PROPS-END
+ link testing 231
+
+ Revision-number: 3
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: test-file
+ Node-kind: file
+ Node-action: change
+ Prop-delta: true
+ Prop-content-length: 27
+ Text-content-length: 17
+ Content-length: 44
+
+ D 11
+ svn:special
+ PROPS-END
+ link testing 321
+ EOF
+ test-svn-fe deleteprop.dump >stream &&
+ git fast-import <stream &&
+ {
+ git rev-list HEAD |
+ git diff-tree --root --stdin |
+ sed "s/$_x40/OBJID/g"
+ } >actual &&
+ test_cmp expect actual
+'
+
+
test_expect_success 'set up svn repo' '
svnconf=$PWD/svnconf &&
mkdir -p "$svnconf" &&
diff --git a/t/t9116-git-svn-log.sh b/t/t9116-git-svn-log.sh
index 5d477e4bda..cf4c05261b 100755
--- a/t/t9116-git-svn-log.sh
+++ b/t/t9116-git-svn-log.sh
@@ -60,6 +60,21 @@ test_expect_success 'test ascending revision range' "
git svn log -r 1:4 | grep '^r[0-9]' | cut -d'|' -f1 | test_cmp expected-range-r1-r2-r4 -
"
+test_expect_success 'test ascending revision range with --show-commit' "
+ git reset --hard trunk &&
+ git svn log --show-commit -r 1:4 | grep '^r[0-9]' | cut -d'|' -f1 | test_cmp expected-range-r1-r2-r4 -
+ "
+
+test_expect_success 'test ascending revision range with --show-commit (sha1)' "
+ git svn find-rev r1 >expected-range-r1-r2-r4-sha1 &&
+ git svn find-rev r2 >>expected-range-r1-r2-r4-sha1 &&
+ git svn find-rev r4 >>expected-range-r1-r2-r4-sha1 &&
+ git reset --hard trunk &&
+ git svn log --show-commit -r 1:4 | grep '^r[0-9]' | cut -d'|' -f2 >out &&
+ git rev-parse \$(cat out) >actual &&
+ test_cmp expected-range-r1-r2-r4-sha1 actual
+ "
+
printf 'r4 \nr2 \nr1 \n' > expected-range-r4-r2-r1
test_expect_success 'test descending revision range' "
diff --git a/t/t9130-git-svn-authors-file.sh b/t/t9130-git-svn-authors-file.sh
index ec0a106614..b324c491c5 100755
--- a/t/t9130-git-svn-authors-file.sh
+++ b/t/t9130-git-svn-authors-file.sh
@@ -96,7 +96,6 @@ test_expect_success 'fresh clone with svn.authors-file in config' '
rm -r "$GIT_DIR" &&
test x = x"$(git config svn.authorsfile)" &&
test_config="$HOME"/.gitconfig &&
- unset GIT_CONFIG_NOGLOBAL &&
unset GIT_DIR &&
unset GIT_CONFIG &&
git config --global \
diff --git a/t/t9146-git-svn-empty-dirs.sh b/t/t9146-git-svn-empty-dirs.sh
index 158c8e33ef..6d3130e618 100755
--- a/t/t9146-git-svn-empty-dirs.sh
+++ b/t/t9146-git-svn-empty-dirs.sh
@@ -28,6 +28,23 @@ test_expect_success 'empty directories exist' '
)
'
+test_expect_success 'option automkdirs set to false' '
+ (
+ git svn init "$svnrepo" cloned-no-mkdirs &&
+ cd cloned-no-mkdirs &&
+ git config svn-remote.svn.automkdirs false &&
+ git svn fetch &&
+ for i in a b c d d/e d/e/f "weird file name"
+ do
+ if test -d "$i"
+ then
+ echo >&2 "$i exists"
+ exit 1
+ fi
+ done
+ )
+'
+
test_expect_success 'more emptiness' '
svn_cmd mkdir -m "bang bang" "$svnrepo"/"! !"
'
diff --git a/t/t9158-git-svn-mergeinfo.sh b/t/t9158-git-svn-mergeinfo.sh
index 3ab43902b3..8c9539e1b4 100755
--- a/t/t9158-git-svn-mergeinfo.sh
+++ b/t/t9158-git-svn-mergeinfo.sh
@@ -38,4 +38,17 @@ test_expect_success 'verify svn:mergeinfo' '
test "$mergeinfo" = "/branches/foo:1-10"
'
+test_expect_success 'change svn:mergeinfo multiline' '
+ touch baz &&
+ git add baz &&
+ git commit -m "baz" &&
+ git svn dcommit --mergeinfo="/branches/bar:1-10 /branches/other:3-5,8,10-11"
+'
+
+test_expect_success 'verify svn:mergeinfo multiline' '
+ mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/trunk)
+ test "$mergeinfo" = "/branches/bar:1-10
+/branches/other:3-5,8,10-11"
+'
+
test_done
diff --git a/t/t9159-git-svn-no-parent-mergeinfo.sh b/t/t9159-git-svn-no-parent-mergeinfo.sh
new file mode 100755
index 0000000000..69e4815781
--- /dev/null
+++ b/t/t9159-git-svn-no-parent-mergeinfo.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+test_description='git svn handling of root commits in merge ranges'
+. ./lib-git-svn.sh
+
+svn_ver="$(svn --version --quiet)"
+case $svn_ver in
+0.* | 1.[0-4].*)
+ skip_all="skipping git-svn test - SVN too old ($svn_ver)"
+ test_done
+ ;;
+esac
+
+test_expect_success 'test handling of root commits in merge ranges' '
+ mkdir -p init/trunk init/branches init/tags &&
+ echo "r1" > init/trunk/file.txt &&
+ svn_cmd import -m "initial import" init "$svnrepo" &&
+ svn_cmd co "$svnrepo" tmp &&
+ (
+ cd tmp &&
+ echo "r2" > trunk/file.txt &&
+ svn_cmd commit -m "Modify file.txt on trunk" &&
+ svn_cmd cp trunk@1 branches/a &&
+ svn_cmd commit -m "Create branch a from trunk r1" &&
+ svn_cmd propset svn:mergeinfo /trunk:1-2 branches/a &&
+ svn_cmd commit -m "Fake merge of trunk r2 into branch a" &&
+ mkdir branches/b &&
+ echo "r5" > branches/b/file2.txt &&
+ svn_cmd add branches/b &&
+ svn_cmd commit -m "Create branch b from thin air" &&
+ echo "r6" > branches/b/file2.txt &&
+ svn_cmd commit -m "Modify file2.txt on branch b" &&
+ svn_cmd cp branches/b@5 branches/c &&
+ svn_cmd commit -m "Create branch c from branch b r5" &&
+ svn_cmd propset svn:mergeinfo /branches/b:5-6 branches/c &&
+ svn_cmd commit -m "Fake merge of branch b r6 into branch c"
+ ) &&
+ git svn init -s "$svnrepo" &&
+ git svn fetch
+ '
+
+test_done
diff --git a/t/t9160-git-svn-preserve-empty-dirs.sh b/t/t9160-git-svn-preserve-empty-dirs.sh
new file mode 100755
index 0000000000..b4a4434604
--- /dev/null
+++ b/t/t9160-git-svn-preserve-empty-dirs.sh
@@ -0,0 +1,153 @@
+#!/bin/sh
+#
+# Copyright (c) 2011 Ray Chen
+#
+
+test_description='git svn test (option --preserve-empty-dirs)
+
+This test uses git to clone a Subversion repository that contains empty
+directories, and checks that corresponding directories are created in the
+local Git repository with placeholder files.'
+
+. ./lib-git-svn.sh
+
+say 'define NO_SVN_TESTS to skip git svn tests'
+GIT_REPO=git-svn-repo
+
+test_expect_success 'initialize source svn repo containing empty dirs' '
+ svn_cmd mkdir -m x "$svnrepo"/trunk &&
+ svn_cmd co "$svnrepo"/trunk "$SVN_TREE" &&
+ (
+ cd "$SVN_TREE" &&
+ mkdir -p 1 2 3/a 3/b 4 5 6 &&
+ echo "First non-empty file" > 2/file1.txt &&
+ echo "Second non-empty file" > 2/file2.txt &&
+ echo "Third non-empty file" > 3/a/file1.txt &&
+ echo "Fourth non-empty file" > 3/b/file1.txt &&
+ svn_cmd add 1 2 3 4 5 6 &&
+ svn_cmd commit -m "initial commit" &&
+
+ mkdir 4/a &&
+ svn_cmd add 4/a &&
+ svn_cmd commit -m "nested empty directory" &&
+ mkdir 4/a/b &&
+ svn_cmd add 4/a/b &&
+ svn_cmd commit -m "deeply nested empty directory" &&
+ mkdir 4/a/b/c &&
+ svn_cmd add 4/a/b/c &&
+ svn_cmd commit -m "really deeply nested empty directory" &&
+ echo "Kill the placeholder file" > 4/a/b/c/foo &&
+ svn_cmd add 4/a/b/c/foo &&
+ svn_cmd commit -m "Regular file to remove placeholder" &&
+
+ svn_cmd del 2/file2.txt &&
+ svn_cmd del 3/b &&
+ svn_cmd commit -m "delete non-last entry in directory" &&
+
+ svn_cmd del 2/file1.txt &&
+ svn_cmd del 3/a &&
+ svn_cmd commit -m "delete last entry in directory" &&
+
+ echo "Conflict file" > 5/.placeholder &&
+ mkdir 6/.placeholder &&
+ svn_cmd add 5/.placeholder 6/.placeholder &&
+ svn_cmd commit -m "Placeholder Namespace conflict"
+ ) &&
+ rm -rf "$SVN_TREE"
+'
+
+test_expect_success 'clone svn repo with --preserve-empty-dirs' '
+ git svn clone "$svnrepo"/trunk --preserve-empty-dirs "$GIT_REPO"
+'
+
+# "$GIT_REPO"/1 should only contain the placeholder file.
+test_expect_success 'directory empty from inception' '
+ test -f "$GIT_REPO"/1/.gitignore &&
+ test $(find "$GIT_REPO"/1 -type f | wc -l) = "1"
+'
+
+# "$GIT_REPO"/2 and "$GIT_REPO"/3 should only contain the placeholder file.
+test_expect_success 'directory empty from subsequent svn commit' '
+ test -f "$GIT_REPO"/2/.gitignore &&
+ test $(find "$GIT_REPO"/2 -type f | wc -l) = "1" &&
+ test -f "$GIT_REPO"/3/.gitignore &&
+ test $(find "$GIT_REPO"/3 -type f | wc -l) = "1"
+'
+
+# No placeholder files should exist in "$GIT_REPO"/4, even though one was
+# generated for every sub-directory at some point in the repo's history.
+test_expect_success 'add entry to previously empty directory' '
+ test $(find "$GIT_REPO"/4 -type f | wc -l) = "1" &&
+ test -f "$GIT_REPO"/4/a/b/c/foo
+'
+
+# The HEAD~2 commit should not have introduced .gitignore placeholder files.
+test_expect_success 'remove non-last entry from directory' '
+ (
+ cd "$GIT_REPO" &&
+ git checkout HEAD~2
+ ) &&
+ test_must_fail test -f "$GIT_REPO"/2/.gitignore &&
+ test_must_fail test -f "$GIT_REPO"/3/.gitignore
+'
+
+# After re-cloning the repository with --placeholder-file specified, there
+# should be 5 files named ".placeholder" in the local Git repo.
+test_expect_success 'clone svn repo with --placeholder-file specified' '
+ rm -rf "$GIT_REPO" &&
+ git svn clone "$svnrepo"/trunk --preserve-empty-dirs \
+ --placeholder-file=.placeholder "$GIT_REPO" &&
+ find "$GIT_REPO" -type f -name ".placeholder" &&
+ test $(find "$GIT_REPO" -type f -name ".placeholder" | wc -l) = "5"
+'
+
+# "$GIT_REPO"/5/.placeholder should be a file, and non-empty.
+test_expect_success 'placeholder namespace conflict with file' '
+ test -s "$GIT_REPO"/5/.placeholder
+'
+
+# "$GIT_REPO"/6/.placeholder should be a directory, and the "$GIT_REPO"/6 tree
+# should only contain one file: the placeholder.
+test_expect_success 'placeholder namespace conflict with directory' '
+ test -d "$GIT_REPO"/6/.placeholder &&
+ test -f "$GIT_REPO"/6/.placeholder/.placeholder &&
+ test $(find "$GIT_REPO"/6 -type f | wc -l) = "1"
+'
+
+# Prepare a second set of svn commits to test persistence during rebase.
+test_expect_success 'second set of svn commits and rebase' '
+ svn_cmd co "$svnrepo"/trunk "$SVN_TREE" &&
+ (
+ cd "$SVN_TREE" &&
+ mkdir -p 7 &&
+ echo "This should remove placeholder" > 1/file1.txt &&
+ echo "This should not remove placeholder" > 5/file1.txt &&
+ svn_cmd add 7 1/file1.txt 5/file1.txt &&
+ svn_cmd commit -m "subsequent svn commit for persistence tests"
+ ) &&
+ rm -rf "$SVN_TREE" &&
+ (
+ cd "$GIT_REPO" &&
+ git svn rebase
+ )
+'
+
+# Check that --preserve-empty-dirs and --placeholder-file flag state
+# stays persistent over multiple invocations.
+test_expect_success 'flag persistence during subsqeuent rebase' '
+ test -f "$GIT_REPO"/7/.placeholder &&
+ test $(find "$GIT_REPO"/7 -type f | wc -l) = "1"
+'
+
+# Check that placeholder files are properly removed when unnecessary,
+# even across multiple invocations.
+test_expect_success 'placeholder list persistence during subsqeuent rebase' '
+ test -f "$GIT_REPO"/1/file1.txt &&
+ test $(find "$GIT_REPO"/1 -type f | wc -l) = "1" &&
+
+ test -f "$GIT_REPO"/5/file1.txt &&
+ test -f "$GIT_REPO"/5/.placeholder &&
+ test $(find "$GIT_REPO"/5 -type f | wc -l) = "2"
+'
+
+test_done
diff --git a/t/t9161-git-svn-mergeinfo-push.sh b/t/t9161-git-svn-mergeinfo-push.sh
new file mode 100755
index 0000000000..6ef0c0bde3
--- /dev/null
+++ b/t/t9161-git-svn-mergeinfo-push.sh
@@ -0,0 +1,104 @@
+#!/bin/sh
+#
+# Portions copyright (c) 2007, 2009 Sam Vilain
+# Portions copyright (c) 2011 Bryan Jacobs
+#
+
+test_description='git-svn svn mergeinfo propagation'
+
+. ./lib-git-svn.sh
+
+test_expect_success 'load svn dump' "
+ svnadmin load -q '$rawsvnrepo' \
+ < '$TEST_DIRECTORY/t9161/branches.dump' &&
+ git svn init --minimize-url -R svnmerge \
+ -T trunk -b branches '$svnrepo' &&
+ git svn fetch --all
+ "
+
+test_expect_success 'propagate merge information' '
+ git config svn.pushmergeinfo yes &&
+ git checkout svnb1 &&
+ git merge --no-ff svnb2 &&
+ git svn dcommit
+ '
+
+test_expect_success 'check svn:mergeinfo' '
+ mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/branches/svnb1)
+ test "$mergeinfo" = "/branches/svnb2:3,8"
+ '
+
+test_expect_success 'merge another branch' '
+ git merge --no-ff svnb3 &&
+ git svn dcommit
+ '
+
+test_expect_success 'check primary parent mergeinfo respected' '
+ mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/branches/svnb1)
+ test "$mergeinfo" = "/branches/svnb2:3,8
+/branches/svnb3:4,9"
+ '
+
+test_expect_success 'merge existing merge' '
+ git merge --no-ff svnb4 &&
+ git svn dcommit
+ '
+
+test_expect_success "check both parents' mergeinfo respected" '
+ mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/branches/svnb1)
+ test "$mergeinfo" = "/branches/svnb2:3,8
+/branches/svnb3:4,9
+/branches/svnb4:5-6,10-12
+/branches/svnb5:6,11"
+ '
+
+test_expect_success 'make further commits to branch' '
+ git checkout svnb2 &&
+ touch newb2file &&
+ git add newb2file &&
+ git commit -m "later b2 commit" &&
+ touch newb2file-2 &&
+ git add newb2file-2 &&
+ git commit -m "later b2 commit 2" &&
+ git svn dcommit
+ '
+
+test_expect_success 'second forward merge' '
+ git checkout svnb1 &&
+ git merge --no-ff svnb2 &&
+ git svn dcommit
+ '
+
+test_expect_success 'check new mergeinfo added' '
+ mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/branches/svnb1)
+ test "$mergeinfo" = "/branches/svnb2:3,8,16-17
+/branches/svnb3:4,9
+/branches/svnb4:5-6,10-12
+/branches/svnb5:6,11"
+ '
+
+test_expect_success 'reintegration merge' '
+ git checkout svnb4 &&
+ git merge --no-ff svnb1 &&
+ git svn dcommit
+ '
+
+test_expect_success 'check reintegration mergeinfo' '
+ mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/branches/svnb4)
+ test "$mergeinfo" = "/branches/svnb1:2-4,7-9,13-18
+/branches/svnb2:3,8,16-17
+/branches/svnb3:4,9
+/branches/svnb4:5-6,10-12
+/branches/svnb5:6,11"
+ '
+
+test_expect_success 'dcommit a merge at the top of a stack' '
+ git checkout svnb1 &&
+ touch anotherfile &&
+ git add anotherfile &&
+ git commit -m "a commit" &&
+ git merge svnb4 &&
+ git svn dcommit
+ '
+
+test_done
diff --git a/t/t9161/branches.dump b/t/t9161/branches.dump
new file mode 100644
index 0000000000..e61c3e7236
--- /dev/null
+++ b/t/t9161/branches.dump
@@ -0,0 +1,374 @@
+SVN-fs-dump-format-version: 2
+
+UUID: 1ef08553-f2d1-45df-b38c-19af6b7c926d
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2011-09-02T16:08:02.941384Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 114
+Content-length: 114
+
+K 7
+svn:log
+V 12
+Base commit
+
+K 10
+svn:author
+V 7
+bjacobs
+K 8
+svn:date
+V 27
+2011-09-02T16:08:27.205062Z
+PROPS-END
+
+Node-path: branches
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 2
+Prop-content-length: 121
+Content-length: 121
+
+K 7
+svn:log
+V 19
+Create branch svnb1
+K 10
+svn:author
+V 7
+bjacobs
+K 8
+svn:date
+V 27
+2011-09-02T16:09:43.628137Z
+PROPS-END
+
+Node-path: branches/svnb1
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 1
+Node-copyfrom-path: trunk
+
+
+Revision-number: 3
+Prop-content-length: 121
+Content-length: 121
+
+K 7
+svn:log
+V 19
+Create branch svnb2
+K 10
+svn:author
+V 7
+bjacobs
+K 8
+svn:date
+V 27
+2011-09-02T16:09:46.339930Z
+PROPS-END
+
+Node-path: branches/svnb2
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 1
+Node-copyfrom-path: trunk
+
+
+Revision-number: 4
+Prop-content-length: 121
+Content-length: 121
+
+K 7
+svn:log
+V 19
+Create branch svnb3
+K 10
+svn:author
+V 7
+bjacobs
+K 8
+svn:date
+V 27
+2011-09-02T16:09:49.394515Z
+PROPS-END
+
+Node-path: branches/svnb3
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 1
+Node-copyfrom-path: trunk
+
+
+Revision-number: 5
+Prop-content-length: 121
+Content-length: 121
+
+K 7
+svn:log
+V 19
+Create branch svnb4
+K 10
+svn:author
+V 7
+bjacobs
+K 8
+svn:date
+V 27
+2011-09-02T16:09:54.114607Z
+PROPS-END
+
+Node-path: branches/svnb4
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 1
+Node-copyfrom-path: trunk
+
+
+Revision-number: 6
+Prop-content-length: 121
+Content-length: 121
+
+K 7
+svn:log
+V 19
+Create branch svnb5
+K 10
+svn:author
+V 7
+bjacobs
+K 8
+svn:date
+V 27
+2011-09-02T16:09:58.602623Z
+PROPS-END
+
+Node-path: branches/svnb5
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 1
+Node-copyfrom-path: trunk
+
+
+Revision-number: 7
+Prop-content-length: 110
+Content-length: 110
+
+K 7
+svn:log
+V 9
+b1 commit
+K 10
+svn:author
+V 7
+bjacobs
+K 8
+svn:date
+V 27
+2011-09-02T16:10:20.292369Z
+PROPS-END
+
+Node-path: branches/svnb1/b1file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 0
+Text-content-md5: d41d8cd98f00b204e9800998ecf8427e
+Text-content-sha1: da39a3ee5e6b4b0d3255bfef95601890afd80709
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 8
+Prop-content-length: 110
+Content-length: 110
+
+K 7
+svn:log
+V 9
+b2 commit
+K 10
+svn:author
+V 7
+bjacobs
+K 8
+svn:date
+V 27
+2011-09-02T16:10:38.429199Z
+PROPS-END
+
+Node-path: branches/svnb2/b2file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 0
+Text-content-md5: d41d8cd98f00b204e9800998ecf8427e
+Text-content-sha1: da39a3ee5e6b4b0d3255bfef95601890afd80709
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 9
+Prop-content-length: 110
+Content-length: 110
+
+K 7
+svn:log
+V 9
+b3 commit
+K 10
+svn:author
+V 7
+bjacobs
+K 8
+svn:date
+V 27
+2011-09-02T16:10:52.843023Z
+PROPS-END
+
+Node-path: branches/svnb3/b3file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 0
+Text-content-md5: d41d8cd98f00b204e9800998ecf8427e
+Text-content-sha1: da39a3ee5e6b4b0d3255bfef95601890afd80709
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 10
+Prop-content-length: 110
+Content-length: 110
+
+K 7
+svn:log
+V 9
+b4 commit
+K 10
+svn:author
+V 7
+bjacobs
+K 8
+svn:date
+V 27
+2011-09-02T16:11:17.489870Z
+PROPS-END
+
+Node-path: branches/svnb4/b4file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 0
+Text-content-md5: d41d8cd98f00b204e9800998ecf8427e
+Text-content-sha1: da39a3ee5e6b4b0d3255bfef95601890afd80709
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 11
+Prop-content-length: 110
+Content-length: 110
+
+K 7
+svn:log
+V 9
+b5 commit
+K 10
+svn:author
+V 7
+bjacobs
+K 8
+svn:date
+V 27
+2011-09-02T16:11:32.277404Z
+PROPS-END
+
+Node-path: branches/svnb5/b5file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 0
+Text-content-md5: d41d8cd98f00b204e9800998ecf8427e
+Text-content-sha1: da39a3ee5e6b4b0d3255bfef95601890afd80709
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 12
+Prop-content-length: 192
+Content-length: 192
+
+K 7
+svn:log
+V 90
+Merge remote-tracking branch 'svnb5' into HEAD
+
+* svnb5:
+ b5 commit
+ Create branch svnb5
+K 10
+svn:author
+V 7
+bjacobs
+K 8
+svn:date
+V 27
+2011-09-02T16:11:54.274722Z
+PROPS-END
+
+Node-path: branches/svnb4
+Node-kind: dir
+Node-action: change
+Prop-content-length: 56
+Content-length: 56
+
+K 13
+svn:mergeinfo
+V 21
+/branches/svnb5:6,11
+
+PROPS-END
+
+
+Node-path: branches/svnb4/b5file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 0
+Text-content-md5: d41d8cd98f00b204e9800998ecf8427e
+Text-content-sha1: da39a3ee5e6b4b0d3255bfef95601890afd80709
+Content-length: 10
+
+PROPS-END
+
+
diff --git a/t/t9162-git-svn-dcommit-interactive.sh b/t/t9162-git-svn-dcommit-interactive.sh
new file mode 100755
index 0000000000..e38d9fa37b
--- /dev/null
+++ b/t/t9162-git-svn-dcommit-interactive.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+#
+# Copyright (c) 2011 Frédéric Heitzmann
+
+test_description='git svn dcommit --interactive series'
+. ./lib-git-svn.sh
+
+test_expect_success 'initialize repo' '
+ svn_cmd mkdir -m"mkdir test-interactive" "$svnrepo/test-interactive" &&
+ git svn clone "$svnrepo/test-interactive" test-interactive &&
+ cd test-interactive &&
+ touch foo && git add foo && git commit -m"foo: first commit" &&
+ git svn dcommit
+ '
+
+test_expect_success 'answers: y [\n] yes' '
+ (
+ echo "change #1" >> foo && git commit -a -m"change #1" &&
+ echo "change #2" >> foo && git commit -a -m"change #2" &&
+ echo "change #3" >> foo && git commit -a -m"change #3" &&
+ ( echo "y
+
+y" | GIT_SVN_NOTTY=1 git svn dcommit --interactive ) &&
+ test $(git rev-parse HEAD) = $(git rev-parse remotes/git-svn)
+ )
+ '
+
+test_expect_success 'answers: yes yes no' '
+ (
+ echo "change #1" >> foo && git commit -a -m"change #1" &&
+ echo "change #2" >> foo && git commit -a -m"change #2" &&
+ echo "change #3" >> foo && git commit -a -m"change #3" &&
+ ( echo "yes
+yes
+no" | GIT_SVN_NOTTY=1 git svn dcommit --interactive ) &&
+ test $(git rev-parse HEAD^^^) = $(git rev-parse remotes/git-svn) &&
+ git reset --hard remotes/git-svn
+ )
+ '
+
+test_expect_success 'answers: yes quit' '
+ (
+ echo "change #1" >> foo && git commit -a -m"change #1" &&
+ echo "change #2" >> foo && git commit -a -m"change #2" &&
+ echo "change #3" >> foo && git commit -a -m"change #3" &&
+ ( echo "yes
+quit" | GIT_SVN_NOTTY=1 git svn dcommit --interactive ) &&
+ test $(git rev-parse HEAD^^^) = $(git rev-parse remotes/git-svn) &&
+ git reset --hard remotes/git-svn
+ )
+ '
+
+test_expect_success 'answers: all' '
+ (
+ echo "change #1" >> foo && git commit -a -m"change #1" &&
+ echo "change #2" >> foo && git commit -a -m"change #2" &&
+ echo "change #3" >> foo && git commit -a -m"change #3" &&
+ ( echo "all" | GIT_SVN_NOTTY=1 git svn dcommit --interactive ) &&
+ test $(git rev-parse HEAD) = $(git rev-parse remotes/git-svn) &&
+ git reset --hard remotes/git-svn
+ )
+ '
+
+test_done
diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh
index e5da65b99f..41db05cb4a 100755
--- a/t/t9200-git-cvsexportcommit.sh
+++ b/t/t9200-git-cvsexportcommit.sh
@@ -50,8 +50,8 @@ test_expect_success \
'mkdir A B C D E F &&
echo hello1 >A/newfile1.txt &&
echo hello2 >B/newfile2.txt &&
- cp "$TEST_DIRECTORY"/test9200a.png C/newfile3.png &&
- cp "$TEST_DIRECTORY"/test9200a.png D/newfile4.png &&
+ cp "$TEST_DIRECTORY"/test-binary-1.png C/newfile3.png &&
+ cp "$TEST_DIRECTORY"/test-binary-1.png D/newfile4.png &&
git add A/newfile1.txt &&
git add B/newfile2.txt &&
git add C/newfile3.png &&
@@ -76,8 +76,8 @@ test_expect_success \
rm -f B/newfile2.txt &&
rm -f C/newfile3.png &&
echo Hello5 >E/newfile5.txt &&
- cp "$TEST_DIRECTORY"/test9200b.png D/newfile4.png &&
- cp "$TEST_DIRECTORY"/test9200a.png F/newfile6.png &&
+ cp "$TEST_DIRECTORY"/test-binary-2.png D/newfile4.png &&
+ cp "$TEST_DIRECTORY"/test-binary-1.png F/newfile6.png &&
git add E/newfile5.txt &&
git add F/newfile6.png &&
git commit -a -m "Test: Remove, add and update" &&
@@ -165,7 +165,7 @@ test_expect_success \
'mkdir "G g" &&
echo ok then >"G g/with spaces.txt" &&
git add "G g/with spaces.txt" && \
- cp "$TEST_DIRECTORY"/test9200a.png "G g/with spaces.png" && \
+ cp "$TEST_DIRECTORY"/test-binary-1.png "G g/with spaces.png" && \
git add "G g/with spaces.png" &&
git commit -a -m "With spaces" &&
id=$(git rev-list --max-count=1 HEAD) &&
@@ -177,7 +177,7 @@ test_expect_success \
test_expect_success \
'Update file with spaces in file name' \
'echo Ok then >>"G g/with spaces.txt" &&
- cat "$TEST_DIRECTORY"/test9200a.png >>"G g/with spaces.png" && \
+ cat "$TEST_DIRECTORY"/test-binary-1.png >>"G g/with spaces.png" && \
git add "G g/with spaces.png" &&
git commit -a -m "Update with spaces" &&
id=$(git rev-list --max-count=1 HEAD) &&
@@ -202,7 +202,7 @@ test_expect_success \
'mkdir -p Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö &&
echo Foo >Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.txt &&
git add Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.txt &&
- cp "$TEST_DIRECTORY"/test9200a.png Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.png &&
+ cp "$TEST_DIRECTORY"/test-binary-1.png Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.png &&
git add Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.png &&
git commit -a -m "Går det så går det" && \
id=$(git rev-list --max-count=1 HEAD) &&
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index 986bc14d58..438aaf6b14 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -42,6 +42,14 @@ echo "$@"'
>empty
+test_expect_success 'setup: have pipes?' '
+ rm -f frob &&
+ if mkfifo frob
+ then
+ test_set_prereq PIPE
+ fi
+'
+
###
### series A
###
@@ -86,6 +94,12 @@ data <<EOF
An annotated tag without a tagger
EOF
+tag series-A-blob
+from :3
+data <<EOF
+An annotated tag that annotates a blob.
+EOF
+
INPUT_END
test_expect_success \
'A: create pack from stdin' \
@@ -144,6 +158,18 @@ test_expect_success 'A: verify tag/series-A' '
'
cat >expect <<EOF
+object $(git rev-parse refs/heads/master:file3)
+type blob
+tag series-A-blob
+
+An annotated tag that annotates a blob.
+EOF
+test_expect_success 'A: verify tag/series-A-blob' '
+ git cat-file tag tags/series-A-blob >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<EOF
:2 `git rev-parse --verify master:file2`
:3 `git rev-parse --verify master:file3`
:4 `git rev-parse --verify master:file4`
@@ -162,6 +188,55 @@ test_expect_success \
test_cmp expect marks.new'
test_tick
+new_blob=$(echo testing | git hash-object --stdin)
+cat >input <<INPUT_END
+tag series-A-blob-2
+from $(git rev-parse refs/heads/master:file3)
+data <<EOF
+Tag blob by sha1.
+EOF
+
+blob
+mark :6
+data <<EOF
+testing
+EOF
+
+commit refs/heads/new_blob
+committer <> 0 +0000
+data 0
+M 644 :6 new_blob
+#pretend we got sha1 from fast-import
+ls "new_blob"
+
+tag series-A-blob-3
+from $new_blob
+data <<EOF
+Tag new_blob.
+EOF
+INPUT_END
+
+cat >expect <<EOF
+object $(git rev-parse refs/heads/master:file3)
+type blob
+tag series-A-blob-2
+
+Tag blob by sha1.
+object $new_blob
+type blob
+tag series-A-blob-3
+
+Tag new_blob.
+EOF
+
+test_expect_success \
+ 'A: tag blob by sha1' \
+ 'git fast-import <input &&
+ git cat-file tag tags/series-A-blob-2 >actual &&
+ git cat-file tag tags/series-A-blob-3 >>actual &&
+ test_cmp expect actual'
+
+test_tick
cat >input <<INPUT_END
commit refs/heads/verify--import-marks
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
@@ -316,6 +391,105 @@ test_expect_success \
test `git rev-parse master` = `git rev-parse TEMP_TAG^`'
rm -f .git/TEMP_TAG
+git gc 2>/dev/null >/dev/null
+git prune 2>/dev/null >/dev/null
+
+cat >input <<INPUT_END
+commit refs/heads/empty-committer-1
+committer <> $GIT_COMMITTER_DATE
+data <<COMMIT
+empty commit
+COMMIT
+INPUT_END
+test_expect_success 'B: accept empty committer' '
+ git fast-import <input &&
+ out=$(git fsck) &&
+ echo "$out" &&
+ test -z "$out"
+'
+git update-ref -d refs/heads/empty-committer-1 || true
+
+git gc 2>/dev/null >/dev/null
+git prune 2>/dev/null >/dev/null
+
+cat >input <<INPUT_END
+commit refs/heads/empty-committer-2
+committer <a@b.com> $GIT_COMMITTER_DATE
+data <<COMMIT
+empty commit
+COMMIT
+INPUT_END
+test_expect_success 'B: accept and fixup committer with no name' '
+ git fast-import <input &&
+ out=$(git fsck) &&
+ echo "$out" &&
+ test -z "$out"
+'
+git update-ref -d refs/heads/empty-committer-2 || true
+
+git gc 2>/dev/null >/dev/null
+git prune 2>/dev/null >/dev/null
+
+cat >input <<INPUT_END
+commit refs/heads/invalid-committer
+committer Name email> $GIT_COMMITTER_DATE
+data <<COMMIT
+empty commit
+COMMIT
+INPUT_END
+test_expect_success 'B: fail on invalid committer (1)' '
+ test_must_fail git fast-import <input
+'
+git update-ref -d refs/heads/invalid-committer || true
+
+cat >input <<INPUT_END
+commit refs/heads/invalid-committer
+committer Name <e<mail> $GIT_COMMITTER_DATE
+data <<COMMIT
+empty commit
+COMMIT
+INPUT_END
+test_expect_success 'B: fail on invalid committer (2)' '
+ test_must_fail git fast-import <input
+'
+git update-ref -d refs/heads/invalid-committer || true
+
+cat >input <<INPUT_END
+commit refs/heads/invalid-committer
+committer Name <email>> $GIT_COMMITTER_DATE
+data <<COMMIT
+empty commit
+COMMIT
+INPUT_END
+test_expect_success 'B: fail on invalid committer (3)' '
+ test_must_fail git fast-import <input
+'
+git update-ref -d refs/heads/invalid-committer || true
+
+cat >input <<INPUT_END
+commit refs/heads/invalid-committer
+committer Name <email $GIT_COMMITTER_DATE
+data <<COMMIT
+empty commit
+COMMIT
+INPUT_END
+test_expect_success 'B: fail on invalid committer (4)' '
+ test_must_fail git fast-import <input
+'
+git update-ref -d refs/heads/invalid-committer || true
+
+cat >input <<INPUT_END
+commit refs/heads/invalid-committer
+committer Name<email> $GIT_COMMITTER_DATE
+data <<COMMIT
+empty commit
+COMMIT
+INPUT_END
+test_expect_success 'B: fail on invalid committer (5)' '
+ test_must_fail git fast-import <input
+'
+git update-ref -d refs/heads/invalid-committer || true
+
###
### series C
###
@@ -646,6 +820,18 @@ test_expect_success \
'test 1 = `git rev-list J | wc -l` &&
test 0 = `git ls-tree J | wc -l`'
+cat >input <<INPUT_END
+reset refs/heads/J2
+
+tag wrong_tag
+from refs/heads/J2
+data <<EOF
+Tag branch that was reset.
+EOF
+INPUT_END
+test_expect_success \
+ 'J: tag must fail on empty branch' \
+ 'test_must_fail git fast-import <input'
###
### series K
###
@@ -726,6 +912,47 @@ test_expect_success \
git diff-tree --abbrev --raw L^ L >output &&
test_cmp expect output'
+cat >input <<INPUT_END
+blob
+mark :1
+data <<EOF
+the data
+EOF
+
+commit refs/heads/L2
+committer C O Mitter <committer@example.com> 1112912473 -0700
+data <<COMMIT
+init L2
+COMMIT
+M 644 :1 a/b/c
+M 644 :1 a/b/d
+M 644 :1 a/e/f
+
+commit refs/heads/L2
+committer C O Mitter <committer@example.com> 1112912473 -0700
+data <<COMMIT
+update L2
+COMMIT
+C a g
+C a/e g/b
+M 644 :1 g/b/h
+INPUT_END
+
+cat <<EOF >expect
+g/b/f
+g/b/h
+EOF
+
+test_expect_success \
+ 'L: nested tree copy does not corrupt deltas' \
+ 'git fast-import <input &&
+ git ls-tree L2 g/b/ >tmp &&
+ cat tmp | cut -f 2 >actual &&
+ test_cmp expect actual &&
+ git fsck `git rev-parse L2`'
+
+git update-ref -d refs/heads/L2
+
###
### series M
###
@@ -898,6 +1125,77 @@ test_expect_success \
git diff-tree -C --find-copies-harder -r N4^ N4 >actual &&
compare_diff_raw expect actual'
+test_expect_success PIPE 'N: read and copy directory' '
+ cat >expect <<-\EOF
+ :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf file3/newf
+ :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100 file2/oldf file3/oldf
+ EOF
+ git update-ref -d refs/heads/N4 &&
+ rm -f backflow &&
+ mkfifo backflow &&
+ (
+ exec <backflow &&
+ cat <<-EOF &&
+ commit refs/heads/N4
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ copy by tree hash, part 2
+ COMMIT
+
+ from refs/heads/branch^0
+ ls "file2"
+ EOF
+ read mode type tree filename &&
+ echo "M 040000 $tree file3"
+ ) |
+ git fast-import --cat-blob-fd=3 3>backflow &&
+ git diff-tree -C --find-copies-harder -r N4^ N4 >actual &&
+ compare_diff_raw expect actual
+'
+
+test_expect_success PIPE 'N: empty directory reads as missing' '
+ cat <<-\EOF >expect &&
+ OBJNAME
+ :000000 100644 OBJNAME OBJNAME A unrelated
+ EOF
+ echo "missing src" >expect.response &&
+ git update-ref -d refs/heads/read-empty &&
+ rm -f backflow &&
+ mkfifo backflow &&
+ (
+ exec <backflow &&
+ cat <<-EOF &&
+ commit refs/heads/read-empty
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ read "empty" (missing) directory
+ COMMIT
+
+ M 100644 inline src/greeting
+ data <<BLOB
+ hello
+ BLOB
+ C src/greeting dst1/non-greeting
+ C src/greeting unrelated
+ # leave behind "empty" src directory
+ D src/greeting
+ ls "src"
+ EOF
+ read -r line &&
+ printf "%s\n" "$line" >response &&
+ cat <<-\EOF
+ D dst1
+ D dst2
+ EOF
+ ) |
+ git fast-import --cat-blob-fd=3 3>backflow &&
+ test_cmp expect.response response &&
+ git rev-list read-empty |
+ git diff-tree -r --root --stdin |
+ sed "s/$_x40/OBJNAME/g" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success \
'N: copy root directory by tree hash' \
'cat >expect <<-\EOF &&
@@ -1689,6 +1987,23 @@ test_expect_success \
'Q: verify second note for second commit' \
'git cat-file blob refs/notes/foobar:$commit2 >actual && test_cmp expect actual'
+cat >input <<EOF
+reset refs/heads/Q0
+
+commit refs/heads/note-Q0
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+Note for an empty branch.
+COMMIT
+
+N inline refs/heads/Q0
+data <<NOTE
+some note
+NOTE
+EOF
+test_expect_success \
+ 'Q: deny note on empty branch' \
+ 'test_must_fail git fast-import <input'
###
### series R (feature and option)
###
@@ -1748,6 +2063,108 @@ test_expect_success \
'cat input | git fast-import --export-marks=other.marks &&
grep :1 other.marks'
+test_expect_success 'R: catch typo in marks file name' '
+ test_must_fail git fast-import --import-marks=nonexistent.marks </dev/null &&
+ echo "feature import-marks=nonexistent.marks" |
+ test_must_fail git fast-import
+'
+
+test_expect_success 'R: import and output marks can be the same file' '
+ rm -f io.marks &&
+ blob=$(echo hi | git hash-object --stdin) &&
+ cat >expect <<-EOF &&
+ :1 $blob
+ :2 $blob
+ EOF
+ git fast-import --export-marks=io.marks <<-\EOF &&
+ blob
+ mark :1
+ data 3
+ hi
+
+ EOF
+ git fast-import --import-marks=io.marks --export-marks=io.marks <<-\EOF &&
+ blob
+ mark :2
+ data 3
+ hi
+
+ EOF
+ test_cmp expect io.marks
+'
+
+test_expect_success 'R: --import-marks=foo --output-marks=foo to create foo fails' '
+ rm -f io.marks &&
+ test_must_fail git fast-import --import-marks=io.marks --export-marks=io.marks <<-\EOF
+ blob
+ mark :1
+ data 3
+ hi
+
+ EOF
+'
+
+test_expect_success 'R: --import-marks-if-exists' '
+ rm -f io.marks &&
+ blob=$(echo hi | git hash-object --stdin) &&
+ echo ":1 $blob" >expect &&
+ git fast-import --import-marks-if-exists=io.marks --export-marks=io.marks <<-\EOF &&
+ blob
+ mark :1
+ data 3
+ hi
+
+ EOF
+ test_cmp expect io.marks
+'
+
+test_expect_success 'R: feature import-marks-if-exists' '
+ rm -f io.marks &&
+ >expect &&
+
+ git fast-import --export-marks=io.marks <<-\EOF &&
+ feature import-marks-if-exists=not_io.marks
+ EOF
+ test_cmp expect io.marks &&
+
+ blob=$(echo hi | git hash-object --stdin) &&
+
+ echo ":1 $blob" >io.marks &&
+ echo ":1 $blob" >expect &&
+ echo ":2 $blob" >>expect &&
+
+ git fast-import --export-marks=io.marks <<-\EOF &&
+ feature import-marks-if-exists=io.marks
+ blob
+ mark :2
+ data 3
+ hi
+
+ EOF
+ test_cmp expect io.marks &&
+
+ echo ":3 $blob" >>expect &&
+
+ git fast-import --import-marks=io.marks \
+ --export-marks=io.marks <<-\EOF &&
+ feature import-marks-if-exists=not_io.marks
+ blob
+ mark :3
+ data 3
+ hi
+
+ EOF
+ test_cmp expect io.marks &&
+
+ >expect &&
+
+ git fast-import --import-marks-if-exists=not_io.marks \
+ --export-marks=io.marks <<-\EOF
+ feature import-marks-if-exists=io.marks
+ EOF
+ test_cmp expect io.marks
+'
+
cat >input << EOF
feature import-marks=marks.out
feature export-marks=marks.new
@@ -1759,7 +2176,7 @@ test_expect_success \
test_cmp marks.out marks.new'
cat >input <<EOF
-feature import-marks=nonexistant.marks
+feature import-marks=nonexistent.marks
feature export-marks=marks.new
EOF
@@ -1770,7 +2187,7 @@ test_expect_success \
cat >input <<EOF
-feature import-marks=nonexistant.marks
+feature import-marks=nonexistent.marks
feature export-marks=combined.marks
EOF
@@ -1806,6 +2223,11 @@ test_expect_success 'R: feature no-relative-marks should be honoured' '
test_cmp marks.new non-relative.out
'
+test_expect_success 'R: feature ls supported' '
+ echo "feature ls" |
+ git fast-import
+'
+
test_expect_success 'R: feature cat-blob supported' '
echo "feature cat-blob" |
git fast-import
@@ -1815,7 +2237,7 @@ test_expect_success 'R: cat-blob-fd must be a nonnegative integer' '
test_must_fail git fast-import --cat-blob-fd=-1 </dev/null
'
-test_expect_success 'R: print old blob' '
+test_expect_success NOT_MINGW 'R: print old blob' '
blob=$(echo "yes it can" | git hash-object -w --stdin) &&
cat >expect <<-EOF &&
${blob} blob 11
@@ -1827,7 +2249,7 @@ test_expect_success 'R: print old blob' '
test_cmp expect actual
'
-test_expect_success 'R: in-stream cat-blob-fd not respected' '
+test_expect_success NOT_MINGW 'R: in-stream cat-blob-fd not respected' '
echo hello >greeting &&
blob=$(git hash-object -w greeting) &&
cat >expect <<-EOF &&
@@ -1848,7 +2270,7 @@ test_expect_success 'R: in-stream cat-blob-fd not respected' '
test_cmp expect actual.1
'
-test_expect_success 'R: print new blob' '
+test_expect_success NOT_MINGW 'R: print new blob' '
blob=$(echo "yep yep yep" | git hash-object --stdin) &&
cat >expect <<-EOF &&
${blob} blob 12
@@ -1866,7 +2288,7 @@ test_expect_success 'R: print new blob' '
test_cmp expect actual
'
-test_expect_success 'R: print new blob by sha1' '
+test_expect_success NOT_MINGW 'R: print new blob by sha1' '
blob=$(echo "a new blob named by sha1" | git hash-object --stdin) &&
cat >expect <<-EOF &&
${blob} blob 25
@@ -1931,14 +2353,6 @@ test_expect_success 'R: print two blobs to stdout' '
test_cmp expect actual
'
-test_expect_success 'setup: have pipes?' '
- rm -f frob &&
- if mkfifo frob
- then
- test_set_prereq PIPE
- fi
-'
-
test_expect_success PIPE 'R: copy using cat-file' '
expect_id=$(git hash-object big) &&
expect_len=$(wc -c <big) &&
@@ -2066,6 +2480,48 @@ test_expect_success 'R: quiet option results in no stats being output' '
test_cmp empty output
'
+test_expect_success 'R: feature done means terminating "done" is mandatory' '
+ echo feature done | test_must_fail git fast-import &&
+ test_must_fail git fast-import --done </dev/null
+'
+
+test_expect_success 'R: terminating "done" with trailing gibberish is ok' '
+ git fast-import <<-\EOF &&
+ feature done
+ done
+ trailing gibberish
+ EOF
+ git fast-import <<-\EOF
+ done
+ more trailing gibberish
+ EOF
+'
+
+test_expect_success 'R: terminating "done" within commit' '
+ cat >expect <<-\EOF &&
+ OBJID
+ :000000 100644 OBJID OBJID A hello.c
+ :000000 100644 OBJID OBJID A hello2.c
+ EOF
+ git fast-import <<-EOF &&
+ commit refs/heads/done-ends
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<EOT
+ Commit terminated by "done" command
+ EOT
+ M 100644 inline hello.c
+ data <<EOT
+ Hello, world.
+ EOT
+ C hello.c hello2.c
+ done
+ EOF
+ git rev-list done-ends |
+ git diff-tree -r --stdin --root --always |
+ sed -e "s/$_x40/OBJID/g" >actual &&
+ test_cmp expect actual
+'
+
cat >input <<EOF
option git non-existing-option
EOF
diff --git a/t/t9301-fast-import-notes.sh b/t/t9301-fast-import-notes.sh
index 7cf8cd8a2f..463254c727 100755
--- a/t/t9301-fast-import-notes.sh
+++ b/t/t9301-fast-import-notes.sh
@@ -120,6 +120,7 @@ test_expect_success 'add notes with simple M command' '
test_tick
cat >input <<INPUT_END
+feature notes
commit refs/notes/test
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
data <<COMMIT
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index f823c05305..950d0ff498 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -228,7 +228,7 @@ test_expect_success 'fast-export -C -C | fast-import' '
mkdir new &&
git --git-dir=new/.git init &&
git fast-export -C -C --signed-tags=strip --all > output &&
- grep "^C \"file6\" \"file7\"\$" output &&
+ grep "^C file6 file7\$" output &&
cat output |
(cd new &&
git fast-import &&
@@ -414,4 +414,30 @@ test_expect_success SYMLINKS 'directory becomes symlink' '
(cd result && git show master:foo)
'
+test_expect_success 'fast-export quotes pathnames' '
+ git init crazy-paths &&
+ (cd crazy-paths &&
+ blob=`echo foo | git hash-object -w --stdin` &&
+ git update-index --add \
+ --cacheinfo 100644 $blob "$(printf "path with\\nnewline")" \
+ --cacheinfo 100644 $blob "path with \"quote\"" \
+ --cacheinfo 100644 $blob "path with \\backslash" \
+ --cacheinfo 100644 $blob "path with space" &&
+ git commit -m addition &&
+ git ls-files -z -s | perl -0pe "s{\\t}{$&subdir/}" >index &&
+ git read-tree --empty &&
+ git update-index -z --index-info <index &&
+ git commit -m rename &&
+ git read-tree --empty &&
+ git commit -m deletion &&
+ git fast-export HEAD >export.out &&
+ git rev-list HEAD >expect &&
+ git init result &&
+ cd result &&
+ git fast-import <../export.out &&
+ git rev-list HEAD >actual &&
+ test_cmp ../expect actual
+ )
+'
+
test_done
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
index 21cd286bb7..53297156a3 100755
--- a/t/t9500-gitweb-standalone-no-errors.sh
+++ b/t/t9500-gitweb-standalone-no-errors.sh
@@ -18,42 +18,34 @@ or warnings to log.'
test_expect_success \
'no commits: projects_list (implicit)' \
'gitweb_run'
-test_debug 'cat gitweb.log'
test_expect_success \
'no commits: projects_index' \
'gitweb_run "a=project_index"'
-test_debug 'cat gitweb.log'
test_expect_success \
'no commits: .git summary (implicit)' \
'gitweb_run "p=.git"'
-test_debug 'cat gitweb.log'
test_expect_success \
'no commits: .git commit (implicit HEAD)' \
'gitweb_run "p=.git;a=commit"'
-test_debug 'cat gitweb.log'
test_expect_success \
'no commits: .git commitdiff (implicit HEAD)' \
'gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
test_expect_success \
'no commits: .git tree (implicit HEAD)' \
'gitweb_run "p=.git;a=tree"'
-test_debug 'cat gitweb.log'
test_expect_success \
'no commits: .git heads' \
'gitweb_run "p=.git;a=heads"'
-test_debug 'cat gitweb.log'
test_expect_success \
'no commits: .git tags' \
'gitweb_run "p=.git;a=tags"'
-test_debug 'cat gitweb.log'
# ----------------------------------------------------------------------
@@ -69,52 +61,42 @@ test_expect_success \
test_expect_success \
'projects_list (implicit)' \
'gitweb_run'
-test_debug 'cat gitweb.log'
test_expect_success \
'projects_index' \
'gitweb_run "a=project_index"'
-test_debug 'cat gitweb.log'
test_expect_success \
'.git summary (implicit)' \
'gitweb_run "p=.git"'
-test_debug 'cat gitweb.log'
test_expect_success \
'.git commit (implicit HEAD)' \
'gitweb_run "p=.git;a=commit"'
-test_debug 'cat gitweb.log'
test_expect_success \
'.git commitdiff (implicit HEAD, root commit)' \
'gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
test_expect_success \
'.git commitdiff_plain (implicit HEAD, root commit)' \
'gitweb_run "p=.git;a=commitdiff_plain"'
-test_debug 'cat gitweb.log'
test_expect_success \
'.git commit (HEAD)' \
'gitweb_run "p=.git;a=commit;h=HEAD"'
-test_debug 'cat gitweb.log'
test_expect_success \
'.git tree (implicit HEAD)' \
'gitweb_run "p=.git;a=tree"'
-test_debug 'cat gitweb.log'
test_expect_success \
'.git blob (file)' \
'gitweb_run "p=.git;a=blob;f=file"'
-test_debug 'cat gitweb.log'
test_expect_success \
'.git blob_plain (file)' \
'gitweb_run "p=.git;a=blob_plain;f=file"'
-test_debug 'cat gitweb.log'
# ----------------------------------------------------------------------
# nonexistent objects
@@ -122,37 +104,30 @@ test_debug 'cat gitweb.log'
test_expect_success \
'.git commit (non-existent)' \
'gitweb_run "p=.git;a=commit;h=non-existent"'
-test_debug 'cat gitweb.log'
test_expect_success \
'.git commitdiff (non-existent)' \
'gitweb_run "p=.git;a=commitdiff;h=non-existent"'
-test_debug 'cat gitweb.log'
test_expect_success \
'.git commitdiff (non-existent vs HEAD)' \
'gitweb_run "p=.git;a=commitdiff;hp=non-existent;h=HEAD"'
-test_debug 'cat gitweb.log'
test_expect_success \
'.git tree (0000000000000000000000000000000000000000)' \
'gitweb_run "p=.git;a=tree;h=0000000000000000000000000000000000000000"'
-test_debug 'cat gitweb.log'
test_expect_success \
'.git tag (0000000000000000000000000000000000000000)' \
'gitweb_run "p=.git;a=tag;h=0000000000000000000000000000000000000000"'
-test_debug 'cat gitweb.log'
test_expect_success \
'.git blob (non-existent)' \
'gitweb_run "p=.git;a=blob;f=non-existent"'
-test_debug 'cat gitweb.log'
test_expect_success \
'.git blob_plain (non-existent)' \
'gitweb_run "p=.git;a=blob_plain;f=non-existent"'
-test_debug 'cat gitweb.log'
# ----------------------------------------------------------------------
@@ -161,7 +136,6 @@ test_debug 'cat gitweb.log'
test_expect_success \
'commitdiff(0): root' \
'gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
test_expect_success \
'commitdiff(0): file added' \
@@ -169,21 +143,18 @@ test_expect_success \
git add new_file &&
git commit -a -m "File added." &&
gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
test_expect_success \
'commitdiff(0): mode change' \
'test_chmod +x new_file &&
git commit -a -m "Mode changed." &&
gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
test_expect_success \
'commitdiff(0): file renamed' \
'git mv new_file renamed_file &&
git commit -a -m "File renamed." &&
gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
test_expect_success SYMLINKS \
'commitdiff(0): file to symlink' \
@@ -191,7 +162,6 @@ test_expect_success SYMLINKS \
ln -s file renamed_file &&
git commit -a -m "File to symlink." &&
gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
test_expect_success \
'commitdiff(0): file deleted' \
@@ -199,7 +169,6 @@ test_expect_success \
rm -f renamed_file &&
git commit -a -m "File removed." &&
gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
test_expect_success \
'commitdiff(0): file copied / new file' \
@@ -207,7 +176,6 @@ test_expect_success \
git add file2 &&
git commit -a -m "File copied." &&
gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
test_expect_success \
'commitdiff(0): mode change and modified' \
@@ -215,7 +183,6 @@ test_expect_success \
test_chmod +x file2 &&
git commit -a -m "Mode change and modification." &&
gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
test_expect_success \
'commitdiff(0): renamed and modified' \
@@ -233,7 +200,6 @@ EOF
echo "Propter nomen suum." >> file3 &&
git commit -a -m "File rename and modification." &&
gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
test_expect_success \
'commitdiff(0): renamed, mode change and modified' \
@@ -242,7 +208,6 @@ test_expect_success \
test_chmod +x file2 &&
git commit -a -m "File rename, mode change and modification." &&
gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
# ----------------------------------------------------------------------
# commitdiff testing (taken from t4114-apply-typechange.sh)
@@ -279,42 +244,34 @@ test_expect_success SYMLINKS 'setup typechange commits' '
test_expect_success \
'commitdiff(2): file renamed from foo to foo/baz' \
'gitweb_run "p=.git;a=commitdiff;hp=initial;h=foo-baz-renamed-from-foo"'
-test_debug 'cat gitweb.log'
test_expect_success \
'commitdiff(2): file renamed from foo/baz to foo' \
'gitweb_run "p=.git;a=commitdiff;hp=foo-baz-renamed-from-foo;h=initial"'
-test_debug 'cat gitweb.log'
test_expect_success \
'commitdiff(2): directory becomes file' \
'gitweb_run "p=.git;a=commitdiff;hp=foo-becomes-a-directory;h=initial"'
-test_debug 'cat gitweb.log'
test_expect_success \
'commitdiff(2): file becomes directory' \
'gitweb_run "p=.git;a=commitdiff;hp=initial;h=foo-becomes-a-directory"'
-test_debug 'cat gitweb.log'
test_expect_success \
'commitdiff(2): file becomes symlink' \
'gitweb_run "p=.git;a=commitdiff;hp=initial;h=foo-symlinked-to-bar"'
-test_debug 'cat gitweb.log'
test_expect_success \
'commitdiff(2): symlink becomes file' \
'gitweb_run "p=.git;a=commitdiff;hp=foo-symlinked-to-bar;h=foo-back-to-file"'
-test_debug 'cat gitweb.log'
test_expect_success \
'commitdiff(2): symlink becomes directory' \
'gitweb_run "p=.git;a=commitdiff;hp=foo-symlinked-to-bar;h=foo-becomes-a-directory"'
-test_debug 'cat gitweb.log'
test_expect_success \
'commitdiff(2): directory becomes symlink' \
'gitweb_run "p=.git;a=commitdiff;hp=foo-becomes-a-directory;h=foo-symlinked-to-bar"'
-test_debug 'cat gitweb.log'
# ----------------------------------------------------------------------
# commit, commitdiff: merge, large
@@ -330,12 +287,10 @@ test_expect_success \
test_expect_success \
'commit(0): merge commit' \
'gitweb_run "p=.git;a=commit"'
-test_debug 'cat gitweb.log'
test_expect_success \
'commitdiff(0): merge commit' \
'gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
test_expect_success \
'Prepare large commit' \
@@ -371,12 +326,10 @@ test_expect_success \
test_expect_success \
'commit(1): large commit' \
'gitweb_run "p=.git;a=commit;h=b"'
-test_debug 'cat gitweb.log'
test_expect_success \
'commitdiff(1): large commit' \
'gitweb_run "p=.git;a=commitdiff;h=b"'
-test_debug 'cat gitweb.log'
# ----------------------------------------------------------------------
# tags testing
@@ -394,17 +347,14 @@ test_expect_success \
git tag lightweight/tag-tree HEAD^{tree} &&
git tag lightweight/tag-blob HEAD:file &&
gitweb_run "p=.git;a=tags"'
-test_debug 'cat gitweb.log'
test_expect_success \
'tag: Tag to commit object' \
'gitweb_run "p=.git;a=tag;h=tag-commit"'
-test_debug 'cat gitweb.log'
test_expect_success \
'tag: on lightweight tag (invalid)' \
'gitweb_run "p=.git;a=tag;h=lightweight/tag-commit"'
-test_debug 'cat gitweb.log'
# ----------------------------------------------------------------------
# logs
@@ -412,22 +362,18 @@ test_debug 'cat gitweb.log'
test_expect_success \
'logs: log (implicit HEAD)' \
'gitweb_run "p=.git;a=log"'
-test_debug 'cat gitweb.log'
test_expect_success \
'logs: shortlog (implicit HEAD)' \
'gitweb_run "p=.git;a=shortlog"'
-test_debug 'cat gitweb.log'
test_expect_success \
'logs: history (implicit HEAD, file)' \
'gitweb_run "p=.git;a=history;f=file"'
-test_debug 'cat gitweb.log'
test_expect_success \
'logs: history (implicit HEAD, non-existent file)' \
'gitweb_run "p=.git;a=history;f=non-existent"'
-test_debug 'cat gitweb.log'
test_expect_success \
'logs: history (implicit HEAD, deleted file)' \
@@ -438,55 +384,45 @@ test_expect_success \
git rm deleted_file &&
git commit -m "Delete file" &&
gitweb_run "p=.git;a=history;f=deleted_file"'
-test_debug 'cat gitweb.log'
# ----------------------------------------------------------------------
# path_info links
test_expect_success \
'path_info: project' \
'gitweb_run "" "/.git"'
-test_debug 'cat gitweb.log'
test_expect_success \
'path_info: project/branch' \
'gitweb_run "" "/.git/b"'
-test_debug 'cat gitweb.log'
test_expect_success \
'path_info: project/branch:file' \
'gitweb_run "" "/.git/master:file"'
-test_debug 'cat gitweb.log'
test_expect_success \
'path_info: project/branch:dir/' \
'gitweb_run "" "/.git/master:foo/"'
-test_debug 'cat gitweb.log'
test_expect_success \
'path_info: project/branch:file (non-existent)' \
'gitweb_run "" "/.git/master:non-existent"'
-test_debug 'cat gitweb.log'
test_expect_success \
'path_info: project/branch:dir/ (non-existent)' \
'gitweb_run "" "/.git/master:non-existent/"'
-test_debug 'cat gitweb.log'
test_expect_success \
'path_info: project/branch:/file' \
'gitweb_run "" "/.git/master:/file"'
-test_debug 'cat gitweb.log'
test_expect_success \
'path_info: project/:/file (implicit HEAD)' \
'gitweb_run "" "/.git/:/file"'
-test_debug 'cat gitweb.log'
test_expect_success \
'path_info: project/:/ (implicit HEAD, top tree)' \
'gitweb_run "" "/.git/:/"'
-test_debug 'cat gitweb.log'
# ----------------------------------------------------------------------
@@ -495,17 +431,14 @@ test_debug 'cat gitweb.log'
test_expect_success \
'feeds: OPML' \
'gitweb_run "a=opml"'
-test_debug 'cat gitweb.log'
test_expect_success \
'feed: RSS' \
'gitweb_run "p=.git;a=rss"'
-test_debug 'cat gitweb.log'
test_expect_success \
'feed: Atom' \
'gitweb_run "p=.git;a=atom"'
-test_debug 'cat gitweb.log'
# ----------------------------------------------------------------------
# encoding/decoding
@@ -513,27 +446,28 @@ test_debug 'cat gitweb.log'
test_expect_success \
'encode(commit): utf8' \
'. "$TEST_DIRECTORY"/t3901-utf8.txt &&
+ test_when_finished "GIT_AUTHOR_NAME=\"A U Thor\"" &&
+ test_when_finished "GIT_COMMITTER_NAME=\"C O Mitter\"" &&
echo "UTF-8" >> file &&
git add file &&
git commit -F "$TEST_DIRECTORY"/t3900/1-UTF-8.txt &&
gitweb_run "p=.git;a=commit"'
-test_debug 'cat gitweb.log'
test_expect_success \
'encode(commit): iso-8859-1' \
'. "$TEST_DIRECTORY"/t3901-8859-1.txt &&
+ test_when_finished "GIT_AUTHOR_NAME=\"A U Thor\"" &&
+ test_when_finished "GIT_COMMITTER_NAME=\"C O Mitter\"" &&
echo "ISO-8859-1" >> file &&
git add file &&
git config i18n.commitencoding ISO-8859-1 &&
+ test_when_finished "git config --unset i18n.commitencoding" &&
git commit -F "$TEST_DIRECTORY"/t3900/ISO8859-1.txt &&
- git config --unset i18n.commitencoding &&
gitweb_run "p=.git;a=commit"'
-test_debug 'cat gitweb.log'
test_expect_success \
'encode(log): utf-8 and iso-8859-1' \
'gitweb_run "p=.git;a=log"'
-test_debug 'cat gitweb.log'
# ----------------------------------------------------------------------
# extra options
@@ -541,27 +475,22 @@ test_debug 'cat gitweb.log'
test_expect_success \
'opt: log --no-merges' \
'gitweb_run "p=.git;a=log;opt=--no-merges"'
-test_debug 'cat gitweb.log'
test_expect_success \
'opt: atom --no-merges' \
'gitweb_run "p=.git;a=log;opt=--no-merges"'
-test_debug 'cat gitweb.log'
test_expect_success \
'opt: "file" history --no-merges' \
'gitweb_run "p=.git;a=history;f=file;opt=--no-merges"'
-test_debug 'cat gitweb.log'
test_expect_success \
'opt: log --no-such-option (invalid option)' \
'gitweb_run "p=.git;a=log;opt=--no-such-option"'
-test_debug 'cat gitweb.log'
test_expect_success \
'opt: tree --no-merges (invalid option for action)' \
'gitweb_run "p=.git;a=tree;opt=--no-merges"'
-test_debug 'cat gitweb.log'
# ----------------------------------------------------------------------
# testing config_to_multi / cloneurl
@@ -569,14 +498,12 @@ test_debug 'cat gitweb.log'
test_expect_success \
'URL: no project URLs, no base URL' \
'gitweb_run "p=.git;a=summary"'
-test_debug 'cat gitweb.log'
test_expect_success \
'URL: project URLs via gitweb.url' \
'git config --add gitweb.url git://example.com/git/trash.git &&
git config --add gitweb.url http://example.com/git/trash.git &&
gitweb_run "p=.git;a=summary"'
-test_debug 'cat gitweb.log'
cat >.git/cloneurl <<\EOF
git://example.com/git/trash.git
@@ -586,7 +513,6 @@ EOF
test_expect_success \
'URL: project URLs via cloneurl file' \
'gitweb_run "p=.git;a=summary"'
-test_debug 'cat gitweb.log'
# ----------------------------------------------------------------------
# gitweb config and repo config
@@ -604,12 +530,10 @@ EOF
test_expect_success \
'config override: projects list (implicit)' \
'gitweb_run'
-test_debug 'cat gitweb.log'
test_expect_success \
'config override: tree view, features not overridden in repo config' \
'gitweb_run "p=.git;a=tree"'
-test_debug 'cat gitweb.log'
test_expect_success \
'config override: tree view, features disabled in repo config' \
@@ -617,14 +541,12 @@ test_expect_success \
git config gitweb.snapshot none &&
git config gitweb.avatar gravatar &&
gitweb_run "p=.git;a=tree"'
-test_debug 'cat gitweb.log'
test_expect_success \
'config override: tree view, features enabled in repo config (1)' \
'git config gitweb.blame yes &&
git config gitweb.snapshot "zip,tgz, tbz2" &&
gitweb_run "p=.git;a=tree"'
-test_debug 'cat gitweb.log'
cat >.git/config <<\EOF
# testing noval and alternate separator
@@ -635,7 +557,6 @@ EOF
test_expect_success \
'config override: tree view, features enabled in repo config (2)' \
'gitweb_run "p=.git;a=tree"'
-test_debug 'cat gitweb.log'
# ----------------------------------------------------------------------
# non-ASCII in README.html
@@ -645,7 +566,6 @@ test_expect_success \
'echo "<b>UTF-8 example:</b><br />" > .git/README.html &&
cat "$TEST_DIRECTORY"/t3900/1-UTF-8.txt >> .git/README.html &&
gitweb_run "p=.git;a=summary"'
-test_debug 'cat gitweb.log'
# ----------------------------------------------------------------------
# syntax highlighting
@@ -666,7 +586,6 @@ test_expect_success HIGHLIGHT \
'syntax highlighting (no highlight, unknown syntax)' \
'git config gitweb.highlight yes &&
gitweb_run "p=.git;a=blob;f=file"'
-test_debug 'cat gitweb.log'
test_expect_success HIGHLIGHT \
'syntax highlighting (highlighted, shell script)' \
@@ -675,6 +594,70 @@ test_expect_success HIGHLIGHT \
git add test.sh &&
git commit -m "Add test.sh" &&
gitweb_run "p=.git;a=blob;f=test.sh"'
-test_debug 'cat gitweb.log'
+
+# ----------------------------------------------------------------------
+# forks of projects
+
+cat >>gitweb_config.perl <<\EOF &&
+$feature{'forks'}{'default'} = [1];
+EOF
+
+test_expect_success \
+ 'forks: prepare' \
+ 'git init --bare foo.git &&
+ git --git-dir=foo.git --work-tree=. add file &&
+ git --git-dir=foo.git --work-tree=. commit -m "Initial commit" &&
+ echo "foo" > foo.git/description &&
+ mkdir -p foo &&
+ (cd foo &&
+ git clone --shared --bare ../foo.git foo-forked.git &&
+ echo "fork of foo" > foo-forked.git/description)'
+
+test_expect_success \
+ 'forks: projects list' \
+ 'gitweb_run'
+
+test_expect_success \
+ 'forks: forks action' \
+ 'gitweb_run "p=foo.git;a=forks"'
+
+# ----------------------------------------------------------------------
+# content tags (tag cloud)
+
+cat >>gitweb_config.perl <<-\EOF &&
+# we don't test _setting_ content tags, so any true value is good
+$feature{'ctags'}{'default'} = ['ctags_script.cgi'];
+EOF
+
+test_expect_success \
+ 'ctags: tag cloud in projects list' \
+ 'mkdir .git/ctags &&
+ echo "2" > .git/ctags/foo &&
+ echo "1" > .git/ctags/bar &&
+ gitweb_run'
+
+test_expect_success \
+ 'ctags: search projects by existing tag' \
+ 'gitweb_run "by_tag=foo"'
+
+test_expect_success \
+ 'ctags: search projects by non existent tag' \
+ 'gitweb_run "by_tag=non-existent"'
+
+test_expect_success \
+ 'ctags: malformed tag weights' \
+ 'mkdir -p .git/ctags &&
+ echo "not-a-number" > .git/ctags/nan &&
+ echo "not-a-number-2" > .git/ctags/nan2 &&
+ echo "0.1" >.git/ctags/floating-point &&
+ gitweb_run'
+
+# ----------------------------------------------------------------------
+# categories
+
+test_expect_success \
+ 'categories: projects list, only default category' \
+ 'echo "\$projects_list_group_categories = 1;" >>gitweb_config.perl &&
+ gitweb_run'
test_done
diff --git a/t/t9501-gitweb-standalone-http-status.sh b/t/t9501-gitweb-standalone-http-status.sh
index 18825aff89..26102ee9b0 100755
--- a/t/t9501-gitweb-standalone-http-status.sh
+++ b/t/t9501-gitweb-standalone-http-status.sh
@@ -126,7 +126,6 @@ test_expect_success 'load checking: load too high (default action)' '
grep "Status: 503 Service Unavailable" gitweb.headers &&
grep "503 - The load average on the server is too high" gitweb.body
'
-test_debug 'cat gitweb.log' # just in case
test_debug 'cat gitweb.headers'
# turn off load checking
diff --git a/t/t9502-gitweb-standalone-parse-output.sh b/t/t9502-gitweb-standalone-parse-output.sh
index dd83890001..731e64c3ad 100755
--- a/t/t9502-gitweb-standalone-parse-output.sh
+++ b/t/t9502-gitweb-standalone-parse-output.sh
@@ -112,4 +112,78 @@ test_expect_success 'snapshot: hierarchical branch name (xx/test)' '
'
test_debug 'cat gitweb.headers'
+# ----------------------------------------------------------------------
+# forks of projects
+
+test_expect_success 'forks: setup' '
+ git init --bare foo.git &&
+ echo file > file &&
+ git --git-dir=foo.git --work-tree=. add file &&
+ git --git-dir=foo.git --work-tree=. commit -m "Initial commit" &&
+ echo "foo" > foo.git/description &&
+ git clone --bare foo.git foo.bar.git &&
+ echo "foo.bar" > foo.bar.git/description &&
+ git clone --bare foo.git foo_baz.git &&
+ echo "foo_baz" > foo_baz.git/description &&
+ rm -fr foo &&
+ mkdir -p foo &&
+ (
+ cd foo &&
+ git clone --shared --bare ../foo.git foo-forked.git &&
+ echo "fork of foo" > foo-forked.git/description
+ )
+'
+
+test_expect_success 'forks: not skipped unless "forks" feature enabled' '
+ gitweb_run "a=project_list" &&
+ grep -q ">\\.git<" gitweb.body &&
+ grep -q ">foo\\.git<" gitweb.body &&
+ grep -q ">foo_baz\\.git<" gitweb.body &&
+ grep -q ">foo\\.bar\\.git<" gitweb.body &&
+ grep -q ">foo_baz\\.git<" gitweb.body &&
+ grep -q ">foo/foo-forked\\.git<" gitweb.body &&
+ grep -q ">fork of .*<" gitweb.body
+'
+
+cat >>gitweb_config.perl <<\EOF &&
+$feature{'forks'}{'default'} = [1];
+EOF
+
+test_expect_success 'forks: forks skipped if "forks" feature enabled' '
+ gitweb_run "a=project_list" &&
+ grep -q ">\\.git<" gitweb.body &&
+ grep -q ">foo\\.git<" gitweb.body &&
+ grep -q ">foo_baz\\.git<" gitweb.body &&
+ grep -q ">foo\\.bar\\.git<" gitweb.body &&
+ grep -q ">foo_baz\\.git<" gitweb.body &&
+ grep -v ">foo/foo-forked\\.git<" gitweb.body &&
+ grep -v ">fork of .*<" gitweb.body
+'
+
+test_expect_success 'forks: "forks" action for forked repository' '
+ gitweb_run "p=foo.git;a=forks" &&
+ grep -q ">foo/foo-forked\\.git<" gitweb.body &&
+ grep -q ">fork of foo<" gitweb.body
+'
+
+test_expect_success 'forks: can access forked repository' '
+ gitweb_run "p=foo/foo-forked.git;a=summary" &&
+ grep -q "200 OK" gitweb.headers &&
+ grep -q ">fork of foo<" gitweb.body
+'
+
+test_expect_success 'forks: project_index lists all projects (incl. forks)' '
+ cat >expected <<-\EOF
+ .git
+ foo.bar.git
+ foo.git
+ foo/foo-forked.git
+ foo_baz.git
+ EOF
+ gitweb_run "a=project_index" &&
+ sed -e "s/ .*//" <gitweb.body | sort >actual &&
+ test_cmp expected actual
+'
+
+
test_done
diff --git a/t/t9700-perl-git.sh b/t/t9700-perl-git.sh
index 3787186703..435d896476 100755
--- a/t/t9700-perl-git.sh
+++ b/t/t9700-perl-git.sh
@@ -43,7 +43,11 @@ test_expect_success \
git config --add test.booltrue true &&
git config --add test.boolfalse no &&
git config --add test.boolother other &&
- git config --add test.int 2k
+ git config --add test.int 2k &&
+ git config --add test.path "~/foo" &&
+ git config --add test.pathexpanded "$HOME/foo" &&
+ git config --add test.pathmulti foo &&
+ git config --add test.pathmulti bar
'
# The external test will outputs its own plan
diff --git a/t/t9700/test.pl b/t/t9700/test.pl
index c15ca2d647..3b9b48408a 100755
--- a/t/t9700/test.pl
+++ b/t/t9700/test.pl
@@ -33,6 +33,10 @@ is($r->config_int("test.int"), 2048, "config_int: integer");
is($r->config_int("test.nonexistent"), undef, "config_int: nonexistent");
ok($r->config_bool("test.booltrue"), "config_bool: true");
ok(!$r->config_bool("test.boolfalse"), "config_bool: false");
+is($r->config_path("test.path"), $r->config("test.pathexpanded"),
+ "config_path: ~/foo expansion");
+is_deeply([$r->config_path("test.pathmulti")], ["foo", "bar"],
+ "config_path: multiple values");
our $ansi_green = "\x1b[32m";
is($r->get_color("color.test.slot1", "red"), $ansi_green, "get_color");
# Cannot test $r->get_colorbool("color.foo")) because we do not
@@ -113,6 +117,16 @@ like($last_commit, qr/^[0-9a-fA-F]{40}$/, 'rev-parse returned hash');
my $dir_commit = $r2->command_oneline('log', '-n1', '--pretty=format:%H', '.');
isnt($last_commit, $dir_commit, 'log . does not show last commit');
+# commands outside working tree
+chdir($abs_repo_dir . '/..');
+my $r3 = Git->repository(Directory => $abs_repo_dir);
+my $tmpfile3 = "$abs_repo_dir/file3.tmp";
+open TEMPFILE3, "+>$tmpfile3" or die "Can't open $tmpfile3: $!";
+is($r3->cat_blob($file1hash, \*TEMPFILE3), 15, "cat_blob(outside): size");
+close TEMPFILE3;
+unlink $tmpfile3;
+chdir($abs_repo_dir);
+
printf "1..%d\n", Test::More->builder->current_test;
my $is_passing = eval { Test::More->is_passing };
diff --git a/t/t9800-git-p4.sh b/t/t9800-git-p4.sh
new file mode 100755
index 0000000000..272de3fea3
--- /dev/null
+++ b/t/t9800-git-p4.sh
@@ -0,0 +1,404 @@
+#!/bin/sh
+
+test_description='git-p4 tests'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+ start_p4d
+'
+
+test_expect_success 'add p4 files' '
+ (
+ cd "$cli" &&
+ echo file1 >file1 &&
+ p4 add file1 &&
+ p4 submit -d "file1" &&
+ echo file2 >file2 &&
+ p4 add file2 &&
+ p4 submit -d "file2"
+ )
+'
+
+test_expect_success 'basic git-p4 clone' '
+ "$GITP4" clone --dest="$git" //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ git log --oneline >lines &&
+ test_line_count = 1 lines
+ )
+'
+
+test_expect_success 'git-p4 clone @all' '
+ "$GITP4" clone --dest="$git" //depot@all &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ git log --oneline >lines &&
+ test_line_count = 2 lines
+ )
+'
+
+test_expect_success 'git-p4 sync uninitialized repo' '
+ test_create_repo "$git" &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ test_must_fail "$GITP4" sync
+ )
+'
+
+#
+# Create a git repo by hand. Add a commit so that HEAD is valid.
+# Test imports a new p4 repository into a new git branch.
+#
+test_expect_success 'git-p4 sync new branch' '
+ test_create_repo "$git" &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ test_commit head &&
+ "$GITP4" sync --branch=refs/remotes/p4/depot //depot@all &&
+ git log --oneline p4/depot >lines &&
+ test_line_count = 2 lines
+ )
+'
+
+test_expect_success 'exit when p4 fails to produce marshaled output' '
+ badp4dir="$TRASH_DIRECTORY/badp4dir" &&
+ mkdir "$badp4dir" &&
+ test_when_finished "rm \"$badp4dir/p4\" && rmdir \"$badp4dir\"" &&
+ cat >"$badp4dir"/p4 <<-EOF &&
+ #!$SHELL_PATH
+ exit 1
+ EOF
+ chmod 755 "$badp4dir"/p4 &&
+ PATH="$badp4dir:$PATH" "$GITP4" clone --dest="$git" //depot >errs 2>&1 ; retval=$? &&
+ test $retval -eq 1 &&
+ test_must_fail grep -q Traceback errs
+'
+
+test_expect_success 'add p4 files with wildcards in the names' '
+ (
+ cd "$cli" &&
+ echo file-wild-hash >file-wild#hash &&
+ echo file-wild-star >file-wild\*star &&
+ echo file-wild-at >file-wild@at &&
+ echo file-wild-percent >file-wild%percent &&
+ p4 add -f file-wild* &&
+ p4 submit -d "file wildcards"
+ )
+'
+
+test_expect_success 'wildcard files git-p4 clone' '
+ "$GITP4" clone --dest="$git" //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ test -f file-wild#hash &&
+ test -f file-wild\*star &&
+ test -f file-wild@at &&
+ test -f file-wild%percent
+ )
+'
+
+test_expect_success 'clone bare' '
+ "$GITP4" clone --dest="$git" --bare //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ test ! -d .git &&
+ bare=`git config --get core.bare` &&
+ test "$bare" = true
+ )
+'
+
+p4_add_user() {
+ name=$1 fullname=$2 &&
+ p4 user -f -i <<-EOF &&
+ User: $name
+ Email: $name@localhost
+ FullName: $fullname
+ EOF
+ p4 passwd -P secret $name
+}
+
+p4_grant_admin() {
+ name=$1 &&
+ {
+ p4 protect -o &&
+ echo " admin user $name * //depot/..."
+ } | p4 protect -i
+}
+
+p4_check_commit_author() {
+ file=$1 user=$2 &&
+ p4 changes -m 1 //depot/$file | grep -q $user
+}
+
+make_change_by_user() {
+ file=$1 name=$2 email=$3 &&
+ echo "username: a change by $name" >>"$file" &&
+ git add "$file" &&
+ git commit --author "$name <$email>" -m "a change by $name"
+}
+
+# Test username support, submitting as user 'alice'
+test_expect_success 'preserve users' '
+ p4_add_user alice Alice &&
+ p4_add_user bob Bob &&
+ p4_grant_admin alice &&
+ "$GITP4" clone --dest="$git" //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ echo "username: a change by alice" >>file1 &&
+ echo "username: a change by bob" >>file2 &&
+ git commit --author "Alice <alice@localhost>" -m "a change by alice" file1 &&
+ git commit --author "Bob <bob@localhost>" -m "a change by bob" file2 &&
+ git config git-p4.skipSubmitEditCheck true &&
+ P4EDITOR=touch P4USER=alice P4PASSWD=secret "$GITP4" commit --preserve-user &&
+ p4_check_commit_author file1 alice &&
+ p4_check_commit_author file2 bob
+ )
+'
+
+# Test username support, submitting as bob, who lacks admin rights. Should
+# not submit change to p4 (git diff should show deltas).
+test_expect_success 'refuse to preserve users without perms' '
+ "$GITP4" clone --dest="$git" //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEditCheck true &&
+ echo "username-noperms: a change by alice" >>file1 &&
+ git commit --author "Alice <alice@localhost>" -m "perms: a change by alice" file1 &&
+ P4EDITOR=touch P4USER=bob P4PASSWD=secret test_must_fail "$GITP4" commit --preserve-user &&
+ test_must_fail git diff --exit-code HEAD..p4/master
+ )
+'
+
+# What happens with unknown author? Without allowMissingP4Users it should fail.
+test_expect_success 'preserve user where author is unknown to p4' '
+ "$GITP4" clone --dest="$git" //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEditCheck true &&
+ echo "username-bob: a change by bob" >>file1 &&
+ git commit --author "Bob <bob@localhost>" -m "preserve: a change by bob" file1 &&
+ echo "username-unknown: a change by charlie" >>file1 &&
+ git commit --author "Charlie <charlie@localhost>" -m "preserve: a change by charlie" file1 &&
+ P4EDITOR=touch P4USER=alice P4PASSWD=secret test_must_fail "$GITP4" commit --preserve-user &&
+ test_must_fail git diff --exit-code HEAD..p4/master &&
+
+ echo "$0: repeat with allowMissingP4Users enabled" &&
+ git config git-p4.allowMissingP4Users true &&
+ git config git-p4.preserveUser true &&
+ P4EDITOR=touch P4USER=alice P4PASSWD=secret "$GITP4" commit &&
+ git diff --exit-code HEAD..p4/master &&
+ p4_check_commit_author file1 alice
+ )
+'
+
+# If we're *not* using --preserve-user, git-p4 should warn if we're submitting
+# changes that are not all ours.
+# Test: user in p4 and user unknown to p4.
+# Test: warning disabled and user is the same.
+test_expect_success 'not preserving user with mixed authorship' '
+ "$GITP4" clone --dest="$git" //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEditCheck true &&
+ p4_add_user derek Derek &&
+
+ make_change_by_user usernamefile3 Derek derek@localhost &&
+ P4EDITOR=cat P4USER=alice P4PASSWD=secret "$GITP4" commit |\
+ grep "git author derek@localhost does not match" &&
+
+ make_change_by_user usernamefile3 Charlie charlie@localhost &&
+ P4EDITOR=cat P4USER=alice P4PASSWD=secret "$GITP4" commit |\
+ grep "git author charlie@localhost does not match" &&
+
+ make_change_by_user usernamefile3 alice alice@localhost &&
+ P4EDITOR=cat P4USER=alice P4PASSWD=secret "$GITP4" |\
+ test_must_fail grep "git author.*does not match" &&
+
+ git config git-p4.skipUserNameCheck true &&
+ make_change_by_user usernamefile3 Charlie charlie@localhost &&
+ P4EDITOR=cat P4USER=alice P4PASSWD=secret "$GITP4" commit |\
+ test_must_fail grep "git author.*does not match" &&
+
+ p4_check_commit_author usernamefile3 alice
+ )
+'
+
+marshal_dump() {
+ what=$1
+ "$PYTHON_PATH" -c 'import marshal, sys; d = marshal.load(sys.stdin); print d["'$what'"]'
+}
+
+# Sleep a bit so that the top-most p4 change did not happen "now". Then
+# import the repo and make sure that the initial import has the same time
+# as the top-most change.
+test_expect_success 'initial import time from top change time' '
+ p4change=$(p4 -G changes -m 1 //depot/... | marshal_dump change) &&
+ p4time=$(p4 -G changes -m 1 //depot/... | marshal_dump time) &&
+ sleep 3 &&
+ "$GITP4" clone --dest="$git" //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ gittime=$(git show -s --raw --pretty=format:%at HEAD) &&
+ echo $p4time $gittime &&
+ test $p4time = $gittime
+ )
+'
+
+# Rename a file and confirm that rename is not detected in P4.
+# Rename the new file again with detectRenames option enabled and confirm that
+# this is detected in P4.
+# Rename the new file again adding an extra line, configure a big threshold in
+# detectRenames and confirm that rename is not detected in P4.
+# Repeat, this time with a smaller threshold and confirm that the rename is
+# detected in P4.
+test_expect_success 'detect renames' '
+ "$GITP4" clone --dest="$git" //depot@all &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEditCheck true &&
+
+ git mv file1 file4 &&
+ git commit -a -m "Rename file1 to file4" &&
+ git diff-tree -r -M HEAD &&
+ "$GITP4" submit &&
+ p4 filelog //depot/file4 &&
+ p4 filelog //depot/file4 | test_must_fail grep -q "branch from" &&
+
+ git mv file4 file5 &&
+ git commit -a -m "Rename file4 to file5" &&
+ git diff-tree -r -M HEAD &&
+ git config git-p4.detectRenames true &&
+ "$GITP4" submit &&
+ p4 filelog //depot/file5 &&
+ p4 filelog //depot/file5 | grep -q "branch from //depot/file4" &&
+
+ git mv file5 file6 &&
+ echo update >>file6 &&
+ git add file6 &&
+ git commit -a -m "Rename file5 to file6 with changes" &&
+ git diff-tree -r -M HEAD &&
+ level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") &&
+ test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 &&
+ git config git-p4.detectRenames $(($level + 2)) &&
+ "$GITP4" submit &&
+ p4 filelog //depot/file6 &&
+ p4 filelog //depot/file6 | test_must_fail grep -q "branch from" &&
+
+ git mv file6 file7 &&
+ echo update >>file7 &&
+ git add file7 &&
+ git commit -a -m "Rename file6 to file7 with changes" &&
+ git diff-tree -r -M HEAD &&
+ level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") &&
+ test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 &&
+ git config git-p4.detectRenames $(($level - 2)) &&
+ "$GITP4" submit &&
+ p4 filelog //depot/file7 &&
+ p4 filelog //depot/file7 | grep -q "branch from //depot/file6"
+ )
+'
+
+# Copy a file and confirm that copy is not detected in P4.
+# Copy a file with detectCopies option enabled and confirm that copy is not
+# detected in P4.
+# Modify and copy a file with detectCopies option enabled and confirm that copy
+# is detected in P4.
+# Copy a file with detectCopies and detectCopiesHarder options enabled and
+# confirm that copy is detected in P4.
+# Modify and copy a file, configure a bigger threshold in detectCopies and
+# confirm that copy is not detected in P4.
+# Modify and copy a file, configure a smaller threshold in detectCopies and
+# confirm that copy is detected in P4.
+test_expect_success 'detect copies' '
+ "$GITP4" clone --dest="$git" //depot@all &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEditCheck true &&
+
+ cp file2 file8 &&
+ git add file8 &&
+ git commit -a -m "Copy file2 to file8" &&
+ git diff-tree -r -C HEAD &&
+ "$GITP4" submit &&
+ p4 filelog //depot/file8 &&
+ p4 filelog //depot/file8 | test_must_fail grep -q "branch from" &&
+
+ cp file2 file9 &&
+ git add file9 &&
+ git commit -a -m "Copy file2 to file9" &&
+ git diff-tree -r -C HEAD &&
+ git config git-p4.detectCopies true &&
+ "$GITP4" submit &&
+ p4 filelog //depot/file9 &&
+ p4 filelog //depot/file9 | test_must_fail grep -q "branch from" &&
+
+ echo "file2" >>file2 &&
+ cp file2 file10 &&
+ git add file2 file10 &&
+ git commit -a -m "Modify and copy file2 to file10" &&
+ git diff-tree -r -C HEAD &&
+ "$GITP4" submit &&
+ p4 filelog //depot/file10 &&
+ p4 filelog //depot/file10 | grep -q "branch from //depot/file" &&
+
+ cp file2 file11 &&
+ git add file11 &&
+ git commit -a -m "Copy file2 to file11" &&
+ git diff-tree -r -C --find-copies-harder HEAD &&
+ src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
+ test "$src" = file10 &&
+ git config git-p4.detectCopiesHarder true &&
+ "$GITP4" submit &&
+ p4 filelog //depot/file11 &&
+ p4 filelog //depot/file11 | grep -q "branch from //depot/file" &&
+
+ cp file2 file12 &&
+ echo "some text" >>file12 &&
+ git add file12 &&
+ git commit -a -m "Copy file2 to file12 with changes" &&
+ git diff-tree -r -C --find-copies-harder HEAD &&
+ level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") &&
+ test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 &&
+ src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
+ test "$src" = file10 &&
+ git config git-p4.detectCopies $(($level + 2)) &&
+ "$GITP4" submit &&
+ p4 filelog //depot/file12 &&
+ p4 filelog //depot/file12 | test_must_fail grep -q "branch from" &&
+
+ cp file2 file13 &&
+ echo "different text" >>file13 &&
+ git add file13 &&
+ git commit -a -m "Copy file2 to file13 with changes" &&
+ git diff-tree -r -C --find-copies-harder HEAD &&
+ level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") &&
+ test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 &&
+ src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
+ test "$src" = file10 &&
+ git config git-p4.detectCopies $(($level - 2)) &&
+ "$GITP4" submit &&
+ p4 filelog //depot/file13 &&
+ p4 filelog //depot/file13 | grep -q "branch from //depot/file"
+ )
+'
+
+test_expect_success 'kill p4d' '
+ kill_p4d
+'
+
+test_done
diff --git a/t/t9801-git-p4-branch.sh b/t/t9801-git-p4-branch.sh
new file mode 100755
index 0000000000..a25f18d36a
--- /dev/null
+++ b/t/t9801-git-p4-branch.sh
@@ -0,0 +1,233 @@
+#!/bin/sh
+
+test_description='git-p4 p4 branching tests'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+ start_p4d
+'
+
+#
+# 1: //depot/main/f1
+# 2: //depot/main/f2
+# 3: integrate //depot/main/... -> //depot/branch1/...
+# 4: //depot/main/f4
+# 5: //depot/branch1/f5
+# .: named branch branch2
+# 6: integrate -b branch2
+# 7: //depot/branch2/f7
+# 8: //depot/main/f8
+#
+test_expect_success 'basic p4 branches' '
+ (
+ cd "$cli" &&
+ mkdir -p main &&
+
+ echo f1 >main/f1 &&
+ p4 add main/f1 &&
+ p4 submit -d "main/f1" &&
+
+ echo f2 >main/f2 &&
+ p4 add main/f2 &&
+ p4 submit -d "main/f2" &&
+
+ p4 integrate //depot/main/... //depot/branch1/... &&
+ p4 submit -d "integrate main to branch1" &&
+
+ echo f4 >main/f4 &&
+ p4 add main/f4 &&
+ p4 submit -d "main/f4" &&
+
+ echo f5 >branch1/f5 &&
+ p4 add branch1/f5 &&
+ p4 submit -d "branch1/f5" &&
+
+ p4 branch -i <<-EOF &&
+ Branch: branch2
+ View: //depot/main/... //depot/branch2/...
+ EOF
+
+ p4 integrate -b branch2 &&
+ p4 submit -d "integrate main to branch2" &&
+
+ echo f7 >branch2/f7 &&
+ p4 add branch2/f7 &&
+ p4 submit -d "branch2/f7" &&
+
+ echo f8 >main/f8 &&
+ p4 add main/f8 &&
+ p4 submit -d "main/f8"
+ )
+'
+
+test_expect_success 'import main, no branch detection' '
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --dest="$git" //depot/main@all &&
+ (
+ cd "$git" &&
+ git log --oneline --graph --decorate --all &&
+ git rev-list master >wc &&
+ test_line_count = 4 wc
+ )
+'
+
+test_expect_success 'import branch1, no branch detection' '
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --dest="$git" //depot/branch1@all &&
+ (
+ cd "$git" &&
+ git log --oneline --graph --decorate --all &&
+ git rev-list master >wc &&
+ test_line_count = 2 wc
+ )
+'
+
+test_expect_success 'import branch2, no branch detection' '
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --dest="$git" //depot/branch2@all &&
+ (
+ cd "$git" &&
+ git log --oneline --graph --decorate --all &&
+ git rev-list master >wc &&
+ test_line_count = 2 wc
+ )
+'
+
+test_expect_success 'import depot, no branch detection' '
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --dest="$git" //depot@all &&
+ (
+ cd "$git" &&
+ git log --oneline --graph --decorate --all &&
+ git rev-list master >wc &&
+ test_line_count = 8 wc
+ )
+'
+
+test_expect_success 'import depot, branch detection' '
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --dest="$git" --detect-branches //depot@all &&
+ (
+ cd "$git" &&
+
+ git log --oneline --graph --decorate --all &&
+
+ # 4 main commits
+ git rev-list master >wc &&
+ test_line_count = 4 wc &&
+
+ # 3 main, 1 integrate, 1 on branch2
+ git rev-list p4/depot/branch2 >wc &&
+ test_line_count = 5 wc &&
+
+ # no branch1, since no p4 branch created for it
+ test_must_fail git show-ref p4/depot/branch1
+ )
+'
+
+test_expect_success 'import depot, branch detection, branchList branch definition' '
+ test_when_finished cleanup_git &&
+ test_create_repo "$git" &&
+ (
+ cd "$git" &&
+ git config git-p4.branchList main:branch1 &&
+ "$GITP4" clone --dest=. --detect-branches //depot@all &&
+
+ git log --oneline --graph --decorate --all &&
+
+ # 4 main commits
+ git rev-list master >wc &&
+ test_line_count = 4 wc &&
+
+ # 3 main, 1 integrate, 1 on branch2
+ git rev-list p4/depot/branch2 >wc &&
+ test_line_count = 5 wc &&
+
+ # 2 main, 1 integrate, 1 on branch1
+ git rev-list p4/depot/branch1 >wc &&
+ test_line_count = 4 wc
+ )
+'
+
+test_expect_success 'restart p4d' '
+ kill_p4d &&
+ start_p4d
+'
+
+#
+# 1: //depot/branch1/file1
+# //depot/branch1/file2
+# 2: integrate //depot/branch1/... -> //depot/branch2/...
+# 3: //depot/branch1/file3
+# 4: //depot/branch1/file2 (edit)
+# 5: integrate //depot/branch1/... -> //depot/branch3/...
+#
+## Create a simple branch structure in P4 depot.
+test_expect_success 'add simple p4 branches' '
+ (
+ cd "$cli" &&
+ mkdir branch1 &&
+ cd branch1 &&
+ echo file1 >file1 &&
+ echo file2 >file2 &&
+ p4 add file1 file2 &&
+ p4 submit -d "branch1" &&
+ p4 integrate //depot/branch1/... //depot/branch2/... &&
+ p4 submit -d "branch2" &&
+ echo file3 >file3 &&
+ p4 add file3 &&
+ p4 submit -d "add file3 in branch1" &&
+ p4 open file2 &&
+ echo update >>file2 &&
+ p4 submit -d "update file2 in branch1" &&
+ p4 integrate //depot/branch1/... //depot/branch3/... &&
+ p4 submit -d "branch3"
+ )
+'
+
+# Configure branches through git-config and clone them.
+# All files are tested to make sure branches were cloned correctly.
+# Finally, make an update to branch1 on P4 side to check if it is imported
+# correctly by git-p4.
+test_expect_success 'git-p4 clone simple branches' '
+ test_when_finished cleanup_git &&
+ test_create_repo "$git" &&
+ (
+ cd "$git" &&
+ git config git-p4.branchList branch1:branch2 &&
+ git config --add git-p4.branchList branch1:branch3 &&
+ "$GITP4" clone --dest=. --detect-branches //depot@all &&
+ git log --all --graph --decorate --stat &&
+ git reset --hard p4/depot/branch1 &&
+ test -f file1 &&
+ test -f file2 &&
+ test -f file3 &&
+ grep -q update file2 &&
+ git reset --hard p4/depot/branch2 &&
+ test -f file1 &&
+ test -f file2 &&
+ test ! -f file3 &&
+ test_must_fail grep -q update file2 &&
+ git reset --hard p4/depot/branch3 &&
+ test -f file1 &&
+ test -f file2 &&
+ test -f file3 &&
+ grep -q update file2 &&
+ cd "$cli" &&
+ cd branch1 &&
+ p4 edit file2 &&
+ echo file2_ >>file2 &&
+ p4 submit -d "update file2 in branch3" &&
+ cd "$git" &&
+ git reset --hard p4/depot/branch1 &&
+ "$GITP4" rebase &&
+ grep -q file2_ file2
+ )
+'
+
+test_expect_success 'kill p4d' '
+ kill_p4d
+'
+
+test_done
diff --git a/t/t9802-git-p4-filetype.sh b/t/t9802-git-p4-filetype.sh
new file mode 100755
index 0000000000..3b358ef8d8
--- /dev/null
+++ b/t/t9802-git-p4-filetype.sh
@@ -0,0 +1,108 @@
+#!/bin/sh
+
+test_description='git-p4 p4 filetype tests'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+ start_p4d
+'
+
+test_expect_success 'utf-16 file create' '
+ (
+ cd "$cli" &&
+
+ # p4 saves this verbatim
+ printf "three\nline\ntext\n" >f-ascii &&
+ p4 add -t text f-ascii &&
+
+ # p4 adds \377\376 header
+ cp f-ascii f-ascii-as-utf16 &&
+ p4 add -t utf16 f-ascii-as-utf16 &&
+
+ # p4 saves this exactly as iconv produced it
+ printf "three\nline\ntext\n" | iconv -f ascii -t utf-16 >f-utf16 &&
+ p4 add -t utf16 f-utf16 &&
+
+ # this also is unchanged
+ cp f-utf16 f-utf16-as-text &&
+ p4 add -t text f-utf16-as-text &&
+
+ p4 submit -d "f files" &&
+
+ # force update of client files
+ p4 sync -f
+ )
+'
+
+test_expect_success 'utf-16 file test' '
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --dest="$git" //depot@all &&
+ (
+ cd "$git" &&
+
+ test_cmp "$cli/f-ascii" f-ascii &&
+ test_cmp "$cli/f-ascii-as-utf16" f-ascii-as-utf16 &&
+ test_cmp "$cli/f-utf16" f-utf16 &&
+ test_cmp "$cli/f-utf16-as-text" f-utf16-as-text
+ )
+'
+
+test_expect_success 'keyword file create' '
+ (
+ cd "$cli" &&
+
+ printf "id\n\$Id\$\n\$Author\$\ntext\n" >k-text-k &&
+ p4 add -t text+k k-text-k &&
+
+ cp k-text-k k-text-ko &&
+ p4 add -t text+ko k-text-ko &&
+
+ cat k-text-k | iconv -f ascii -t utf-16 >k-utf16-k &&
+ p4 add -t utf16+k k-utf16-k &&
+
+ cp k-utf16-k k-utf16-ko &&
+ p4 add -t utf16+ko k-utf16-ko &&
+
+ p4 submit -d "k files" &&
+ p4 sync -f
+ )
+'
+
+build_smush() {
+ cat >k_smush.py <<-\EOF &&
+ import re, sys
+ sys.stdout.write(re.sub(r'(?i)\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$', r'$\1$', sys.stdin.read()))
+ EOF
+ cat >ko_smush.py <<-\EOF
+ import re, sys
+ sys.stdout.write(re.sub(r'(?i)\$(Id|Header):[^$]*\$', r'$\1$', sys.stdin.read()))
+ EOF
+}
+
+test_expect_success 'keyword file test' '
+ build_smush &&
+ test_when_finished rm -f k_smush.py ko_smush.py &&
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --dest="$git" //depot@all &&
+ (
+ cd "$git" &&
+
+ # text, ensure unexpanded
+ "$PYTHON_PATH" "$TRASH_DIRECTORY/k_smush.py" <"$cli/k-text-k" >cli-k-text-k-smush &&
+ test_cmp cli-k-text-k-smush k-text-k &&
+ "$PYTHON_PATH" "$TRASH_DIRECTORY/ko_smush.py" <"$cli/k-text-ko" >cli-k-text-ko-smush &&
+ test_cmp cli-k-text-ko-smush k-text-ko &&
+
+ # utf16, even though p4 expands keywords, git-p4 does not
+ # try to undo that
+ test_cmp "$cli/k-utf16-k" k-utf16-k &&
+ test_cmp "$cli/k-utf16-ko" k-utf16-ko
+ )
+'
+
+test_expect_success 'kill p4d' '
+ kill_p4d
+'
+
+test_done
diff --git a/t/t9803-git-shell-metachars.sh b/t/t9803-git-shell-metachars.sh
new file mode 100755
index 0000000000..db04375a13
--- /dev/null
+++ b/t/t9803-git-shell-metachars.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+test_description='git-p4 transparency to shell metachars in filenames'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+ start_p4d
+'
+
+test_expect_success 'init depot' '
+ (
+ cd "$cli" &&
+ echo file1 >file1 &&
+ p4 add file1 &&
+ p4 submit -d "file1"
+ )
+'
+
+test_expect_success 'shell metachars in filenames' '
+ "$GITP4" clone --dest="$git" //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEditCheck true &&
+ echo f1 >foo\$bar &&
+ git add foo\$bar &&
+ echo f2 >"file with spaces" &&
+ git add "file with spaces" &&
+ git commit -m "add files" &&
+ P4EDITOR=touch "$GITP4" submit
+ ) &&
+ (
+ cd "$cli" &&
+ p4 sync ... &&
+ test -e "file with spaces" &&
+ test -e "foo\$bar"
+ )
+'
+
+test_expect_success 'deleting with shell metachars' '
+ "$GITP4" clone --dest="$git" //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEditCheck true &&
+ git rm foo\$bar &&
+ git rm file\ with\ spaces &&
+ git commit -m "remove files" &&
+ P4EDITOR=touch "$GITP4" submit
+ ) &&
+ (
+ cd "$cli" &&
+ p4 sync ... &&
+ test ! -e "file with spaces" &&
+ test ! -e foo\$bar
+ )
+'
+
+test_expect_success 'kill p4d' '
+ kill_p4d
+'
+
+test_done
diff --git a/t/t9901-git-web--browse.sh b/t/t9901-git-web--browse.sh
new file mode 100755
index 0000000000..b0a6bad8dd
--- /dev/null
+++ b/t/t9901-git-web--browse.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+#
+
+test_description='git web--browse basic tests
+
+This test checks that git web--browse can handle various valid URLs.'
+
+. ./test-lib.sh
+
+test_web_browse () {
+ # browser=$1 url=$2
+ git web--browse --browser="$1" "$2" >actual &&
+ tr -d '\015' <actual >text &&
+ test_cmp expect text
+}
+
+test_expect_success \
+ 'URL with an ampersand in it' '
+ echo http://example.com/foo\&bar >expect &&
+ git config browser.custom.cmd echo &&
+ test_web_browse custom http://example.com/foo\&bar
+'
+
+test_expect_success \
+ 'URL with a semi-colon in it' '
+ echo http://example.com/foo\;bar >expect &&
+ git config browser.custom.cmd echo &&
+ test_web_browse custom http://example.com/foo\;bar
+'
+
+test_expect_success \
+ 'URL with a hash in it' '
+ echo http://example.com/foo#bar >expect &&
+ git config browser.custom.cmd echo &&
+ test_web_browse custom http://example.com/foo#bar
+'
+
+test_expect_success \
+ 'browser paths are properly quoted' '
+ echo fake: http://example.com/foo >expect &&
+ cat >"fake browser" <<-\EOF &&
+ #!/bin/sh
+ echo fake: "$@"
+ EOF
+ chmod +x "fake browser" &&
+ git config browser.w3m.path "`pwd`/fake browser" &&
+ test_web_browse w3m http://example.com/foo
+'
+
+test_expect_success \
+ 'browser command allows arbitrary shell code' '
+ echo "arg: http://example.com/foo" >expect &&
+ git config browser.custom.cmd "
+ f() {
+ for i in \"\$@\"; do
+ echo arg: \$i
+ done
+ }
+ f" &&
+ test_web_browse custom http://example.com/foo
+'
+
+test_done
diff --git a/t/test4012.png b/t/test-binary-1.png
index 7b181d15ce..7b181d15ce 100644
--- a/t/test4012.png
+++ b/t/test-binary-1.png
Binary files differ
diff --git a/t/test9200b.png b/t/test-binary-2.png
index ac22ccbd3e..ac22ccbd3e 100644
--- a/t/test9200b.png
+++ b/t/test-binary-2.png
Binary files differ
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 0fdc541a7c..bdd9513b84 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -43,36 +43,25 @@ TERM=dumb
export LANG LC_ALL PAGER TERM TZ
EDITOR=:
unset VISUAL
-unset GIT_EDITOR
-unset AUTHOR_DATE
-unset AUTHOR_EMAIL
-unset AUTHOR_NAME
-unset COMMIT_AUTHOR_EMAIL
-unset COMMIT_AUTHOR_NAME
unset EMAIL
-unset GIT_ALTERNATE_OBJECT_DIRECTORIES
-unset GIT_AUTHOR_DATE
+unset $(perl -e '
+ my @env = keys %ENV;
+ my $ok = join("|", qw(
+ TRACE
+ DEBUG
+ USE_LOOKUP
+ TEST
+ .*_TEST
+ PROVE
+ VALGRIND
+ ));
+ my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
+ print join("\n", @vars);
+')
GIT_AUTHOR_EMAIL=author@example.com
GIT_AUTHOR_NAME='A U Thor'
-unset GIT_COMMITTER_DATE
GIT_COMMITTER_EMAIL=committer@example.com
GIT_COMMITTER_NAME='C O Mitter'
-unset GIT_DIFF_OPTS
-unset GIT_DIR
-unset GIT_WORK_TREE
-unset GIT_EXTERNAL_DIFF
-unset GIT_INDEX_FILE
-unset GIT_OBJECT_DIRECTORY
-unset GIT_CEILING_DIRECTORIES
-unset SHA1_FILE_DIRECTORIES
-unset SHA1_FILE_DIRECTORY
-unset GIT_NOTES_REF
-unset GIT_NOTES_DISPLAY_REF
-unset GIT_NOTES_REWRITE_REF
-unset GIT_NOTES_REWRITE_MODE
-unset GIT_REFLOG_ACTION
-unset GIT_CHERRY_PICK_HELP
-unset GIT_QUIET
GIT_MERGE_VERBOSITY=5
export GIT_MERGE_VERBOSITY
export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
@@ -100,6 +89,13 @@ esac
_x05='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
_x40="$_x05$_x05$_x05$_x05$_x05$_x05$_x05$_x05"
+# Zero SHA-1
+_z40=0000000000000000000000000000000000000000
+
+# Line feed
+LF='
+'
+
# Each test should start with something like this, after copyright notices:
#
# test_description='Description of this test...
@@ -365,6 +361,24 @@ test_chmod () {
git update-index --add "--chmod=$@"
}
+# Unset a configuration variable, but don't fail if it doesn't exist.
+test_unconfig () {
+ git config --unset-all "$@"
+ config_status=$?
+ case "$config_status" in
+ 5) # ok, nothing to unset
+ config_status=0
+ ;;
+ esac
+ return $config_status
+}
+
+# Set git config, automatically unsetting it after the test is over.
+test_config () {
+ test_when_finished "test_unconfig '$1'" &&
+ git config "$@"
+}
+
# Use test_set_prereq to tell that a particular prerequisite is available.
# The prerequisite can later be checked for in two ways:
#
@@ -452,15 +466,26 @@ test_debug () {
test "$debug" = "" || eval "$1"
}
+test_eval_ () {
+ # This is a separate function because some tests use
+ # "return" to end a test_expect_success block early.
+ eval >&3 2>&4 "$*"
+}
+
test_run_ () {
test_cleanup=:
- eval >&3 2>&4 "$1"
+ expecting_failure=$2
+ test_eval_ "$1"
eval_ret=$?
- eval >&3 2>&4 "$test_cleanup"
+
+ if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure"
+ then
+ test_eval_ "$test_cleanup"
+ fi
if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then
echo ""
fi
- return 0
+ return "$eval_ret"
}
test_skip () {
@@ -505,8 +530,7 @@ test_expect_failure () {
if ! test_skip "$@"
then
say >&3 "checking known breakage: $2"
- test_run_ "$2"
- if [ "$?" = 0 -a "$eval_ret" = 0 ]
+ if test_run_ "$2" expecting_failure
then
test_known_broken_ok_ "$1"
else
@@ -524,8 +548,7 @@ test_expect_success () {
if ! test_skip "$@"
then
say >&3 "expecting success: $2"
- test_run_ "$2"
- if [ "$?" = 0 -a "$eval_ret" = 0 ]
+ if test_run_ "$2"
then
test_ok_ "$1"
else
@@ -586,7 +609,7 @@ test_external () {
test_external_without_stderr () {
# The temporary file has no (and must have no) security
# implications.
- tmp="$TMPDIR"; if [ -z "$tmp" ]; then tmp=/tmp; fi
+ tmp=${TMPDIR:-/tmp}
stderr="$tmp/git-external-stderr.$$.tmp"
test_external "$@" 4> "$stderr"
[ -f "$stderr" ] || error "Internal error: $stderr disappeared."
@@ -739,12 +762,11 @@ test_expect_code () {
exit_code=$?
if test $exit_code = $want_code
then
- echo >&2 "test_expect_code: command exited with $exit_code: $*"
return 0
- else
- echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*"
- return 1
fi
+
+ echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*"
+ return 1
}
# test_cmp is a helper function to compare actual and expected output.
@@ -783,6 +805,9 @@ test_cmp() {
#
# except that the greeting and config --unset must both succeed for
# the test to pass.
+#
+# Note that under --immediate mode, no clean-up is done to help diagnose
+# what went wrong.
test_when_finished () {
test_cleanup="{ $*
@@ -812,12 +837,14 @@ test_done () {
mkdir -p "$test_results_dir"
test_results_path="$test_results_dir/${0%.sh}-$$.counts"
- echo "total $test_count" >> $test_results_path
- echo "success $test_success" >> $test_results_path
- echo "fixed $test_fixed" >> $test_results_path
- echo "broken $test_broken" >> $test_results_path
- echo "failed $test_failure" >> $test_results_path
- echo "" >> $test_results_path
+ cat >>"$test_results_path" <<-EOF
+ total $test_count
+ success $test_success
+ fixed $test_fixed
+ broken $test_broken
+ failed $test_failure
+
+ EOF
fi
if test "$test_fixed" != 0
@@ -891,8 +918,13 @@ then
}
make_valgrind_symlink () {
- # handle only executables
- test -x "$1" || return
+ # handle only executables, unless they are shell libraries that
+ # need to be in the exec-path. We will just use "#!" as a
+ # guess for a shell-script, since we have no idea what the user
+ # may have configured as the shell path.
+ test -x "$1" ||
+ test "#!" = "$(head -c 2 <"$1")" ||
+ return;
base=$(basename "$1")
symlink_target=$GIT_BUILD_DIR/$base
@@ -918,6 +950,8 @@ then
do
make_valgrind_symlink $file
done
+ # special-case the mergetools loadables
+ make_symlink "$GIT_BUILD_DIR"/mergetools "$GIT_VALGRIND/bin/mergetools"
OLDIFS=$IFS
IFS=:
for path in $PATH
@@ -954,8 +988,8 @@ fi
GIT_TEMPLATE_DIR="$GIT_BUILD_DIR"/templates/blt
unset GIT_CONFIG
GIT_CONFIG_NOSYSTEM=1
-GIT_CONFIG_NOGLOBAL=1
-export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOBAL
+GIT_ATTR_NOSYSTEM=1
+export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM
. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS
@@ -1004,14 +1038,14 @@ rm -fr "$test" || {
exit 1
}
+HOME="$TRASH_DIRECTORY"
+export HOME
+
test_create_repo "$test"
# Use -P to resolve symlinks in our working directory so that the cwd
# in subprocesses like git equals our $PWD (for pathname comparisons).
cd -P "$test" || exit 1
-HOME=$(pwd)
-export HOME
-
this_test=${0##*/}
this_test=${this_test%%-*}
for skp in $GIT_SKIP_TESTS
@@ -1078,6 +1112,42 @@ esac
test -z "$NO_PERL" && test_set_prereq PERL
test -z "$NO_PYTHON" && test_set_prereq PYTHON
+test -n "$USE_LIBPCRE" && test_set_prereq LIBPCRE
+
+# Can we rely on git's output in the C locale?
+if test -n "$GETTEXT_POISON"
+then
+ GIT_GETTEXT_POISON=YesPlease
+ export GIT_GETTEXT_POISON
+else
+ test_set_prereq C_LOCALE_OUTPUT
+fi
+
+# Use this instead of test_cmp to compare files that contain expected and
+# actual output from git commands that can be translated. When running
+# under GETTEXT_POISON this pretends that the command produced expected
+# results.
+test_i18ncmp () {
+ test -n "$GETTEXT_POISON" || test_cmp "$@"
+}
+
+# Use this instead of "grep expected-string actual" to see if the
+# output from a git command that can be translated either contains an
+# expected string, or does not contain an unwanted one. When running
+# under GETTEXT_POISON this pretends that the command produced expected
+# results.
+test_i18ngrep () {
+ if test -n "$GETTEXT_POISON"
+ then
+ : # pretend success
+ elif test "x!" = "x$1"
+ then
+ shift
+ ! grep "$@"
+ else
+ grep "$@"
+ fi
+}
# test whether the filesystem supports symbolic links
ln -s x y 2>/dev/null && test -h y 2>/dev/null && test_set_prereq SYMLINKS
diff --git a/t/test9200a.png b/t/test9200a.png
deleted file mode 100644
index 7b181d15ce..0000000000
--- a/t/test9200a.png
+++ /dev/null
Binary files differ
diff --git a/t/valgrind/default.supp b/t/valgrind/default.supp
index 9e013fa3b2..0a6724fcc4 100644
--- a/t/valgrind/default.supp
+++ b/t/valgrind/default.supp
@@ -43,3 +43,9 @@
fun:write_buffer
fun:write_loose_object
}
+
+{
+ ignore-sse-strlen-invalid-read-size
+ Memcheck:Addr4
+ fun:copy_ref
+}