summaryrefslogtreecommitdiff
path: root/t
diff options
context:
space:
mode:
Diffstat (limited to 't')
-rw-r--r--t/README47
-rw-r--r--t/helper/test-advise.c2
-rw-r--r--t/helper/test-bitmap.c10
-rw-r--r--t/helper/test-dump-untracked-cache.c6
-rw-r--r--t/helper/test-fast-rebase.c54
-rw-r--r--t/helper/test-getcwd.c26
-rw-r--r--t/helper/test-hash-speed.c2
-rw-r--r--t/helper/test-hash.c2
-rw-r--r--t/helper/test-match-trees.c2
-rw-r--r--t/helper/test-mergesort.c368
-rw-r--r--t/helper/test-oidtree.c49
-rw-r--r--t/helper/test-parse-options.c1
-rw-r--r--t/helper/test-partial-clone.c43
-rw-r--r--t/helper/test-path-utils.c46
-rw-r--r--t/helper/test-pkt-line.c12
-rw-r--r--t/helper/test-reach.c2
-rw-r--r--t/helper/test-read-midx.c43
-rw-r--r--t/helper/test-ref-store.c2
-rw-r--r--t/helper/test-run-command.c9
-rw-r--r--t/helper/test-serve-v2.c14
-rw-r--r--t/helper/test-simple-ipc.c233
-rw-r--r--t/helper/test-submodule-nested-repo-config.c4
-rw-r--r--t/helper/test-tool.c3
-rw-r--r--t/helper/test-tool.h3
-rw-r--r--t/lib-bitmap.sh240
-rw-r--r--t/lib-encoding.sh25
-rw-r--r--t/lib-git-svn.sh22
-rw-r--r--t/lib-httpd/apache.conf7
-rw-r--r--t/lib-midx.sh8
-rw-r--r--t/lib-parallel-checkout.sh45
-rw-r--r--t/lib-rebase.sh56
-rw-r--r--t/lib-submodule-update.sh3
-rw-r--r--t/lib-subtest.sh95
-rwxr-xr-xt/perf/aggregate.perl9
-rw-r--r--t/perf/lib-bitmap.sh69
-rwxr-xr-xt/perf/p0071-sort.sh40
-rwxr-xr-xt/perf/p2000-sparse-operations.sh47
-rwxr-xr-xt/perf/p3400-rebase.sh2
-rwxr-xr-xt/perf/p4209-pickaxe.sh70
-rwxr-xr-xt/perf/p5310-pack-bitmaps.sh65
-rwxr-xr-xt/perf/p5326-multi-pack-bitmaps.sh52
-rwxr-xr-xt/perf/p5600-partial-clone.sh4
-rw-r--r--t/perf/perf-lib.sh7
-rwxr-xr-xt/perf/run27
-rwxr-xr-xt/t0000-basic.sh451
-rwxr-xr-xt/t0001-init.sh33
-rwxr-xr-xt/t0004-unwritable.sh3
-rwxr-xr-xt/t0011-hashmap.sh2
-rwxr-xr-xt/t0012-help.sh65
-rwxr-xr-xt/t0016-oidmap.sh2
-rwxr-xr-xt/t0017-env-helper.sh1
-rwxr-xr-xt/t0018-advice.sh1
-rwxr-xr-xt/t0021-conversion.sh71
-rwxr-xr-xt/t0027-auto-crlf.sh7
-rwxr-xr-xt/t0028-working-tree-encoding.sh25
-rwxr-xr-xt/t0030-stripspace.sh1
-rwxr-xr-xt/t0040-parse-options.sh5
-rwxr-xr-xt/t0060-path-utils.sh56
-rwxr-xr-xt/t0063-string-list.sh1
-rwxr-xr-xt/t0069-oidtree.sh49
-rwxr-xr-xt/t0071-sort.sh11
-rwxr-xr-xt/t0090-cache-tree.sh1
-rwxr-xr-xt/t0091-bugreport.sh1
-rw-r--r--t/t0210/scrub_normal.perl6
-rw-r--r--t/t0211/scrub_perf.perl5
-rw-r--r--t/t0212/parse_events.perl5
-rwxr-xr-xt/t0301-credential-cache.sh32
-rwxr-xr-xt/t0410-partial-clone.sh35
-rwxr-xr-xt/t1006-cat-file.sh97
-rwxr-xr-xt/t1013-read-tree-submodule.sh1
-rwxr-xr-xt/t1022-read-tree-partial-clone.sh33
-rwxr-xr-xt/t1091-sparse-checkout-builtin.sh88
-rwxr-xr-xt/t1092-sparse-checkout-compatibility.sh543
-rwxr-xr-xt/t1300-config.sh100
-rwxr-xr-xt/t1301-shared-repo.sh2
-rwxr-xr-xt/t1306-xdg-files.sh2
-rwxr-xr-xt/t1307-config-blob.sh4
-rwxr-xr-xt/t1350-config-hooks-path.sh1
-rwxr-xr-xt/t1400-update-ref.sh43
-rwxr-xr-xt/t1401-symbolic-ref.sh25
-rwxr-xr-xt/t1403-show-ref.sh6
-rwxr-xr-xt/t1404-update-ref-errors.sh30
-rwxr-xr-xt/t1405-main-ref-store.sh18
-rwxr-xr-xt/t1407-worktree-ref-store.sh9
-rwxr-xr-xt/t1410-reflog.sh4
-rwxr-xr-xt/t1413-reflog-detach.sh5
-rwxr-xr-xt/t1414-reflog-walk.sh4
-rwxr-xr-xt/t1415-worktree-refs.sh15
-rwxr-xr-xt/t1430-bad-ref-name.sh2
-rwxr-xr-xt/t1500-rev-parse.sh4
-rwxr-xr-xt/t1502-rev-parse-parseopt.sh54
-rwxr-xr-xt/t1503-rev-parse-verify.sh2
-rwxr-xr-xt/t1600-index.sh13
-rwxr-xr-xt/t1700-split-index.sh34
-rwxr-xr-xt/t2017-checkout-orphan.sh2
-rwxr-xr-xt/t2021-checkout-overwrite.sh1
-rwxr-xr-xt/t2030-unresolve-info.sh3
-rwxr-xr-xt/t2080-parallel-checkout-basics.sh229
-rwxr-xr-xt/t2081-parallel-checkout-collisions.sh162
-rwxr-xr-xt/t2082-parallel-checkout-attributes.sh194
-rwxr-xr-xt/t2400-worktree-add.sh16
-rwxr-xr-xt/t2402-worktree-list.sh2
-rwxr-xr-xt/t2500-untracked-overwriting.sh244
-rwxr-xr-xt/t3001-ls-files-others-exclude.sh5
-rwxr-xr-xt/t3003-ls-files-exclude.sh4
-rwxr-xr-xt/t3070-wildmatch.sh5
-rwxr-xr-xt/t3200-branch.sh13
-rwxr-xr-xt/t3202-show-branch-octopus.sh70
-rwxr-xr-xt/t3202-show-branch.sh149
-rwxr-xr-xt/t3203-branch-output.sh4
-rwxr-xr-xt/t3210-pack-refs.sh2
-rwxr-xr-xt/t3320-notes-merge-worktrees.sh12
-rwxr-xr-xt/t3400-rebase.sh10
-rwxr-xr-xt/t3403-rebase-skip.sh13
-rwxr-xr-xt/t3404-rebase-interactive.sh90
-rwxr-xr-xt/t3407-rebase-abort.sh105
-rwxr-xr-xt/t3408-rebase-multi-line.sh10
-rwxr-xr-xt/t3409-rebase-preserve-merges.sh130
-rwxr-xr-xt/t3410-rebase-preserve-dropped-merges.sh90
-rwxr-xr-xt/t3411-rebase-preserve-around-merges.sh80
-rwxr-xr-xt/t3412-rebase-root.sh37
-rwxr-xr-xt/t3414-rebase-preserve-onto.sh85
-rwxr-xr-xt/t3418-rebase-continue.sh60
-rwxr-xr-xt/t3421-rebase-topology-linear.sh19
-rwxr-xr-xt/t3422-rebase-incompatible-options.sh11
-rwxr-xr-xt/t3425-rebase-topology-merges.sh151
-rwxr-xr-xt/t3427-rebase-subtree.sh26
-rwxr-xr-xt/t3430-rebase-merges.sh38
-rwxr-xr-xt/t3435-rebase-gpg-sign.sh1
-rwxr-xr-xt/t3501-revert-cherry-pick.sh16
-rwxr-xr-xt/t3507-cherry-pick-conflict.sh17
-rwxr-xr-xt/t3510-cherry-pick-sequence.sh1
-rwxr-xr-xt/t3513-revert-submodule.sh4
-rwxr-xr-xt/t3602-rm-sparse-checkout.sh108
-rwxr-xr-xt/t3700-add.sh10
-rwxr-xr-xt/t3705-add-sparse-checkout.sh217
-rwxr-xr-xt/t3800-mktag.sh121
-rwxr-xr-xt/t3903-stash.sh60
-rwxr-xr-xt/t3905-stash-include-untracked.sh19
-rwxr-xr-xt/t3920-crlf-messages.sh2
-rwxr-xr-xt/t4006-diff-mode.sh6
-rwxr-xr-xt/t4013-diff-various.sh57
-rw-r--r--t/t4013/diff.diff-tree_-m_master11
-rw-r--r--t/t4013/diff.log_-m_--raw_master61
-rw-r--r--t/t4013/diff.log_-m_--stat_master66
-rw-r--r--t/t4018/java-class-member-function4
-rw-r--r--t/t4018/java-enum-constant6
-rw-r--r--t/t4018/java-method-return-generic-bounded9
-rw-r--r--t/t4018/java-method-return-generic-wildcard9
-rw-r--r--t/t4018/java-nested-field6
-rw-r--r--t/t4018/php-enum4
-rwxr-xr-xt/t4030-diff-textconv.sh8
-rwxr-xr-xt/t4034-diff-words.sh5
-rwxr-xr-xt/t4045-diff-relative.sh53
-rwxr-xr-xt/t4060-diff-submodule-option-diff-format.sh159
-rwxr-xr-xt/t4103-apply-binary.sh23
-rwxr-xr-xt/t4108-apply-threeway.sh45
-rwxr-xr-xt/t4151-am-abort.sh39
-rwxr-xr-xt/t4202-log.sh32
-rwxr-xr-xt/t4203-mailmap.sh2
-rwxr-xr-xt/t4205-log-pretty-formats.sh17
-rwxr-xr-xt/t4209-log-pickaxe.sh114
-rwxr-xr-xt/t4210-log-i18n.sh7
-rwxr-xr-xt/t4258-am-quoted-cr.sh37
-rw-r--r--t/t4258/mbox12
-rwxr-xr-xt/t5000-tar-tree.sh122
-rwxr-xr-xt/t5100-mailinfo.sh40
-rw-r--r--t/t5100/quoted-cr-info5
-rw-r--r--t/t5100/quoted-cr-msg2
-rw-r--r--t/t5100/quoted-cr-patch22
-rw-r--r--t/t5100/quoted-cr.mbox47
-rwxr-xr-xt/t5300-pack-object.sh357
-rwxr-xr-xt/t5304-prune.sh100
-rwxr-xr-xt/t5310-pack-bitmaps.sh233
-rwxr-xr-xt/t5312-prune-corruption.sh48
-rwxr-xr-xt/t5316-pack-delta-depth.sh15
-rwxr-xr-xt/t5318-commit-graph.sh19
-rwxr-xr-xt/t5319-multi-pack-index.sh108
-rwxr-xr-xt/t5323-pack-redundant.sh4
-rwxr-xr-xt/t5326-multi-pack-bitmaps.sh398
-rwxr-xr-xt/t5406-remote-rejects.sh1
-rwxr-xr-xt/t5407-post-rewrite-hook.sh2
-rwxr-xr-xt/t5409-colorize-remote-messages.sh1
-rw-r--r--t/t5411/common-functions.sh54
-rw-r--r--t/t5411/once-0010-report-status-v1.sh4
-rw-r--r--t/t5411/test-0000-standard-git-push.sh82
-rw-r--r--t/t5411/test-0001-standard-git-push--porcelain.sh90
-rw-r--r--t/t5411/test-0003-pre-receive-declined--porcelain.sh8
-rw-r--r--t/t5411/test-0011-no-hook-error.sh40
-rw-r--r--t/t5411/test-0012-no-hook-error--porcelain.sh42
-rw-r--r--t/t5411/test-0013-bad-protocol.sh62
-rw-r--r--t/t5411/test-0014-bad-protocol--porcelain.sh80
-rw-r--r--t/t5411/test-0020-report-ng.sh32
-rw-r--r--t/t5411/test-0021-report-ng--porcelain.sh36
-rw-r--r--t/t5411/test-0022-report-unexpect-ref.sh26
-rw-r--r--t/t5411/test-0023-report-unexpect-ref--porcelain.sh28
-rw-r--r--t/t5411/test-0024-report-unknown-ref.sh18
-rw-r--r--t/t5411/test-0025-report-unknown-ref--porcelain.sh20
-rw-r--r--t/t5411/test-0026-push-options.sh58
-rw-r--r--t/t5411/test-0027-push-options--porcelain.sh62
-rw-r--r--t/t5411/test-0030-report-ok.sh20
-rw-r--r--t/t5411/test-0031-report-ok--porcelain.sh22
-rw-r--r--t/t5411/test-0032-report-with-options.sh186
-rw-r--r--t/t5411/test-0033-report-with-options--porcelain.sh200
-rw-r--r--t/t5411/test-0034-report-ft.sh22
-rw-r--r--t/t5411/test-0035-report-ft--porcelain.sh24
-rw-r--r--t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh132
-rw-r--r--t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh138
-rw-r--r--t/t5411/test-0038-report-mixed-refs.sh74
-rw-r--r--t/t5411/test-0039-report-mixed-refs--porcelain.sh76
-rw-r--r--t/t5411/test-0040-process-all-refs.sh80
-rw-r--r--t/t5411/test-0041-process-all-refs--porcelain.sh82
-rw-r--r--t/t5411/test-0050-proc-receive-refs-with-modifiers.sh90
-rwxr-xr-xt/t5505-remote.sh2
-rwxr-xr-xt/t5510-fetch.sh13
-rwxr-xr-xt/t5516-fetch-push.sh58
-rwxr-xr-xt/t5520-pull.sh54
-rwxr-xr-xt/t5521-pull-options.sh4
-rwxr-xr-xt/t5524-pull-msg.sh4
-rwxr-xr-xt/t5548-push-porcelain.sh97
-rwxr-xr-xt/t5549-fetch-push-http.sh72
-rwxr-xr-xt/t5551-http-fetch-smart.sh74
-rwxr-xr-xt/t5553-set-upstream.sh14
-rwxr-xr-xt/t5555-http-smart-common.sh161
-rwxr-xr-xt/t5562-http-backend-content-length.sh2
-rw-r--r--t/t5562/invoke-with-content-length.pl16
-rwxr-xr-xt/t5570-git-daemon.sh2
-rwxr-xr-xt/t5582-fetch-negative-refspec.sh1
-rwxr-xr-xt/t5600-clone-fail-cleanup.sh11
-rwxr-xr-xt/t5601-clone.sh5
-rwxr-xr-xt/t5604-clone-reference.sh4
-rwxr-xr-xt/t5606-clone-options.sh12
-rwxr-xr-xt/t5607-clone-bundle.sh73
-rwxr-xr-xt/t5616-partial-clone.sh8
-rwxr-xr-xt/t5701-git-serve.sh103
-rwxr-xr-xt/t5702-protocol-v2.sh124
-rwxr-xr-xt/t5703-upload-pack-ref-in-want.sh208
-rwxr-xr-xt/t5704-protocol-violations.sh15
-rwxr-xr-xt/t5705-session-id-in-capabilities.sh11
-rwxr-xr-xt/t6000-rev-list-misc.sh31
-rwxr-xr-xt/t6001-rev-list-graft.sh3
-rwxr-xr-xt/t6006-rev-list-format.sh80
-rwxr-xr-xt/t6020-bundle-misc.sh93
-rwxr-xr-xt/t6030-bisect-porcelain.sh29
-rwxr-xr-xt/t6041-bisect-submodule.sh4
-rwxr-xr-xt/t6050-replace.sh2
-rwxr-xr-xt/t6112-rev-list-filters-objects.sh72
-rwxr-xr-xt/t6113-rev-list-bitmap-filters.sh68
-rwxr-xr-xt/t6120-describe.sh196
-rwxr-xr-xt/t6300-for-each-ref.sh264
-rwxr-xr-xt/t6302-for-each-ref-filter.sh19
-rwxr-xr-xt/t6400-merge-df.sh16
-rwxr-xr-xt/t6402-merge-rename.sh150
-rwxr-xr-xt/t6406-merge-attr.sh18
-rwxr-xr-xt/t6409-merge-subtree.sh6
-rwxr-xr-xt/t6415-merge-dir-to-symlink.sh6
-rwxr-xr-xt/t6417-merge-ours-theirs.sh10
-rwxr-xr-xt/t6421-merge-partial-clone.sh440
-rwxr-xr-xt/t6423-merge-rename-directories.sh237
-rwxr-xr-xt/t6424-merge-unrelated-index-changes.sh1
-rwxr-xr-xt/t6429-merge-sequence-rename-caching.sh700
-rwxr-xr-xt/t6430-merge-recursive.sh4
-rwxr-xr-xt/t6436-merge-overwrite.sh3
-rwxr-xr-xt/t6500-gc.sh51
-rwxr-xr-xt/t6501-freshen-objects.sh22
-rwxr-xr-xt/t7002-mv-sparse-checkout.sh189
-rwxr-xr-xt/t7003-filter-branch.sh7
-rwxr-xr-xt/t7004-tag.sh4
-rwxr-xr-xt/t7011-skip-worktree-reading.sh5
-rwxr-xr-xt/t7012-skip-worktree-writing.sh19
-rwxr-xr-xt/t7030-verify-tag.sh4
-rwxr-xr-xt/t7063-status-untracked-cache.sh206
-rwxr-xr-xt/t7064-wtstatus-pv2.sh5
-rwxr-xr-xt/t7112-reset-submodule.sh1
-rwxr-xr-xt/t7201-co.sh1
-rwxr-xr-xt/t7300-clean.sh42
-rwxr-xr-xt/t7400-submodule-basic.sh13
-rwxr-xr-xt/t7406-submodule-update.sh34
-rwxr-xr-xt/t7450-bad-git-dotfiles.sh (renamed from t/t7415-submodule-names.sh)129
-rwxr-xr-xt/t7500-commit-template-squash-signoff.sh13
-rwxr-xr-xt/t7505-prepare-commit-msg-hook.sh1
-rwxr-xr-xt/t7508-status.sh2
-rwxr-xr-xt/t7509-commit-authorship.sh4
-rwxr-xr-xt/t7513-interpret-trailers.sh84
-rwxr-xr-xt/t7517-per-repo-email.sh13
-rwxr-xr-xt/t7519-status-fsmonitor.sh65
-rwxr-xr-xt/t7600-merge.sh20
-rwxr-xr-xt/t7601-merge-pull-config.sh244
-rwxr-xr-xt/t7603-merge-reduce-heads.sh2
-rwxr-xr-xt/t7700-repack.sh156
-rwxr-xr-xt/t7703-repack-geometric.sh24
-rwxr-xr-xt/t7800-difftool.sh76
-rwxr-xr-xt/t7810-grep.sh9
-rwxr-xr-xt/t7814-grep-recurse-submodules.sh106
-rwxr-xr-xt/t7816-grep-binary-pattern.sh4
-rwxr-xr-xt/t7900-maintenance.sh134
-rwxr-xr-xt/t9001-send-email.sh147
-rwxr-xr-xt/t9002-column.sh18
-rwxr-xr-xt/t9100-git-svn-basic.sh16
-rwxr-xr-xt/t9115-git-svn-dcommit-funky-renames.sh6
-rwxr-xr-xt/t9117-git-svn-init-clone.sh6
-rwxr-xr-xt/t9129-git-svn-i18n-commitencoding.sh4
-rwxr-xr-xt/t9148-git-svn-propset.sh27
-rwxr-xr-xt/t9300-fast-import.sh3
-rwxr-xr-xt/t9351-fast-export-anonymize.sh10
-rwxr-xr-xt/t9400-git-cvsserver-server.sh9
-rwxr-xr-xt/t9801-git-p4-branch.sh2
-rwxr-xr-xt/t9802-git-p4-filetype.sh4
-rwxr-xr-xt/t9902-completion.sh50
-rw-r--r--t/test-lib-functions.sh239
-rw-r--r--t/test-lib.sh147
311 files changed, 12639 insertions, 4074 deletions
diff --git a/t/README b/t/README
index 8eb9e46b1d..b92155a822 100644
--- a/t/README
+++ b/t/README
@@ -196,6 +196,11 @@ appropriately before running "make". Short options can be bundled, i.e.
this feature by setting the GIT_TEST_CHAIN_LINT environment
variable to "1" or "0", respectively.
+ A few test scripts disable some of the more advanced
+ chain-linting detection in the name of efficiency. You can
+ override this by setting the GIT_TEST_CHAIN_LINT_HARDER
+ environment variable to "1".
+
--stress::
Run the test script repeatedly in multiple parallel jobs until
one of them fails. Useful for reproducing rare failures in
@@ -361,6 +366,13 @@ excluded as so much relies on it, but this might change in the future.
GIT_TEST_SPLIT_INDEX=<boolean> forces split-index mode on the whole
test suite. Accept any boolean values that are accepted by git-config.
+GIT_TEST_PASSING_SANITIZE_LEAK=<boolean> when compiled with
+SANITIZE=leak will run only those tests that have whitelisted
+themselves as passing with no memory leaks. Tests can be whitelisted
+by setting "TEST_PASSES_SANITIZE_LEAK=true" before sourcing
+"test-lib.sh" itself at the top of the test script. This test mode is
+used by the "linux-leaks" CI target.
+
GIT_TEST_PROTOCOL_VERSION=<n>, when set, makes 'protocol.version'
default to n.
@@ -420,6 +432,10 @@ GIT_TEST_MULTI_PACK_INDEX=<boolean>, when true, forces the multi-pack-
index to be written after every 'git repack' command, and overrides the
'core.multiPackIndex' setting to true.
+GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=<boolean>, when true, sets the
+'--bitmap' option on all invocations of 'git multi-pack-index write',
+and ignores pack-objects' '--write-bitmap-index'.
+
GIT_TEST_SIDEBAND_ALL=<boolean>, when true, overrides the
'uploadpack.allowSidebandAll' setting to true, and when false, forces
fetch-pack to not request sideband-all (even if the server advertises
@@ -439,6 +455,20 @@ GIT_TEST_WRITE_REV_INDEX=<boolean>, when true enables the
GIT_TEST_SPARSE_INDEX=<boolean>, when true enables index writes to use the
sparse-index format by default.
+GIT_TEST_CHECKOUT_WORKERS=<n> overrides the 'checkout.workers' setting
+to <n> and 'checkout.thresholdForParallelism' to 0, forcing the
+execution of the parallel-checkout code.
+
+GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=<boolean>, when true, makes
+registering submodule ODBs as alternates a fatal action. Support for
+this environment variable can be removed once the migration to
+explicitly providing repositories when accessing submodule objects is
+complete (in which case we might want to replace this with a trace2
+call so that users can make it visible if accessing submodule objects
+without an explicit repository still happens) or needs to be abandoned
+for whatever reason (in which case the migrated codepaths still retain
+their performance benefits).
+
Naming Tests
------------
@@ -744,7 +774,8 @@ Test harness library
--------------------
There are a handful helper functions defined in the test harness
-library for your script to use.
+library for your script to use. Some of them are listed below;
+see test-lib-functions.sh for the full list and their options.
- test_expect_success [<prereq>] <message> <script>
@@ -790,10 +821,12 @@ library for your script to use.
argument. This is primarily meant for use during the
development of a new test script.
- - debug <git-command>
+ - debug [options] <git-command>
Run a git command inside a debugger. This is primarily meant for
- use when debugging a failing test script.
+ use when debugging a failing test script. With '-t', use your
+ original TERM instead of test-lib.sh's "dumb", so that your
+ debugger interface has colors.
- test_done
@@ -980,7 +1013,7 @@ library for your script to use.
EOF
- - test_pause
+ - test_pause [options]
This command is useful for writing and debugging tests and must be
removed before submitting. It halts the execution of the test and
@@ -1117,6 +1150,12 @@ use these, and "test_set_prereq" for how to define your own.
Git wasn't compiled with NO_PTHREADS=YesPlease.
+ - REFFILES
+
+ Test is specific to packed/loose ref storage, and should be
+ disabled for other ref storage backends
+
+
Tips for Writing Tests
----------------------
diff --git a/t/helper/test-advise.c b/t/helper/test-advise.c
index a7043df1d3..cb881139f7 100644
--- a/t/helper/test-advise.c
+++ b/t/helper/test-advise.c
@@ -16,7 +16,7 @@ int cmd__advise_if_enabled(int argc, const char **argv)
* selected here and in t0018 where this command is being
* executed.
*/
- advise_if_enabled(ADVICE_NESTED_TAG, argv[1]);
+ advise_if_enabled(ADVICE_NESTED_TAG, "%s", argv[1]);
return 0;
}
diff --git a/t/helper/test-bitmap.c b/t/helper/test-bitmap.c
index 134a1e9d76..ff35f5999b 100644
--- a/t/helper/test-bitmap.c
+++ b/t/helper/test-bitmap.c
@@ -7,6 +7,11 @@ static int bitmap_list_commits(void)
return test_bitmap_commits(the_repository);
}
+static int bitmap_dump_hashes(void)
+{
+ return test_bitmap_hashes(the_repository);
+}
+
int cmd__bitmap(int argc, const char **argv)
{
setup_git_directory();
@@ -16,9 +21,12 @@ int cmd__bitmap(int argc, const char **argv)
if (!strcmp(argv[1], "list-commits"))
return bitmap_list_commits();
+ if (!strcmp(argv[1], "dump-hashes"))
+ return bitmap_dump_hashes();
usage:
- usage("\ttest-tool bitmap list-commits");
+ usage("\ttest-tool bitmap list-commits\n"
+ "\ttest-tool bitmap dump-hashes");
return -1;
}
diff --git a/t/helper/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c
index cf0f2c7228..99010614f6 100644
--- a/t/helper/test-dump-untracked-cache.c
+++ b/t/helper/test-dump-untracked-cache.c
@@ -45,8 +45,10 @@ int cmd__dump_untracked_cache(int ac, const char **av)
struct untracked_cache *uc;
struct strbuf base = STRBUF_INIT;
- /* Hack to avoid modifying the untracked cache when we read it */
- ignore_untracked_cache_config = 1;
+ /* Set core.untrackedCache=keep before setup_git_directory() */
+ xsetenv("GIT_CONFIG_COUNT", "1", 1);
+ xsetenv("GIT_CONFIG_KEY_0", "core.untrackedCache", 1);
+ xsetenv("GIT_CONFIG_VALUE_0", "keep", 1);
setup_git_directory();
if (read_cache() < 0)
diff --git a/t/helper/test-fast-rebase.c b/t/helper/test-fast-rebase.c
index 373212256a..fc2d460904 100644
--- a/t/helper/test-fast-rebase.c
+++ b/t/helper/test-fast-rebase.c
@@ -91,7 +91,6 @@ int cmd__fast_rebase(int argc, const char **argv)
struct commit *last_commit = NULL, *last_picked_commit = NULL;
struct object_id head;
struct lock_file lock = LOCK_INIT;
- int clean = 1;
struct strvec rev_walk_args = STRVEC_INIT;
struct rev_info revs;
struct commit *commit;
@@ -124,7 +123,8 @@ int cmd__fast_rebase(int argc, const char **argv)
assert(oideq(&onto->object.oid, &head));
hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
- assert(repo_read_index(the_repository) >= 0);
+ if (repo_read_index(the_repository) < 0)
+ BUG("Could not read index");
repo_init_revisions(the_repository, &revs, NULL);
revs.verbose_header = 1;
@@ -175,11 +175,10 @@ int cmd__fast_rebase(int argc, const char **argv)
free((char*)merge_opt.ancestor);
merge_opt.ancestor = NULL;
if (!result.clean)
- die("Aborting: Hit a conflict and restarting is not implemented.");
+ break;
last_picked_commit = commit;
last_commit = create_commit(result.tree, commit, last_commit);
}
- fprintf(stderr, "\nDone.\n");
/* TODO: There should be some kind of rev_info_free(&revs) call... */
memset(&revs, 0, sizeof(revs));
@@ -188,24 +187,39 @@ int cmd__fast_rebase(int argc, const char **argv)
if (result.clean < 0)
exit(128);
- strbuf_addf(&reflog_msg, "finish rebase %s onto %s",
- oid_to_hex(&last_picked_commit->object.oid),
- oid_to_hex(&last_commit->object.oid));
- if (update_ref(reflog_msg.buf, branch_name.buf,
- &last_commit->object.oid,
- &last_picked_commit->object.oid,
- REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) {
- error(_("could not update %s"), argv[4]);
- die("Failed to update %s", argv[4]);
+ if (result.clean) {
+ fprintf(stderr, "\nDone.\n");
+ strbuf_addf(&reflog_msg, "finish rebase %s onto %s",
+ oid_to_hex(&last_picked_commit->object.oid),
+ oid_to_hex(&last_commit->object.oid));
+ if (update_ref(reflog_msg.buf, branch_name.buf,
+ &last_commit->object.oid,
+ &last_picked_commit->object.oid,
+ REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) {
+ error(_("could not update %s"), argv[4]);
+ die("Failed to update %s", argv[4]);
+ }
+ if (create_symref("HEAD", branch_name.buf, reflog_msg.buf) < 0)
+ die(_("unable to update HEAD"));
+ strbuf_release(&reflog_msg);
+ strbuf_release(&branch_name);
+
+ prime_cache_tree(the_repository, the_repository->index,
+ result.tree);
+ } else {
+ fprintf(stderr, "\nAborting: Hit a conflict.\n");
+ strbuf_addf(&reflog_msg, "rebase progress up to %s",
+ oid_to_hex(&last_picked_commit->object.oid));
+ if (update_ref(reflog_msg.buf, "HEAD",
+ &last_commit->object.oid,
+ &head,
+ REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) {
+ error(_("could not update %s"), argv[4]);
+ die("Failed to update %s", argv[4]);
+ }
}
- if (create_symref("HEAD", branch_name.buf, reflog_msg.buf) < 0)
- die(_("unable to update HEAD"));
- strbuf_release(&reflog_msg);
- strbuf_release(&branch_name);
-
- prime_cache_tree(the_repository, the_repository->index, result.tree);
if (write_locked_index(&the_index, &lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("unable to write %s"), get_index_file());
- return (clean == 0);
+ return (result.clean == 0);
}
diff --git a/t/helper/test-getcwd.c b/t/helper/test-getcwd.c
new file mode 100644
index 0000000000..d680038a78
--- /dev/null
+++ b/t/helper/test-getcwd.c
@@ -0,0 +1,26 @@
+#include "test-tool.h"
+#include "git-compat-util.h"
+#include "parse-options.h"
+
+static const char *getcwd_usage[] = {
+ "test-tool getcwd",
+ NULL
+};
+
+int cmd__getcwd(int argc, const char **argv)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+ char *cwd;
+
+ argc = parse_options(argc, argv, "test-tools", options, getcwd_usage, 0);
+ if (argc > 0)
+ usage_with_options(getcwd_usage, options);
+
+ cwd = xgetcwd();
+ puts(cwd);
+ free(cwd);
+
+ return 0;
+}
diff --git a/t/helper/test-hash-speed.c b/t/helper/test-hash-speed.c
index 432233c7f0..f40d9ad0c2 100644
--- a/t/helper/test-hash-speed.c
+++ b/t/helper/test-hash-speed.c
@@ -57,5 +57,5 @@ int cmd__hash_speed(int ac, const char **av)
free(p);
}
- exit(0);
+ return 0;
}
diff --git a/t/helper/test-hash.c b/t/helper/test-hash.c
index 0a31de66f3..261c545b9d 100644
--- a/t/helper/test-hash.c
+++ b/t/helper/test-hash.c
@@ -54,5 +54,5 @@ int cmd_hash_impl(int ac, const char **av, int algo)
fwrite(hash, 1, algop->rawsz, stdout);
else
puts(hash_to_hex_algop(hash, algop));
- exit(0);
+ return 0;
}
diff --git a/t/helper/test-match-trees.c b/t/helper/test-match-trees.c
index b9fd427571..4079fdee06 100644
--- a/t/helper/test-match-trees.c
+++ b/t/helper/test-match-trees.c
@@ -23,5 +23,5 @@ int cmd__match_trees(int ac, const char **av)
shift_tree(the_repository, &one->object.oid, &two->object.oid, &shifted, -1);
printf("shifted: %s\n", oid_to_hex(&shifted));
- exit(0);
+ return 0;
}
diff --git a/t/helper/test-mergesort.c b/t/helper/test-mergesort.c
index c5cffaa4b7..ebf68f7de8 100644
--- a/t/helper/test-mergesort.c
+++ b/t/helper/test-mergesort.c
@@ -2,6 +2,12 @@
#include "cache.h"
#include "mergesort.h"
+static uint32_t minstd_rand(uint32_t *state)
+{
+ *state = (uint64_t)*state * 48271 % 2147483647;
+ return *state;
+}
+
struct line {
char *text;
struct line *next;
@@ -23,14 +29,12 @@ static int compare_strings(const void *a, const void *b)
return strcmp(x->text, y->text);
}
-int cmd__mergesort(int argc, const char **argv)
+static int sort_stdin(void)
{
struct line *line, *p = NULL, *lines = NULL;
struct strbuf sb = STRBUF_INIT;
- for (;;) {
- if (strbuf_getwholeline(&sb, stdin, '\n'))
- break;
+ while (!strbuf_getline(&sb, stdin)) {
line = xmalloc(sizeof(struct line));
line->text = strbuf_detach(&sb, NULL);
if (p) {
@@ -46,8 +50,362 @@ int cmd__mergesort(int argc, const char **argv)
lines = llist_mergesort(lines, get_next, set_next, compare_strings);
while (lines) {
- printf("%s", lines->text);
+ puts(lines->text);
lines = lines->next;
}
return 0;
}
+
+static void dist_sawtooth(int *arr, int n, int m)
+{
+ int i;
+ for (i = 0; i < n; i++)
+ arr[i] = i % m;
+}
+
+static void dist_rand(int *arr, int n, int m)
+{
+ int i;
+ uint32_t seed = 1;
+ for (i = 0; i < n; i++)
+ arr[i] = minstd_rand(&seed) % m;
+}
+
+static void dist_stagger(int *arr, int n, int m)
+{
+ int i;
+ for (i = 0; i < n; i++)
+ arr[i] = (i * m + i) % n;
+}
+
+static void dist_plateau(int *arr, int n, int m)
+{
+ int i;
+ for (i = 0; i < n; i++)
+ arr[i] = (i < m) ? i : m;
+}
+
+static void dist_shuffle(int *arr, int n, int m)
+{
+ int i, j, k;
+ uint32_t seed = 1;
+ for (i = j = 0, k = 1; i < n; i++)
+ arr[i] = minstd_rand(&seed) % m ? (j += 2) : (k += 2);
+}
+
+#define DIST(name) { #name, dist_##name }
+
+static struct dist {
+ const char *name;
+ void (*fn)(int *arr, int n, int m);
+} dist[] = {
+ DIST(sawtooth),
+ DIST(rand),
+ DIST(stagger),
+ DIST(plateau),
+ DIST(shuffle),
+};
+
+static const struct dist *get_dist_by_name(const char *name)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(dist); i++) {
+ if (!strcmp(dist[i].name, name))
+ return &dist[i];
+ }
+ return NULL;
+}
+
+static void mode_copy(int *arr, int n)
+{
+ /* nothing */
+}
+
+static void mode_reverse(int *arr, int n)
+{
+ int i, j;
+ for (i = 0, j = n - 1; i < j; i++, j--)
+ SWAP(arr[i], arr[j]);
+}
+
+static void mode_reverse_1st_half(int *arr, int n)
+{
+ mode_reverse(arr, n / 2);
+}
+
+static void mode_reverse_2nd_half(int *arr, int n)
+{
+ int half = n / 2;
+ mode_reverse(arr + half, n - half);
+}
+
+static int compare_ints(const void *av, const void *bv)
+{
+ const int *ap = av, *bp = bv;
+ int a = *ap, b = *bp;
+ return (a > b) - (a < b);
+}
+
+static void mode_sort(int *arr, int n)
+{
+ QSORT(arr, n, compare_ints);
+}
+
+static void mode_dither(int *arr, int n)
+{
+ int i;
+ for (i = 0; i < n; i++)
+ arr[i] += i % 5;
+}
+
+static void unriffle(int *arr, int n, int *tmp)
+{
+ int i, j;
+ COPY_ARRAY(tmp, arr, n);
+ for (i = j = 0; i < n; i += 2)
+ arr[j++] = tmp[i];
+ for (i = 1; i < n; i += 2)
+ arr[j++] = tmp[i];
+}
+
+static void unriffle_recursively(int *arr, int n, int *tmp)
+{
+ if (n > 1) {
+ int half = n / 2;
+ unriffle(arr, n, tmp);
+ unriffle_recursively(arr, half, tmp);
+ unriffle_recursively(arr + half, n - half, tmp);
+ }
+}
+
+static void mode_unriffle(int *arr, int n)
+{
+ int *tmp;
+ ALLOC_ARRAY(tmp, n);
+ unriffle_recursively(arr, n, tmp);
+ free(tmp);
+}
+
+static unsigned int prev_pow2(unsigned int n)
+{
+ unsigned int pow2 = 1;
+ while (pow2 * 2 < n)
+ pow2 *= 2;
+ return pow2;
+}
+
+static void unriffle_recursively_skewed(int *arr, int n, int *tmp)
+{
+ if (n > 1) {
+ int pow2 = prev_pow2(n);
+ int rest = n - pow2;
+ unriffle(arr + pow2 - rest, rest * 2, tmp);
+ unriffle_recursively_skewed(arr, pow2, tmp);
+ unriffle_recursively_skewed(arr + pow2, rest, tmp);
+ }
+}
+
+static void mode_unriffle_skewed(int *arr, int n)
+{
+ int *tmp;
+ ALLOC_ARRAY(tmp, n);
+ unriffle_recursively_skewed(arr, n, tmp);
+ free(tmp);
+}
+
+#define MODE(name) { #name, mode_##name }
+
+static struct mode {
+ const char *name;
+ void (*fn)(int *arr, int n);
+} mode[] = {
+ MODE(copy),
+ MODE(reverse),
+ MODE(reverse_1st_half),
+ MODE(reverse_2nd_half),
+ MODE(sort),
+ MODE(dither),
+ MODE(unriffle),
+ MODE(unriffle_skewed),
+};
+
+static const struct mode *get_mode_by_name(const char *name)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(mode); i++) {
+ if (!strcmp(mode[i].name, name))
+ return &mode[i];
+ }
+ return NULL;
+}
+
+static int generate(int argc, const char **argv)
+{
+ const struct dist *dist = NULL;
+ const struct mode *mode = NULL;
+ int i, n, m, *arr;
+
+ if (argc != 4)
+ return 1;
+
+ dist = get_dist_by_name(argv[0]);
+ mode = get_mode_by_name(argv[1]);
+ n = strtol(argv[2], NULL, 10);
+ m = strtol(argv[3], NULL, 10);
+ if (!dist || !mode)
+ return 1;
+
+ ALLOC_ARRAY(arr, n);
+ dist->fn(arr, n, m);
+ mode->fn(arr, n);
+ for (i = 0; i < n; i++)
+ printf("%08x\n", arr[i]);
+ free(arr);
+ return 0;
+}
+
+static struct stats {
+ int get_next, set_next, compare;
+} stats;
+
+struct number {
+ int value, rank;
+ struct number *next;
+};
+
+static void *get_next_number(const void *a)
+{
+ stats.get_next++;
+ return ((const struct number *)a)->next;
+}
+
+static void set_next_number(void *a, void *b)
+{
+ stats.set_next++;
+ ((struct number *)a)->next = b;
+}
+
+static int compare_numbers(const void *av, const void *bv)
+{
+ const struct number *an = av, *bn = bv;
+ int a = an->value, b = bn->value;
+ stats.compare++;
+ return (a > b) - (a < b);
+}
+
+static void clear_numbers(struct number *list)
+{
+ while (list) {
+ struct number *next = list->next;
+ free(list);
+ list = next;
+ }
+}
+
+static int test(const struct dist *dist, const struct mode *mode, int n, int m)
+{
+ int *arr;
+ size_t i;
+ struct number *curr, *list, **tail;
+ int is_sorted = 1;
+ int is_stable = 1;
+ const char *verdict;
+ int result = -1;
+
+ ALLOC_ARRAY(arr, n);
+ dist->fn(arr, n, m);
+ mode->fn(arr, n);
+ for (i = 0, tail = &list; i < n; i++) {
+ curr = xmalloc(sizeof(*curr));
+ curr->value = arr[i];
+ curr->rank = i;
+ *tail = curr;
+ tail = &curr->next;
+ }
+ *tail = NULL;
+
+ stats.get_next = stats.set_next = stats.compare = 0;
+ list = llist_mergesort(list, get_next_number, set_next_number,
+ compare_numbers);
+
+ QSORT(arr, n, compare_ints);
+ for (i = 0, curr = list; i < n && curr; i++, curr = curr->next) {
+ if (arr[i] != curr->value)
+ is_sorted = 0;
+ if (curr->next && curr->value == curr->next->value &&
+ curr->rank >= curr->next->rank)
+ is_stable = 0;
+ }
+ if (i < n) {
+ verdict = "too short";
+ } else if (curr) {
+ verdict = "too long";
+ } else if (!is_sorted) {
+ verdict = "not sorted";
+ } else if (!is_stable) {
+ verdict = "unstable";
+ } else {
+ verdict = "OK";
+ result = 0;
+ }
+
+ printf("%-9s %-16s %8d %8d %8d %8d %8d %s\n",
+ dist->name, mode->name, n, m, stats.get_next, stats.set_next,
+ stats.compare, verdict);
+
+ clear_numbers(list);
+ free(arr);
+
+ return result;
+}
+
+/*
+ * A version of the qsort certification program from "Engineering a Sort
+ * Function" by Bentley and McIlroy, Software—Practice and Experience,
+ * Volume 23, Issue 11, 1249–1265 (November 1993).
+ */
+static int run_tests(int argc, const char **argv)
+{
+ const char *argv_default[] = { "100", "1023", "1024", "1025" };
+ if (!argc)
+ return run_tests(ARRAY_SIZE(argv_default), argv_default);
+ printf("%-9s %-16s %8s %8s %8s %8s %8s %s\n",
+ "distribut", "mode", "n", "m", "get_next", "set_next",
+ "compare", "verdict");
+ while (argc--) {
+ int i, j, m, n = strtol(*argv++, NULL, 10);
+ for (i = 0; i < ARRAY_SIZE(dist); i++) {
+ for (j = 0; j < ARRAY_SIZE(mode); j++) {
+ for (m = 1; m < 2 * n; m *= 2) {
+ if (test(&dist[i], &mode[j], n, m))
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+int cmd__mergesort(int argc, const char **argv)
+{
+ int i;
+ const char *sep;
+
+ if (argc == 6 && !strcmp(argv[1], "generate"))
+ return generate(argc - 2, argv + 2);
+ if (argc == 2 && !strcmp(argv[1], "sort"))
+ return sort_stdin();
+ if (argc > 1 && !strcmp(argv[1], "test"))
+ return run_tests(argc - 2, argv + 2);
+ fprintf(stderr, "usage: test-tool mergesort generate <distribution> <mode> <n> <m>\n");
+ fprintf(stderr, " or: test-tool mergesort sort\n");
+ fprintf(stderr, " or: test-tool mergesort test [<n>...]\n");
+ fprintf(stderr, "\n");
+ for (i = 0, sep = "distributions: "; i < ARRAY_SIZE(dist); i++, sep = ", ")
+ fprintf(stderr, "%s%s", sep, dist[i].name);
+ fprintf(stderr, "\n");
+ for (i = 0, sep = "modes: "; i < ARRAY_SIZE(mode); i++, sep = ", ")
+ fprintf(stderr, "%s%s", sep, mode[i].name);
+ fprintf(stderr, "\n");
+ return 129;
+}
diff --git a/t/helper/test-oidtree.c b/t/helper/test-oidtree.c
new file mode 100644
index 0000000000..180ee28dd9
--- /dev/null
+++ b/t/helper/test-oidtree.c
@@ -0,0 +1,49 @@
+#include "test-tool.h"
+#include "cache.h"
+#include "oidtree.h"
+
+static enum cb_next print_oid(const struct object_id *oid, void *data)
+{
+ puts(oid_to_hex(oid));
+ return CB_CONTINUE;
+}
+
+int cmd__oidtree(int argc, const char **argv)
+{
+ struct oidtree ot;
+ struct strbuf line = STRBUF_INIT;
+ int nongit_ok;
+ int algo = GIT_HASH_UNKNOWN;
+
+ oidtree_init(&ot);
+ setup_git_directory_gently(&nongit_ok);
+
+ while (strbuf_getline(&line, stdin) != EOF) {
+ const char *arg;
+ struct object_id oid;
+
+ if (skip_prefix(line.buf, "insert ", &arg)) {
+ if (get_oid_hex_any(arg, &oid) == GIT_HASH_UNKNOWN)
+ die("insert not a hexadecimal oid: %s", arg);
+ algo = oid.algo;
+ oidtree_insert(&ot, &oid);
+ } else if (skip_prefix(line.buf, "contains ", &arg)) {
+ if (get_oid_hex(arg, &oid))
+ die("contains not a hexadecimal oid: %s", arg);
+ printf("%d\n", oidtree_contains(&ot, &oid));
+ } else if (skip_prefix(line.buf, "each ", &arg)) {
+ char buf[GIT_MAX_HEXSZ + 1] = { '0' };
+ memset(&oid, 0, sizeof(oid));
+ memcpy(buf, arg, strlen(arg));
+ buf[hash_algos[algo].hexsz] = '\0';
+ get_oid_hex_any(buf, &oid);
+ oid.algo = algo;
+ oidtree_each(&ot, &oid, strlen(arg), print_oid, NULL);
+ } else if (!strcmp(line.buf, "clear")) {
+ oidtree_clear(&ot);
+ } else {
+ die("unknown command: %s", line.buf);
+ }
+ }
+ return 0;
+}
diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c
index 2051ce57db..a282b6ff13 100644
--- a/t/helper/test-parse-options.c
+++ b/t/helper/test-parse-options.c
@@ -134,7 +134,6 @@ int cmd__parse_options(int argc, const char **argv)
OPT_NOOP_NOARG(0, "obsolete"),
OPT_STRING_LIST(0, "list", &list, "str", "add str to list"),
OPT_GROUP("Magic arguments"),
- OPT_ARGUMENT("quux", NULL, "means --quux"),
OPT_NUMBER_CALLBACK(&integer, "set integer to NUM",
number_callback),
{ OPTION_COUNTUP, '+', NULL, &boolean, NULL, "same as -b",
diff --git a/t/helper/test-partial-clone.c b/t/helper/test-partial-clone.c
new file mode 100644
index 0000000000..3f102cfddd
--- /dev/null
+++ b/t/helper/test-partial-clone.c
@@ -0,0 +1,43 @@
+#include "cache.h"
+#include "test-tool.h"
+#include "repository.h"
+#include "object-store.h"
+
+/*
+ * Prints the size of the object corresponding to the given hash in a specific
+ * gitdir. This is similar to "git -C gitdir cat-file -s", except that this
+ * exercises the code that accesses the object of an arbitrary repository that
+ * is not the_repository. ("git -C gitdir" makes it so that the_repository is
+ * the one in gitdir.)
+ */
+static void object_info(const char *gitdir, const char *oid_hex)
+{
+ struct repository r;
+ struct object_id oid;
+ unsigned long size;
+ struct object_info oi = {.sizep = &size};
+ const char *p;
+
+ if (repo_init(&r, gitdir, NULL))
+ die("could not init repo");
+ if (parse_oid_hex(oid_hex, &oid, &p))
+ die("could not parse oid");
+ if (oid_object_info_extended(&r, &oid, &oi, 0))
+ die("could not obtain object info");
+ printf("%d\n", (int) size);
+}
+
+int cmd__partial_clone(int argc, const char **argv)
+{
+ setup_git_directory();
+
+ if (argc < 4)
+ die("too few arguments");
+
+ if (!strcmp(argv[1], "object-info"))
+ object_info(argv[2], argv[3]);
+ else
+ die("invalid argument '%s'", argv[1]);
+
+ return 0;
+}
diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c
index 313a153209..229ed416b0 100644
--- a/t/helper/test-path-utils.c
+++ b/t/helper/test-path-utils.c
@@ -172,9 +172,22 @@ static struct test_data dirname_data[] = {
{ NULL, NULL }
};
-static int is_dotgitmodules(const char *path)
+static int check_dotfile(const char *x, const char **argv,
+ int (*is_hfs)(const char *),
+ int (*is_ntfs)(const char *))
{
- return is_hfs_dotgitmodules(path) || is_ntfs_dotgitmodules(path);
+ int res = 0, expect = 1;
+ for (; *argv; argv++) {
+ if (!strcmp("--not", *argv))
+ expect = !expect;
+ else if (expect != (is_hfs(*argv) || is_ntfs(*argv)))
+ res = error("'%s' is %s.git%s", *argv,
+ expect ? "not " : "", x);
+ else
+ fprintf(stderr, "ok: '%s' is %s.git%s\n",
+ *argv, expect ? "" : "not ", x);
+ }
+ return !!res;
}
static int cmp_by_st_size(const void *a, const void *b)
@@ -382,17 +395,24 @@ int cmd__path_utils(int argc, const char **argv)
return test_function(dirname_data, posix_dirname, argv[1]);
if (argc > 2 && !strcmp(argv[1], "is_dotgitmodules")) {
- int res = 0, expect = 1, i;
- for (i = 2; i < argc; i++)
- if (!strcmp("--not", argv[i]))
- expect = !expect;
- else if (expect != is_dotgitmodules(argv[i]))
- res = error("'%s' is %s.gitmodules", argv[i],
- expect ? "not " : "");
- else
- fprintf(stderr, "ok: '%s' is %s.gitmodules\n",
- argv[i], expect ? "" : "not ");
- return !!res;
+ return check_dotfile("modules", argv + 2,
+ is_hfs_dotgitmodules,
+ is_ntfs_dotgitmodules);
+ }
+ if (argc > 2 && !strcmp(argv[1], "is_dotgitignore")) {
+ return check_dotfile("ignore", argv + 2,
+ is_hfs_dotgitignore,
+ is_ntfs_dotgitignore);
+ }
+ if (argc > 2 && !strcmp(argv[1], "is_dotgitattributes")) {
+ return check_dotfile("attributes", argv + 2,
+ is_hfs_dotgitattributes,
+ is_ntfs_dotgitattributes);
+ }
+ if (argc > 2 && !strcmp(argv[1], "is_dotmailmap")) {
+ return check_dotfile("mailmap", argv + 2,
+ is_hfs_dotmailmap,
+ is_ntfs_dotmailmap);
}
if (argc > 2 && !strcmp(argv[1], "file-size")) {
diff --git a/t/helper/test-pkt-line.c b/t/helper/test-pkt-line.c
index 5e638f0b97..c5e052e537 100644
--- a/t/helper/test-pkt-line.c
+++ b/t/helper/test-pkt-line.c
@@ -26,6 +26,16 @@ static void pack(int argc, const char **argv)
}
}
+static void pack_raw_stdin(void)
+{
+ struct strbuf sb = STRBUF_INIT;
+
+ if (strbuf_read(&sb, 0, 0) < 0)
+ die_errno("failed to read from stdin");
+ packet_write(1, sb.buf, sb.len);
+ strbuf_release(&sb);
+}
+
static void unpack(void)
{
struct packet_reader reader;
@@ -110,6 +120,8 @@ int cmd__pkt_line(int argc, const char **argv)
if (!strcmp(argv[1], "pack"))
pack(argc - 2, argv + 2);
+ else if (!strcmp(argv[1], "pack-raw-stdin"))
+ pack_raw_stdin();
else if (!strcmp(argv[1], "unpack"))
unpack();
else if (!strcmp(argv[1], "unpack-sideband"))
diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c
index cda804ed79..2f65c7f6a5 100644
--- a/t/helper/test-reach.c
+++ b/t/helper/test-reach.c
@@ -166,5 +166,5 @@ int cmd__reach(int ac, const char **av)
print_sorted_commit_ids(list);
}
- exit(0);
+ return 0;
}
diff --git a/t/helper/test-read-midx.c b/t/helper/test-read-midx.c
index 7c2eb11a8e..9d6fa7a377 100644
--- a/t/helper/test-read-midx.c
+++ b/t/helper/test-read-midx.c
@@ -3,6 +3,7 @@
#include "midx.h"
#include "repository.h"
#include "object-store.h"
+#include "pack-bitmap.h"
static int read_midx_file(const char *object_dir, int show_objects)
{
@@ -60,12 +61,52 @@ static int read_midx_file(const char *object_dir, int show_objects)
return 0;
}
+static int read_midx_checksum(const char *object_dir)
+{
+ struct multi_pack_index *m;
+
+ setup_git_directory();
+ m = load_multi_pack_index(object_dir, 1);
+ if (!m)
+ return 1;
+ printf("%s\n", hash_to_hex(get_midx_checksum(m)));
+ return 0;
+}
+
+static int read_midx_preferred_pack(const char *object_dir)
+{
+ struct multi_pack_index *midx = NULL;
+ struct bitmap_index *bitmap = NULL;
+
+ setup_git_directory();
+
+ midx = load_multi_pack_index(object_dir, 1);
+ if (!midx)
+ return 1;
+
+ bitmap = prepare_bitmap_git(the_repository);
+ if (!bitmap)
+ return 1;
+ if (!bitmap_is_midx(bitmap)) {
+ free_bitmap_index(bitmap);
+ return 1;
+ }
+
+ printf("%s\n", midx->pack_names[midx_preferred_pack(bitmap)]);
+ free_bitmap_index(bitmap);
+ return 0;
+}
+
int cmd__read_midx(int argc, const char **argv)
{
if (!(argc == 2 || argc == 3))
- usage("read-midx [--show-objects] <object-dir>");
+ usage("read-midx [--show-objects|--checksum|--preferred-pack] <object-dir>");
if (!strcmp(argv[1], "--show-objects"))
return read_midx_file(argv[2], 1);
+ else if (!strcmp(argv[1], "--checksum"))
+ return read_midx_checksum(argv[2]);
+ else if (!strcmp(argv[1], "--preferred-pack"))
+ return read_midx_preferred_pack(argv[2]);
return read_midx_file(argv[1], 0);
}
diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c
index bba5f841c6..b314b81a45 100644
--- a/t/helper/test-ref-store.c
+++ b/t/helper/test-ref-store.c
@@ -118,7 +118,7 @@ static int cmd_for_each_ref(struct ref_store *refs, const char **argv)
static int cmd_resolve_ref(struct ref_store *refs, const char **argv)
{
- struct object_id oid;
+ struct object_id oid = *null_oid();
const char *refname = notnull(*argv++, "refname");
int resolve_flags = arg_flags(*argv++, "resolve-flags");
int flags;
diff --git a/t/helper/test-run-command.c b/t/helper/test-run-command.c
index 7ae03dc712..3c4fb86223 100644
--- a/t/helper/test-run-command.c
+++ b/t/helper/test-run-command.c
@@ -60,8 +60,10 @@ struct testsuite {
int next;
int quiet, immediate, verbose, verbose_log, trace, write_junit_xml;
};
-#define TESTSUITE_INIT \
- { STRING_LIST_INIT_DUP, STRING_LIST_INIT_DUP, -1, 0, 0, 0, 0, 0, 0 }
+#define TESTSUITE_INIT { \
+ .tests = STRING_LIST_INIT_DUP, \
+ .failed = STRING_LIST_INIT_DUP, \
+}
static int next_test(struct child_process *cp, struct strbuf *err, void *cb,
void **task_cb)
@@ -142,9 +144,6 @@ static int testsuite(int argc, const char **argv)
OPT_END()
};
- memset(&suite, 0, sizeof(suite));
- suite.tests.strdup_strings = suite.failed.strdup_strings = 1;
-
argc = parse_options(argc, argv, NULL, options,
testsuite_usage, PARSE_OPT_STOP_AT_NON_OPTION);
diff --git a/t/helper/test-serve-v2.c b/t/helper/test-serve-v2.c
index aee35e5aef..28e905afc3 100644
--- a/t/helper/test-serve-v2.c
+++ b/t/helper/test-serve-v2.c
@@ -10,12 +10,12 @@ static char const * const serve_usage[] = {
int cmd__serve_v2(int argc, const char **argv)
{
- struct serve_options opts = SERVE_OPTIONS_INIT;
-
+ int stateless_rpc = 0;
+ int advertise_capabilities = 0;
struct option options[] = {
- OPT_BOOL(0, "stateless-rpc", &opts.stateless_rpc,
+ OPT_BOOL(0, "stateless-rpc", &stateless_rpc,
N_("quit after a single request/response exchange")),
- OPT_BOOL(0, "advertise-capabilities", &opts.advertise_capabilities,
+ OPT_BOOL(0, "advertise-capabilities", &advertise_capabilities,
N_("exit immediately after advertising capabilities")),
OPT_END()
};
@@ -25,7 +25,11 @@ int cmd__serve_v2(int argc, const char **argv)
argc = parse_options(argc, argv, prefix, options, serve_usage,
PARSE_OPT_KEEP_DASHDASH |
PARSE_OPT_KEEP_UNKNOWN);
- serve(&opts);
+
+ if (advertise_capabilities)
+ protocol_v2_advertise_capabilities();
+ else
+ protocol_v2_serve_loop(stateless_rpc);
return 0;
}
diff --git a/t/helper/test-simple-ipc.c b/t/helper/test-simple-ipc.c
index 42040ef81b..28365ff85b 100644
--- a/t/helper/test-simple-ipc.c
+++ b/t/helper/test-simple-ipc.c
@@ -9,6 +9,7 @@
#include "parse-options.h"
#include "thread-utils.h"
#include "strvec.h"
+#include "run-command.h"
#ifndef SUPPORTS_SIMPLE_IPC
int cmd__simple_ipc(int argc, const char **argv)
@@ -112,7 +113,7 @@ static int app__slow_command(ipc_server_reply_cb *reply_cb,
/*
* The client sent a command followed by a (possibly very) large buffer.
*/
-static int app__sendbytes_command(const char *received,
+static int app__sendbytes_command(const char *received, size_t received_len,
ipc_server_reply_cb *reply_cb,
struct ipc_server_reply_data *reply_data)
{
@@ -123,6 +124,13 @@ static int app__sendbytes_command(const char *received,
int errs = 0;
int ret;
+ /*
+ * The test is setup to send:
+ * "sendbytes" SP <n * char>
+ */
+ if (received_len < strlen("sendbytes "))
+ BUG("received_len is short in app__sendbytes_command");
+
if (skip_prefix(received, "sendbytes ", &p))
len_ballast = strlen(p);
@@ -160,7 +168,7 @@ static ipc_server_application_cb test_app_cb;
* by this application.
*/
static int test_app_cb(void *application_data,
- const char *command,
+ const char *command, size_t command_len,
ipc_server_reply_cb *reply_cb,
struct ipc_server_reply_data *reply_data)
{
@@ -173,7 +181,7 @@ static int test_app_cb(void *application_data,
if (application_data != (void*)&my_app_data)
BUG("application_cb: application_data pointer wrong");
- if (!strcmp(command, "quit")) {
+ if (command_len == 4 && !strncmp(command, "quit", 4)) {
/*
* The client sent a "quit" command. This is an async
* request for the server to shutdown.
@@ -193,22 +201,23 @@ static int test_app_cb(void *application_data,
return SIMPLE_IPC_QUIT;
}
- if (!strcmp(command, "ping")) {
+ if (command_len == 4 && !strncmp(command, "ping", 4)) {
const char *answer = "pong";
return reply_cb(reply_data, answer, strlen(answer));
}
- if (!strcmp(command, "big"))
+ if (command_len == 3 && !strncmp(command, "big", 3))
return app__big_command(reply_cb, reply_data);
- if (!strcmp(command, "chunk"))
+ if (command_len == 5 && !strncmp(command, "chunk", 5))
return app__chunk_command(reply_cb, reply_data);
- if (!strcmp(command, "slow"))
+ if (command_len == 4 && !strncmp(command, "slow", 4))
return app__slow_command(reply_cb, reply_data);
- if (starts_with(command, "sendbytes "))
- return app__sendbytes_command(command, reply_cb, reply_data);
+ if (command_len >= 10 && starts_with(command, "sendbytes "))
+ return app__sendbytes_command(command, command_len,
+ reply_cb, reply_data);
return app__unhandled_command(command, reply_cb, reply_data);
}
@@ -259,186 +268,72 @@ static int daemon__run_server(void)
*/
ret = ipc_server_run(cl_args.path, &opts, test_app_cb, (void*)&my_app_data);
if (ret == -2)
- error(_("socket/pipe already in use: '%s'"), cl_args.path);
+ error("socket/pipe already in use: '%s'", cl_args.path);
else if (ret == -1)
- error_errno(_("could not start server on: '%s'"), cl_args.path);
+ error_errno("could not start server on: '%s'", cl_args.path);
return ret;
}
-#ifndef GIT_WINDOWS_NATIVE
-/*
- * This is adapted from `daemonize()`. Use `fork()` to directly create and
- * run the daemon in a child process.
- */
-static int spawn_server(pid_t *pid)
-{
- struct ipc_server_opts opts = {
- .nr_threads = cl_args.nr_threads,
- };
-
- *pid = fork();
+static start_bg_wait_cb bg_wait_cb;
- switch (*pid) {
- case 0:
- if (setsid() == -1)
- error_errno(_("setsid failed"));
- close(0);
- close(1);
- close(2);
- sanitize_stdfds();
+static int bg_wait_cb(const struct child_process *cp, void *cb_data)
+{
+ int s = ipc_get_active_state(cl_args.path);
- return ipc_server_run(cl_args.path, &opts, test_app_cb,
- (void*)&my_app_data);
+ switch (s) {
+ case IPC_STATE__LISTENING:
+ /* child is "ready" */
+ return 0;
- case -1:
- return error_errno(_("could not spawn daemon in the background"));
+ case IPC_STATE__NOT_LISTENING:
+ case IPC_STATE__PATH_NOT_FOUND:
+ /* give child more time */
+ return 1;
default:
- return 0;
+ case IPC_STATE__INVALID_PATH:
+ case IPC_STATE__OTHER_ERROR:
+ /* all the time in world won't help */
+ return -1;
}
}
-#else
-/*
- * Conceptually like `daemonize()` but different because Windows does not
- * have `fork(2)`. Spawn a normal Windows child process but without the
- * limitations of `start_command()` and `finish_command()`.
- */
-static int spawn_server(pid_t *pid)
-{
- char test_tool_exe[MAX_PATH];
- struct strvec args = STRVEC_INIT;
- int in, out;
-
- GetModuleFileNameA(NULL, test_tool_exe, MAX_PATH);
-
- in = open("/dev/null", O_RDONLY);
- out = open("/dev/null", O_WRONLY);
-
- strvec_push(&args, test_tool_exe);
- strvec_push(&args, "simple-ipc");
- strvec_push(&args, "run-daemon");
- strvec_pushf(&args, "--name=%s", cl_args.path);
- strvec_pushf(&args, "--threads=%d", cl_args.nr_threads);
- *pid = mingw_spawnvpe(args.v[0], args.v, NULL, NULL, in, out, out);
- close(in);
- close(out);
-
- strvec_clear(&args);
-
- if (*pid < 0)
- return error(_("could not spawn daemon in the background"));
-
- return 0;
-}
-#endif
-
-/*
- * This is adapted from `wait_or_whine()`. Watch the child process and
- * let it get started and begin listening for requests on the socket
- * before reporting our success.
- */
-static int wait_for_server_startup(pid_t pid_child)
+static int daemon__start_server(void)
{
- int status;
- pid_t pid_seen;
- enum ipc_active_state s;
- time_t time_limit, now;
+ struct child_process cp = CHILD_PROCESS_INIT;
+ enum start_bg_result sbgr;
- time(&time_limit);
- time_limit += cl_args.max_wait_sec;
+ strvec_push(&cp.args, "test-tool");
+ strvec_push(&cp.args, "simple-ipc");
+ strvec_push(&cp.args, "run-daemon");
+ strvec_pushf(&cp.args, "--name=%s", cl_args.path);
+ strvec_pushf(&cp.args, "--threads=%d", cl_args.nr_threads);
- for (;;) {
- pid_seen = waitpid(pid_child, &status, WNOHANG);
-
- if (pid_seen == -1)
- return error_errno(_("waitpid failed"));
-
- else if (pid_seen == 0) {
- /*
- * The child is still running (this should be
- * the normal case). Try to connect to it on
- * the socket and see if it is ready for
- * business.
- *
- * If there is another daemon already running,
- * our child will fail to start (possibly
- * after a timeout on the lock), but we don't
- * care (who responds) if the socket is live.
- */
- s = ipc_get_active_state(cl_args.path);
- if (s == IPC_STATE__LISTENING)
- return 0;
+ cp.no_stdin = 1;
+ cp.no_stdout = 1;
+ cp.no_stderr = 1;
- time(&now);
- if (now > time_limit)
- return error(_("daemon not online yet"));
+ sbgr = start_bg_command(&cp, bg_wait_cb, NULL, cl_args.max_wait_sec);
- continue;
- }
+ switch (sbgr) {
+ case SBGR_READY:
+ return 0;
- else if (pid_seen == pid_child) {
- /*
- * The new child daemon process shutdown while
- * it was starting up, so it is not listening
- * on the socket.
- *
- * Try to ping the socket in the odd chance
- * that another daemon started (or was already
- * running) while our child was starting.
- *
- * Again, we don't care who services the socket.
- */
- s = ipc_get_active_state(cl_args.path);
- if (s == IPC_STATE__LISTENING)
- return 0;
+ default:
+ case SBGR_ERROR:
+ case SBGR_CB_ERROR:
+ return error("daemon failed to start");
- /*
- * We don't care about the WEXITSTATUS() nor
- * any of the WIF*(status) values because
- * `cmd__simple_ipc()` does the `!!result`
- * trick on all function return values.
- *
- * So it is sufficient to just report the
- * early shutdown as an error.
- */
- return error(_("daemon failed to start"));
- }
+ case SBGR_TIMEOUT:
+ return error("daemon not online yet");
- else
- return error(_("waitpid is confused"));
+ case SBGR_DIED:
+ return error("daemon terminated");
}
}
/*
- * This process will start a simple-ipc server in a background process and
- * wait for it to become ready. This is like `daemonize()` but gives us
- * more control and better error reporting (and makes it easier to write
- * unit tests).
- */
-static int daemon__start_server(void)
-{
- pid_t pid_child;
- int ret;
-
- /*
- * Run the actual daemon in a background process.
- */
- ret = spawn_server(&pid_child);
- if (pid_child <= 0)
- return ret;
-
- /*
- * Let the parent wait for the child process to get started
- * and begin listening for requests on the socket.
- */
- ret = wait_for_server_startup(pid_child);
-
- return ret;
-}
-
-/*
* This process will run a quick probe to see if a simple-ipc server
* is active on this path.
*
@@ -488,7 +383,9 @@ static int client__send_ipc(void)
options.wait_if_busy = 1;
options.wait_if_not_found = 0;
- if (!ipc_client_send_command(cl_args.path, &options, command, &buf)) {
+ if (!ipc_client_send_command(cl_args.path, &options,
+ command, strlen(command),
+ &buf)) {
if (buf.len) {
printf("%s\n", buf.buf);
fflush(stdout);
@@ -538,7 +435,7 @@ static int client__stop_server(void)
time(&now);
if (now > time_limit)
- return error(_("daemon has not shutdown yet"));
+ return error("daemon has not shutdown yet");
}
}
@@ -556,7 +453,9 @@ static int do_sendbytes(int bytecount, char byte, const char *path,
strbuf_addstr(&buf_send, "sendbytes ");
strbuf_addchars(&buf_send, byte, bytecount);
- if (!ipc_client_send_command(path, options, buf_send.buf, &buf_resp)) {
+ if (!ipc_client_send_command(path, options,
+ buf_send.buf, buf_send.len,
+ &buf_resp)) {
strbuf_rtrim(&buf_resp);
printf("sent:%c%08d %s\n", byte, bytecount, buf_resp.buf);
fflush(stdout);
diff --git a/t/helper/test-submodule-nested-repo-config.c b/t/helper/test-submodule-nested-repo-config.c
index c5fd4527dc..dc1c14bde3 100644
--- a/t/helper/test-submodule-nested-repo-config.c
+++ b/t/helper/test-submodule-nested-repo-config.c
@@ -11,15 +11,13 @@ static void die_usage(const char **argv, const char *msg)
int cmd__submodule_nested_repo_config(int argc, const char **argv)
{
struct repository subrepo;
- const struct submodule *sub;
if (argc < 3)
die_usage(argv, "Wrong number of arguments.");
setup_git_directory();
- sub = submodule_from_path(the_repository, &null_oid, argv[1]);
- if (repo_submodule_init(&subrepo, the_repository, sub)) {
+ if (repo_submodule_init(&subrepo, the_repository, argv[1], null_oid())) {
die_usage(argv, "Submodule not found.");
}
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index c5bd0c6d4c..3ce5585e53 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -33,6 +33,7 @@ static struct test_cmd cmds[] = {
{ "fast-rebase", cmd__fast_rebase },
{ "genrandom", cmd__genrandom },
{ "genzeros", cmd__genzeros },
+ { "getcwd", cmd__getcwd },
{ "hashmap", cmd__hashmap },
{ "hash-speed", cmd__hash_speed },
{ "index-version", cmd__index_version },
@@ -43,9 +44,11 @@ static struct test_cmd cmds[] = {
{ "mktemp", cmd__mktemp },
{ "oid-array", cmd__oid_array },
{ "oidmap", cmd__oidmap },
+ { "oidtree", cmd__oidtree },
{ "online-cpus", cmd__online_cpus },
{ "parse-options", cmd__parse_options },
{ "parse-pathspec-file", cmd__parse_pathspec_file },
+ { "partial-clone", cmd__partial_clone },
{ "path-utils", cmd__path_utils },
{ "pcre2-config", cmd__pcre2_config },
{ "pkt-line", cmd__pkt_line },
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index e8069a3b22..9f0f522850 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -23,6 +23,7 @@ int cmd__example_decorate(int argc, const char **argv);
int cmd__fast_rebase(int argc, const char **argv);
int cmd__genrandom(int argc, const char **argv);
int cmd__genzeros(int argc, const char **argv);
+int cmd__getcwd(int argc, const char **argv);
int cmd__hashmap(int argc, const char **argv);
int cmd__hash_speed(int argc, const char **argv);
int cmd__index_version(int argc, const char **argv);
@@ -32,9 +33,11 @@ int cmd__match_trees(int argc, const char **argv);
int cmd__mergesort(int argc, const char **argv);
int cmd__mktemp(int argc, const char **argv);
int cmd__oidmap(int argc, const char **argv);
+int cmd__oidtree(int argc, const char **argv);
int cmd__online_cpus(int argc, const char **argv);
int cmd__parse_options(int argc, const char **argv);
int cmd__parse_pathspec_file(int argc, const char** argv);
+int cmd__partial_clone(int argc, const char **argv);
int cmd__path_utils(int argc, const char **argv);
int cmd__pcre2_config(int argc, const char **argv);
int cmd__pkt_line(int argc, const char **argv);
diff --git a/t/lib-bitmap.sh b/t/lib-bitmap.sh
index fe3f98be24..21d0392dda 100644
--- a/t/lib-bitmap.sh
+++ b/t/lib-bitmap.sh
@@ -1,3 +1,6 @@
+# Helpers for scripts testing bitmap functionality; see t5310 for
+# example usage.
+
# Compare a file containing rev-list bitmap traversal output to its non-bitmap
# counterpart. You can't just use test_cmp for this, because the two produce
# subtly different output:
@@ -24,3 +27,240 @@ test_bitmap_traversal () {
test_cmp "$1.normalized" "$2.normalized" &&
rm -f "$1.normalized" "$2.normalized"
}
+
+# To ensure the logic for "maximal commits" is exercised, make
+# the repository a bit more complicated.
+#
+# other second
+# * *
+# (99 commits) (99 commits)
+# * *
+# |\ /|
+# | * octo-other octo-second * |
+# |/|\_________ ____________/|\|
+# | \ \/ __________/ |
+# | | ________/\ / |
+# * |/ * merge-right *
+# | _|__________/ \____________ |
+# |/ | \|
+# (l1) * * merge-left * (r1)
+# | / \________________________ |
+# |/ \|
+# (l2) * * (r2)
+# \___________________________ |
+# \|
+# * (base)
+#
+# We only push bits down the first-parent history, which
+# makes some of these commits unimportant!
+#
+# The important part for the maximal commit algorithm is how
+# the bitmasks are extended. Assuming starting bit positions
+# for second (bit 0) and other (bit 1), the bitmasks at the
+# end should be:
+#
+# second: 1 (maximal, selected)
+# other: 01 (maximal, selected)
+# (base): 11 (maximal)
+#
+# This complicated history was important for a previous
+# version of the walk that guarantees never walking a
+# commit multiple times. That goal might be important
+# again, so preserve this complicated case. For now, this
+# test will guarantee that the bitmaps are computed
+# correctly, even with the repeat calculations.
+setup_bitmap_history() {
+ test_expect_success 'setup repo with moderate-sized history' '
+ test_commit_bulk --id=file 10 &&
+ git branch -M second &&
+ git checkout -b other HEAD~5 &&
+ test_commit_bulk --id=side 10 &&
+
+ # add complicated history setup, including merges and
+ # ambiguous merge-bases
+
+ git checkout -b merge-left other~2 &&
+ git merge second~2 -m "merge-left" &&
+
+ git checkout -b merge-right second~1 &&
+ git merge other~1 -m "merge-right" &&
+
+ git checkout -b octo-second second &&
+ git merge merge-left merge-right -m "octopus-second" &&
+
+ git checkout -b octo-other other &&
+ git merge merge-left merge-right -m "octopus-other" &&
+
+ git checkout other &&
+ git merge octo-other -m "pull octopus" &&
+
+ git checkout second &&
+ git merge octo-second -m "pull octopus" &&
+
+ # Remove these branches so they are not selected
+ # as bitmap tips
+ git branch -D merge-left &&
+ git branch -D merge-right &&
+ git branch -D octo-other &&
+ git branch -D octo-second &&
+
+ # add padding to make these merges less interesting
+ # and avoid having them selected for bitmaps
+ test_commit_bulk --id=file 100 &&
+ git checkout other &&
+ test_commit_bulk --id=side 100 &&
+ git checkout second &&
+
+ bitmaptip=$(git rev-parse second) &&
+ blob=$(echo tagged-blob | git hash-object -w --stdin) &&
+ git tag tagged-blob $blob
+ '
+}
+
+rev_list_tests_head () {
+ test_expect_success "counting commits via bitmap ($state, $branch)" '
+ git rev-list --count $branch >expect &&
+ git rev-list --use-bitmap-index --count $branch >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "counting partial commits via bitmap ($state, $branch)" '
+ git rev-list --count $branch~5..$branch >expect &&
+ git rev-list --use-bitmap-index --count $branch~5..$branch >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "counting commits with limit ($state, $branch)" '
+ git rev-list --count -n 1 $branch >expect &&
+ git rev-list --use-bitmap-index --count -n 1 $branch >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "counting non-linear history ($state, $branch)" '
+ git rev-list --count other...second >expect &&
+ git rev-list --use-bitmap-index --count other...second >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "counting commits with limiting ($state, $branch)" '
+ git rev-list --count $branch -- 1.t >expect &&
+ git rev-list --use-bitmap-index --count $branch -- 1.t >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "counting objects via bitmap ($state, $branch)" '
+ git rev-list --count --objects $branch >expect &&
+ git rev-list --use-bitmap-index --count --objects $branch >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "enumerate commits ($state, $branch)" '
+ git rev-list --use-bitmap-index $branch >actual &&
+ git rev-list $branch >expect &&
+ test_bitmap_traversal --no-confirm-bitmaps expect actual
+ '
+
+ test_expect_success "enumerate --objects ($state, $branch)" '
+ git rev-list --objects --use-bitmap-index $branch >actual &&
+ git rev-list --objects $branch >expect &&
+ test_bitmap_traversal expect actual
+ '
+
+ test_expect_success "bitmap --objects handles non-commit objects ($state, $branch)" '
+ git rev-list --objects --use-bitmap-index $branch tagged-blob >actual &&
+ grep $blob actual
+ '
+}
+
+rev_list_tests () {
+ state=$1
+
+ for branch in "second" "other"
+ do
+ rev_list_tests_head
+ done
+}
+
+basic_bitmap_tests () {
+ tip="$1"
+ test_expect_success 'rev-list --test-bitmap verifies bitmaps' "
+ git rev-list --test-bitmap "${tip:-HEAD}"
+ "
+
+ rev_list_tests 'full bitmap'
+
+ test_expect_success 'clone from bitmapped repository' '
+ rm -fr clone.git &&
+ git clone --no-local --bare . clone.git &&
+ git rev-parse HEAD >expect &&
+ git --git-dir=clone.git rev-parse HEAD >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success 'partial clone from bitmapped repository' '
+ test_config uploadpack.allowfilter true &&
+ rm -fr partial-clone.git &&
+ git clone --no-local --bare --filter=blob:none . partial-clone.git &&
+ (
+ cd partial-clone.git &&
+ pack=$(echo objects/pack/*.pack) &&
+ git verify-pack -v "$pack" >have &&
+ awk "/blob/ { print \$1 }" <have >blobs &&
+ # we expect this single blob because of the direct ref
+ git rev-parse refs/tags/tagged-blob >expect &&
+ test_cmp expect blobs
+ )
+ '
+
+ test_expect_success 'setup further non-bitmapped commits' '
+ test_commit_bulk --id=further 10
+ '
+
+ rev_list_tests 'partial bitmap'
+
+ test_expect_success 'fetch (partial bitmap)' '
+ git --git-dir=clone.git fetch origin second:second &&
+ git rev-parse HEAD >expect &&
+ git --git-dir=clone.git rev-parse HEAD >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success 'enumerating progress counts pack-reused objects' '
+ count=$(git rev-list --objects --all --count) &&
+ git repack -adb &&
+
+ # check first with only reused objects; confirm that our
+ # progress showed the right number, and also that we did
+ # pack-reuse as expected. Check only the final "done"
+ # line of the meter (there may be an arbitrary number of
+ # intermediate lines ending with CR).
+ GIT_PROGRESS_DELAY=0 \
+ git pack-objects --all --stdout --progress \
+ </dev/null >/dev/null 2>stderr &&
+ grep "Enumerating objects: $count, done" stderr &&
+ grep "pack-reused $count" stderr &&
+
+ # now the same but with one non-reused object
+ git commit --allow-empty -m "an extra commit object" &&
+ GIT_PROGRESS_DELAY=0 \
+ git pack-objects --all --stdout --progress \
+ </dev/null >/dev/null 2>stderr &&
+ grep "Enumerating objects: $((count+1)), done" stderr &&
+ grep "pack-reused $count" stderr
+ '
+}
+
+# have_delta <obj> <expected_base>
+#
+# Note that because this relies on cat-file, it might find _any_ copy of an
+# object in the repository. The caller is responsible for making sure
+# there's only one (e.g., via "repack -ad", or having just fetched a copy).
+have_delta () {
+ echo $2 >expect &&
+ echo $1 | git cat-file --batch-check="%(deltabase)" >actual &&
+ test_cmp expect actual
+}
+
+midx_checksum () {
+ test-tool read-midx --checksum "$1"
+}
diff --git a/t/lib-encoding.sh b/t/lib-encoding.sh
new file mode 100644
index 0000000000..2dabc8c73e
--- /dev/null
+++ b/t/lib-encoding.sh
@@ -0,0 +1,25 @@
+# Encoding helpers
+
+test_lazy_prereq NO_UTF16_BOM '
+ test $(printf abc | iconv -f UTF-8 -t UTF-16 | wc -c) = 6
+'
+
+test_lazy_prereq NO_UTF32_BOM '
+ test $(printf abc | iconv -f UTF-8 -t UTF-32 | wc -c) = 12
+'
+
+write_utf16 () {
+ if test_have_prereq NO_UTF16_BOM
+ then
+ printf '\376\377'
+ fi &&
+ iconv -f UTF-8 -t UTF-16
+}
+
+write_utf32 () {
+ if test_have_prereq NO_UTF32_BOM
+ then
+ printf '\0\0\376\377'
+ fi &&
+ iconv -f UTF-8 -t UTF-32
+}
diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh
index 547eb3c31a..2fde2353fd 100644
--- a/t/lib-git-svn.sh
+++ b/t/lib-git-svn.sh
@@ -121,12 +121,22 @@ start_svnserve () {
--listen-host 127.0.0.1 &
}
-prepare_a_utf8_locale () {
- a_utf8_locale=$(locale -a | sed -n '/\.[uU][tT][fF]-*8$/{
- p
- q
-}')
- if test -n "$a_utf8_locale"
+prepare_utf8_locale () {
+ if test -z "$GIT_TEST_UTF8_LOCALE"
+ then
+ case "${LC_ALL:-$LANG}" in
+ *.[Uu][Tt][Ff]8 | *.[Uu][Tt][Ff]-8)
+ GIT_TEST_UTF8_LOCALE="${LC_ALL:-$LANG}"
+ ;;
+ *)
+ GIT_TEST_UTF8_LOCALE=$(locale -a | sed -n '/\.[uU][tT][fF]-*8$/{
+ p
+ q
+ }')
+ ;;
+ esac
+ fi
+ if test -n "$GIT_TEST_UTF8_LOCALE"
then
test_set_prereq UTF8
else
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index afa91e38b0..180a41fe96 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -81,8 +81,6 @@ PassEnv GIT_TRACE
PassEnv GIT_CONFIG_NOSYSTEM
PassEnv GIT_TEST_SIDEBAND_ALL
-SetEnvIf Git-Protocol ".*" GIT_PROTOCOL=$0
-
Alias /dumb/ www/
Alias /auth/dumb/ www/auth/dumb/
@@ -117,6 +115,11 @@ Alias /auth/dumb/ www/auth/dumb/
SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
SetEnv GIT_HTTP_EXPORT_ALL
</LocationMatch>
+<LocationMatch /smart_v0/>
+ SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
+ SetEnv GIT_HTTP_EXPORT_ALL
+ SetEnv GIT_PROTOCOL
+</LocationMatch>
ScriptAlias /smart/incomplete_length/git-upload-pack incomplete-length-upload-pack-v2-http.sh/
ScriptAlias /smart/incomplete_body/git-upload-pack incomplete-body-upload-pack-v2-http.sh/
ScriptAliasMatch /error_git_upload_pack/(.*)/git-upload-pack error.sh/
diff --git a/t/lib-midx.sh b/t/lib-midx.sh
new file mode 100644
index 0000000000..1261994744
--- /dev/null
+++ b/t/lib-midx.sh
@@ -0,0 +1,8 @@
+# test_midx_consistent <objdir>
+test_midx_consistent () {
+ ls $1/pack/pack-*.idx | xargs -n 1 basename | sort >expect &&
+ test-tool read-midx $1 | grep ^pack-.*\.idx$ | sort >actual &&
+
+ test_cmp expect actual &&
+ git multi-pack-index --object-dir=$1 verify
+}
diff --git a/t/lib-parallel-checkout.sh b/t/lib-parallel-checkout.sh
new file mode 100644
index 0000000000..83b279a846
--- /dev/null
+++ b/t/lib-parallel-checkout.sh
@@ -0,0 +1,45 @@
+# Helpers for tests invoking parallel-checkout
+
+# Parallel checkout tests need full control of the number of workers
+unset GIT_TEST_CHECKOUT_WORKERS
+
+set_checkout_config () {
+ if test $# -ne 2
+ then
+ BUG "usage: set_checkout_config <workers> <threshold>"
+ fi &&
+
+ test_config_global checkout.workers $1 &&
+ test_config_global checkout.thresholdForParallelism $2
+}
+
+# Run "${@:2}" and check that $1 checkout workers were used
+test_checkout_workers () {
+ if test $# -lt 2
+ then
+ BUG "too few arguments to test_checkout_workers"
+ fi &&
+
+ local expected_workers=$1 &&
+ shift &&
+
+ local trace_file=trace-test-checkout-workers &&
+ rm -f "$trace_file" &&
+ GIT_TRACE2="$(pwd)/$trace_file" "$@" 2>&8 &&
+
+ local workers="$(grep "child_start\[..*\] git checkout--worker" "$trace_file" | wc -l)" &&
+ test $workers -eq $expected_workers &&
+ rm "$trace_file"
+} 8>&2 2>&4
+
+# Verify that both the working tree and the index were created correctly
+verify_checkout () {
+ if test $# -ne 1
+ then
+ BUG "usage: verify_checkout <repository path>"
+ fi &&
+
+ git -C "$1" diff-index --ignore-submodules=none --exit-code HEAD -- &&
+ git -C "$1" status --porcelain >"$1".status &&
+ test_must_be_empty "$1".status
+}
diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh
index dc75b83451..ec6b9b107d 100644
--- a/t/lib-rebase.sh
+++ b/t/lib-rebase.sh
@@ -151,3 +151,59 @@ test_editor_unchanged () {
EOF
test_cmp expect actual
}
+
+# Set up an editor for testing reword commands
+# Checks that there are no uncommitted changes when rewording and that the
+# todo-list is reread after each
+set_reword_editor () {
+ >reword-actual &&
+ >reword-oid &&
+
+ # Check rewording keeps the original authorship
+ GIT_AUTHOR_NAME="Reword Author"
+ GIT_AUTHOR_EMAIL="reword.author@example.com"
+ GIT_AUTHOR_DATE=@123456
+
+ write_script reword-sequence-editor.sh <<-\EOF &&
+ todo="$(cat "$1")" &&
+ echo "exec git log -1 --pretty=format:'%an <%ae> %at%n%B%n' \
+ >>reword-actual" >"$1" &&
+ printf "%s\n" "$todo" >>"$1"
+ EOF
+
+ write_script reword-editor.sh <<-EOF &&
+ # Save the oid of the first reworded commit so we can check rebase
+ # fast-forwards to it. Also check that we do not write .git/MERGE_MSG
+ # when fast-forwarding
+ if ! test -s reword-oid
+ then
+ git rev-parse HEAD >reword-oid &&
+ if test -f .git/MERGE_MSG
+ then
+ echo 1>&2 "error: .git/MERGE_MSG exists"
+ exit 1
+ fi
+ fi &&
+ # There should be no uncommited changes
+ git diff --exit-code HEAD &&
+ # The todo-list should be re-read after a reword
+ GIT_SEQUENCE_EDITOR="\"$PWD/reword-sequence-editor.sh\"" \
+ git rebase --edit-todo &&
+ echo edited >>"\$1"
+ EOF
+
+ test_set_editor "$PWD/reword-editor.sh"
+}
+
+# Check the results of a rebase after calling set_reword_editor
+# Pass the commits that were reworded in the order that they were picked
+# Expects the first pick to be a fast-forward
+check_reworded_commits () {
+ test_cmp_rev "$(cat reword-oid)" "$1^{commit}" &&
+ git log --format="%an <%ae> %at%n%B%nedited%n" --no-walk=unsorted "$@" \
+ >reword-expected &&
+ test_cmp reword-expected reword-actual &&
+ git log --format="%an <%ae> %at%n%B" -n $# --first-parent --reverse \
+ >reword-log &&
+ test_cmp reword-expected reword-log
+}
diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh
index 4b714e9308..f7c7df0ca4 100644
--- a/t/lib-submodule-update.sh
+++ b/t/lib-submodule-update.sh
@@ -63,6 +63,7 @@ create_lib_submodule_repo () {
git init submodule_update_repo &&
(
cd submodule_update_repo &&
+ branch=$(git symbolic-ref --short HEAD) &&
echo "expect" >>.gitignore &&
echo "actual" >>.gitignore &&
echo "x" >file1 &&
@@ -144,7 +145,7 @@ create_lib_submodule_repo () {
git checkout -b valid_sub1 &&
git revert HEAD &&
- git checkout "${GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME-master}"
+ git checkout "$branch"
)
}
diff --git a/t/lib-subtest.sh b/t/lib-subtest.sh
new file mode 100644
index 0000000000..56ee927f0c
--- /dev/null
+++ b/t/lib-subtest.sh
@@ -0,0 +1,95 @@
+write_sub_test_lib_test () {
+ name="$1" # stdin is the body of the test code
+ mkdir "$name" &&
+ write_script "$name/$name.sh" "$TEST_SHELL_PATH" <<-EOF &&
+ test_description='A test of test-lib.sh itself'
+
+ # Point to the t/test-lib.sh, which isn't in ../ as usual
+ . "\$TEST_DIRECTORY"/test-lib.sh
+ EOF
+ cat >>"$name/$name.sh"
+}
+
+_run_sub_test_lib_test_common () {
+ cmp_op="$1" want_code="$2" name="$3" # stdin is the body of the test code
+ shift 3
+
+ # intercept pseudo-options at the front of the argument list that we
+ # will not pass to child script
+ skip=
+ while test $# -gt 0
+ do
+ case "$1" in
+ --skip=*)
+ skip=${1#--*=}
+ shift
+ ;;
+ *)
+ break
+ ;;
+ esac
+ done
+
+ (
+ cd "$name" &&
+
+ # Pretend we're not running under a test harness, whether we
+ # are or not. The test-lib output depends on the setting of
+ # this variable, so we need a stable setting under which to run
+ # the sub-test.
+ sane_unset HARNESS_ACTIVE &&
+
+ export TEST_DIRECTORY &&
+ # The child test re-sources GIT-BUILD-OPTIONS and may thus
+ # override the test output directory. We thus pass it as an
+ # explicit override to the child.
+ TEST_OUTPUT_DIRECTORY_OVERRIDE=$(pwd) &&
+ export TEST_OUTPUT_DIRECTORY_OVERRIDE &&
+ GIT_SKIP_TESTS=$skip &&
+ export GIT_SKIP_TESTS &&
+ sane_unset GIT_TEST_FAIL_PREREQS &&
+ ./"$name.sh" "$@" >out 2>err;
+ ret=$? &&
+ test "$ret" "$cmp_op" "$want_code"
+ )
+}
+
+write_and_run_sub_test_lib_test () {
+ name="$1" descr="$2" # stdin is the body of the test code
+ write_sub_test_lib_test "$@" || return 1
+ _run_sub_test_lib_test_common -eq 0 "$@"
+}
+
+write_and_run_sub_test_lib_test_err () {
+ name="$1" descr="$2" # stdin is the body of the test code
+ write_sub_test_lib_test "$@" || return 1
+ _run_sub_test_lib_test_common -eq 1 "$@"
+}
+
+run_sub_test_lib_test () {
+ _run_sub_test_lib_test_common -eq 0 "$@"
+}
+
+run_sub_test_lib_test_err () {
+ _run_sub_test_lib_test_common -eq 1 "$@"
+}
+
+_check_sub_test_lib_test_common () {
+ name="$1" &&
+ sed -e 's/^> //' -e 's/Z$//' >"$name"/expect.out &&
+ test_cmp "$name"/expect.out "$name"/out
+}
+
+check_sub_test_lib_test () {
+ name="$1" # stdin is the expected output from the test
+ _check_sub_test_lib_test_common "$name" &&
+ test_must_be_empty "$name"/err
+}
+
+check_sub_test_lib_test_err () {
+ name="$1" # stdin is the expected output from the test
+ _check_sub_test_lib_test_common "$name" &&
+ # expected error output is in descriptor 3
+ sed -e 's/^> //' -e 's/Z$//' <&3 >"$name"/expect.err &&
+ test_cmp "$name"/expect.err "$name"/err
+}
diff --git a/t/perf/aggregate.perl b/t/perf/aggregate.perl
index 14e4cda287..575d2000cc 100755
--- a/t/perf/aggregate.perl
+++ b/t/perf/aggregate.perl
@@ -17,8 +17,8 @@ sub get_times {
my $rt = ((defined $1 ? $1 : 0.0)*60+$2)*60+$3;
return ($rt, $4, $5);
# size
- } elsif ($line =~ /^\d+$/) {
- return $&;
+ } elsif ($line =~ /^\s*(\d+)$/) {
+ return $1;
} else {
die "bad input line: $line";
}
@@ -58,6 +58,7 @@ sub usage {
Options:
--codespeed * Format output for Codespeed
--reponame <str> * Send given reponame to codespeed
+ --results-dir <str> * Directory where test results are located
--sort-by <str> * Sort output (only "regression" criteria is supported)
--subsection <str> * Use results from given subsection
@@ -91,11 +92,13 @@ sub sane_backticks {
my (@dirs, %dirnames, %dirabbrevs, %prefixes, @tests,
$codespeed, $sortby, $subsection, $reponame);
+my $resultsdir = "test-results";
Getopt::Long::Configure qw/ require_order /;
my $rc = GetOptions("codespeed" => \$codespeed,
"reponame=s" => \$reponame,
+ "results-dir=s" => \$resultsdir,
"sort-by=s" => \$sortby,
"subsection=s" => \$subsection);
usage() unless $rc;
@@ -137,8 +140,6 @@ if (not @tests) {
@tests = glob "p????-*.sh";
}
-my $resultsdir = "test-results";
-
if (! $subsection and
exists $ENV{GIT_PERF_SUBSECTION} and
$ENV{GIT_PERF_SUBSECTION} ne "") {
diff --git a/t/perf/lib-bitmap.sh b/t/perf/lib-bitmap.sh
new file mode 100644
index 0000000000..63d3bc7cec
--- /dev/null
+++ b/t/perf/lib-bitmap.sh
@@ -0,0 +1,69 @@
+# Helper functions for testing bitmap performance; see p5310.
+
+test_full_bitmap () {
+ test_perf 'simulated clone' '
+ git pack-objects --stdout --all </dev/null >/dev/null
+ '
+
+ test_perf 'simulated fetch' '
+ have=$(git rev-list HEAD~100 -1) &&
+ {
+ echo HEAD &&
+ echo ^$have
+ } | git pack-objects --revs --stdout >/dev/null
+ '
+
+ test_perf 'pack to file (bitmap)' '
+ git pack-objects --use-bitmap-index --all pack1b </dev/null >/dev/null
+ '
+
+ test_perf 'rev-list (commits)' '
+ git rev-list --all --use-bitmap-index >/dev/null
+ '
+
+ test_perf 'rev-list (objects)' '
+ git rev-list --all --use-bitmap-index --objects >/dev/null
+ '
+
+ test_perf 'rev-list with tag negated via --not --all (objects)' '
+ git rev-list perf-tag --not --all --use-bitmap-index --objects >/dev/null
+ '
+
+ test_perf 'rev-list with negative tag (objects)' '
+ git rev-list HEAD --not perf-tag --use-bitmap-index --objects >/dev/null
+ '
+
+ test_perf 'rev-list count with blob:none' '
+ git rev-list --use-bitmap-index --count --objects --all \
+ --filter=blob:none >/dev/null
+ '
+
+ test_perf 'rev-list count with blob:limit=1k' '
+ git rev-list --use-bitmap-index --count --objects --all \
+ --filter=blob:limit=1k >/dev/null
+ '
+
+ test_perf 'rev-list count with tree:0' '
+ git rev-list --use-bitmap-index --count --objects --all \
+ --filter=tree:0 >/dev/null
+ '
+
+ test_perf 'simulated partial clone' '
+ git pack-objects --stdout --all --filter=blob:none </dev/null >/dev/null
+ '
+}
+
+test_partial_bitmap () {
+ test_perf 'clone (partial bitmap)' '
+ git pack-objects --stdout --all </dev/null >/dev/null
+ '
+
+ test_perf 'pack to file (partial bitmap)' '
+ git pack-objects --use-bitmap-index --all pack2b </dev/null >/dev/null
+ '
+
+ test_perf 'rev-list with tree filter (partial bitmap)' '
+ git rev-list --use-bitmap-index --count --objects --all \
+ --filter=tree:0 >/dev/null
+ '
+}
diff --git a/t/perf/p0071-sort.sh b/t/perf/p0071-sort.sh
index 6e924f5fa3..ed366e2e12 100755
--- a/t/perf/p0071-sort.sh
+++ b/t/perf/p0071-sort.sh
@@ -11,16 +11,42 @@ test_expect_success 'setup' '
git cat-file --batch >unsorted
'
-test_perf 'sort(1)' '
- sort <unsorted >expect
+test_perf 'sort(1) unsorted' '
+ sort <unsorted >sorted
'
-test_perf 'string_list_sort()' '
- test-tool string-list sort <unsorted >actual
+test_expect_success 'reverse' '
+ sort -r <unsorted >reversed
'
-test_expect_success 'string_list_sort() sorts like sort(1)' '
- test_cmp_bin expect actual
-'
+for file in sorted reversed
+do
+ test_perf "sort(1) $file" "
+ sort <$file >actual
+ "
+done
+
+for file in unsorted sorted reversed
+do
+
+ test_perf "string_list_sort() $file" "
+ test-tool string-list sort <$file >actual
+ "
+
+ test_expect_success "string_list_sort() $file sorts like sort(1)" "
+ test_cmp_bin sorted actual
+ "
+done
+
+for file in unsorted sorted reversed
+do
+ test_perf "llist_mergesort() $file" "
+ test-tool mergesort sort <$file >actual
+ "
+
+ test_expect_success "llist_mergesort() $file sorts like sort(1)" "
+ test_cmp_bin sorted actual
+ "
+done
test_done
diff --git a/t/perf/p2000-sparse-operations.sh b/t/perf/p2000-sparse-operations.sh
index 94513c9774..597626276f 100755
--- a/t/perf/p2000-sparse-operations.sh
+++ b/t/perf/p2000-sparse-operations.sh
@@ -6,7 +6,7 @@ test_description="test performance of Git operations using the index"
test_perf_default_repo
-SPARSE_CONE=f2/f4/f1
+SPARSE_CONE=f2/f4
test_expect_success 'setup repo and indexes' '
git reset --hard HEAD &&
@@ -27,7 +27,7 @@ test_expect_success 'setup repo and indexes' '
OLD_COMMIT=$(git rev-parse HEAD) &&
OLD_TREE=$(git rev-parse HEAD^{tree}) &&
- for i in $(test_seq 1 4)
+ for i in $(test_seq 1 3)
do
cat >in <<-EOF &&
100755 blob $BLOB a
@@ -43,45 +43,57 @@ test_expect_success 'setup repo and indexes' '
done &&
git sparse-checkout init --cone &&
- git branch -f wide $OLD_COMMIT &&
- git -c core.sparseCheckoutCone=true clone --branch=wide --sparse . full-index-v3 &&
+ git sparse-checkout set $SPARSE_CONE &&
+ git checkout -b wide $OLD_COMMIT &&
+
+ for l2 in f1 f2 f3 f4
+ do
+ echo more bogus >>$SPARSE_CONE/$l2/a &&
+ git commit -a -m "edit $SPARSE_CONE/$l2/a" || return 1
+ done &&
+
+ git -c core.sparseCheckoutCone=true clone --branch=wide --sparse . full-v3 &&
(
- cd full-index-v3 &&
+ cd full-v3 &&
git sparse-checkout init --cone &&
git sparse-checkout set $SPARSE_CONE &&
git config index.version 3 &&
- git update-index --index-version=3
+ git update-index --index-version=3 &&
+ git checkout HEAD~4
) &&
- git -c core.sparseCheckoutCone=true clone --branch=wide --sparse . full-index-v4 &&
+ git -c core.sparseCheckoutCone=true clone --branch=wide --sparse . full-v4 &&
(
- cd full-index-v4 &&
+ cd full-v4 &&
git sparse-checkout init --cone &&
git sparse-checkout set $SPARSE_CONE &&
git config index.version 4 &&
- git update-index --index-version=4
+ git update-index --index-version=4 &&
+ git checkout HEAD~4
) &&
- git -c core.sparseCheckoutCone=true clone --branch=wide --sparse . sparse-index-v3 &&
+ git -c core.sparseCheckoutCone=true clone --branch=wide --sparse . sparse-v3 &&
(
- cd sparse-index-v3 &&
+ cd sparse-v3 &&
git sparse-checkout init --cone --sparse-index &&
git sparse-checkout set $SPARSE_CONE &&
git config index.version 3 &&
- git update-index --index-version=3
+ git update-index --index-version=3 &&
+ git checkout HEAD~4
) &&
- git -c core.sparseCheckoutCone=true clone --branch=wide --sparse . sparse-index-v4 &&
+ git -c core.sparseCheckoutCone=true clone --branch=wide --sparse . sparse-v4 &&
(
- cd sparse-index-v4 &&
+ cd sparse-v4 &&
git sparse-checkout init --cone --sparse-index &&
git sparse-checkout set $SPARSE_CONE &&
git config index.version 4 &&
- git update-index --index-version=4
+ git update-index --index-version=4 &&
+ git checkout HEAD~4
)
'
test_perf_on_all () {
command="$@"
- for repo in full-index-v3 full-index-v4 \
- sparse-index-v3 sparse-index-v4
+ for repo in full-v3 full-v4 \
+ sparse-v3 sparse-v4
do
test_perf "$command ($repo)" "
(
@@ -97,5 +109,6 @@ test_perf_on_all git status
test_perf_on_all git add -A
test_perf_on_all git add .
test_perf_on_all git commit -a -m A
+test_perf_on_all git checkout -f -
test_done
diff --git a/t/perf/p3400-rebase.sh b/t/perf/p3400-rebase.sh
index 7a0bb29448..43d5a34e8c 100755
--- a/t/perf/p3400-rebase.sh
+++ b/t/perf/p3400-rebase.sh
@@ -18,7 +18,7 @@ test_expect_success 'setup rebasing on top of a lot of changes' '
test_tick &&
git commit -m commit$i unrelated-file$i &&
echo change$i >unrelated-file$i &&
- test_seq 1000 | tac >>unrelated-file$i &&
+ test_seq 1000 | sort -nr >>unrelated-file$i &&
git add unrelated-file$i &&
test_tick &&
git commit -m commit$i-reverse unrelated-file$i ||
diff --git a/t/perf/p4209-pickaxe.sh b/t/perf/p4209-pickaxe.sh
new file mode 100755
index 0000000000..f585a4465a
--- /dev/null
+++ b/t/perf/p4209-pickaxe.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+
+test_description="Test pickaxe performance"
+
+. ./perf-lib.sh
+
+test_perf_default_repo
+
+# Not --max-count, as that's the number of matching commit, so it's
+# unbounded. We want to limit our revision walk here.
+from_rev_desc=
+from_rev=
+max_count=1000
+if test_have_prereq EXPENSIVE
+then
+ max_count=10000
+fi
+from_rev=" $(git rev-list HEAD | head -n $max_count | tail -n 1).."
+from_rev_desc=" <limit-rev>.."
+
+for icase in \
+ '' \
+ '-i '
+do
+ # -S (no regex)
+ for pattern in \
+ 'int main' \
+ 'æ'
+ do
+ for opts in \
+ '-S'
+ do
+ test_perf "git log $icase$opts'$pattern'$from_rev_desc" "
+ git log --pretty=format:%H $icase$opts'$pattern'$from_rev
+ "
+ done
+ done
+
+ # -S (regex)
+ for pattern in \
+ '(int|void|null)' \
+ 'if *\([^ ]+ & ' \
+ '[àáâãäåæñøùúûüýþ]'
+ do
+ for opts in \
+ '--pickaxe-regex -S'
+ do
+ test_perf "git log $icase$opts'$pattern'$from_rev_desc" "
+ git log --pretty=format:%H $icase$opts'$pattern'$from_rev
+ "
+ done
+ done
+
+ # -G
+ for pattern in \
+ '(int|void|null)' \
+ 'if *\([^ ]+ & ' \
+ '[àáâãäåæñøùúûüýþ]'
+ do
+ for opts in \
+ '-G'
+ do
+ test_perf "git log $icase$opts'$pattern'$from_rev_desc" "
+ git log --pretty=format:%H $icase$opts'$pattern'$from_rev
+ "
+ done
+ done
+done
+
+test_done
diff --git a/t/perf/p5310-pack-bitmaps.sh b/t/perf/p5310-pack-bitmaps.sh
index 452be01056..7ad4f237bc 100755
--- a/t/perf/p5310-pack-bitmaps.sh
+++ b/t/perf/p5310-pack-bitmaps.sh
@@ -2,6 +2,7 @@
test_description='Tests pack performance using bitmaps'
. ./perf-lib.sh
+. "${TEST_DIRECTORY}/perf/lib-bitmap.sh"
test_perf_large_repo
@@ -25,56 +26,7 @@ test_perf 'repack to disk' '
git repack -ad
'
-test_perf 'simulated clone' '
- git pack-objects --stdout --all </dev/null >/dev/null
-'
-
-test_perf 'simulated fetch' '
- have=$(git rev-list HEAD~100 -1) &&
- {
- echo HEAD &&
- echo ^$have
- } | git pack-objects --revs --stdout >/dev/null
-'
-
-test_perf 'pack to file (bitmap)' '
- git pack-objects --use-bitmap-index --all pack1b </dev/null >/dev/null
-'
-
-test_perf 'rev-list (commits)' '
- git rev-list --all --use-bitmap-index >/dev/null
-'
-
-test_perf 'rev-list (objects)' '
- git rev-list --all --use-bitmap-index --objects >/dev/null
-'
-
-test_perf 'rev-list with tag negated via --not --all (objects)' '
- git rev-list perf-tag --not --all --use-bitmap-index --objects >/dev/null
-'
-
-test_perf 'rev-list with negative tag (objects)' '
- git rev-list HEAD --not perf-tag --use-bitmap-index --objects >/dev/null
-'
-
-test_perf 'rev-list count with blob:none' '
- git rev-list --use-bitmap-index --count --objects --all \
- --filter=blob:none >/dev/null
-'
-
-test_perf 'rev-list count with blob:limit=1k' '
- git rev-list --use-bitmap-index --count --objects --all \
- --filter=blob:limit=1k >/dev/null
-'
-
-test_perf 'rev-list count with tree:0' '
- git rev-list --use-bitmap-index --count --objects --all \
- --filter=tree:0 >/dev/null
-'
-
-test_perf 'simulated partial clone' '
- git pack-objects --stdout --all --filter=blob:none </dev/null >/dev/null
-'
+test_full_bitmap
test_expect_success 'create partial bitmap state' '
# pick a commit to represent the repo tip in the past
@@ -97,17 +49,6 @@ test_expect_success 'create partial bitmap state' '
git update-ref HEAD $orig_tip
'
-test_perf 'clone (partial bitmap)' '
- git pack-objects --stdout --all </dev/null >/dev/null
-'
-
-test_perf 'pack to file (partial bitmap)' '
- git pack-objects --use-bitmap-index --all pack2b </dev/null >/dev/null
-'
-
-test_perf 'rev-list with tree filter (partial bitmap)' '
- git rev-list --use-bitmap-index --count --objects --all \
- --filter=tree:0 >/dev/null
-'
+test_partial_bitmap
test_done
diff --git a/t/perf/p5326-multi-pack-bitmaps.sh b/t/perf/p5326-multi-pack-bitmaps.sh
new file mode 100755
index 0000000000..f2fa228f16
--- /dev/null
+++ b/t/perf/p5326-multi-pack-bitmaps.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+test_description='Tests performance using midx bitmaps'
+. ./perf-lib.sh
+. "${TEST_DIRECTORY}/perf/lib-bitmap.sh"
+
+test_perf_large_repo
+
+# we need to create the tag up front such that it is covered by the repack and
+# thus by generated bitmaps.
+test_expect_success 'create tags' '
+ git tag --message="tag pointing to HEAD" perf-tag HEAD
+'
+
+test_expect_success 'start with bitmapped pack' '
+ git repack -adb
+'
+
+test_perf 'setup multi-pack index' '
+ git multi-pack-index write --bitmap
+'
+
+test_expect_success 'drop pack bitmap' '
+ rm -f .git/objects/pack/pack-*.bitmap
+'
+
+test_full_bitmap
+
+test_expect_success 'create partial bitmap state' '
+ # pick a commit to represent the repo tip in the past
+ cutoff=$(git rev-list HEAD~100 -1) &&
+ orig_tip=$(git rev-parse HEAD) &&
+
+ # now pretend we have just one tip
+ rm -rf .git/logs .git/refs/* .git/packed-refs &&
+ git update-ref HEAD $cutoff &&
+
+ # and then repack, which will leave us with a nice
+ # big bitmap pack of the "old" history, and all of
+ # the new history will be loose, as if it had been pushed
+ # up incrementally and exploded via unpack-objects
+ git repack -Ad &&
+ git multi-pack-index write --bitmap &&
+
+ # and now restore our original tip, as if the pushes
+ # had happened
+ git update-ref HEAD $orig_tip
+'
+
+test_partial_bitmap
+
+test_done
diff --git a/t/perf/p5600-partial-clone.sh b/t/perf/p5600-partial-clone.sh
index ca785a3341..a965f2c4d6 100755
--- a/t/perf/p5600-partial-clone.sh
+++ b/t/perf/p5600-partial-clone.sh
@@ -35,4 +35,8 @@ test_perf 'count non-promisor commits' '
git -C bare.git rev-list --all --count --exclude-promisor-objects
'
+test_perf 'gc' '
+ git -C bare.git gc
+'
+
test_done
diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh
index 601d9f67dd..f5ed092ee5 100644
--- a/t/perf/perf-lib.sh
+++ b/t/perf/perf-lib.sh
@@ -45,7 +45,7 @@ export TEST_DIRECTORY TRASH_DIRECTORY GIT_BUILD_DIR GIT_TEST_CMP
MODERN_GIT=$GIT_BUILD_DIR/bin-wrappers/git
export MODERN_GIT
-perf_results_dir=$TEST_OUTPUT_DIRECTORY/test-results
+perf_results_dir=$TEST_RESULTS_DIR
test -n "$GIT_PERF_SUBSECTION" && perf_results_dir="$perf_results_dir/$GIT_PERF_SUBSECTION"
mkdir -p "$perf_results_dir"
rm -f "$perf_results_dir"/$(basename "$0" .sh).subtests
@@ -253,7 +253,10 @@ test_size () {
# and does it after running everything)
test_at_end_hook_ () {
if test -z "$GIT_PERF_AGGREGATING_LATER"; then
- ( cd "$TEST_DIRECTORY"/perf && ./aggregate.perl $(basename "$0") )
+ (
+ cd "$TEST_DIRECTORY"/perf &&
+ ./aggregate.perl --results-dir="$TEST_RESULTS_DIR" $(basename "$0")
+ )
fi
}
diff --git a/t/perf/run b/t/perf/run
index c7b86104e1..55219aa405 100755
--- a/t/perf/run
+++ b/t/perf/run
@@ -74,7 +74,7 @@ set_git_test_installed () {
mydir=$1
mydir_abs=$(cd $mydir && pwd)
- mydir_abs_wrappers="$mydir_abs_wrappers/bin-wrappers"
+ mydir_abs_wrappers="$mydir_abs/bin-wrappers"
if test -d "$mydir_abs_wrappers"
then
GIT_TEST_INSTALLED=$mydir_abs_wrappers
@@ -188,10 +188,10 @@ run_subsection () {
if test -z "$GIT_PERF_SEND_TO_CODESPEED"
then
- ./aggregate.perl $codespeed_opt "$@"
+ ./aggregate.perl --results-dir="$TEST_RESULTS_DIR" $codespeed_opt "$@"
else
- json_res_file="test-results/$GIT_PERF_SUBSECTION/aggregate.json"
- ./aggregate.perl --codespeed "$@" | tee "$json_res_file"
+ json_res_file=""$TEST_RESULTS_DIR"/$GIT_PERF_SUBSECTION/aggregate.json"
+ ./aggregate.perl --results-dir="$TEST_RESULTS_DIR" --codespeed "$@" | tee "$json_res_file"
send_data_url="$GIT_PERF_SEND_TO_CODESPEED/result/add/json/"
curl -v --request POST --data-urlencode "json=$(cat "$json_res_file")" "$send_data_url"
fi
@@ -203,10 +203,17 @@ get_var_from_env_or_config "GIT_PERF_SEND_TO_CODESPEED" "perf" "sendToCodespeed"
cd "$(dirname $0)"
. ../../GIT-BUILD-OPTIONS
-mkdir -p test-results
-get_subsections "perf" >test-results/run_subsections.names
+if test -n "$TEST_OUTPUT_DIRECTORY"
+then
+ TEST_RESULTS_DIR="$TEST_OUTPUT_DIRECTORY/test-results"
+else
+ TEST_RESULTS_DIR=test-results
+fi
+
+mkdir -p "$TEST_RESULTS_DIR"
+get_subsections "perf" >"$TEST_RESULTS_DIR"/run_subsections.names
-if test $(wc -l <test-results/run_subsections.names) -eq 0
+if test $(wc -l <"$TEST_RESULTS_DIR"/run_subsections.names) -eq 0
then
if test -n "$GIT_PERF_SUBSECTION"
then
@@ -222,10 +229,10 @@ then
)
elif test -n "$GIT_PERF_SUBSECTION"
then
- egrep "^$GIT_PERF_SUBSECTION\$" test-results/run_subsections.names >/dev/null ||
+ egrep "^$GIT_PERF_SUBSECTION\$" "$TEST_RESULTS_DIR"/run_subsections.names >/dev/null ||
die "subsection '$GIT_PERF_SUBSECTION' not found in '$GIT_PERF_CONFIG_FILE'"
- egrep "^$GIT_PERF_SUBSECTION\$" test-results/run_subsections.names | while read -r subsec
+ egrep "^$GIT_PERF_SUBSECTION\$" "$TEST_RESULTS_DIR"/run_subsections.names | while read -r subsec
do
(
GIT_PERF_SUBSECTION="$subsec"
@@ -243,5 +250,5 @@ else
echo "======== Run for subsection '$GIT_PERF_SUBSECTION' ========"
run_subsection "$@"
)
- done <test-results/run_subsections.names
+ done <"$TEST_RESULTS_DIR"/run_subsections.names
fi
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 705d62cc27..b007f0efef 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -19,6 +19,7 @@ modification *should* take notice and update the test vectors here.
'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-subtest.sh
try_local_xy () {
local x="local" y="alsolocal" &&
@@ -66,77 +67,8 @@ test_expect_success 'success is reported like this' '
:
'
-_run_sub_test_lib_test_common () {
- neg="$1" name="$2" descr="$3" # stdin is the body of the test code
- shift 3
- mkdir "$name" &&
- (
- # Pretend we're not running under a test harness, whether we
- # are or not. The test-lib output depends on the setting of
- # this variable, so we need a stable setting under which to run
- # the sub-test.
- sane_unset HARNESS_ACTIVE &&
- cd "$name" &&
- write_script "$name.sh" "$TEST_SHELL_PATH" <<-EOF &&
- test_description='$descr (run in sub test-lib)
-
- This is run in a sub test-lib so that we do not get incorrect
- passing metrics
- '
-
- # Tell the framework that we are self-testing to make sure
- # it yields a stable result.
- GIT_TEST_FRAMEWORK_SELFTEST=t &&
-
- # Point to the t/test-lib.sh, which isn't in ../ as usual
- . "\$TEST_DIRECTORY"/test-lib.sh
- EOF
- cat >>"$name.sh" &&
- export TEST_DIRECTORY &&
- TEST_OUTPUT_DIRECTORY=$(pwd) &&
- export TEST_OUTPUT_DIRECTORY &&
- sane_unset GIT_TEST_FAIL_PREREQS &&
- if test -z "$neg"
- then
- ./"$name.sh" "$@" >out 2>err
- else
- ! ./"$name.sh" "$@" >out 2>err
- fi
- )
-}
-
-run_sub_test_lib_test () {
- _run_sub_test_lib_test_common '' "$@"
-}
-
-run_sub_test_lib_test_err () {
- _run_sub_test_lib_test_common '!' "$@"
-}
-
-check_sub_test_lib_test () {
- name="$1" # stdin is the expected output from the test
- (
- cd "$name" &&
- test_must_be_empty err &&
- sed -e 's/^> //' -e 's/Z$//' >expect &&
- test_cmp expect out
- )
-}
-
-check_sub_test_lib_test_err () {
- name="$1" # stdin is the expected output from the test
- # expected error output is in descriptor 3
- (
- cd "$name" &&
- sed -e 's/^> //' -e 's/Z$//' >expect.out &&
- test_cmp expect.out out &&
- sed -e 's/^> //' -e 's/Z$//' <&3 >expect.err &&
- test_cmp expect.err err
- )
-}
-
-test_expect_success 'pretend we have a fully passing test suite' '
- run_sub_test_lib_test full-pass "3 passing tests" <<-\EOF &&
+test_expect_success 'subtest: 3 passing tests' '
+ write_and_run_sub_test_lib_test full-pass <<-\EOF &&
for i in 1 2 3
do
test_expect_success "passing test #$i" "true"
@@ -152,9 +84,8 @@ test_expect_success 'pretend we have a fully passing test suite' '
EOF
'
-test_expect_success 'pretend we have a partially passing test suite' '
- run_sub_test_lib_test_err \
- partial-pass "2/3 tests passing" <<-\EOF &&
+test_expect_success 'subtest: 2/3 tests passing' '
+ write_and_run_sub_test_lib_test_err partial-pass <<-\EOF &&
test_expect_success "passing test #1" "true"
test_expect_success "failing test #2" "false"
test_expect_success "passing test #3" "true"
@@ -170,8 +101,8 @@ test_expect_success 'pretend we have a partially passing test suite' '
EOF
'
-test_expect_success 'pretend we have a known breakage' '
- run_sub_test_lib_test failing-todo "A failing TODO test" <<-\EOF &&
+test_expect_success 'subtest: a failing TODO test' '
+ write_and_run_sub_test_lib_test failing-todo <<-\EOF &&
test_expect_success "passing test" "true"
test_expect_failure "pretend we have a known breakage" "false"
test_done
@@ -185,8 +116,8 @@ test_expect_success 'pretend we have a known breakage' '
EOF
'
-test_expect_success 'pretend we have fixed a known breakage' '
- run_sub_test_lib_test passing-todo "A passing TODO test" <<-\EOF &&
+test_expect_success 'subtest: a passing TODO test' '
+ write_and_run_sub_test_lib_test passing-todo <<-\EOF &&
test_expect_failure "pretend we have fixed a known breakage" "true"
test_done
EOF
@@ -197,9 +128,8 @@ test_expect_success 'pretend we have fixed a known breakage' '
EOF
'
-test_expect_success 'pretend we have fixed one of two known breakages (run in sub test-lib)' '
- run_sub_test_lib_test partially-passing-todos \
- "2 TODO tests, one passing" <<-\EOF &&
+test_expect_success 'subtest: 2 TODO tests, one passin' '
+ write_and_run_sub_test_lib_test partially-passing-todos <<-\EOF &&
test_expect_failure "pretend we have a known breakage" "false"
test_expect_success "pretend we have a passing test" "true"
test_expect_failure "pretend we have fixed another known breakage" "true"
@@ -216,9 +146,8 @@ test_expect_success 'pretend we have fixed one of two known breakages (run in su
EOF
'
-test_expect_success 'pretend we have a pass, fail, and known breakage' '
- run_sub_test_lib_test_err \
- mixed-results1 "mixed results #1" <<-\EOF &&
+test_expect_success 'subtest: mixed results: pass, failure and a TODO test' '
+ write_and_run_sub_test_lib_test_err mixed-results1 <<-\EOF &&
test_expect_success "passing test" "true"
test_expect_success "failing test" "false"
test_expect_failure "pretend we have a known breakage" "false"
@@ -235,9 +164,8 @@ test_expect_success 'pretend we have a pass, fail, and known breakage' '
EOF
'
-test_expect_success 'pretend we have a mix of all possible results' '
- run_sub_test_lib_test_err \
- mixed-results2 "mixed results #2" <<-\EOF &&
+test_expect_success 'subtest: mixed results: a mixture of all possible results' '
+ write_and_run_sub_test_lib_test_err mixed-results2 <<-\EOF &&
test_expect_success "passing test" "true"
test_expect_success "passing test" "true"
test_expect_success "passing test" "true"
@@ -271,9 +199,8 @@ test_expect_success 'pretend we have a mix of all possible results' '
EOF
'
-test_expect_success 'test --verbose' '
- run_sub_test_lib_test_err \
- t1234-verbose "test verbose" --verbose <<-\EOF &&
+test_expect_success 'subtest: --verbose option' '
+ write_and_run_sub_test_lib_test_err t1234-verbose --verbose <<-\EOF &&
test_expect_success "passing test" true
test_expect_success "test with output" "echo foo"
test_expect_success "failing test" false
@@ -298,19 +225,14 @@ test_expect_success 'test --verbose' '
EOF
'
-test_expect_success 'test --verbose-only' '
+test_expect_success 'subtest: --verbose-only option' '
run_sub_test_lib_test_err \
- t2345-verbose-only-2 "test verbose-only=2" \
- --verbose-only=2 <<-\EOF &&
- test_expect_success "passing test" true
- test_expect_success "test with output" "echo foo"
- test_expect_success "failing test" false
- test_done
- EOF
- check_sub_test_lib_test t2345-verbose-only-2 <<-\EOF
+ t1234-verbose \
+ --verbose-only=2 &&
+ check_sub_test_lib_test t1234-verbose <<-\EOF
> ok 1 - passing test
> Z
- > expecting success of 2345.2 '\''test with output'\'': echo foo
+ > expecting success of 1234.2 '\''test with output'\'': echo foo
> foo
> ok 2 - test with output
> Z
@@ -321,18 +243,11 @@ test_expect_success 'test --verbose-only' '
EOF
'
-test_expect_success 'GIT_SKIP_TESTS' '
+test_expect_success 'subtest: skip one with GIT_SKIP_TESTS' '
(
- GIT_SKIP_TESTS="git.2" && export GIT_SKIP_TESTS &&
- run_sub_test_lib_test git-skip-tests-basic \
- "GIT_SKIP_TESTS" <<-\EOF &&
- for i in 1 2 3
- do
- test_expect_success "passing test #$i" "true"
- done
- test_done
- EOF
- check_sub_test_lib_test git-skip-tests-basic <<-\EOF
+ run_sub_test_lib_test full-pass \
+ --skip="full.2" &&
+ check_sub_test_lib_test full-pass <<-\EOF
> ok 1 - passing test #1
> ok 2 # skip passing test #2 (GIT_SKIP_TESTS)
> ok 3 - passing test #3
@@ -342,11 +257,10 @@ test_expect_success 'GIT_SKIP_TESTS' '
)
'
-test_expect_success 'GIT_SKIP_TESTS several tests' '
+test_expect_success 'subtest: skip several with GIT_SKIP_TESTS' '
(
- GIT_SKIP_TESTS="git.2 git.5" && export GIT_SKIP_TESTS &&
- run_sub_test_lib_test git-skip-tests-several \
- "GIT_SKIP_TESTS several tests" <<-\EOF &&
+ write_and_run_sub_test_lib_test git-skip-tests-several \
+ --skip="git.2 git.5" <<-\EOF &&
for i in 1 2 3 4 5 6
do
test_expect_success "passing test #$i" "true"
@@ -366,18 +280,11 @@ test_expect_success 'GIT_SKIP_TESTS several tests' '
)
'
-test_expect_success 'GIT_SKIP_TESTS sh pattern' '
+test_expect_success 'subtest: sh pattern skipping with GIT_SKIP_TESTS' '
(
- GIT_SKIP_TESTS="git.[2-5]" && export GIT_SKIP_TESTS &&
- run_sub_test_lib_test git-skip-tests-sh-pattern \
- "GIT_SKIP_TESTS sh pattern" <<-\EOF &&
- for i in 1 2 3 4 5 6
- do
- test_expect_success "passing test #$i" "true"
- done
- test_done
- EOF
- check_sub_test_lib_test git-skip-tests-sh-pattern <<-\EOF
+ run_sub_test_lib_test git-skip-tests-several \
+ --skip="git.[2-5]" &&
+ check_sub_test_lib_test git-skip-tests-several <<-\EOF
> ok 1 - passing test #1
> ok 2 # skip passing test #2 (GIT_SKIP_TESTS)
> ok 3 # skip passing test #3 (GIT_SKIP_TESTS)
@@ -390,35 +297,23 @@ test_expect_success 'GIT_SKIP_TESTS sh pattern' '
)
'
-test_expect_success 'GIT_SKIP_TESTS entire suite' '
+test_expect_success 'subtest: skip entire test suite with GIT_SKIP_TESTS' '
(
GIT_SKIP_TESTS="git" && export GIT_SKIP_TESTS &&
- run_sub_test_lib_test git-skip-tests-entire-suite \
- "GIT_SKIP_TESTS entire suite" <<-\EOF &&
- for i in 1 2 3
- do
- test_expect_success "passing test #$i" "true"
- done
- test_done
- EOF
- check_sub_test_lib_test git-skip-tests-entire-suite <<-\EOF
+ run_sub_test_lib_test git-skip-tests-several \
+ --skip="git" &&
+ check_sub_test_lib_test git-skip-tests-several <<-\EOF
> 1..0 # SKIP skip all tests in git
EOF
)
'
-test_expect_success 'GIT_SKIP_TESTS does not skip unmatched suite' '
+test_expect_success 'subtest: GIT_SKIP_TESTS does not skip unmatched suite' '
(
GIT_SKIP_TESTS="notgit" && export GIT_SKIP_TESTS &&
- run_sub_test_lib_test git-skip-tests-unmatched-suite \
- "GIT_SKIP_TESTS does not skip unmatched suite" <<-\EOF &&
- for i in 1 2 3
- do
- test_expect_success "passing test #$i" "true"
- done
- test_done
- EOF
- check_sub_test_lib_test git-skip-tests-unmatched-suite <<-\EOF
+ run_sub_test_lib_test full-pass \
+ --skip="notfull" &&
+ check_sub_test_lib_test full-pass <<-\EOF
> ok 1 - passing test #1
> ok 2 - passing test #2
> ok 3 - passing test #3
@@ -428,16 +323,9 @@ test_expect_success 'GIT_SKIP_TESTS does not skip unmatched suite' '
)
'
-test_expect_success '--run basic' '
- run_sub_test_lib_test run-basic \
- "--run basic" --run="1,3,5" <<-\EOF &&
- for i in 1 2 3 4 5 6
- do
- test_expect_success "passing test #$i" "true"
- done
- test_done
- EOF
- check_sub_test_lib_test run-basic <<-\EOF
+test_expect_success 'subtest: --run basic' '
+ run_sub_test_lib_test git-skip-tests-several --run="1,3,5" &&
+ check_sub_test_lib_test git-skip-tests-several <<-\EOF
> ok 1 - passing test #1
> ok 2 # skip passing test #2 (--run)
> ok 3 - passing test #3
@@ -449,16 +337,10 @@ test_expect_success '--run basic' '
EOF
'
-test_expect_success '--run with a range' '
- run_sub_test_lib_test run-range \
- "--run with a range" --run="1-3" <<-\EOF &&
- for i in 1 2 3 4 5 6
- do
- test_expect_success "passing test #$i" "true"
- done
- test_done
- EOF
- check_sub_test_lib_test run-range <<-\EOF
+test_expect_success 'subtest: --run with a range' '
+ run_sub_test_lib_test git-skip-tests-several \
+ --run="1-3" &&
+ check_sub_test_lib_test git-skip-tests-several <<-\EOF
> ok 1 - passing test #1
> ok 2 - passing test #2
> ok 3 - passing test #3
@@ -470,16 +352,10 @@ test_expect_success '--run with a range' '
EOF
'
-test_expect_success '--run with two ranges' '
- run_sub_test_lib_test run-two-ranges \
- "--run with two ranges" --run="1-2,5-6" <<-\EOF &&
- for i in 1 2 3 4 5 6
- do
- test_expect_success "passing test #$i" "true"
- done
- test_done
- EOF
- check_sub_test_lib_test run-two-ranges <<-\EOF
+test_expect_success 'subtest: --run with two ranges' '
+ run_sub_test_lib_test git-skip-tests-several \
+ --run="1-2,5-6" &&
+ check_sub_test_lib_test git-skip-tests-several <<-\EOF
> ok 1 - passing test #1
> ok 2 - passing test #2
> ok 3 # skip passing test #3 (--run)
@@ -491,16 +367,10 @@ test_expect_success '--run with two ranges' '
EOF
'
-test_expect_success '--run with a left open range' '
- run_sub_test_lib_test run-left-open-range \
- "--run with a left open range" --run="-3" <<-\EOF &&
- for i in 1 2 3 4 5 6
- do
- test_expect_success "passing test #$i" "true"
- done
- test_done
- EOF
- check_sub_test_lib_test run-left-open-range <<-\EOF
+test_expect_success 'subtest: --run with a left open range' '
+ run_sub_test_lib_test git-skip-tests-several \
+ --run="-3" &&
+ check_sub_test_lib_test git-skip-tests-several <<-\EOF
> ok 1 - passing test #1
> ok 2 - passing test #2
> ok 3 - passing test #3
@@ -512,16 +382,10 @@ test_expect_success '--run with a left open range' '
EOF
'
-test_expect_success '--run with a right open range' '
- run_sub_test_lib_test run-right-open-range \
- "--run with a right open range" --run="4-" <<-\EOF &&
- for i in 1 2 3 4 5 6
- do
- test_expect_success "passing test #$i" "true"
- done
- test_done
- EOF
- check_sub_test_lib_test run-right-open-range <<-\EOF
+test_expect_success 'subtest: --run with a right open range' '
+ run_sub_test_lib_test git-skip-tests-several \
+ --run="4-" &&
+ check_sub_test_lib_test git-skip-tests-several <<-\EOF
> ok 1 # skip passing test #1 (--run)
> ok 2 # skip passing test #2 (--run)
> ok 3 # skip passing test #3 (--run)
@@ -533,16 +397,10 @@ test_expect_success '--run with a right open range' '
EOF
'
-test_expect_success '--run with basic negation' '
- run_sub_test_lib_test run-basic-neg \
- "--run with basic negation" --run="!3" <<-\EOF &&
- for i in 1 2 3 4 5 6
- do
- test_expect_success "passing test #$i" "true"
- done
- test_done
- EOF
- check_sub_test_lib_test run-basic-neg <<-\EOF
+test_expect_success 'subtest: --run with basic negation' '
+ run_sub_test_lib_test git-skip-tests-several \
+ --run="!3" &&
+ check_sub_test_lib_test git-skip-tests-several <<-\EOF
> ok 1 - passing test #1
> ok 2 - passing test #2
> ok 3 # skip passing test #3 (--run)
@@ -554,16 +412,10 @@ test_expect_success '--run with basic negation' '
EOF
'
-test_expect_success '--run with two negations' '
- run_sub_test_lib_test run-two-neg \
- "--run with two negations" --run="!3,!6" <<-\EOF &&
- for i in 1 2 3 4 5 6
- do
- test_expect_success "passing test #$i" "true"
- done
- test_done
- EOF
- check_sub_test_lib_test run-two-neg <<-\EOF
+test_expect_success 'subtest: --run with two negations' '
+ run_sub_test_lib_test git-skip-tests-several \
+ --run="!3,!6" &&
+ check_sub_test_lib_test git-skip-tests-several <<-\EOF
> ok 1 - passing test #1
> ok 2 - passing test #2
> ok 3 # skip passing test #3 (--run)
@@ -575,16 +427,10 @@ test_expect_success '--run with two negations' '
EOF
'
-test_expect_success '--run a range and negation' '
- run_sub_test_lib_test run-range-and-neg \
- "--run a range and negation" --run="-4,!2" <<-\EOF &&
- for i in 1 2 3 4 5 6
- do
- test_expect_success "passing test #$i" "true"
- done
- test_done
- EOF
- check_sub_test_lib_test run-range-and-neg <<-\EOF
+test_expect_success 'subtest: --run a range and negation' '
+ run_sub_test_lib_test git-skip-tests-several \
+ --run="-4,!2" &&
+ check_sub_test_lib_test git-skip-tests-several <<-\EOF
> ok 1 - passing test #1
> ok 2 # skip passing test #2 (--run)
> ok 3 - passing test #3
@@ -596,16 +442,10 @@ test_expect_success '--run a range and negation' '
EOF
'
-test_expect_success '--run range negation' '
- run_sub_test_lib_test run-range-neg \
- "--run range negation" --run="!1-3" <<-\EOF &&
- for i in 1 2 3 4 5 6
- do
- test_expect_success "passing test #$i" "true"
- done
- test_done
- EOF
- check_sub_test_lib_test run-range-neg <<-\EOF
+test_expect_success 'subtest: --run range negation' '
+ run_sub_test_lib_test git-skip-tests-several \
+ --run="!1-3" &&
+ check_sub_test_lib_test git-skip-tests-several <<-\EOF
> ok 1 # skip passing test #1 (--run)
> ok 2 # skip passing test #2 (--run)
> ok 3 # skip passing test #3 (--run)
@@ -617,17 +457,10 @@ test_expect_success '--run range negation' '
EOF
'
-test_expect_success '--run include, exclude and include' '
- run_sub_test_lib_test run-inc-neg-inc \
- "--run include, exclude and include" \
- --run="1-5,!1-3,2" <<-\EOF &&
- for i in 1 2 3 4 5 6
- do
- test_expect_success "passing test #$i" "true"
- done
- test_done
- EOF
- check_sub_test_lib_test run-inc-neg-inc <<-\EOF
+test_expect_success 'subtest: --run include, exclude and include' '
+ run_sub_test_lib_test git-skip-tests-several \
+ --run="1-5,!1-3,2" &&
+ check_sub_test_lib_test git-skip-tests-several <<-\EOF
> ok 1 # skip passing test #1 (--run)
> ok 2 - passing test #2
> ok 3 # skip passing test #3 (--run)
@@ -639,17 +472,10 @@ test_expect_success '--run include, exclude and include' '
EOF
'
-test_expect_success '--run include, exclude and include, comma separated' '
- run_sub_test_lib_test run-inc-neg-inc-comma \
- "--run include, exclude and include, comma separated" \
- --run=1-5,!1-3,2 <<-\EOF &&
- for i in 1 2 3 4 5 6
- do
- test_expect_success "passing test #$i" "true"
- done
- test_done
- EOF
- check_sub_test_lib_test run-inc-neg-inc-comma <<-\EOF
+test_expect_success 'subtest: --run include, exclude and include, comma separated' '
+ run_sub_test_lib_test git-skip-tests-several \
+ --run=1-5,!1-3,2 &&
+ check_sub_test_lib_test git-skip-tests-several <<-\EOF
> ok 1 # skip passing test #1 (--run)
> ok 2 - passing test #2
> ok 3 # skip passing test #3 (--run)
@@ -661,17 +487,10 @@ test_expect_success '--run include, exclude and include, comma separated' '
EOF
'
-test_expect_success '--run exclude and include' '
- run_sub_test_lib_test run-neg-inc \
- "--run exclude and include" \
- --run="!3-,5" <<-\EOF &&
- for i in 1 2 3 4 5 6
- do
- test_expect_success "passing test #$i" "true"
- done
- test_done
- EOF
- check_sub_test_lib_test run-neg-inc <<-\EOF
+test_expect_success 'subtest: --run exclude and include' '
+ run_sub_test_lib_test git-skip-tests-several \
+ --run="!3-,5" &&
+ check_sub_test_lib_test git-skip-tests-several <<-\EOF
> ok 1 - passing test #1
> ok 2 - passing test #2
> ok 3 # skip passing test #3 (--run)
@@ -683,17 +502,10 @@ test_expect_success '--run exclude and include' '
EOF
'
-test_expect_success '--run empty selectors' '
- run_sub_test_lib_test run-empty-sel \
- "--run empty selectors" \
- --run="1,,3,,,5" <<-\EOF &&
- for i in 1 2 3 4 5 6
- do
- test_expect_success "passing test #$i" "true"
- done
- test_done
- EOF
- check_sub_test_lib_test run-empty-sel <<-\EOF
+test_expect_success 'subtest: --run empty selectors' '
+ run_sub_test_lib_test git-skip-tests-several \
+ --run="1,,3,,,5" &&
+ check_sub_test_lib_test git-skip-tests-several <<-\EOF
> ok 1 - passing test #1
> ok 2 # skip passing test #2 (--run)
> ok 3 - passing test #3
@@ -705,9 +517,8 @@ test_expect_success '--run empty selectors' '
EOF
'
-test_expect_success '--run substring selector' '
- run_sub_test_lib_test run-substring-selector \
- "--run empty selectors" \
+test_expect_success 'subtest: --run substring selector' '
+ write_and_run_sub_test_lib_test run-substring-selector \
--run="relevant" <<-\EOF &&
test_expect_success "relevant test" "true"
for i in 1 2 3 4 5 6
@@ -729,9 +540,8 @@ test_expect_success '--run substring selector' '
EOF
'
-test_expect_success '--run keyword selection' '
- run_sub_test_lib_test_err run-inv-range-start \
- "--run invalid range start" \
+test_expect_success 'subtest: --run keyword selection' '
+ write_and_run_sub_test_lib_test_err run-inv-range-start \
--run="a-5" <<-\EOF &&
test_expect_success "passing test #1" "true"
test_done
@@ -744,14 +554,10 @@ test_expect_success '--run keyword selection' '
EOF_ERR
'
-test_expect_success '--run invalid range end' '
- run_sub_test_lib_test_err run-inv-range-end \
- "--run invalid range end" \
- --run="1-z" <<-\EOF &&
- test_expect_success "passing test #1" "true"
- test_done
- EOF
- check_sub_test_lib_test_err run-inv-range-end \
+test_expect_success 'subtest: --run invalid range end' '
+ run_sub_test_lib_test_err run-inv-range-start \
+ --run="1-z" &&
+ check_sub_test_lib_test_err run-inv-range-start \
<<-\EOF_OUT 3<<-EOF_ERR
> FATAL: Unexpected exit with code 1
EOF_OUT
@@ -759,8 +565,8 @@ test_expect_success '--run invalid range end' '
EOF_ERR
'
-test_expect_success 'tests respect prerequisites' '
- run_sub_test_lib_test prereqs "tests respect prereqs" <<-\EOF &&
+test_expect_success 'subtest: tests respect prerequisites' '
+ write_and_run_sub_test_lib_test prereqs <<-\EOF &&
test_set_prereq HAVEIT
test_expect_success HAVEIT "prereq is satisfied" "true"
@@ -789,8 +595,8 @@ test_expect_success 'tests respect prerequisites' '
EOF
'
-test_expect_success 'tests respect lazy prerequisites' '
- run_sub_test_lib_test lazy-prereqs "respect lazy prereqs" <<-\EOF &&
+test_expect_success 'subtest: tests respect lazy prerequisites' '
+ write_and_run_sub_test_lib_test lazy-prereqs <<-\EOF &&
test_lazy_prereq LAZY_TRUE true
test_expect_success LAZY_TRUE "lazy prereq is satisifed" "true"
@@ -813,8 +619,8 @@ test_expect_success 'tests respect lazy prerequisites' '
EOF
'
-test_expect_success 'nested lazy prerequisites' '
- run_sub_test_lib_test nested-lazy "nested lazy prereqs" <<-\EOF &&
+test_expect_success 'subtest: nested lazy prerequisites' '
+ write_and_run_sub_test_lib_test nested-lazy <<-\EOF &&
test_lazy_prereq NESTED_INNER "
>inner &&
@@ -839,9 +645,9 @@ test_expect_success 'nested lazy prerequisites' '
EOF
'
-test_expect_success 'lazy prereqs do not turn off tracing' '
- run_sub_test_lib_test lazy-prereq-and-tracing \
- "lazy prereqs and -x" -v -x <<-\EOF &&
+test_expect_success 'subtest: lazy prereqs do not turn off tracing' '
+ write_and_run_sub_test_lib_test lazy-prereq-and-tracing \
+ -v -x <<-\EOF &&
test_lazy_prereq LAZY true
test_expect_success lazy "test_have_prereq LAZY && echo trace"
@@ -852,8 +658,8 @@ test_expect_success 'lazy prereqs do not turn off tracing' '
grep "echo trace" lazy-prereq-and-tracing/err
'
-test_expect_success 'tests clean up after themselves' '
- run_sub_test_lib_test cleanup "test with cleanup" <<-\EOF &&
+test_expect_success 'subtest: tests clean up after themselves' '
+ write_and_run_sub_test_lib_test cleanup <<-\EOF &&
clean=no
test_expect_success "do cleanup" "
test_when_finished clean=yes
@@ -872,9 +678,9 @@ test_expect_success 'tests clean up after themselves' '
EOF
'
-test_expect_success 'tests clean up even on failures' '
- run_sub_test_lib_test_err \
- failing-cleanup "Failing tests with cleanup commands" <<-\EOF &&
+test_expect_success 'subtest: tests clean up even on failures' '
+ write_and_run_sub_test_lib_test_err \
+ failing-cleanup <<-\EOF &&
test_expect_success "tests clean up even after a failure" "
touch clean-after-failure &&
test_when_finished rm clean-after-failure &&
@@ -901,9 +707,9 @@ test_expect_success 'tests clean up even on failures' '
EOF
'
-test_expect_success 'test_atexit is run' '
- run_sub_test_lib_test_err \
- atexit-cleanup "Run atexit commands" -i <<-\EOF &&
+test_expect_success 'subtest: test_atexit is run' '
+ write_and_run_sub_test_lib_test_err \
+ atexit-cleanup -i <<-\EOF &&
test_expect_success "tests clean up even after a failure" "
> ../../clean-atexit &&
test_atexit rm ../../clean-atexit &&
@@ -1253,28 +1059,29 @@ P=$(test_oid root)
test_expect_success 'git commit-tree records the correct tree in a commit' '
commit0=$(echo NO | git commit-tree $P) &&
- tree=$(git show --pretty=raw $commit0 |
- sed -n -e "s/^tree //p" -e "/^author /q") &&
+ git show --pretty=raw $commit0 >out &&
+ tree=$(sed -n -e "s/^tree //p" -e "/^author /q" out) &&
test "z$tree" = "z$P"
'
test_expect_success 'git commit-tree records the correct parent in a commit' '
commit1=$(echo NO | git commit-tree $P -p $commit0) &&
- parent=$(git show --pretty=raw $commit1 |
- sed -n -e "s/^parent //p" -e "/^author /q") &&
+ git show --pretty=raw $commit1 >out &&
+ parent=$(sed -n -e "s/^parent //p" -e "/^author /q" out) &&
test "z$commit0" = "z$parent"
'
test_expect_success 'git commit-tree omits duplicated parent in a commit' '
commit2=$(echo NO | git commit-tree $P -p $commit0 -p $commit0) &&
- parent=$(git show --pretty=raw $commit2 |
- sed -n -e "s/^parent //p" -e "/^author /q" |
- sort -u) &&
+ git show --pretty=raw $commit2 >out &&
+ cat >match.sed <<-\EOF &&
+ s/^parent //p
+ /^author /q
+ EOF
+ parent=$(sed -n -f match.sed out | sort -u) &&
test "z$commit0" = "z$parent" &&
- numparent=$(git show --pretty=raw $commit2 |
- sed -n -e "s/^parent //p" -e "/^author /q" |
- wc -l) &&
- test $numparent = 1
+ git show --pretty=raw $commit2 >out &&
+ test_stdout_line_count = 1 sed -n -f match.sed out
'
test_expect_success 'update-index D/F conflict' '
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index 0803994874..df544bb321 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -186,21 +186,33 @@ test_expect_success 'init with --template (blank)' '
test_path_is_missing template-blank/.git/info/exclude
'
-test_expect_success 'init with init.templatedir set' '
- mkdir templatedir-source &&
- echo Content >templatedir-source/file &&
- test_config_global init.templatedir "${HOME}/templatedir-source" &&
+init_no_templatedir_env () {
(
- mkdir templatedir-set &&
- cd templatedir-set &&
sane_unset GIT_TEMPLATE_DIR &&
NO_SET_GIT_TEMPLATE_DIR=t &&
export NO_SET_GIT_TEMPLATE_DIR &&
- git init
- ) &&
+ git init "$1"
+ )
+}
+
+test_expect_success 'init with init.templatedir set' '
+ mkdir templatedir-source &&
+ echo Content >templatedir-source/file &&
+ test_config_global init.templatedir "${HOME}/templatedir-source" &&
+
+ init_no_templatedir_env templatedir-set &&
test_cmp templatedir-source/file templatedir-set/.git/file
'
+test_expect_success 'init with init.templatedir using ~ expansion' '
+ mkdir -p templatedir-source &&
+ echo Content >templatedir-source/file &&
+ test_config_global init.templatedir "~/templatedir-source" &&
+
+ init_no_templatedir_env templatedir-expansion &&
+ test_cmp templatedir-source/file templatedir-expansion/.git/file
+'
+
test_expect_success 'init --bare/--shared overrides system/global config' '
test_config_global core.bare false &&
test_config_global core.sharedRepository 0640 &&
@@ -344,7 +356,10 @@ test_lazy_prereq GETCWD_IGNORES_PERMS '
chmod 100 $base ||
BUG "cannot prepare $base"
- (cd $base/dir && /bin/pwd -P)
+ (
+ cd $base/dir &&
+ test-tool getcwd
+ )
status=$?
chmod 700 $base &&
diff --git a/t/t0004-unwritable.sh b/t/t0004-unwritable.sh
index e3137d638e..37d68ef03b 100755
--- a/t/t0004-unwritable.sh
+++ b/t/t0004-unwritable.sh
@@ -2,6 +2,7 @@
test_description='detect unwritable repository and fail correctly'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
@@ -21,7 +22,7 @@ test_expect_success POSIXPERM,SANITY 'write-tree should notice unwritable reposi
test_must_fail git write-tree
'
-test_expect_success POSIXPERM,SANITY 'commit should notice unwritable repository' '
+test_expect_success POSIXPERM,SANITY,!SANITIZE_LEAK 'commit should notice unwritable repository' '
test_when_finished "chmod 775 .git/objects .git/objects/??" &&
chmod a-w .git/objects .git/objects/?? &&
test_must_fail git commit -m second
diff --git a/t/t0011-hashmap.sh b/t/t0011-hashmap.sh
index 5343ffd3f9..e094975b13 100755
--- a/t/t0011-hashmap.sh
+++ b/t/t0011-hashmap.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='test hashmap and string hash functions'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_hashmap() {
diff --git a/t/t0012-help.sh b/t/t0012-help.sh
index 5679e29c62..91b68c74a1 100755
--- a/t/t0012-help.sh
+++ b/t/t0012-help.sh
@@ -34,6 +34,18 @@ test_expect_success 'basic help commands' '
git help -a >/dev/null
'
+test_expect_success 'invalid usage' '
+ test_expect_code 129 git help -g add &&
+ test_expect_code 129 git help -a -c &&
+
+ test_expect_code 129 git help -g add &&
+ test_expect_code 129 git help -a -g &&
+
+ test_expect_code 129 git help -g -c &&
+ test_expect_code 129 git help --config-for-completion add &&
+ test_expect_code 129 git help --config-sections-for-completion add
+'
+
test_expect_success "works for commands and guides by default" '
configure_help &&
git help status &&
@@ -73,6 +85,59 @@ test_expect_success 'git help -g' '
test_i18ngrep "^ tutorial " help.output
'
+test_expect_success 'git help fails for non-existing html pages' '
+ configure_help &&
+ mkdir html-empty &&
+ test_must_fail git -c help.htmlpath=html-empty help status &&
+ test_must_be_empty test-browser.log
+'
+
+test_expect_success 'git help succeeds without git.html' '
+ configure_help &&
+ mkdir html-with-docs &&
+ touch html-with-docs/git-status.html &&
+ git -c help.htmlpath=html-with-docs help status &&
+ echo "html-with-docs/git-status.html" >expect &&
+ test_cmp expect test-browser.log
+'
+
+test_expect_success 'git help -c' '
+ git help -c >help.output &&
+ cat >expect <<-\EOF &&
+
+ '\''git help config'\'' for more information
+ EOF
+ grep -v -E \
+ -e "^[^.]+\.[^.]+$" \
+ -e "^[^.]+\.[^.]+\.[^.]+$" \
+ help.output >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git help --config-for-completion' '
+ git help -c >human &&
+ grep -E \
+ -e "^[^.]+\.[^.]+$" \
+ -e "^[^.]+\.[^.]+\.[^.]+$" human |
+ sed -e "s/\*.*//" -e "s/<.*//" |
+ sort -u >human.munged &&
+
+ git help --config-for-completion >vars &&
+ test_cmp human.munged vars
+'
+
+test_expect_success 'git help --config-sections-for-completion' '
+ git help -c >human &&
+ grep -E \
+ -e "^[^.]+\.[^.]+$" \
+ -e "^[^.]+\.[^.]+\.[^.]+$" human |
+ sed -e "s/\..*//" |
+ sort -u >human.munged &&
+
+ git help --config-sections-for-completion >sections &&
+ test_cmp human.munged sections
+'
+
test_expect_success 'generate builtin list' '
git --list-cmds=builtins >builtins
'
diff --git a/t/t0016-oidmap.sh b/t/t0016-oidmap.sh
index 31f8276ba8..0faef1f4f1 100755
--- a/t/t0016-oidmap.sh
+++ b/t/t0016-oidmap.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='test oidmap'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# This purposefully is very similar to t0011-hashmap.sh
diff --git a/t/t0017-env-helper.sh b/t/t0017-env-helper.sh
index 4a159f99e4..2e42fba956 100755
--- a/t/t0017-env-helper.sh
+++ b/t/t0017-env-helper.sh
@@ -2,6 +2,7 @@
test_description='test env--helper'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
diff --git a/t/t0018-advice.sh b/t/t0018-advice.sh
index 39e5e4b34f..c13057a4ca 100755
--- a/t/t0018-advice.sh
+++ b/t/t0018-advice.sh
@@ -2,6 +2,7 @@
test_description='Test advise_if_enabled functionality'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'advice should be printed when config variable is unset' '
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index b5749f327d..33dfc9cd56 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -6,6 +6,7 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
TEST_ROOT="$PWD"
PATH=$TEST_ROOT:$PATH
@@ -1061,4 +1062,74 @@ test_expect_success PERL,SYMLINKS,CASE_INSENSITIVE_FS \
)
'
+test_expect_success PERL 'setup for progress tests' '
+ git init progress &&
+ (
+ cd progress &&
+ git config filter.delay.process "rot13-filter.pl delay-progress.log clean smudge delay" &&
+ git config filter.delay.required true &&
+
+ echo "*.a filter=delay" >.gitattributes &&
+ touch test-delay10.a &&
+ git add . &&
+ git commit -m files
+ )
+'
+
+test_delayed_checkout_progress () {
+ if test "$1" = "!"
+ then
+ local expect_progress=N &&
+ shift
+ else
+ local expect_progress=
+ fi &&
+
+ if test $# -lt 1
+ then
+ BUG "no command given to test_delayed_checkout_progress"
+ fi &&
+
+ (
+ cd progress &&
+ GIT_PROGRESS_DELAY=0 &&
+ export GIT_PROGRESS_DELAY &&
+ rm -f *.a delay-progress.log &&
+
+ "$@" 2>err &&
+ grep "IN: smudge test-delay10.a .* \\[DELAYED\\]" delay-progress.log &&
+ if test "$expect_progress" = N
+ then
+ ! grep "Filtering content" err
+ else
+ grep "Filtering content" err
+ fi
+ )
+}
+
+for mode in pathspec branch
+do
+ case "$mode" in
+ pathspec) opt='.' ;;
+ branch) opt='-f HEAD' ;;
+ esac
+
+ test_expect_success PERL,TTY "delayed checkout shows progress by default on tty ($mode checkout)" '
+ test_delayed_checkout_progress test_terminal git checkout $opt
+ '
+
+ test_expect_success PERL "delayed checkout ommits progress on non-tty ($mode checkout)" '
+ test_delayed_checkout_progress ! git checkout $opt
+ '
+
+ test_expect_success PERL,TTY "delayed checkout ommits progress with --quiet ($mode checkout)" '
+ test_delayed_checkout_progress ! test_terminal git checkout --quiet $opt
+ '
+
+ test_expect_success PERL,TTY "delayed checkout honors --[no]-progress ($mode checkout)" '
+ test_delayed_checkout_progress ! test_terminal git checkout --no-progress $opt &&
+ test_delayed_checkout_progress test_terminal git checkout --quiet --progress $opt
+ '
+done
+
test_done
diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh
index d24d5acfbc..4a5c5c602c 100755
--- a/t/t0027-auto-crlf.sh
+++ b/t/t0027-auto-crlf.sh
@@ -386,7 +386,9 @@ test_expect_success 'setup main' '
test_tick
'
-
+# Disable extra chain-linting for the next set of tests. There are many
+# auto-generated ones that are not worth checking over and over.
+GIT_TEST_CHAIN_LINT_HARDER_DEFAULT=0
warn_LF_CRLF="LF will be replaced by CRLF"
warn_CRLF_LF="CRLF will be replaced by LF"
@@ -597,6 +599,9 @@ do
checkout_files auto "$id" "" false native $NL CRLF CRLF_mix_LF LF_mix_CR LF_nul
done
+# The rest of the tests are unique; do the usual linting.
+unset GIT_TEST_CHAIN_LINT_HARDER_DEFAULT
+
# Should be the last test case: remove some files from the worktree
test_expect_success 'ls-files --eol -d -z' '
rm crlf_false_attr__CRLF.txt crlf_false_attr__CRLF_mix_LF.txt crlf_false_attr__LF.txt .gitattributes &&
diff --git a/t/t0028-working-tree-encoding.sh b/t/t0028-working-tree-encoding.sh
index f970a9806b..82905a2156 100755
--- a/t/t0028-working-tree-encoding.sh
+++ b/t/t0028-working-tree-encoding.sh
@@ -6,33 +6,10 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
+. "$TEST_DIRECTORY/lib-encoding.sh"
GIT_TRACE_WORKING_TREE_ENCODING=1 && export GIT_TRACE_WORKING_TREE_ENCODING
-test_lazy_prereq NO_UTF16_BOM '
- test $(printf abc | iconv -f UTF-8 -t UTF-16 | wc -c) = 6
-'
-
-test_lazy_prereq NO_UTF32_BOM '
- test $(printf abc | iconv -f UTF-8 -t UTF-32 | wc -c) = 12
-'
-
-write_utf16 () {
- if test_have_prereq NO_UTF16_BOM
- then
- printf '\376\377'
- fi &&
- iconv -f UTF-8 -t UTF-16
-}
-
-write_utf32 () {
- if test_have_prereq NO_UTF32_BOM
- then
- printf '\0\0\376\377'
- fi &&
- iconv -f UTF-8 -t UTF-32
-}
-
test_expect_success 'setup test files' '
git config core.eol lf &&
diff --git a/t/t0030-stripspace.sh b/t/t0030-stripspace.sh
index 0c24a0f9a3..ae1ca380c1 100755
--- a/t/t0030-stripspace.sh
+++ b/t/t0030-stripspace.sh
@@ -5,6 +5,7 @@
test_description='git stripspace'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
t40='A quick brown fox jumps over the lazy do'
diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index ad4746d899..da310ed29b 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -37,7 +37,6 @@ String options
--list <str> add str to list
Magic arguments
- --quux means --quux
-NUM set integer to NUM
+ same as -b
--ambiguous positive ambiguity
@@ -263,10 +262,6 @@ test_expect_success 'detect possible typos' '
test_cmp typo.err output.err
'
-test_expect_success 'keep some options as arguments' '
- test-tool parse-options --expect="arg 00: --quux" --quux
-'
-
cat >expect <<\EOF
Callback: "four", 0
boolean: 5
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 0ff06b5d1b..34d1061f32 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -468,6 +468,36 @@ test_expect_success 'match .gitmodules' '
.gitmodules,:\$DATA
'
+test_expect_success 'match .gitattributes' '
+ test-tool path-utils is_dotgitattributes \
+ .gitattributes \
+ .git${u200c}attributes \
+ .Gitattributes \
+ .gitattributeS \
+ GITATT~1 \
+ GI7D29~1
+'
+
+test_expect_success 'match .gitignore' '
+ test-tool path-utils is_dotgitignore \
+ .gitignore \
+ .git${u200c}ignore \
+ .Gitignore \
+ .gitignorE \
+ GITIGN~1 \
+ GI250A~1
+'
+
+test_expect_success 'match .mailmap' '
+ test-tool path-utils is_dotmailmap \
+ .mailmap \
+ .mail${u200c}map \
+ .Mailmap \
+ .mailmaP \
+ MAILMA~1 \
+ MABA30~1
+'
+
test_expect_success MINGW 'is_valid_path() on Windows' '
test-tool path-utils is_valid_path \
win32 \
@@ -495,4 +525,30 @@ test_expect_success MINGW 'is_valid_path() on Windows' '
"PRN./abc"
'
+test_lazy_prereq RUNTIME_PREFIX '
+ test true = "$RUNTIME_PREFIX"
+'
+
+test_lazy_prereq CAN_EXEC_IN_PWD '
+ cp "$GIT_EXEC_PATH"/git$X ./ &&
+ ./git rev-parse
+'
+
+test_expect_success RUNTIME_PREFIX,CAN_EXEC_IN_PWD 'RUNTIME_PREFIX works' '
+ mkdir -p pretend/bin pretend/libexec/git-core &&
+ echo "echo HERE" | write_script pretend/libexec/git-core/git-here &&
+ cp "$GIT_EXEC_PATH"/git$X pretend/bin/ &&
+ GIT_EXEC_PATH= ./pretend/bin/git here >actual &&
+ echo HERE >expect &&
+ test_cmp expect actual'
+
+test_expect_success RUNTIME_PREFIX,CAN_EXEC_IN_PWD '%(prefix)/ works' '
+ mkdir -p pretend/bin &&
+ cp "$GIT_EXEC_PATH"/git$X pretend/bin/ &&
+ git config yes.path "%(prefix)/yes" &&
+ GIT_EXEC_PATH= ./pretend/bin/git config --path yes.path >actual &&
+ echo "$(pwd)/pretend/yes" >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t0063-string-list.sh b/t/t0063-string-list.sh
index c6ee9f66b1..46d4839194 100755
--- a/t/t0063-string-list.sh
+++ b/t/t0063-string-list.sh
@@ -5,6 +5,7 @@
test_description='Test string list functionality'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_split () {
diff --git a/t/t0069-oidtree.sh b/t/t0069-oidtree.sh
new file mode 100755
index 0000000000..bfb1397d7b
--- /dev/null
+++ b/t/t0069-oidtree.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+test_description='basic tests for the oidtree implementation'
+. ./test-lib.sh
+
+maxhexsz=$(test_oid hexsz)
+echoid () {
+ prefix="${1:+$1 }"
+ shift
+ while test $# -gt 0
+ do
+ shortoid="$1"
+ shift
+ difference=$(($maxhexsz - ${#shortoid}))
+ printf "%s%s%0${difference}d\\n" "$prefix" "$shortoid" "0"
+ done
+}
+
+test_expect_success 'oidtree insert and contains' '
+ cat >expect <<-\EOF &&
+ 0
+ 0
+ 0
+ 1
+ 1
+ 0
+ EOF
+ {
+ echoid insert 444 1 2 3 4 5 a b c d e &&
+ echoid contains 44 441 440 444 4440 4444
+ echo clear
+ } | test-tool oidtree >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'oidtree each' '
+ echoid "" 123 321 321 >expect &&
+ {
+ echoid insert f 9 8 123 321 a b c d e
+ echo each 12300
+ echo each 3211
+ echo each 3210
+ echo each 32100
+ echo clear
+ } | test-tool oidtree >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t0071-sort.sh b/t/t0071-sort.sh
new file mode 100755
index 0000000000..a8ab174879
--- /dev/null
+++ b/t/t0071-sort.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+test_description='verify sort functions'
+
+. ./test-lib.sh
+
+test_expect_success 'llist_mergesort()' '
+ test-tool mergesort test
+'
+
+test_done
diff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh
index 9bf66c9e68..9067572648 100755
--- a/t/t0090-cache-tree.sh
+++ b/t/t0090-cache-tree.sh
@@ -195,6 +195,7 @@ test_expect_success 'reset --hard gives cache-tree' '
test_expect_success 'reset --hard without index gives cache-tree' '
rm -f .git/index &&
+ git clean -fd &&
git reset --hard &&
test_cache_tree
'
diff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh
index 526304ff95..eeedbfa919 100755
--- a/t/t0091-bugreport.sh
+++ b/t/t0091-bugreport.sh
@@ -2,6 +2,7 @@
test_description='git bugreport'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Headers "[System Info]" will be followed by a non-empty line if we put some
diff --git a/t/t0210/scrub_normal.perl b/t/t0210/scrub_normal.perl
index c65d1a815e..7cc4de392a 100644
--- a/t/t0210/scrub_normal.perl
+++ b/t/t0210/scrub_normal.perl
@@ -42,6 +42,12 @@ while (<>) {
# so just omit it for testing purposes.
# print "cmd_path _EXE_\n";
}
+ elsif ($line =~ m/^cmd_ancestry/) {
+ # 'cmd_ancestry' is not implemented everywhere, so for portability's
+ # sake, skip it when parsing normal.
+ #
+ # print "$line";
+ }
else {
print "$line";
}
diff --git a/t/t0211/scrub_perf.perl b/t/t0211/scrub_perf.perl
index 351af7844e..d164b750ff 100644
--- a/t/t0211/scrub_perf.perl
+++ b/t/t0211/scrub_perf.perl
@@ -44,6 +44,11 @@ while (<>) {
# $tokens[$col_rest] = "_EXE_";
goto SKIP_LINE;
}
+ elsif ($tokens[$col_event] =~ m/cmd_ancestry/) {
+ # 'cmd_ancestry' is platform-specific and not implemented everywhere,
+ # so skip it.
+ goto SKIP_LINE;
+ }
elsif ($tokens[$col_event] =~ m/child_exit/) {
$tokens[$col_rest] =~ s/ pid:\d* / pid:_PID_ /;
}
diff --git a/t/t0212/parse_events.perl b/t/t0212/parse_events.perl
index 6584bb5634..b6408560c0 100644
--- a/t/t0212/parse_events.perl
+++ b/t/t0212/parse_events.perl
@@ -132,7 +132,10 @@ while (<>) {
# just omit it for testing purposes.
# $processes->{$sid}->{'path'} = "_EXE_";
}
-
+ elsif ($event eq 'cmd_ancestry') {
+ # 'cmd_ancestry' is platform-specific and not implemented everywhere, so
+ # just skip it for testing purposes.
+ }
elsif ($event eq 'cmd_name') {
$processes->{$sid}->{'name'} = $line->{'name'};
$processes->{$sid}->{'hierarchy'} = $line->{'hierarchy'};
diff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh
index ebd5fa5249..698b7159f0 100755
--- a/t/t0301-credential-cache.sh
+++ b/t/t0301-credential-cache.sh
@@ -9,6 +9,21 @@ test -z "$NO_UNIX_SOCKETS" || {
test_done
}
+uname_s=$(uname -s)
+case $uname_s in
+*MINGW*)
+ test_path_is_socket () {
+ # `test -S` cannot detect Win10's Unix sockets
+ test_path_exists "$1"
+ }
+ ;;
+*)
+ test_path_is_socket () {
+ test -S "$1"
+ }
+ ;;
+esac
+
# don't leave a stale daemon running
test_atexit 'git credential-cache exit'
@@ -21,7 +36,7 @@ test_expect_success 'socket defaults to ~/.cache/git/credential/socket' '
rmdir -p .cache/git/credential/
" &&
test_path_is_missing "$HOME/.git-credential-cache" &&
- test -S "$HOME/.cache/git/credential/socket"
+ test_path_is_socket "$HOME/.cache/git/credential/socket"
'
XDG_CACHE_HOME="$HOME/xdg"
@@ -31,7 +46,7 @@ helper_test cache
test_expect_success "use custom XDG_CACHE_HOME if set and default sockets are not created" '
test_when_finished "git credential-cache exit" &&
- test -S "$XDG_CACHE_HOME/git/credential/socket" &&
+ test_path_is_socket "$XDG_CACHE_HOME/git/credential/socket" &&
test_path_is_missing "$HOME/.git-credential-cache/socket" &&
test_path_is_missing "$HOME/.cache/git/credential/socket"
'
@@ -48,7 +63,7 @@ test_expect_success 'credential-cache --socket option overrides default location
username=store-user
password=store-pass
EOF
- test -S "$HOME/dir/socket"
+ test_path_is_socket "$HOME/dir/socket"
'
test_expect_success "use custom XDG_CACHE_HOME even if xdg socket exists" '
@@ -62,7 +77,7 @@ test_expect_success "use custom XDG_CACHE_HOME even if xdg socket exists" '
username=store-user
password=store-pass
EOF
- test -S "$HOME/.cache/git/credential/socket" &&
+ test_path_is_socket "$HOME/.cache/git/credential/socket" &&
XDG_CACHE_HOME="$HOME/xdg" &&
export XDG_CACHE_HOME &&
check approve cache <<-\EOF &&
@@ -71,7 +86,7 @@ test_expect_success "use custom XDG_CACHE_HOME even if xdg socket exists" '
username=store-user
password=store-pass
EOF
- test -S "$XDG_CACHE_HOME/git/credential/socket"
+ test_path_is_socket "$XDG_CACHE_HOME/git/credential/socket"
'
test_expect_success 'use user socket if user directory exists' '
@@ -79,14 +94,15 @@ test_expect_success 'use user socket if user directory exists' '
git credential-cache exit &&
rmdir \"\$HOME/.git-credential-cache/\"
" &&
- mkdir -p -m 700 "$HOME/.git-credential-cache/" &&
+ mkdir -p "$HOME/.git-credential-cache/" &&
+ chmod 700 "$HOME/.git-credential-cache/" &&
check approve cache <<-\EOF &&
protocol=https
host=example.com
username=store-user
password=store-pass
EOF
- test -S "$HOME/.git-credential-cache/socket"
+ test_path_is_socket "$HOME/.git-credential-cache/socket"
'
test_expect_success SYMLINKS 'use user socket if user directory is a symlink to a directory' '
@@ -103,7 +119,7 @@ test_expect_success SYMLINKS 'use user socket if user directory is a symlink to
username=store-user
password=store-pass
EOF
- test -S "$HOME/.git-credential-cache/socket"
+ test_path_is_socket "$HOME/.git-credential-cache/socket"
'
helper_test_timeout cache --timeout=1
diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh
index 584a039b85..bba679685f 100755
--- a/t/t0410-partial-clone.sh
+++ b/t/t0410-partial-clone.sh
@@ -4,6 +4,9 @@ test_description='partial clone'
. ./test-lib.sh
+# missing promisor objects cause repacks which write bitmaps to fail
+GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
+
delete_object () {
rm $1/.git/objects/$(echo $2 | sed -e 's|^..|&/|')
}
@@ -536,7 +539,13 @@ test_expect_success 'gc does not repack promisor objects if there are none' '
repack_and_check () {
rm -rf repo2 &&
cp -r repo repo2 &&
- git -C repo2 repack $1 -d &&
+ if test x"$1" = "x--must-fail"
+ then
+ shift
+ test_must_fail git -C repo2 repack $1 -d
+ else
+ git -C repo2 repack $1 -d
+ fi &&
git -C repo2 fsck &&
git -C repo2 cat-file -e $2 &&
@@ -561,6 +570,7 @@ test_expect_success 'repack -d does not irreversibly delete promisor objects' '
printf "$THREE\n" | pack_as_from_promisor &&
delete_object repo "$ONE" &&
+ repack_and_check --must-fail -ab "$TWO" "$THREE" &&
repack_and_check -a "$TWO" "$THREE" &&
repack_and_check -A "$TWO" "$THREE" &&
repack_and_check -l "$TWO" "$THREE"
@@ -604,6 +614,29 @@ test_expect_success 'do not fetch when checking existence of tree we construct o
git -C repo cherry-pick side1
'
+test_expect_success 'lazy-fetch when accessing object not in the_repository' '
+ rm -rf full partial.git &&
+ test_create_repo full &&
+ test_commit -C full create-a-file file.txt &&
+
+ test_config -C full uploadpack.allowfilter 1 &&
+ test_config -C full uploadpack.allowanysha1inwant 1 &&
+ git clone --filter=blob:none --bare "file://$(pwd)/full" partial.git &&
+ FILE_HASH=$(git -C full rev-parse HEAD:file.txt) &&
+
+ # Sanity check that the file is missing
+ git -C partial.git rev-list --objects --missing=print HEAD >out &&
+ grep "[?]$FILE_HASH" out &&
+
+ git -C full cat-file -s "$FILE_HASH" >expect &&
+ test-tool partial-clone object-info partial.git "$FILE_HASH" >actual &&
+ test_cmp expect actual &&
+
+ # Sanity check that the file is now present
+ git -C partial.git rev-list --objects --missing=print HEAD >out &&
+ ! grep "[?]$FILE_HASH" out
+'
+
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index 5d2dc99b74..4a753705ec 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -331,6 +331,11 @@ test_expect_success "Size of broken object is correct" '
git cat-file -s --allow-unknown-type $bogus_sha1 >actual &&
test_cmp expect actual
'
+
+test_expect_success 'clean up broken object' '
+ rm .git/objects/$(test_oid_to_path $bogus_sha1)
+'
+
bogus_type="abcdefghijklmnopqrstuvwxyz1234679"
bogus_content="bogus"
bogus_size=$(strlen "$bogus_content")
@@ -348,6 +353,10 @@ test_expect_success "Size of large broken object is correct when type is large"
test_cmp expect actual
'
+test_expect_success 'clean up broken object' '
+ rm .git/objects/$(test_oid_to_path $bogus_sha1)
+'
+
# Tests for git cat-file --follow-symlinks
test_expect_success 'prep for symlink tests' '
echo_without_newline "$hello_content" >morx &&
@@ -586,4 +595,92 @@ test_expect_success 'cat-file --unordered works' '
test_cmp expect actual
'
+test_expect_success 'set up object list for --batch-all-objects tests' '
+ git -C all-two cat-file --batch-all-objects --batch-check="%(objectname)" >objects
+'
+
+test_expect_success 'cat-file --batch="%(objectname)" with --batch-all-objects will work' '
+ git -C all-two cat-file --batch="%(objectname)" <objects >expect &&
+ git -C all-two cat-file --batch-all-objects --batch="%(objectname)" >actual &&
+ cmp expect actual
+'
+
+test_expect_success 'cat-file --batch="%(rest)" with --batch-all-objects will work' '
+ git -C all-two cat-file --batch="%(rest)" <objects >expect &&
+ git -C all-two cat-file --batch-all-objects --batch="%(rest)" >actual &&
+ cmp expect actual
+'
+
+test_expect_success 'cat-file --batch="batman" with --batch-all-objects will work' '
+ git -C all-two cat-file --batch="batman" <objects >expect &&
+ git -C all-two cat-file --batch-all-objects --batch="batman" >actual &&
+ cmp expect actual
+'
+
+test_expect_success 'set up replacement object' '
+ orig=$(git rev-parse HEAD) &&
+ git cat-file commit $orig >orig &&
+ {
+ cat orig &&
+ echo extra
+ } >fake &&
+ fake=$(git hash-object -t commit -w fake) &&
+ orig_size=$(git cat-file -s $orig) &&
+ fake_size=$(git cat-file -s $fake) &&
+ git replace $orig $fake
+'
+
+test_expect_success 'cat-file --batch respects replace objects' '
+ git cat-file --batch >actual <<-EOF &&
+ $orig
+ EOF
+ {
+ echo "$orig commit $fake_size" &&
+ cat fake &&
+ echo
+ } >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cat-file --batch-check respects replace objects' '
+ git cat-file --batch-check >actual <<-EOF &&
+ $orig
+ EOF
+ echo "$orig commit $fake_size" >expect &&
+ test_cmp expect actual
+'
+
+# Pull the entry for object with oid "$1" out of the output of
+# "cat-file --batch", including its object content (which requires
+# parsing and reading a set amount of bytes, hence perl).
+extract_batch_output () {
+ perl -ne '
+ BEGIN { $oid = shift }
+ if (/^$oid \S+ (\d+)$/) {
+ print;
+ read STDIN, my $buf, $1;
+ print $buf;
+ print "\n";
+ }
+ ' "$@"
+}
+
+test_expect_success 'cat-file --batch-all-objects --batch ignores replace' '
+ git cat-file --batch-all-objects --batch >actual.raw &&
+ extract_batch_output $orig <actual.raw >actual &&
+ {
+ echo "$orig commit $orig_size" &&
+ cat orig &&
+ echo
+ } >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cat-file --batch-all-objects --batch-check ignores replace' '
+ git cat-file --batch-all-objects --batch-check >actual.raw &&
+ grep ^$orig actual.raw >actual &&
+ echo "$orig commit $orig_size" >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t1013-read-tree-submodule.sh b/t/t1013-read-tree-submodule.sh
index b6df7444c0..bfc90d4cf2 100755
--- a/t/t1013-read-tree-submodule.sh
+++ b/t/t1013-read-tree-submodule.sh
@@ -6,7 +6,6 @@ test_description='read-tree can handle submodules'
. "$TEST_DIRECTORY"/lib-submodule-update.sh
KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1
-KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED=1
test_submodule_switch_recursing_with_args "read-tree -u -m"
diff --git a/t/t1022-read-tree-partial-clone.sh b/t/t1022-read-tree-partial-clone.sh
new file mode 100755
index 0000000000..a763e27c7d
--- /dev/null
+++ b/t/t1022-read-tree-partial-clone.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+test_description='git read-tree in partial clones'
+
+TEST_NO_CREATE_REPO=1
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+test_expect_success 'read-tree in partial clone prefetches in one batch' '
+ test_when_finished "rm -rf server client trace" &&
+
+ git init server &&
+ echo foo >server/one &&
+ echo bar >server/two &&
+ git -C server add one two &&
+ git -C server commit -m "initial commit" &&
+ TREE=$(git -C server rev-parse HEAD^{tree}) &&
+
+ git -C server config uploadpack.allowfilter 1 &&
+ git -C server config uploadpack.allowanysha1inwant 1 &&
+ git clone --bare --filter=blob:none "file://$(pwd)/server" client &&
+ GIT_TRACE_PACKET="$(pwd)/trace" git -C client read-tree $TREE &&
+
+ # "done" marks the end of negotiation (once per fetch). Expect that
+ # only one fetch occurs.
+ grep "fetch> done" trace >donelines &&
+ test_line_count = 1 donelines
+'
+
+test_done
diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh
index 38fc8340f5..272ba1b566 100755
--- a/t/t1091-sparse-checkout-builtin.sh
+++ b/t/t1091-sparse-checkout-builtin.sh
@@ -206,16 +206,21 @@ test_expect_success 'sparse-checkout disable' '
'
test_expect_success 'sparse-index enabled and disabled' '
- git -C repo sparse-checkout init --cone --sparse-index &&
- test_cmp_config -C repo true index.sparse &&
- test-tool -C repo read-cache --table >cache &&
- grep " tree " cache &&
-
- git -C repo sparse-checkout disable &&
- test-tool -C repo read-cache --table >cache &&
- ! grep " tree " cache &&
- git -C repo config --list >config &&
- ! grep index.sparse config
+ (
+ sane_unset GIT_TEST_SPLIT_INDEX &&
+ git -C repo update-index --no-split-index &&
+
+ git -C repo sparse-checkout init --cone --sparse-index &&
+ test_cmp_config -C repo true index.sparse &&
+ test-tool -C repo read-cache --table >cache &&
+ grep " tree " cache &&
+
+ git -C repo sparse-checkout disable &&
+ test-tool -C repo read-cache --table >cache &&
+ ! grep " tree " cache &&
+ git -C repo config --list >config &&
+ ! grep index.sparse config
+ )
'
test_expect_success 'cone mode: init and set' '
@@ -406,7 +411,7 @@ test_expect_success 'sparse-checkout (init|set|disable) warns with unmerged stat
git -C unmerged sparse-checkout disable
'
-test_expect_success 'sparse-checkout reapply' '
+test_expect_failure 'sparse-checkout reapply' '
git clone repo tweak &&
echo dirty >tweak/deep/deeper2/a &&
@@ -438,6 +443,8 @@ test_expect_success 'sparse-checkout reapply' '
test_i18ngrep "warning.*The following paths are unmerged" err &&
test_path_is_file tweak/folder1/a &&
+ # NEEDSWORK: We are asking to update a file outside of the
+ # sparse-checkout cone, but this is no longer allowed.
git -C tweak add folder1/a &&
git -C tweak sparse-checkout reapply 2>err &&
test_must_be_empty err &&
@@ -642,4 +649,63 @@ test_expect_success MINGW 'cone mode replaces backslashes with slashes' '
check_files repo/deep a deeper1
'
+test_expect_success 'cone mode clears ignored subdirectories' '
+ rm repo/.git/info/sparse-checkout &&
+
+ git -C repo sparse-checkout init --cone &&
+ git -C repo sparse-checkout set deep/deeper1 &&
+
+ cat >repo/.gitignore <<-\EOF &&
+ obj/
+ *.o
+ EOF
+
+ git -C repo add .gitignore &&
+ git -C repo commit -m ".gitignore" &&
+
+ mkdir -p repo/obj repo/folder1/obj repo/deep/deeper2/obj &&
+ for file in folder1/obj/a obj/a folder1/file.o folder1.o \
+ deep/deeper2/obj/a deep/deeper2/file.o file.o
+ do
+ echo ignored >repo/$file || return 1
+ done &&
+
+ git -C repo status --porcelain=v2 >out &&
+ test_must_be_empty out &&
+
+ git -C repo sparse-checkout reapply &&
+ test_path_is_missing repo/folder1 &&
+ test_path_is_missing repo/deep/deeper2 &&
+ test_path_is_dir repo/obj &&
+ test_path_is_file repo/file.o &&
+
+ git -C repo status --porcelain=v2 >out &&
+ test_must_be_empty out &&
+
+ git -C repo sparse-checkout set deep/deeper2 &&
+ test_path_is_missing repo/deep/deeper1 &&
+ test_path_is_dir repo/deep/deeper2 &&
+ test_path_is_dir repo/obj &&
+ test_path_is_file repo/file.o &&
+
+ >repo/deep/deeper2/ignored.o &&
+ >repo/deep/deeper2/untracked &&
+
+ # When an untracked file is in the way, all untracked files
+ # (even ignored files) are preserved.
+ git -C repo sparse-checkout set folder1 2>err &&
+ grep "contains untracked files" err &&
+ test_path_is_file repo/deep/deeper2/ignored.o &&
+ test_path_is_file repo/deep/deeper2/untracked &&
+
+ # The rest of the cone matches expectation
+ test_path_is_missing repo/deep/deeper1 &&
+ test_path_is_dir repo/obj &&
+ test_path_is_file repo/file.o &&
+
+ git -C repo status --porcelain=v2 >out &&
+ echo "? deep/deeper2/untracked" >expect &&
+ test_cmp expect out
+'
+
test_done
diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh
index 12e6c45302..ca91c6a67f 100755
--- a/t/t1092-sparse-checkout-compatibility.sh
+++ b/t/t1092-sparse-checkout-compatibility.sh
@@ -17,7 +17,7 @@ test_expect_success 'setup' '
echo "after folder1" >g &&
echo "after x" >z &&
mkdir folder1 folder2 deep x &&
- mkdir deep/deeper1 deep/deeper2 &&
+ mkdir deep/deeper1 deep/deeper2 deep/before deep/later &&
mkdir deep/deeper1/deepest &&
echo "after deeper1" >deep/e &&
echo "after deepest" >deep/deeper1/e &&
@@ -25,22 +25,35 @@ test_expect_success 'setup' '
cp a folder2 &&
cp a x &&
cp a deep &&
+ cp a deep/before &&
cp a deep/deeper1 &&
cp a deep/deeper2 &&
+ cp a deep/later &&
cp a deep/deeper1/deepest &&
cp -r deep/deeper1/deepest deep/deeper2 &&
+ mkdir deep/deeper1/0 &&
+ mkdir deep/deeper1/0/0 &&
+ touch deep/deeper1/0/1 &&
+ touch deep/deeper1/0/0/0 &&
+ >folder1- &&
+ >folder1.x &&
+ >folder10 &&
+ cp -r deep/deeper1/0 folder1 &&
+ cp -r deep/deeper1/0 folder2 &&
+ echo >>folder1/0/0/0 &&
+ echo >>folder2/0/1 &&
git add . &&
git commit -m "initial commit" &&
git checkout -b base &&
for dir in folder1 folder2 deep
do
- git checkout -b update-$dir &&
+ git checkout -b update-$dir base &&
echo "updated $dir" >$dir/a &&
git commit -a -m "update $dir" || return 1
done &&
git checkout -b rename-base base &&
- echo >folder1/larger-content <<-\EOF &&
+ cat >folder1/larger-content <<-\EOF &&
matching
lines
help
@@ -56,11 +69,17 @@ test_expect_success 'setup' '
mv folder1/a folder2/b &&
mv folder1/larger-content folder2/edited-content &&
echo >>folder2/edited-content &&
+ echo >>folder2/0/1 &&
+ echo stuff >>deep/deeper1/a &&
git add . &&
git commit -m "rename folder1/... to folder2/..." &&
git checkout -b rename-out-to-in rename-base &&
mv folder1/a deep/deeper1/b &&
+ echo more stuff >>deep/deeper1/a &&
+ rm folder2/0/1 &&
+ mkdir folder2/0/1 &&
+ echo >>folder2/0/1/1 &&
mv folder1/larger-content deep/deeper1/edited-content &&
echo >>deep/deeper1/edited-content &&
git add . &&
@@ -68,11 +87,43 @@ test_expect_success 'setup' '
git checkout -b rename-in-to-out rename-base &&
mv deep/deeper1/a folder1/b &&
+ echo >>folder2/0/1 &&
+ rm -rf folder1/0/0 &&
+ echo >>folder1/0/0 &&
mv deep/deeper1/larger-content folder1/edited-content &&
echo >>folder1/edited-content &&
git add . &&
git commit -m "rename deep/deeper1/... to folder1/..." &&
+ git checkout -b df-conflict-1 base &&
+ rm -rf folder1 &&
+ echo content >folder1 &&
+ git add . &&
+ git commit -m "dir to file" &&
+
+ git checkout -b df-conflict-2 base &&
+ rm -rf folder2 &&
+ echo content >folder2 &&
+ git add . &&
+ git commit -m "dir to file" &&
+
+ git checkout -b fd-conflict base &&
+ rm a &&
+ mkdir a &&
+ echo content >a/a &&
+ git add . &&
+ git commit -m "file to dir" &&
+
+ for side in left right
+ do
+ git checkout -b merge-$side base &&
+ echo $side >>deep/deeper2/a &&
+ echo $side >>folder1/a &&
+ echo $side >>folder2/a &&
+ git add . &&
+ git commit -m "$side" || return 1
+ done &&
+
git checkout -b deepest base &&
echo "updated deepest" >deep/deeper1/deepest/a &&
git commit -a -m "update deepest" &&
@@ -106,18 +157,18 @@ init_repos () {
run_on_sparse () {
(
cd sparse-checkout &&
- "$@" >../sparse-checkout-out 2>../sparse-checkout-err
+ GIT_PROGRESS_DELAY=100000 "$@" >../sparse-checkout-out 2>../sparse-checkout-err
) &&
(
cd sparse-index &&
- "$@" >../sparse-index-out 2>../sparse-index-err
+ GIT_PROGRESS_DELAY=100000 "$@" >../sparse-index-out 2>../sparse-index-err
)
}
run_on_all () {
(
cd full-checkout &&
- "$@" >../full-checkout-out 2>../full-checkout-err
+ GIT_PROGRESS_DELAY=100000 "$@" >../full-checkout-out 2>../full-checkout-err
) &&
run_on_sparse "$@"
}
@@ -136,6 +187,16 @@ test_sparse_match () {
test_cmp sparse-checkout-err sparse-index-err
}
+test_sparse_unstaged () {
+ file=$1 &&
+ for repo in sparse-checkout sparse-index
+ do
+ # Skip "unmerged" paths
+ git -C $repo diff --staged --diff-filter=u -- "$file" >diff &&
+ test_must_be_empty diff || return 1
+ done
+}
+
test_expect_success 'sparse-index contents' '
init_repos &&
@@ -196,6 +257,14 @@ test_expect_success 'status with options' '
test_all_match git status --porcelain=v2 -uno
'
+test_expect_success 'status reports sparse-checkout' '
+ init_repos &&
+ git -C sparse-checkout status >full &&
+ git -C sparse-index status >sparse &&
+ test_i18ngrep "You are in a sparse checkout with " full &&
+ test_i18ngrep "You are in a sparse checkout." sparse
+'
+
test_expect_success 'add, commit, checkout' '
init_repos &&
@@ -232,6 +301,91 @@ test_expect_success 'add, commit, checkout' '
test_all_match git checkout -
'
+test_expect_success 'add outside sparse cone' '
+ init_repos &&
+
+ run_on_sparse mkdir folder1 &&
+ run_on_sparse ../edit-contents folder1/a &&
+ run_on_sparse ../edit-contents folder1/newfile &&
+ test_sparse_match test_must_fail git add folder1/a &&
+ grep "Disable or modify the sparsity rules" sparse-checkout-err &&
+ test_sparse_unstaged folder1/a &&
+ test_sparse_match test_must_fail git add folder1/newfile &&
+ grep "Disable or modify the sparsity rules" sparse-checkout-err &&
+ test_sparse_unstaged folder1/newfile
+'
+
+test_expect_success 'commit including unstaged changes' '
+ init_repos &&
+
+ write_script edit-file <<-\EOF &&
+ echo $1 >$2
+ EOF
+
+ run_on_all ../edit-file 1 a &&
+ run_on_all ../edit-file 1 deep/a &&
+
+ test_all_match git commit -m "-a" -a &&
+ test_all_match git status --porcelain=v2 &&
+
+ run_on_all ../edit-file 2 a &&
+ run_on_all ../edit-file 2 deep/a &&
+
+ test_all_match git commit -m "--include" --include deep/a &&
+ test_all_match git status --porcelain=v2 &&
+ test_all_match git commit -m "--include" --include a &&
+ test_all_match git status --porcelain=v2 &&
+
+ run_on_all ../edit-file 3 a &&
+ run_on_all ../edit-file 3 deep/a &&
+
+ test_all_match git commit -m "--amend" -a --amend &&
+ test_all_match git status --porcelain=v2
+'
+
+test_expect_success 'status/add: outside sparse cone' '
+ init_repos &&
+
+ # folder1 is at HEAD, but outside the sparse cone
+ run_on_sparse mkdir folder1 &&
+ cp initial-repo/folder1/a sparse-checkout/folder1/a &&
+ cp initial-repo/folder1/a sparse-index/folder1/a &&
+
+ test_sparse_match git status &&
+
+ write_script edit-contents <<-\EOF &&
+ echo text >>$1
+ EOF
+ run_on_sparse ../edit-contents folder1/a &&
+ run_on_all ../edit-contents folder1/new &&
+
+ test_sparse_match git status --porcelain=v2 &&
+
+ # Adding the path outside of the sparse-checkout cone should fail.
+ test_sparse_match test_must_fail git add folder1/a &&
+ grep "Disable or modify the sparsity rules" sparse-checkout-err &&
+ test_sparse_unstaged folder1/a &&
+ test_sparse_match test_must_fail git add --refresh folder1/a &&
+ grep "Disable or modify the sparsity rules" sparse-checkout-err &&
+ test_sparse_unstaged folder1/a &&
+ test_sparse_match test_must_fail git add folder1/new &&
+ grep "Disable or modify the sparsity rules" sparse-checkout-err &&
+ test_sparse_unstaged folder1/new &&
+ test_sparse_match git add --sparse folder1/a &&
+ test_sparse_match git add --sparse folder1/new &&
+
+ test_all_match git add --sparse . &&
+ test_all_match git status --porcelain=v2 &&
+ test_all_match git commit -m folder1/new &&
+ test_all_match git rev-parse HEAD^{tree} &&
+
+ run_on_all ../edit-contents folder1/newer &&
+ test_all_match git add --sparse folder1/ &&
+ test_all_match git status --porcelain=v2 &&
+ test_all_match git commit -m folder1/newer &&
+ test_all_match git rev-parse HEAD^{tree}
+'
+
test_expect_success 'checkout and reset --hard' '
init_repos &&
@@ -262,13 +416,40 @@ test_expect_success 'diff --staged' '
test_all_match git diff --staged
'
-test_expect_success 'diff with renames' '
+# NEEDSWORK: sparse-checkout behaves differently from full-checkout when
+# running this test with 'df-conflict-2' after 'df-conflict-1'.
+test_expect_success 'diff with renames and conflicts' '
init_repos &&
- for branch in rename-out-to-out rename-out-to-in rename-in-to-out
+ for branch in rename-out-to-out \
+ rename-out-to-in \
+ rename-in-to-out \
+ df-conflict-1 \
+ fd-conflict
do
test_all_match git checkout rename-base &&
- test_all_match git checkout $branch -- .&&
+ test_all_match git checkout $branch -- . &&
+ test_all_match git status --porcelain=v2 &&
+ test_all_match git diff --staged --no-renames &&
+ test_all_match git diff --staged --find-renames || return 1
+ done
+'
+
+test_expect_success 'diff with directory/file conflicts' '
+ init_repos &&
+
+ for branch in rename-out-to-out \
+ rename-out-to-in \
+ rename-in-to-out \
+ df-conflict-1 \
+ df-conflict-2 \
+ fd-conflict
+ do
+ git -C full-checkout reset --hard &&
+ test_sparse_match git reset --hard &&
+ test_all_match git checkout $branch &&
+ test_all_match git checkout rename-base -- . &&
+ test_all_match git status --porcelain=v2 &&
test_all_match git diff --staged --no-renames &&
test_all_match git diff --staged --find-renames || return 1
done
@@ -308,8 +489,8 @@ test_expect_failure 'blame with pathspec outside sparse definition' '
test_all_match git blame deep/deeper2/deepest/a
'
-# TODO: reset currently does not behave as expected when in a
-# sparse-checkout.
+# NEEDSWORK: a sparse-checkout behaves differently from a full checkout
+# in this scenario, but it shouldn't.
test_expect_failure 'checkout and reset (mixed)' '
init_repos &&
@@ -319,8 +500,8 @@ test_expect_failure 'checkout and reset (mixed)' '
test_all_match git reset update-folder2
'
-# Ensure that sparse-index behaves identically to
-# sparse-checkout with a full index.
+# NEEDSWORK: a sparse-checkout behaves differently from a full checkout
+# in this scenario, but it shouldn't.
test_expect_success 'checkout and reset (mixed) [sparse]' '
init_repos &&
@@ -330,16 +511,97 @@ test_expect_success 'checkout and reset (mixed) [sparse]' '
test_sparse_match git reset update-folder2
'
-test_expect_success 'merge' '
+test_expect_success 'merge, cherry-pick, and rebase' '
init_repos &&
- test_all_match git checkout -b merge update-deep &&
- test_all_match git merge -m "folder1" update-folder1 &&
- test_all_match git rev-parse HEAD^{tree} &&
- test_all_match git merge -m "folder2" update-folder2 &&
+ for OPERATION in "merge -m merge" cherry-pick rebase
+ do
+ test_all_match git checkout -B temp update-deep &&
+ test_all_match git $OPERATION update-folder1 &&
+ test_all_match git rev-parse HEAD^{tree} &&
+ test_all_match git $OPERATION update-folder2 &&
+ test_all_match git rev-parse HEAD^{tree} || return 1
+ done
+'
+
+test_expect_success 'merge with conflict outside cone' '
+ init_repos &&
+
+ test_all_match git checkout -b merge-tip merge-left &&
+ test_all_match git status --porcelain=v2 &&
+ test_all_match test_must_fail git merge -m merge merge-right &&
+ test_all_match git status --porcelain=v2 &&
+
+ # Resolve the conflict in different ways:
+ # 1. Revert to the base
+ test_all_match git checkout base -- deep/deeper2/a &&
+ test_all_match git status --porcelain=v2 &&
+
+ # 2. Add the file with conflict markers
+ test_sparse_match test_must_fail git add folder1/a &&
+ grep "Disable or modify the sparsity rules" sparse-checkout-err &&
+ test_sparse_unstaged folder1/a &&
+ test_all_match git add --sparse folder1/a &&
+ test_all_match git status --porcelain=v2 &&
+
+ # 3. Rename the file to another sparse filename and
+ # accept conflict markers as resolved content.
+ run_on_all mv folder2/a folder2/z &&
+ test_sparse_match test_must_fail git add folder2 &&
+ grep "Disable or modify the sparsity rules" sparse-checkout-err &&
+ test_sparse_unstaged folder2/z &&
+ test_all_match git add --sparse folder2 &&
+ test_all_match git status --porcelain=v2 &&
+
+ test_all_match git merge --continue &&
+ test_all_match git status --porcelain=v2 &&
test_all_match git rev-parse HEAD^{tree}
'
+test_expect_success 'cherry-pick/rebase with conflict outside cone' '
+ init_repos &&
+
+ for OPERATION in cherry-pick rebase
+ do
+ test_all_match git checkout -B tip &&
+ test_all_match git reset --hard merge-left &&
+ test_all_match git status --porcelain=v2 &&
+ test_all_match test_must_fail git $OPERATION merge-right &&
+ test_all_match git status --porcelain=v2 &&
+
+ # Resolve the conflict in different ways:
+ # 1. Revert to the base
+ test_all_match git checkout base -- deep/deeper2/a &&
+ test_all_match git status --porcelain=v2 &&
+
+ # 2. Add the file with conflict markers
+ # NEEDSWORK: Even though the merge conflict removed the
+ # SKIP_WORKTREE bit from the index entry for folder1/a, we should
+ # warn that this is a problematic add.
+ test_sparse_match test_must_fail git add folder1/a &&
+ grep "Disable or modify the sparsity rules" sparse-checkout-err &&
+ test_sparse_unstaged folder1/a &&
+ test_all_match git add --sparse folder1/a &&
+ test_all_match git status --porcelain=v2 &&
+
+ # 3. Rename the file to another sparse filename and
+ # accept conflict markers as resolved content.
+ # NEEDSWORK: This mode now fails, because folder2/z is
+ # outside of the sparse-checkout cone and does not match an
+ # existing index entry with the SKIP_WORKTREE bit cleared.
+ run_on_all mv folder2/a folder2/z &&
+ test_sparse_match test_must_fail git add folder2 &&
+ grep "Disable or modify the sparsity rules" sparse-checkout-err &&
+ test_sparse_unstaged folder2/z &&
+ test_all_match git add --sparse folder2 &&
+ test_all_match git status --porcelain=v2 &&
+
+ test_all_match git $OPERATION --continue &&
+ test_all_match git status --porcelain=v2 &&
+ test_all_match git rev-parse HEAD^{tree} || return 1
+ done
+'
+
test_expect_success 'merge with outside renames' '
init_repos &&
@@ -352,6 +614,28 @@ test_expect_success 'merge with outside renames' '
done
'
+# Sparse-index fails to convert the index in the
+# final 'git cherry-pick' command.
+test_expect_success 'cherry-pick with conflicts' '
+ init_repos &&
+
+ write_script edit-conflict <<-\EOF &&
+ echo $1 >conflict
+ EOF
+
+ test_all_match git checkout -b to-cherry-pick &&
+ run_on_all ../edit-conflict ABC &&
+ test_all_match git add conflict &&
+ test_all_match git commit -m "conflict to pick" &&
+
+ test_all_match git checkout -B base HEAD~1 &&
+ run_on_all ../edit-conflict DEF &&
+ test_all_match git add conflict &&
+ test_all_match git commit -m "conflict in base" &&
+
+ test_all_match test_must_fail git cherry-pick to-cherry-pick
+'
+
test_expect_success 'clean' '
init_repos &&
@@ -385,6 +669,7 @@ test_expect_success 'clean' '
test_expect_success 'submodule handling' '
init_repos &&
+ test_sparse_match git sparse-checkout add modules &&
test_all_match mkdir modules &&
test_all_match touch modules/a &&
test_all_match git add modules &&
@@ -394,6 +679,7 @@ test_expect_success 'submodule handling' '
test_all_match git commit -m "add submodule" &&
# having a submodule prevents "modules" from collapse
+ test_sparse_match git sparse-checkout set deep/deeper1 &&
test-tool -C sparse-index read-cache --table >cache &&
grep "100644 blob .* modules/a" cache &&
grep "160000 commit $(git -C initial-repo rev-parse HEAD) modules/sub" cache
@@ -405,12 +691,223 @@ test_expect_success 'sparse-index is expanded and converted back' '
GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
git -C sparse-index -c core.fsmonitor="" reset --hard &&
test_region index convert_to_sparse trace2.txt &&
- test_region index ensure_full_index trace2.txt &&
-
- rm trace2.txt &&
- GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
- git -C sparse-index -c core.fsmonitor="" status -uno &&
test_region index ensure_full_index trace2.txt
'
+ensure_not_expanded () {
+ rm -f trace2.txt &&
+ echo >>sparse-index/untracked.txt &&
+
+ if test "$1" = "!"
+ then
+ shift &&
+ test_must_fail env \
+ GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
+ git -C sparse-index "$@" || return 1
+ else
+ GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
+ git -C sparse-index "$@" || return 1
+ fi &&
+ test_region ! index ensure_full_index trace2.txt
+}
+
+test_expect_success 'sparse-index is not expanded' '
+ init_repos &&
+
+ ensure_not_expanded status &&
+ ensure_not_expanded commit --allow-empty -m empty &&
+ echo >>sparse-index/a &&
+ ensure_not_expanded commit -a -m a &&
+ echo >>sparse-index/a &&
+ ensure_not_expanded commit --include a -m a &&
+ echo >>sparse-index/deep/deeper1/a &&
+ ensure_not_expanded commit --include deep/deeper1/a -m deeper &&
+ ensure_not_expanded checkout rename-out-to-out &&
+ ensure_not_expanded checkout - &&
+ ensure_not_expanded switch rename-out-to-out &&
+ ensure_not_expanded switch - &&
+ git -C sparse-index reset --hard &&
+ ensure_not_expanded checkout rename-out-to-out -- deep/deeper1 &&
+ git -C sparse-index reset --hard &&
+ ensure_not_expanded restore -s rename-out-to-out -- deep/deeper1 &&
+
+ echo >>sparse-index/README.md &&
+ ensure_not_expanded add -A &&
+ echo >>sparse-index/extra.txt &&
+ ensure_not_expanded add extra.txt &&
+ echo >>sparse-index/untracked.txt &&
+ ensure_not_expanded add . &&
+
+ ensure_not_expanded checkout -f update-deep &&
+ test_config -C sparse-index pull.twohead ort &&
+ (
+ sane_unset GIT_TEST_MERGE_ALGORITHM &&
+ for OPERATION in "merge -m merge" cherry-pick rebase
+ do
+ ensure_not_expanded merge -m merge update-folder1 &&
+ ensure_not_expanded merge -m merge update-folder2 || return 1
+ done
+ )
+'
+
+test_expect_success 'sparse-index is not expanded: merge conflict in cone' '
+ init_repos &&
+
+ for side in right left
+ do
+ git -C sparse-index checkout -b expand-$side base &&
+ echo $side >sparse-index/deep/a &&
+ git -C sparse-index commit -a -m "$side" || return 1
+ done &&
+
+ (
+ sane_unset GIT_TEST_MERGE_ALGORITHM &&
+ git -C sparse-index config pull.twohead ort &&
+ ensure_not_expanded ! merge -m merged expand-right
+ )
+'
+
+# NEEDSWORK: a sparse-checkout behaves differently from a full checkout
+# in this scenario, but it shouldn't.
+test_expect_success 'reset mixed and checkout orphan' '
+ init_repos &&
+
+ test_all_match git checkout rename-out-to-in &&
+
+ # Sparse checkouts do not agree with full checkouts about
+ # how to report a directory/file conflict during a reset.
+ # This command would fail with test_all_match because the
+ # full checkout reports "T folder1/0/1" while a sparse
+ # checkout reports "D folder1/0/1". This matches because
+ # the sparse checkouts skip "adding" the other side of
+ # the conflict.
+ test_sparse_match git reset --mixed HEAD~1 &&
+ test_sparse_match test-tool read-cache --table --expand &&
+ test_sparse_match git status --porcelain=v2 &&
+
+ # At this point, sparse-checkouts behave differently
+ # from the full-checkout.
+ test_sparse_match git checkout --orphan new-branch &&
+ test_sparse_match test-tool read-cache --table --expand &&
+ test_sparse_match git status --porcelain=v2
+'
+
+test_expect_success 'add everything with deep new file' '
+ init_repos &&
+
+ run_on_sparse git sparse-checkout set deep/deeper1/deepest &&
+
+ run_on_all touch deep/deeper1/x &&
+ test_all_match git add . &&
+ test_all_match git status --porcelain=v2
+'
+
+# NEEDSWORK: 'git checkout' behaves incorrectly in the case of
+# directory/file conflicts, even without sparse-checkout. Use this
+# test only as a documentation of the incorrect behavior, not a
+# measure of how it _should_ behave.
+test_expect_success 'checkout behaves oddly with df-conflict-1' '
+ init_repos &&
+
+ test_sparse_match git sparse-checkout disable &&
+
+ write_script edit-content <<-\EOF &&
+ echo content >>folder1/larger-content
+ git add folder1
+ EOF
+
+ run_on_all ../edit-content &&
+ test_all_match git status --porcelain=v2 &&
+
+ git -C sparse-checkout sparse-checkout init --cone &&
+ git -C sparse-index sparse-checkout init --cone --sparse-index &&
+
+ test_all_match git status --porcelain=v2 &&
+
+ # This checkout command should fail, because we have a staged
+ # change to folder1/larger-content, but the destination changes
+ # folder1 to a file.
+ git -C full-checkout checkout df-conflict-1 \
+ 1>full-checkout-out \
+ 2>full-checkout-err &&
+ git -C sparse-checkout checkout df-conflict-1 \
+ 1>sparse-checkout-out \
+ 2>sparse-checkout-err &&
+ git -C sparse-index checkout df-conflict-1 \
+ 1>sparse-index-out \
+ 2>sparse-index-err &&
+
+ # Instead, the checkout deletes the folder1 file and adds the
+ # folder1/larger-content file, leaving all other paths that were
+ # in folder1/ as deleted (without any warning).
+ cat >expect <<-EOF &&
+ D folder1
+ A folder1/larger-content
+ EOF
+ test_cmp expect full-checkout-out &&
+ test_cmp expect sparse-checkout-out &&
+
+ # The sparse-index reports no output
+ test_must_be_empty sparse-index-out &&
+
+ # stderr: Switched to branch df-conflict-1
+ test_cmp full-checkout-err sparse-checkout-err &&
+ test_cmp full-checkout-err sparse-checkout-err
+'
+
+# NEEDSWORK: 'git checkout' behaves incorrectly in the case of
+# directory/file conflicts, even without sparse-checkout. Use this
+# test only as a documentation of the incorrect behavior, not a
+# measure of how it _should_ behave.
+test_expect_success 'checkout behaves oddly with df-conflict-2' '
+ init_repos &&
+
+ test_sparse_match git sparse-checkout disable &&
+
+ write_script edit-content <<-\EOF &&
+ echo content >>folder2/larger-content
+ git add folder2
+ EOF
+
+ run_on_all ../edit-content &&
+ test_all_match git status --porcelain=v2 &&
+
+ git -C sparse-checkout sparse-checkout init --cone &&
+ git -C sparse-index sparse-checkout init --cone --sparse-index &&
+
+ test_all_match git status --porcelain=v2 &&
+
+ # This checkout command should fail, because we have a staged
+ # change to folder1/larger-content, but the destination changes
+ # folder1 to a file.
+ git -C full-checkout checkout df-conflict-2 \
+ 1>full-checkout-out \
+ 2>full-checkout-err &&
+ git -C sparse-checkout checkout df-conflict-2 \
+ 1>sparse-checkout-out \
+ 2>sparse-checkout-err &&
+ git -C sparse-index checkout df-conflict-2 \
+ 1>sparse-index-out \
+ 2>sparse-index-err &&
+
+ # The full checkout deviates from the df-conflict-1 case here!
+ # It drops the change to folder1/larger-content and leaves the
+ # folder1 path as-is on disk. The sparse-index behaves the same.
+ test_must_be_empty full-checkout-out &&
+ test_must_be_empty sparse-index-out &&
+
+ # In the sparse-checkout case, the checkout deletes the folder1
+ # file and adds the folder1/larger-content file, leaving all other
+ # paths that were in folder1/ as deleted (without any warning).
+ cat >expect <<-EOF &&
+ D folder2
+ A folder2/larger-content
+ EOF
+ test_cmp expect sparse-checkout-out &&
+
+ # Switched to branch df-conflict-1
+ test_cmp full-checkout-err sparse-checkout-err &&
+ test_cmp full-checkout-err sparse-index-err
+'
+
test_done
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index e0dd5d65ce..9ff46f3b04 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -1374,16 +1374,29 @@ test_expect_success 'git --config-env=key=envvar support' '
cat >expect <<-\EOF &&
value
value
+ value
+ value
+ false
false
EOF
{
ENVVAR=value git --config-env=core.name=ENVVAR config core.name &&
+ ENVVAR=value git --config-env core.name=ENVVAR config core.name &&
ENVVAR=value git --config-env=foo.CamelCase=ENVVAR config foo.camelcase &&
- ENVVAR= git --config-env=foo.flag=ENVVAR config --bool foo.flag
+ ENVVAR=value git --config-env foo.CamelCase=ENVVAR config foo.camelcase &&
+ ENVVAR= git --config-env=foo.flag=ENVVAR config --bool foo.flag &&
+ ENVVAR= git --config-env foo.flag=ENVVAR config --bool foo.flag
} >actual &&
test_cmp expect actual
'
+test_expect_success 'git --config-env with missing value' '
+ test_must_fail env ENVVAR=value git --config-env 2>error &&
+ grep "no config key given for --config-env" error &&
+ test_must_fail env ENVVAR=value git --config-env config core.name 2>error &&
+ grep "invalid config format: config" error
+'
+
test_expect_success 'git --config-env fails with invalid parameters' '
test_must_fail git --config-env=foo.flag config --bool foo.flag 2>error &&
test_i18ngrep "invalid config format: foo.flag" error &&
@@ -2059,6 +2072,91 @@ test_expect_success '--show-scope with --show-origin' '
test_cmp expect output
'
+test_expect_success 'override global and system config' '
+ test_when_finished rm -f "$HOME"/.config/git &&
+
+ cat >"$HOME"/.gitconfig <<-EOF &&
+ [home]
+ config = true
+ EOF
+ mkdir -p "$HOME"/.config/git &&
+ cat >"$HOME"/.config/git/config <<-EOF &&
+ [xdg]
+ config = true
+ EOF
+ cat >.git/config <<-EOF &&
+ [local]
+ config = true
+ EOF
+ cat >custom-global-config <<-EOF &&
+ [global]
+ config = true
+ EOF
+ cat >custom-system-config <<-EOF &&
+ [system]
+ config = true
+ EOF
+
+ cat >expect <<-EOF &&
+ global xdg.config=true
+ global home.config=true
+ local local.config=true
+ EOF
+ git config --show-scope --list >output &&
+ test_cmp expect output &&
+
+ cat >expect <<-EOF &&
+ system system.config=true
+ global global.config=true
+ local local.config=true
+ EOF
+ GIT_CONFIG_NOSYSTEM=false GIT_CONFIG_SYSTEM=custom-system-config GIT_CONFIG_GLOBAL=custom-global-config \
+ git config --show-scope --list >output &&
+ test_cmp expect output &&
+
+ cat >expect <<-EOF &&
+ local local.config=true
+ EOF
+ GIT_CONFIG_NOSYSTEM=false GIT_CONFIG_SYSTEM=/dev/null GIT_CONFIG_GLOBAL=/dev/null \
+ git config --show-scope --list >output &&
+ test_cmp expect output
+'
+
+test_expect_success 'override global and system config with missing file' '
+ test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=/dev/null git config --global --list &&
+ test_must_fail env GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=does-not-exist git config --system --list &&
+ GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=does-not-exist git version
+'
+
+test_expect_success 'system override has no effect with GIT_CONFIG_NOSYSTEM' '
+ # `git config --system` has different semantics compared to other
+ # commands as it ignores GIT_CONFIG_NOSYSTEM. We thus test whether the
+ # variable has an effect via a different proxy.
+ cat >alias-config <<-EOF &&
+ [alias]
+ hello-world = !echo "hello world"
+ EOF
+ test_must_fail env GIT_CONFIG_NOSYSTEM=true GIT_CONFIG_SYSTEM=alias-config \
+ git hello-world &&
+ GIT_CONFIG_NOSYSTEM=false GIT_CONFIG_SYSTEM=alias-config \
+ git hello-world >actual &&
+ echo "hello world" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'write to overridden global and system config' '
+ cat >expect <<EOF &&
+[config]
+ key = value
+EOF
+
+ GIT_CONFIG_GLOBAL=write-to-global git config --global config.key value &&
+ test_cmp expect write-to-global &&
+
+ GIT_CONFIG_SYSTEM=write-to-system git config --system config.key value &&
+ test_cmp expect write-to-system
+'
+
for opt in --local --worktree
do
test_expect_success "$opt requires a repo" '
diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh
index ac947bff9f..84bf1970d8 100755
--- a/t/t1301-shared-repo.sh
+++ b/t/t1301-shared-repo.sh
@@ -124,7 +124,7 @@ test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' '
: happy
;;
*)
- echo Ooops, .git/logs/refs/heads/main is not 0662 [$actual]
+ echo Ooops, .git/logs/refs/heads/main is not 066x [$actual]
false
;;
esac
diff --git a/t/t1306-xdg-files.sh b/t/t1306-xdg-files.sh
index dd87b43be1..40d3c42618 100755
--- a/t/t1306-xdg-files.sh
+++ b/t/t1306-xdg-files.sh
@@ -116,7 +116,7 @@ test_expect_success 'Exclusion in a non-XDG global ignore file' '
test_expect_success 'Checking XDG ignore file when HOME is unset' '
(sane_unset HOME &&
git config --unset core.excludesfile &&
- git ls-files --exclude-standard --ignored >actual) &&
+ git ls-files --exclude-standard --ignored --others >actual) &&
test_must_be_empty actual
'
diff --git a/t/t1307-config-blob.sh b/t/t1307-config-blob.sh
index 002e6d3388..930dce06f0 100755
--- a/t/t1307-config-blob.sh
+++ b/t/t1307-config-blob.sh
@@ -65,9 +65,7 @@ test_expect_success 'parse errors in blobs are properly attributed' '
'
test_expect_success 'can parse blob ending with CR' '
- printf "[some]key = value\\r" >config &&
- git add config &&
- git commit -m CR &&
+ test_commit --printf CR config "[some]key = value\\r" &&
echo value >expect &&
git config --blob=HEAD:config some.key >actual &&
test_cmp expect actual
diff --git a/t/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh
index f1f9aee9f5..fa9647a7c0 100755
--- a/t/t1350-config-hooks-path.sh
+++ b/t/t1350-config-hooks-path.sh
@@ -5,6 +5,7 @@ test_description='Test the core.hooksPath configuration variable'
. ./test-lib.sh
test_expect_success 'set up a pre-commit hook in core.hooksPath' '
+ >actual &&
mkdir -p .git/custom-hooks .git/hooks &&
write_script .git/custom-hooks/pre-commit <<-\EOF &&
echo CUSTOM >>actual
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index e31f65f381..0d4f73acaa 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -1598,4 +1598,47 @@ test_expect_success 'transaction cannot restart ongoing transaction' '
test_must_fail git show-ref --verify refs/heads/restart
'
+test_expect_success PIPE 'transaction flushes status updates' '
+ mkfifo in out &&
+ (git update-ref --stdin <in >out &) &&
+
+ exec 9>in &&
+ exec 8<out &&
+ test_when_finished "exec 9>&-" &&
+ test_when_finished "exec 8<&-" &&
+
+ echo "start" >&9 &&
+ echo "start: ok" >expected &&
+ read line <&8 &&
+ echo "$line" >actual &&
+ test_cmp expected actual &&
+
+ echo "create refs/heads/flush $A" >&9 &&
+
+ echo prepare >&9 &&
+ echo "prepare: ok" >expected &&
+ read line <&8 &&
+ echo "$line" >actual &&
+ test_cmp expected actual &&
+
+ # This must now fail given that we have locked the ref.
+ test_must_fail git update-ref refs/heads/flush $B 2>stderr &&
+ grep "fatal: update_ref failed for ref ${SQ}refs/heads/flush${SQ}: cannot lock ref" stderr &&
+
+ echo commit >&9 &&
+ echo "commit: ok" >expected &&
+ read line <&8 &&
+ echo "$line" >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'directory not created deleting packed ref' '
+ git branch d1/d2/r1 HEAD &&
+ git pack-refs --all &&
+ test_path_is_missing .git/refs/heads/d1/d2 &&
+ git update-ref -d refs/heads/d1/d2/r1 &&
+ test_path_is_missing .git/refs/heads/d1/d2 &&
+ test_path_is_missing .git/refs/heads/d1
+'
+
test_done
diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh
index a4ebb0b65f..132a1b885a 100755
--- a/t/t1401-symbolic-ref.sh
+++ b/t/t1401-symbolic-ref.sh
@@ -7,17 +7,19 @@ test_description='basic symbolic-ref tests'
# the git repo, meaning that further tests will operate on
# the surrounding git repo instead of the trash directory.
reset_to_sane() {
- echo ref: refs/heads/foo >.git/HEAD
+ rm -rf .git &&
+ "$TAR" xf .git.tar
}
-test_expect_success 'symbolic-ref writes HEAD' '
+test_expect_success 'setup' '
git symbolic-ref HEAD refs/heads/foo &&
- echo ref: refs/heads/foo >expect &&
- test_cmp expect .git/HEAD
+ test_commit file &&
+ "$TAR" cf .git.tar .git/
'
-test_expect_success 'symbolic-ref reads HEAD' '
- echo refs/heads/foo >expect &&
+test_expect_success 'symbolic-ref read/write roundtrip' '
+ git symbolic-ref HEAD refs/heads/read-write-roundtrip &&
+ echo refs/heads/read-write-roundtrip >expect &&
git symbolic-ref HEAD >actual &&
test_cmp expect actual
'
@@ -25,12 +27,13 @@ test_expect_success 'symbolic-ref reads HEAD' '
test_expect_success 'symbolic-ref refuses non-ref for HEAD' '
test_must_fail git symbolic-ref HEAD foo
'
+
reset_to_sane
test_expect_success 'symbolic-ref refuses bare sha1' '
- echo content >file && git add file && git commit -m one &&
test_must_fail git symbolic-ref HEAD $(git rev-parse HEAD)
'
+
reset_to_sane
test_expect_success 'HEAD cannot be removed' '
@@ -42,16 +45,16 @@ reset_to_sane
test_expect_success 'symbolic-ref can be deleted' '
git symbolic-ref NOTHEAD refs/heads/foo &&
git symbolic-ref -d NOTHEAD &&
- test_path_is_file .git/refs/heads/foo &&
- test_path_is_missing .git/NOTHEAD
+ git rev-parse refs/heads/foo &&
+ test_must_fail git symbolic-ref NOTHEAD
'
reset_to_sane
test_expect_success 'symbolic-ref can delete dangling symref' '
git symbolic-ref NOTHEAD refs/heads/missing &&
git symbolic-ref -d NOTHEAD &&
- test_path_is_missing .git/refs/heads/missing &&
- test_path_is_missing .git/NOTHEAD
+ test_must_fail git rev-parse refs/heads/missing &&
+ test_must_fail git symbolic-ref NOTHEAD
'
reset_to_sane
diff --git a/t/t1403-show-ref.sh b/t/t1403-show-ref.sh
index 6ce62f878c..17d3cc1405 100755
--- a/t/t1403-show-ref.sh
+++ b/t/t1403-show-ref.sh
@@ -7,11 +7,9 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
test_expect_success setup '
- test_commit A &&
- git tag -f -a -m "annotated A" A &&
+ test_commit --annotate A &&
git checkout -b side &&
- test_commit B &&
- git tag -f -a -m "annotated B" B &&
+ test_commit --annotate B &&
git checkout main &&
test_commit C &&
git branch B A^0
diff --git a/t/t1404-update-ref-errors.sh b/t/t1404-update-ref-errors.sh
index 8b51c4efc1..b729c1f480 100755
--- a/t/t1404-update-ref-errors.sh
+++ b/t/t1404-update-ref-errors.sh
@@ -189,7 +189,7 @@ test_expect_success 'one new ref is a simple prefix of another' '
'
-test_expect_success 'empty directory should not fool rev-parse' '
+test_expect_success REFFILES 'empty directory should not fool rev-parse' '
prefix=refs/e-rev-parse &&
git update-ref $prefix/foo $C &&
git pack-refs --all &&
@@ -199,7 +199,7 @@ test_expect_success 'empty directory should not fool rev-parse' '
test_cmp expected actual
'
-test_expect_success 'empty directory should not fool for-each-ref' '
+test_expect_success REFFILES 'empty directory should not fool for-each-ref' '
prefix=refs/e-for-each-ref &&
git update-ref $prefix/foo $C &&
git for-each-ref $prefix >expected &&
@@ -209,14 +209,14 @@ test_expect_success 'empty directory should not fool for-each-ref' '
test_cmp expected actual
'
-test_expect_success 'empty directory should not fool create' '
+test_expect_success REFFILES 'empty directory should not fool create' '
prefix=refs/e-create &&
mkdir -p .git/$prefix/foo/bar/baz &&
printf "create %s $C\n" $prefix/foo |
git update-ref --stdin
'
-test_expect_success 'empty directory should not fool verify' '
+test_expect_success REFFILES 'empty directory should not fool verify' '
prefix=refs/e-verify &&
git update-ref $prefix/foo $C &&
git pack-refs --all &&
@@ -225,7 +225,7 @@ test_expect_success 'empty directory should not fool verify' '
git update-ref --stdin
'
-test_expect_success 'empty directory should not fool 1-arg update' '
+test_expect_success REFFILES 'empty directory should not fool 1-arg update' '
prefix=refs/e-update-1 &&
git update-ref $prefix/foo $C &&
git pack-refs --all &&
@@ -234,7 +234,7 @@ test_expect_success 'empty directory should not fool 1-arg update' '
git update-ref --stdin
'
-test_expect_success 'empty directory should not fool 2-arg update' '
+test_expect_success REFFILES 'empty directory should not fool 2-arg update' '
prefix=refs/e-update-2 &&
git update-ref $prefix/foo $C &&
git pack-refs --all &&
@@ -243,7 +243,7 @@ test_expect_success 'empty directory should not fool 2-arg update' '
git update-ref --stdin
'
-test_expect_success 'empty directory should not fool 0-arg delete' '
+test_expect_success REFFILES 'empty directory should not fool 0-arg delete' '
prefix=refs/e-delete-0 &&
git update-ref $prefix/foo $C &&
git pack-refs --all &&
@@ -252,7 +252,7 @@ test_expect_success 'empty directory should not fool 0-arg delete' '
git update-ref --stdin
'
-test_expect_success 'empty directory should not fool 1-arg delete' '
+test_expect_success REFFILES 'empty directory should not fool 1-arg delete' '
prefix=refs/e-delete-1 &&
git update-ref $prefix/foo $C &&
git pack-refs --all &&
@@ -466,7 +466,7 @@ test_expect_success 'incorrect old value blocks indirect no-deref delete' '
test_cmp expected output.err
'
-test_expect_success 'non-empty directory blocks create' '
+test_expect_success REFFILES 'non-empty directory blocks create' '
prefix=refs/ne-create &&
mkdir -p .git/$prefix/foo/bar &&
: >.git/$prefix/foo/bar/baz.lock &&
@@ -485,7 +485,7 @@ test_expect_success 'non-empty directory blocks create' '
test_cmp expected output.err
'
-test_expect_success 'broken reference blocks create' '
+test_expect_success REFFILES 'broken reference blocks create' '
prefix=refs/broken-create &&
mkdir -p .git/$prefix &&
echo "gobbledigook" >.git/$prefix/foo &&
@@ -504,7 +504,7 @@ test_expect_success 'broken reference blocks create' '
test_cmp expected output.err
'
-test_expect_success 'non-empty directory blocks indirect create' '
+test_expect_success REFFILES 'non-empty directory blocks indirect create' '
prefix=refs/ne-indirect-create &&
git symbolic-ref $prefix/symref $prefix/foo &&
mkdir -p .git/$prefix/foo/bar &&
@@ -524,7 +524,7 @@ test_expect_success 'non-empty directory blocks indirect create' '
test_cmp expected output.err
'
-test_expect_success 'broken reference blocks indirect create' '
+test_expect_success REFFILES 'broken reference blocks indirect create' '
prefix=refs/broken-indirect-create &&
git symbolic-ref $prefix/symref $prefix/foo &&
echo "gobbledigook" >.git/$prefix/foo &&
@@ -543,7 +543,7 @@ test_expect_success 'broken reference blocks indirect create' '
test_cmp expected output.err
'
-test_expect_success 'no bogus intermediate values during delete' '
+test_expect_success REFFILES 'no bogus intermediate values during delete' '
prefix=refs/slow-transaction &&
# Set up a reference with differing loose and packed versions:
git update-ref $prefix/foo $C &&
@@ -600,7 +600,7 @@ test_expect_success 'no bogus intermediate values during delete' '
test_must_fail git rev-parse --verify --quiet $prefix/foo
'
-test_expect_success 'delete fails cleanly if packed-refs file is locked' '
+test_expect_success REFFILES 'delete fails cleanly if packed-refs file is locked' '
prefix=refs/locked-packed-refs &&
# Set up a reference with differing loose and packed versions:
git update-ref $prefix/foo $C &&
@@ -616,7 +616,7 @@ test_expect_success 'delete fails cleanly if packed-refs file is locked' '
test_cmp unchanged actual
'
-test_expect_success 'delete fails cleanly if packed-refs.new write fails' '
+test_expect_success REFFILES 'delete fails cleanly if packed-refs.new write fails' '
# Setup and expectations are similar to the test above.
prefix=refs/failed-packed-refs &&
git update-ref $prefix/foo $C &&
diff --git a/t/t1405-main-ref-store.sh b/t/t1405-main-ref-store.sh
index a237d9880e..49718b7ea7 100755
--- a/t/t1405-main-ref-store.sh
+++ b/t/t1405-main-ref-store.sh
@@ -9,12 +9,18 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
RUN="test-tool ref-store main"
-test_expect_success 'pack_refs(PACK_REFS_ALL | PACK_REFS_PRUNE)' '
- test_commit one &&
+
+test_expect_success 'setup' '
+ test_commit one
+'
+
+test_expect_success REFFILES 'pack_refs(PACK_REFS_ALL | PACK_REFS_PRUNE)' '
N=`find .git/refs -type f | wc -l` &&
test "$N" != 0 &&
- $RUN pack-refs 3 &&
- N=`find .git/refs -type f | wc -l`
+ ALL_OR_PRUNE_FLAG=3 &&
+ $RUN pack-refs ${ALL_OR_PRUNE_FLAG} &&
+ N=`find .git/refs -type f` &&
+ test -z "$N"
'
test_expect_success 'create_symref(FOO, refs/heads/main)' '
@@ -98,12 +104,12 @@ test_expect_success 'reflog_exists(HEAD)' '
test_expect_success 'delete_reflog(HEAD)' '
$RUN delete-reflog HEAD &&
- ! test -f .git/logs/HEAD
+ test_must_fail git reflog exists HEAD
'
test_expect_success 'create-reflog(HEAD)' '
$RUN create-reflog HEAD 1 &&
- test -f .git/logs/HEAD
+ git reflog exists HEAD
'
test_expect_success 'delete_ref(refs/heads/foo)' '
diff --git a/t/t1407-worktree-ref-store.sh b/t/t1407-worktree-ref-store.sh
index d3fe777511..ad8006c813 100755
--- a/t/t1407-worktree-ref-store.sh
+++ b/t/t1407-worktree-ref-store.sh
@@ -52,7 +52,14 @@ test_expect_success 'create_symref(FOO, refs/heads/main)' '
test_cmp expected actual
'
-test_expect_success 'for_each_reflog()' '
+# Some refs (refs/bisect/*, pseudorefs) are kept per worktree, so they should
+# only appear in the for-each-reflog output if it is called from the correct
+# worktree, which is exercised in this test. This test is poorly written (and
+# therefore marked REFFILES) for mulitple reasons: 1) it creates invalidly
+# formatted log entres. 2) it uses direct FS access for creating the reflogs. 3)
+# PSEUDO-WT and refs/bisect/random do not create reflogs by default, so it is
+# not testing a realistic scenario.
+test_expect_success REFFILES 'for_each_reflog()' '
echo $ZERO_OID > .git/logs/PSEUDO-MAIN &&
mkdir -p .git/logs/refs/bisect &&
echo $ZERO_OID > .git/logs/refs/bisect/random &&
diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh
index 27b9080251..d42f067ff8 100755
--- a/t/t1410-reflog.sh
+++ b/t/t1410-reflog.sh
@@ -374,7 +374,9 @@ test_expect_failure 'reflog with non-commit entries displays all entries' '
test_line_count = 3 actual
'
-test_expect_success 'reflog expire operates on symref not referrent' '
+# This test takes a lock on an individual ref; this is not supported in
+# reftable.
+test_expect_success REFFILES 'reflog expire operates on symref not referrent' '
git branch --create-reflog the_symref &&
git branch --create-reflog referrent &&
git update-ref referrent HEAD &&
diff --git a/t/t1413-reflog-detach.sh b/t/t1413-reflog-detach.sh
index bde05208ae..934688a1ee 100755
--- a/t/t1413-reflog-detach.sh
+++ b/t/t1413-reflog-detach.sh
@@ -7,8 +7,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
reset_state () {
- git checkout main &&
- cp saved_reflog .git/logs/HEAD
+ rm -rf .git && "$TAR" xf .git-saved.tar
}
test_expect_success setup '
@@ -17,7 +16,7 @@ test_expect_success setup '
git branch side &&
test_tick &&
git commit --allow-empty -m second &&
- cat .git/logs/HEAD >saved_reflog
+ "$TAR" cf .git-saved.tar .git
'
test_expect_success baseline '
diff --git a/t/t1414-reflog-walk.sh b/t/t1414-reflog-walk.sh
index 80d94704d0..ea64cecf47 100755
--- a/t/t1414-reflog-walk.sh
+++ b/t/t1414-reflog-walk.sh
@@ -119,7 +119,9 @@ test_expect_success 'min/max age uses entry date to limit' '
test_cmp expect actual
'
-test_expect_success 'walk prefers reflog to ref tip' '
+# Create a situation where the reflog and ref database disagree about the latest
+# state of HEAD.
+test_expect_success REFFILES 'walk prefers reflog to ref tip' '
head=$(git rev-parse HEAD) &&
one=$(git rev-parse one) &&
ident="$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE" &&
diff --git a/t/t1415-worktree-refs.sh b/t/t1415-worktree-refs.sh
index 7ab91241ab..a3e6ea0808 100755
--- a/t/t1415-worktree-refs.sh
+++ b/t/t1415-worktree-refs.sh
@@ -16,7 +16,10 @@ test_expect_success 'setup' '
git -C wt2 update-ref refs/worktree/foo HEAD
'
-test_expect_success 'refs/worktree must not be packed' '
+# The 'packed-refs' file is stored directly in .git/. This means it is global
+# to the repository, and can only contain refs that are shared across all
+# worktrees.
+test_expect_success REFFILES 'refs/worktree must not be packed' '
git pack-refs --all &&
test_path_is_missing .git/refs/tags/wt1 &&
test_path_is_file .git/refs/worktree/foo &&
@@ -37,9 +40,8 @@ test_expect_success 'resolve main-worktree/HEAD' '
'
test_expect_success 'ambiguous main-worktree/HEAD' '
- mkdir -p .git/refs/heads/main-worktree &&
- test_when_finished rm -f .git/refs/heads/main-worktree/HEAD &&
- cp .git/HEAD .git/refs/heads/main-worktree/HEAD &&
+ test_when_finished git update-ref -d refs/heads/main-worktree/HEAD &&
+ git update-ref refs/heads/main-worktree/HEAD $(git rev-parse HEAD) &&
git rev-parse main-worktree/HEAD 2>warn &&
grep "main-worktree/HEAD.*ambiguous" warn
'
@@ -51,9 +53,8 @@ test_expect_success 'resolve worktrees/xx/HEAD' '
'
test_expect_success 'ambiguous worktrees/xx/HEAD' '
- mkdir -p .git/refs/heads/worktrees/wt1 &&
- test_when_finished rm -f .git/refs/heads/worktrees/wt1/HEAD &&
- cp .git/HEAD .git/refs/heads/worktrees/wt1/HEAD &&
+ git update-ref refs/heads/worktrees/wt1/HEAD $(git rev-parse HEAD) &&
+ test_when_finished git update-ref -d refs/heads/worktrees/wt1/HEAD &&
git rev-parse worktrees/wt1/HEAD 2>warn &&
grep "worktrees/wt1/HEAD.*ambiguous" warn
'
diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh
index b1839e0877..fa3aeb80f2 100755
--- a/t/t1430-bad-ref-name.sh
+++ b/t/t1430-bad-ref-name.sh
@@ -170,7 +170,7 @@ test_expect_success 'for-each-ref emits warnings for broken names' '
! grep -e "badname" output &&
! grep -e "broken\.\.\.symref" output &&
test_i18ngrep "ignoring ref with broken name refs/heads/broken\.\.\.ref" error &&
- test_i18ngrep "ignoring broken ref refs/heads/badname" error &&
+ test_i18ngrep ! "ignoring broken ref refs/heads/badname" error &&
test_i18ngrep "ignoring ref with broken name refs/heads/broken\.\.\.symref" error
'
diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
index deae916707..1c2df08333 100755
--- a/t/t1500-rev-parse.sh
+++ b/t/t1500-rev-parse.sh
@@ -146,6 +146,10 @@ test_expect_success '--path-format can change in the middle of the command line'
test_cmp expect actual
'
+test_expect_success '--path-format does not segfault without an argument' '
+ test_must_fail git rev-parse --path-format
+'
+
test_expect_success 'git-common-dir from worktree root' '
echo .git >expect &&
git rev-parse --git-common-dir >actual &&
diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh
index b29563fc99..284fe18e72 100755
--- a/t/t1502-rev-parse-parseopt.sh
+++ b/t/t1502-rev-parse-parseopt.sh
@@ -282,4 +282,58 @@ test_expect_success 'test --parseopt --stuck-long and short option with unset op
test_cmp expect output
'
+test_expect_success 'test --parseopt help output: "wrapped" options normal "or:" lines' '
+ sed -e "s/^|//" >spec <<-\EOF &&
+ |cmd [--some-option]
+ | [--another-option]
+ |cmd [--yet-another-option]
+ |--
+ |h,help show the help
+ EOF
+
+ sed -e "s/^|//" >expect <<-\END_EXPECT &&
+ |cat <<\EOF
+ |usage: cmd [--some-option]
+ | or: [--another-option]
+ | or: cmd [--yet-another-option]
+ |
+ | -h, --help show the help
+ |
+ |EOF
+ END_EXPECT
+
+ test_must_fail git rev-parse --parseopt -- -h >out <spec >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'test --parseopt help output: multi-line blurb after empty line' '
+ sed -e "s/^|//" >spec <<-\EOF &&
+ |cmd [--some-option]
+ | [--another-option]
+ |
+ |multi
+ |line
+ |blurb
+ |--
+ |h,help show the help
+ EOF
+
+ sed -e "s/^|//" >expect <<-\END_EXPECT &&
+ |cat <<\EOF
+ |usage: cmd [--some-option]
+ | or: [--another-option]
+ |
+ | multi
+ | line
+ | blurb
+ |
+ | -h, --help show the help
+ |
+ |EOF
+ END_EXPECT
+
+ test_must_fail git rev-parse --parseopt -- -h >out <spec >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t1503-rev-parse-verify.sh b/t/t1503-rev-parse-verify.sh
index bf08102391..40958615eb 100755
--- a/t/t1503-rev-parse-verify.sh
+++ b/t/t1503-rev-parse-verify.sh
@@ -142,7 +142,7 @@ test_expect_success 'main@{n} for various n' '
test_must_fail git rev-parse --verify main@{$Np1}
'
-test_expect_success SYMLINKS 'ref resolution not confused by broken symlinks' '
+test_expect_success SYMLINKS,REFFILES 'ref resolution not confused by broken symlinks' '
ln -s does-not-exist .git/refs/heads/broken &&
test_must_fail git rev-parse --verify broken
'
diff --git a/t/t1600-index.sh b/t/t1600-index.sh
index c9b9e718b8..46329c488b 100755
--- a/t/t1600-index.sh
+++ b/t/t1600-index.sh
@@ -4,6 +4,8 @@ test_description='index file specific tests'
. ./test-lib.sh
+sane_unset GIT_TEST_SPLIT_INDEX
+
test_expect_success 'setup' '
echo 1 >a
'
@@ -13,7 +15,8 @@ test_expect_success 'bogus GIT_INDEX_VERSION issues warning' '
rm -f .git/index &&
GIT_INDEX_VERSION=2bogus &&
export GIT_INDEX_VERSION &&
- git add a 2>&1 | sed "s/[0-9]//" >actual.err &&
+ git add a 2>err &&
+ sed "s/[0-9]//" err >actual.err &&
sed -e "s/ Z$/ /" <<-\EOF >expect.err &&
warning: GIT_INDEX_VERSION set, but the value is invalid.
Using version Z
@@ -27,7 +30,8 @@ test_expect_success 'out of bounds GIT_INDEX_VERSION issues warning' '
rm -f .git/index &&
GIT_INDEX_VERSION=1 &&
export GIT_INDEX_VERSION &&
- git add a 2>&1 | sed "s/[0-9]//" >actual.err &&
+ git add a 2>err &&
+ sed "s/[0-9]//" err >actual.err &&
sed -e "s/ Z$/ /" <<-\EOF >expect.err &&
warning: GIT_INDEX_VERSION set, but the value is invalid.
Using version Z
@@ -50,7 +54,8 @@ test_expect_success 'out of bounds index.version issues warning' '
sane_unset GIT_INDEX_VERSION &&
rm -f .git/index &&
git config --add index.version 1 &&
- git add a 2>&1 | sed "s/[0-9]//" >actual.err &&
+ git add a 2>err &&
+ sed "s/[0-9]//" err >actual.err &&
sed -e "s/ Z$/ /" <<-\EOF >expect.err &&
warning: index.version set, but the value is invalid.
Using version Z
@@ -79,7 +84,7 @@ test_index_version () {
else
unset GIT_INDEX_VERSION
fi &&
- git add a 2>&1 &&
+ git add a &&
echo $EXPECTED_OUTPUT_VERSION >expect &&
test-tool index-version <.git/index >actual &&
test_cmp expect actual
diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh
index 986baa612e..decd2527ed 100755
--- a/t/t1700-split-index.sh
+++ b/t/t1700-split-index.sh
@@ -510,4 +510,38 @@ test_expect_success 'do not refresh null base index' '
)
'
+test_expect_success 'reading split index at alternate location' '
+ git init reading-alternate-location &&
+ (
+ cd reading-alternate-location &&
+ >file-in-alternate &&
+ git update-index --split-index --add file-in-alternate
+ ) &&
+ echo file-in-alternate >expect &&
+
+ # Should be able to find the shared index both right next to
+ # the specified split index file ...
+ GIT_INDEX_FILE=./reading-alternate-location/.git/index \
+ git ls-files --cached >actual &&
+ test_cmp expect actual &&
+
+ # ... and, for backwards compatibility, in the current GIT_DIR
+ # as well.
+ mv -v ./reading-alternate-location/.git/sharedindex.* .git &&
+ GIT_INDEX_FILE=./reading-alternate-location/.git/index \
+ git ls-files --cached >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'GIT_TEST_SPLIT_INDEX works' '
+ git init git-test-split-index &&
+ (
+ cd git-test-split-index &&
+ >file &&
+ GIT_TEST_SPLIT_INDEX=1 git update-index --add file &&
+ ls -l .git/sharedindex.* >actual &&
+ test_line_count = 1 actual
+ )
+'
+
test_done
diff --git a/t/t2017-checkout-orphan.sh b/t/t2017-checkout-orphan.sh
index c7adbdd39a..88d6992a5e 100755
--- a/t/t2017-checkout-orphan.sh
+++ b/t/t2017-checkout-orphan.sh
@@ -76,7 +76,7 @@ test_expect_success '--orphan makes reflog by default' '
git rev-parse --verify delta@{0}
'
-test_expect_success '--orphan does not make reflog when core.logAllRefUpdates = false' '
+test_expect_success REFFILES '--orphan does not make reflog when core.logAllRefUpdates = false' '
git checkout main &&
git config core.logAllRefUpdates false &&
git checkout --orphan epsilon &&
diff --git a/t/t2021-checkout-overwrite.sh b/t/t2021-checkout-overwrite.sh
index 70d69263e6..660132ff8d 100755
--- a/t/t2021-checkout-overwrite.sh
+++ b/t/t2021-checkout-overwrite.sh
@@ -48,6 +48,7 @@ test_expect_success 'checkout commit with dir must not remove untracked a/b' '
test_expect_success SYMLINKS 'the symlink remained' '
+ test_when_finished "rm a/b" &&
test -h a/b
'
diff --git a/t/t2030-unresolve-info.sh b/t/t2030-unresolve-info.sh
index be6c84c52a..f691e6d903 100755
--- a/t/t2030-unresolve-info.sh
+++ b/t/t2030-unresolve-info.sh
@@ -179,8 +179,7 @@ test_expect_success 'rerere and rerere forget (subdirectory)' '
test_expect_success 'rerere forget (binary)' '
git checkout -f side &&
- printf "a\0c" >binary &&
- git commit -a -m binary &&
+ test_commit --printf binary binary "a\0c" &&
test_must_fail git merge second &&
git rerere forget binary
'
diff --git a/t/t2080-parallel-checkout-basics.sh b/t/t2080-parallel-checkout-basics.sh
new file mode 100755
index 0000000000..3e0f8c675f
--- /dev/null
+++ b/t/t2080-parallel-checkout-basics.sh
@@ -0,0 +1,229 @@
+#!/bin/sh
+
+test_description='parallel-checkout basics
+
+Ensure that parallel-checkout basically works on clone and checkout, spawning
+the required number of workers and correctly populating both the index and the
+working tree.
+'
+
+TEST_NO_CREATE_REPO=1
+. ./test-lib.sh
+. "$TEST_DIRECTORY/lib-parallel-checkout.sh"
+
+# Test parallel-checkout with a branch switch containing a variety of file
+# creations, deletions, and modifications, involving different entry types.
+# The branches B1 and B2 have the following paths:
+#
+# B1 B2
+# a/a (file) a (file)
+# b (file) b/b (file)
+#
+# c/c (file) c (symlink)
+# d (symlink) d/d (file)
+#
+# e/e (file) e (submodule)
+# f (submodule) f/f (file)
+#
+# g (submodule) g (symlink)
+# h (symlink) h (submodule)
+#
+# Additionally, the following paths are present on both branches, but with
+# different contents:
+#
+# i (file) i (file)
+# j (symlink) j (symlink)
+# k (submodule) k (submodule)
+#
+# And the following paths are only present in one of the branches:
+#
+# l/l (file) -
+# - m/m (file)
+#
+test_expect_success 'setup repo for checkout with various types of changes' '
+ git init sub &&
+ (
+ cd sub &&
+ git checkout -b B2 &&
+ echo B2 >file &&
+ git add file &&
+ git commit -m file &&
+
+ git checkout -b B1 &&
+ echo B1 >file &&
+ git add file &&
+ git commit -m file
+ ) &&
+
+ git init various &&
+ (
+ cd various &&
+
+ git checkout -b B1 &&
+ mkdir a c e &&
+ echo a/a >a/a &&
+ echo b >b &&
+ echo c/c >c/c &&
+ test_ln_s_add c d &&
+ echo e/e >e/e &&
+ git submodule add ../sub f &&
+ git submodule add ../sub g &&
+ test_ln_s_add c h &&
+
+ echo "B1 i" >i &&
+ test_ln_s_add c j &&
+ git submodule add -b B1 ../sub k &&
+ mkdir l &&
+ echo l/l >l/l &&
+
+ git add . &&
+ git commit -m B1 &&
+
+ git checkout -b B2 &&
+ git rm -rf :^.gitmodules :^k &&
+ mkdir b d f &&
+ echo a >a &&
+ echo b/b >b/b &&
+ test_ln_s_add b c &&
+ echo d/d >d/d &&
+ git submodule add ../sub e &&
+ echo f/f >f/f &&
+ test_ln_s_add b g &&
+ git submodule add ../sub h &&
+
+ echo "B2 i" >i &&
+ test_ln_s_add b j &&
+ git -C k checkout B2 &&
+ mkdir m &&
+ echo m/m >m/m &&
+
+ git add . &&
+ git commit -m B2 &&
+
+ git checkout --recurse-submodules B1
+ )
+'
+
+for mode in sequential parallel sequential-fallback
+do
+ case $mode in
+ sequential) workers=1 threshold=0 expected_workers=0 ;;
+ parallel) workers=2 threshold=0 expected_workers=2 ;;
+ sequential-fallback) workers=2 threshold=100 expected_workers=0 ;;
+ esac
+
+ test_expect_success "$mode checkout" '
+ repo=various_$mode &&
+ cp -R -P various $repo &&
+
+ # The just copied files have more recent timestamps than their
+ # associated index entries. So refresh the cached timestamps
+ # to avoid an "entry not up-to-date" error from `git checkout`.
+ # We only have to do this for the submodules as `git checkout`
+ # will already refresh the superproject index before performing
+ # the up-to-date check.
+ #
+ git -C $repo submodule foreach "git update-index --refresh" &&
+
+ set_checkout_config $workers $threshold &&
+ test_checkout_workers $expected_workers \
+ git -C $repo checkout --recurse-submodules B2 &&
+ verify_checkout $repo
+ '
+done
+
+for mode in parallel sequential-fallback
+do
+ case $mode in
+ parallel) workers=2 threshold=0 expected_workers=2 ;;
+ sequential-fallback) workers=2 threshold=100 expected_workers=0 ;;
+ esac
+
+ test_expect_success "$mode checkout on clone" '
+ repo=various_${mode}_clone &&
+ set_checkout_config $workers $threshold &&
+ test_checkout_workers $expected_workers \
+ git clone --recurse-submodules --branch B2 various $repo &&
+ verify_checkout $repo
+ '
+done
+
+# Just to be paranoid, actually compare the working trees' contents directly.
+test_expect_success 'compare the working trees' '
+ rm -rf various_*/.git &&
+ rm -rf various_*/*/.git &&
+
+ # We use `git diff` instead of `diff -r` because the latter would
+ # follow symlinks, and not all `diff` implementations support the
+ # `--no-dereference` option.
+ #
+ git diff --no-index various_sequential various_parallel &&
+ git diff --no-index various_sequential various_parallel_clone &&
+ git diff --no-index various_sequential various_sequential-fallback &&
+ git diff --no-index various_sequential various_sequential-fallback_clone
+'
+
+# Currently, each submodule is checked out in a separated child process, but
+# these subprocesses must also be able to use parallel checkout workers to
+# write the submodules' entries.
+test_expect_success 'submodules can use parallel checkout' '
+ set_checkout_config 2 0 &&
+ git init super &&
+ (
+ cd super &&
+ git init sub &&
+ test_commit -C sub A &&
+ test_commit -C sub B &&
+ git submodule add ./sub &&
+ git commit -m sub &&
+ rm sub/* &&
+ test_checkout_workers 2 git checkout --recurse-submodules .
+ )
+'
+
+test_expect_success 'parallel checkout respects --[no]-force' '
+ set_checkout_config 2 0 &&
+ git init dirty &&
+ (
+ cd dirty &&
+ mkdir D &&
+ test_commit D/F &&
+ test_commit F &&
+
+ rm -rf D &&
+ echo changed >D &&
+ echo changed >F.t &&
+
+ # We expect 0 workers because there is nothing to be done
+ test_checkout_workers 0 git checkout HEAD &&
+ test_path_is_file D &&
+ grep changed D &&
+ grep changed F.t &&
+
+ test_checkout_workers 2 git checkout --force HEAD &&
+ test_path_is_dir D &&
+ grep D/F D/F.t &&
+ grep F F.t
+ )
+'
+
+test_expect_success SYMLINKS 'parallel checkout checks for symlinks in leading dirs' '
+ set_checkout_config 2 0 &&
+ git init symlinks &&
+ (
+ cd symlinks &&
+ mkdir D untracked &&
+ # Commit 2 files to have enough work for 2 parallel workers
+ test_commit D/A &&
+ test_commit D/B &&
+ rm -rf D &&
+ ln -s untracked D &&
+
+ test_checkout_workers 2 git checkout --force HEAD &&
+ ! test -h D &&
+ grep D/A D/A.t &&
+ grep D/B D/B.t
+ )
+'
+
+test_done
diff --git a/t/t2081-parallel-checkout-collisions.sh b/t/t2081-parallel-checkout-collisions.sh
new file mode 100755
index 0000000000..f6fcfc0c1e
--- /dev/null
+++ b/t/t2081-parallel-checkout-collisions.sh
@@ -0,0 +1,162 @@
+#!/bin/sh
+
+test_description="path collisions during parallel checkout
+
+Parallel checkout must detect path collisions to:
+
+1) Avoid racily writing to different paths that represent the same file on disk.
+2) Report the colliding entries on clone.
+
+The tests in this file exercise parallel checkout's collision detection code in
+both these mechanics.
+"
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY/lib-parallel-checkout.sh"
+
+TEST_ROOT="$PWD"
+
+test_expect_success CASE_INSENSITIVE_FS 'setup' '
+ empty_oid=$(git hash-object -w --stdin </dev/null) &&
+ cat >objs <<-EOF &&
+ 100644 $empty_oid FILE_X
+ 100644 $empty_oid FILE_x
+ 100644 $empty_oid file_X
+ 100644 $empty_oid file_x
+ EOF
+ git update-index --index-info <objs &&
+ git commit -m "colliding files" &&
+ git tag basename_collision &&
+
+ write_script "$TEST_ROOT"/logger_script <<-\EOF
+ echo "$@" >>filter.log
+ EOF
+'
+
+test_workers_in_event_trace ()
+{
+ test $1 -eq $(grep ".event.:.child_start..*checkout--worker" $2 | wc -l)
+}
+
+test_expect_success CASE_INSENSITIVE_FS 'worker detects basename collision' '
+ GIT_TRACE2_EVENT="$(pwd)/trace" git \
+ -c checkout.workers=2 -c checkout.thresholdForParallelism=0 \
+ checkout . &&
+
+ test_workers_in_event_trace 2 trace &&
+ collisions=$(grep -i "category.:.pcheckout.,.key.:.collision/basename.,.value.:.file_x.}" trace | wc -l) &&
+ test $collisions -eq 3
+'
+
+test_expect_success CASE_INSENSITIVE_FS 'worker detects dirname collision' '
+ test_config filter.logger.smudge "\"$TEST_ROOT/logger_script\" %f" &&
+ empty_oid=$(git hash-object -w --stdin </dev/null) &&
+
+ # By setting a filter command to "a", we make it ineligible for parallel
+ # checkout, and thus it is checked out *first*. This way we can ensure
+ # that "A/B" and "A/C" will both collide with the regular file "a".
+ #
+ attr_oid=$(echo "a filter=logger" | git hash-object -w --stdin) &&
+
+ cat >objs <<-EOF &&
+ 100644 $empty_oid A/B
+ 100644 $empty_oid A/C
+ 100644 $empty_oid a
+ 100644 $attr_oid .gitattributes
+ EOF
+ git rm -rf . &&
+ git update-index --index-info <objs &&
+
+ rm -f trace filter.log &&
+ GIT_TRACE2_EVENT="$(pwd)/trace" git \
+ -c checkout.workers=2 -c checkout.thresholdForParallelism=0 \
+ checkout . &&
+
+ # Check that "a" (and only "a") was filtered
+ echo a >expected.log &&
+ test_cmp filter.log expected.log &&
+
+ # Check that it used the right number of workers and detected the collisions
+ test_workers_in_event_trace 2 trace &&
+ grep "category.:.pcheckout.,.key.:.collision/dirname.,.value.:.A/B.}" trace &&
+ grep "category.:.pcheckout.,.key.:.collision/dirname.,.value.:.A/C.}" trace
+'
+
+test_expect_success SYMLINKS,CASE_INSENSITIVE_FS 'do not follow symlinks colliding with leading dir' '
+ empty_oid=$(git hash-object -w --stdin </dev/null) &&
+ symlink_oid=$(echo "./e" | git hash-object -w --stdin) &&
+ mkdir e &&
+
+ cat >objs <<-EOF &&
+ 120000 $symlink_oid D
+ 100644 $empty_oid d/x
+ 100644 $empty_oid e/y
+ EOF
+ git rm -rf . &&
+ git update-index --index-info <objs &&
+
+ set_checkout_config 2 0 &&
+ test_checkout_workers 2 git checkout . &&
+ test_path_is_dir e &&
+ test_path_is_missing e/x
+'
+
+# The two following tests check that parallel checkout correctly reports
+# colliding entries on clone. The sequential code detects a collision by
+# calling lstat() before trying to open(O_CREAT) a file. (Note that this only
+# works for clone.) Then, to find the pair of a colliding item k, it searches
+# cache_entry[0, k-1]. This is not sufficient in parallel checkout because:
+#
+# - A colliding file may be created between the lstat() and open() calls;
+# - A colliding entry might appear in the second half of the cache_entry array.
+#
+test_expect_success CASE_INSENSITIVE_FS 'collision report on clone (w/ racy file creation)' '
+ git reset --hard basename_collision &&
+ set_checkout_config 2 0 &&
+ test_checkout_workers 2 git clone . clone-repo 2>stderr &&
+
+ grep FILE_X stderr &&
+ grep FILE_x stderr &&
+ grep file_X stderr &&
+ grep file_x stderr &&
+ grep "the following paths have collided" stderr
+'
+
+# This test ensures that the collision report code is correctly looking for
+# colliding peers in the second half of the cache_entry array. This is done by
+# defining a smudge command for the *last* array entry, which makes it
+# non-eligible for parallel-checkout. Thus, it is checked out *first*, before
+# spawning the workers.
+#
+# Note: this test doesn't work on Windows because, on this system, the
+# collision report code uses strcmp() to find the colliding pairs when
+# core.ignoreCase is false. And we need this setting for this test so that only
+# 'file_x' matches the pattern of the filter attribute. But the test works on
+# OSX, where the colliding pairs are found using inode.
+#
+test_expect_success CASE_INSENSITIVE_FS,!MINGW,!CYGWIN \
+ 'collision report on clone (w/ colliding peer after the detected entry)' '
+
+ test_config_global filter.logger.smudge "\"$TEST_ROOT/logger_script\" %f" &&
+ git reset --hard basename_collision &&
+ echo "file_x filter=logger" >.gitattributes &&
+ git add .gitattributes &&
+ git commit -m "filter for file_x" &&
+
+ rm -rf clone-repo &&
+ set_checkout_config 2 0 &&
+ test_checkout_workers 2 \
+ git -c core.ignoreCase=false clone . clone-repo 2>stderr &&
+
+ grep FILE_X stderr &&
+ grep FILE_x stderr &&
+ grep file_X stderr &&
+ grep file_x stderr &&
+ grep "the following paths have collided" stderr &&
+
+ # Check that only "file_x" was filtered
+ echo file_x >expected.log &&
+ test_cmp clone-repo/filter.log expected.log
+'
+
+test_done
diff --git a/t/t2082-parallel-checkout-attributes.sh b/t/t2082-parallel-checkout-attributes.sh
new file mode 100755
index 0000000000..2525457961
--- /dev/null
+++ b/t/t2082-parallel-checkout-attributes.sh
@@ -0,0 +1,194 @@
+#!/bin/sh
+
+test_description='parallel-checkout: attributes
+
+Verify that parallel-checkout correctly creates files that require
+conversions, as specified in .gitattributes. The main point here is
+to check that the conv_attr data is correctly sent to the workers
+and that it contains sufficient information to smudge files
+properly (without access to the index or attribute stack).
+'
+
+TEST_NO_CREATE_REPO=1
+. ./test-lib.sh
+. "$TEST_DIRECTORY/lib-parallel-checkout.sh"
+. "$TEST_DIRECTORY/lib-encoding.sh"
+
+test_expect_success 'parallel-checkout with ident' '
+ set_checkout_config 2 0 &&
+ git init ident &&
+ (
+ cd ident &&
+ echo "A ident" >.gitattributes &&
+ echo "\$Id\$" >A &&
+ echo "\$Id\$" >B &&
+ git add -A &&
+ git commit -m id &&
+
+ rm A B &&
+ test_checkout_workers 2 git reset --hard &&
+ hexsz=$(test_oid hexsz) &&
+ grep -E "\\\$Id: [0-9a-f]{$hexsz} \\\$" A &&
+ grep "\\\$Id\\\$" B
+ )
+'
+
+test_expect_success 'parallel-checkout with re-encoding' '
+ set_checkout_config 2 0 &&
+ git init encoding &&
+ (
+ cd encoding &&
+ echo text >utf8-text &&
+ write_utf16 <utf8-text >utf16-text &&
+
+ echo "A working-tree-encoding=UTF-16" >.gitattributes &&
+ cp utf16-text A &&
+ cp utf8-text B &&
+ git add A B .gitattributes &&
+ git commit -m encoding &&
+
+ # Check that A is stored in UTF-8
+ git cat-file -p :A >A.internal &&
+ test_cmp_bin utf8-text A.internal &&
+
+ rm A B &&
+ test_checkout_workers 2 git checkout A B &&
+
+ # Check that A (and only A) is re-encoded during checkout
+ test_cmp_bin utf16-text A &&
+ test_cmp_bin utf8-text B
+ )
+'
+
+test_expect_success 'parallel-checkout with eol conversions' '
+ set_checkout_config 2 0 &&
+ git init eol &&
+ (
+ cd eol &&
+ printf "multi\r\nline\r\ntext" >crlf-text &&
+ printf "multi\nline\ntext" >lf-text &&
+
+ git config core.autocrlf false &&
+ echo "A eol=crlf" >.gitattributes &&
+ cp crlf-text A &&
+ cp lf-text B &&
+ git add A B .gitattributes &&
+ git commit -m eol &&
+
+ # Check that A is stored with LF format
+ git cat-file -p :A >A.internal &&
+ test_cmp_bin lf-text A.internal &&
+
+ rm A B &&
+ test_checkout_workers 2 git checkout A B &&
+
+ # Check that A (and only A) is converted to CRLF during checkout
+ test_cmp_bin crlf-text A &&
+ test_cmp_bin lf-text B
+ )
+'
+
+# Entries that require an external filter are not eligible for parallel
+# checkout. Check that both the parallel-eligible and non-eligible entries are
+# properly writen in a single checkout operation.
+#
+test_expect_success 'parallel-checkout and external filter' '
+ set_checkout_config 2 0 &&
+ git init filter &&
+ (
+ cd filter &&
+ write_script <<-\EOF rot13.sh &&
+ tr \
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" \
+ "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM"
+ EOF
+
+ git config filter.rot13.clean "\"$(pwd)/rot13.sh\"" &&
+ git config filter.rot13.smudge "\"$(pwd)/rot13.sh\"" &&
+ git config filter.rot13.required true &&
+
+ echo abcd >original &&
+ echo nopq >rot13 &&
+
+ echo "A filter=rot13" >.gitattributes &&
+ cp original A &&
+ cp original B &&
+ cp original C &&
+ git add A B C .gitattributes &&
+ git commit -m filter &&
+
+ # Check that A (and only A) was cleaned
+ git cat-file -p :A >A.internal &&
+ test_cmp rot13 A.internal &&
+ git cat-file -p :B >B.internal &&
+ test_cmp original B.internal &&
+ git cat-file -p :C >C.internal &&
+ test_cmp original C.internal &&
+
+ rm A B C *.internal &&
+ test_checkout_workers 2 git checkout A B C &&
+
+ # Check that A (and only A) was smudged during checkout
+ test_cmp original A &&
+ test_cmp original B &&
+ test_cmp original C
+ )
+'
+
+# The delayed queue is independent from the parallel queue, and they should be
+# able to work together in the same checkout process.
+#
+test_expect_success PERL 'parallel-checkout and delayed checkout' '
+ write_script rot13-filter.pl "$PERL_PATH" \
+ <"$TEST_DIRECTORY"/t0021/rot13-filter.pl &&
+
+ test_config_global filter.delay.process \
+ "\"$(pwd)/rot13-filter.pl\" --always-delay \"$(pwd)/delayed.log\" clean smudge delay" &&
+ test_config_global filter.delay.required true &&
+
+ echo "abcd" >original &&
+ echo "nopq" >rot13 &&
+
+ git init delayed &&
+ (
+ cd delayed &&
+ echo "*.d filter=delay" >.gitattributes &&
+ cp ../original W.d &&
+ cp ../original X.d &&
+ cp ../original Y &&
+ cp ../original Z &&
+ git add -A &&
+ git commit -m delayed &&
+
+ # Check that *.d files were cleaned
+ git cat-file -p :W.d >W.d.internal &&
+ test_cmp W.d.internal ../rot13 &&
+ git cat-file -p :X.d >X.d.internal &&
+ test_cmp X.d.internal ../rot13 &&
+ git cat-file -p :Y >Y.internal &&
+ test_cmp Y.internal ../original &&
+ git cat-file -p :Z >Z.internal &&
+ test_cmp Z.internal ../original &&
+
+ rm *
+ ) &&
+
+ set_checkout_config 2 0 &&
+ test_checkout_workers 2 git -C delayed checkout -f &&
+ verify_checkout delayed &&
+
+ # Check that the *.d files got to the delay queue and were filtered
+ grep "smudge W.d .* \[DELAYED\]" delayed.log &&
+ grep "smudge X.d .* \[DELAYED\]" delayed.log &&
+ test_cmp delayed/W.d original &&
+ test_cmp delayed/X.d original &&
+
+ # Check that the parallel-eligible entries went to the right queue and
+ # were not filtered
+ ! grep "smudge Y .* \[DELAYED\]" delayed.log &&
+ ! grep "smudge Z .* \[DELAYED\]" delayed.log &&
+ test_cmp delayed/Y original &&
+ test_cmp delayed/Z original
+'
+
+test_done
diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh
index 96dfca1554..37ad79470f 100755
--- a/t/t2400-worktree-add.sh
+++ b/t/t2400-worktree-add.sh
@@ -67,11 +67,25 @@ test_expect_success '"add" worktree' '
'
test_expect_success '"add" worktree with lock' '
- git rev-parse HEAD >expect &&
git worktree add --detach --lock here-with-lock main &&
+ test_when_finished "git worktree unlock here-with-lock || :" &&
test -f .git/worktrees/here-with-lock/locked
'
+test_expect_success '"add" worktree with lock and reason' '
+ lock_reason="why not" &&
+ git worktree add --detach --lock --reason "$lock_reason" here-with-lock-reason main &&
+ test_when_finished "git worktree unlock here-with-lock-reason || :" &&
+ test -f .git/worktrees/here-with-lock-reason/locked &&
+ echo "$lock_reason" >expect &&
+ test_cmp expect .git/worktrees/here-with-lock-reason/locked
+'
+
+test_expect_success '"add" worktree with reason but no lock' '
+ test_must_fail git worktree add --detach --reason "why not" here-with-reason-only main &&
+ test_path_is_missing .git/worktrees/here-with-reason-only/locked
+'
+
test_expect_success '"add" worktree from a subdir' '
(
mkdir sub &&
diff --git a/t/t2402-worktree-list.sh b/t/t2402-worktree-list.sh
index fedcefe8de..4012bd67b0 100755
--- a/t/t2402-worktree-list.sh
+++ b/t/t2402-worktree-list.sh
@@ -230,7 +230,7 @@ test_expect_success 'broken main worktree still at the top' '
EOF
cd linked &&
echo "worktree $(pwd)" >expected &&
- echo "ref: .broken" >../.git/HEAD &&
+ (cd ../ && test-tool ref-store main create-symref HEAD .broken ) &&
git worktree list --porcelain >out &&
head -n 3 out >actual &&
test_cmp ../expected actual &&
diff --git a/t/t2500-untracked-overwriting.sh b/t/t2500-untracked-overwriting.sh
new file mode 100755
index 0000000000..5c0bf4d21f
--- /dev/null
+++ b/t/t2500-untracked-overwriting.sh
@@ -0,0 +1,244 @@
+#!/bin/sh
+
+test_description='Test handling of overwriting untracked files'
+
+. ./test-lib.sh
+
+test_setup_reset () {
+ git init reset_$1 &&
+ (
+ cd reset_$1 &&
+ test_commit init &&
+
+ git branch stable &&
+ git branch work &&
+
+ git checkout work &&
+ test_commit foo &&
+
+ git checkout stable
+ )
+}
+
+test_expect_success 'reset --hard will nuke untracked files/dirs' '
+ test_setup_reset hard &&
+ (
+ cd reset_hard &&
+ git ls-tree -r stable &&
+ git log --all --name-status --oneline &&
+ git ls-tree -r work &&
+
+ mkdir foo.t &&
+ echo precious >foo.t/file &&
+ echo foo >expect &&
+
+ git reset --hard work &&
+
+ # check that untracked directory foo.t/ was nuked
+ test_path_is_file foo.t &&
+ test_cmp expect foo.t
+ )
+'
+
+test_expect_success 'reset --merge will preserve untracked files/dirs' '
+ test_setup_reset merge &&
+ (
+ cd reset_merge &&
+
+ mkdir foo.t &&
+ echo precious >foo.t/file &&
+ cp foo.t/file expect &&
+
+ test_must_fail git reset --merge work 2>error &&
+ test_cmp expect foo.t/file &&
+ grep "Updating .foo.t. would lose untracked files" error
+ )
+'
+
+test_expect_success 'reset --keep will preserve untracked files/dirs' '
+ test_setup_reset keep &&
+ (
+ cd reset_keep &&
+
+ mkdir foo.t &&
+ echo precious >foo.t/file &&
+ cp foo.t/file expect &&
+
+ test_must_fail git reset --merge work 2>error &&
+ test_cmp expect foo.t/file &&
+ grep "Updating.*foo.t.*would lose untracked files" error
+ )
+'
+
+test_setup_checkout_m () {
+ git init checkout &&
+ (
+ cd checkout &&
+ test_commit init &&
+
+ test_write_lines file has some >filler &&
+ git add filler &&
+ git commit -m filler &&
+
+ git branch stable &&
+
+ git switch -c work &&
+ echo stuff >notes.txt &&
+ test_write_lines file has some words >filler &&
+ git add notes.txt filler &&
+ git commit -m filler &&
+
+ git checkout stable
+ )
+}
+
+test_expect_success 'checkout -m does not nuke untracked file' '
+ test_setup_checkout_m &&
+ (
+ cd checkout &&
+
+ # Tweak filler
+ test_write_lines this file has some >filler &&
+ # Make an untracked file, save its contents in "expect"
+ echo precious >notes.txt &&
+ cp notes.txt expect &&
+
+ test_must_fail git checkout -m work &&
+ test_cmp expect notes.txt
+ )
+'
+
+test_setup_sequencing () {
+ git init sequencing_$1 &&
+ (
+ cd sequencing_$1 &&
+ test_commit init &&
+
+ test_write_lines this file has some words >filler &&
+ git add filler &&
+ git commit -m filler &&
+
+ mkdir -p foo/bar &&
+ test_commit foo/bar/baz &&
+
+ git branch simple &&
+ git branch fooey &&
+
+ git checkout fooey &&
+ git rm foo/bar/baz.t &&
+ echo stuff >>filler &&
+ git add -u &&
+ git commit -m "changes" &&
+
+ git checkout simple &&
+ echo items >>filler &&
+ echo newstuff >>newfile &&
+ git add filler newfile &&
+ git commit -m another
+ )
+}
+
+test_expect_success 'git rebase --abort and untracked files' '
+ test_setup_sequencing rebase_abort_and_untracked &&
+ (
+ cd sequencing_rebase_abort_and_untracked &&
+ git checkout fooey &&
+ test_must_fail git rebase simple &&
+
+ cat init.t &&
+ git rm init.t &&
+ echo precious >init.t &&
+ cp init.t expect &&
+ git status --porcelain &&
+ test_must_fail git rebase --abort &&
+ test_cmp expect init.t
+ )
+'
+
+test_expect_success 'git rebase fast forwarding and untracked files' '
+ test_setup_sequencing rebase_fast_forward_and_untracked &&
+ (
+ cd sequencing_rebase_fast_forward_and_untracked &&
+ git checkout init &&
+ echo precious >filler &&
+ cp filler expect &&
+ test_must_fail git rebase init simple &&
+ test_cmp expect filler
+ )
+'
+
+test_expect_failure 'git rebase --autostash and untracked files' '
+ test_setup_sequencing rebase_autostash_and_untracked &&
+ (
+ cd sequencing_rebase_autostash_and_untracked &&
+ git checkout simple &&
+ git rm filler &&
+ mkdir filler &&
+ echo precious >filler/file &&
+ cp filler/file expect &&
+ git rebase --autostash init &&
+ test_path_is_file filler/file
+ )
+'
+
+test_expect_failure 'git stash and untracked files' '
+ test_setup_sequencing stash_and_untracked_files &&
+ (
+ cd sequencing_stash_and_untracked_files &&
+ git checkout simple &&
+ git rm filler &&
+ mkdir filler &&
+ echo precious >filler/file &&
+ cp filler/file expect &&
+ git status --porcelain &&
+ git stash push &&
+ git status --porcelain &&
+ test_path_is_file filler/file
+ )
+'
+
+test_expect_success 'git am --abort and untracked dir vs. unmerged file' '
+ test_setup_sequencing am_abort_and_untracked &&
+ (
+ cd sequencing_am_abort_and_untracked &&
+ git format-patch -1 --stdout fooey >changes.mbox &&
+ test_must_fail git am --3way changes.mbox &&
+
+ # Delete the conflicted file; we will stage and commit it later
+ rm filler &&
+
+ # Put an unrelated untracked directory there
+ mkdir filler &&
+ echo foo >filler/file1 &&
+ echo bar >filler/file2 &&
+
+ test_must_fail git am --abort 2>errors &&
+ test_path_is_dir filler &&
+ grep "Updating .filler. would lose untracked files in it" errors
+ )
+'
+
+test_expect_success 'git am --skip and untracked dir vs deleted file' '
+ test_setup_sequencing am_skip_and_untracked &&
+ (
+ cd sequencing_am_skip_and_untracked &&
+ git checkout fooey &&
+ git format-patch -1 --stdout simple >changes.mbox &&
+ test_must_fail git am --3way changes.mbox &&
+
+ # Delete newfile
+ rm newfile &&
+
+ # Put an unrelated untracked directory there
+ mkdir newfile &&
+ echo foo >newfile/file1 &&
+ echo bar >newfile/file2 &&
+
+ # Change our mind about resolutions, just skip this patch
+ test_must_fail git am --skip 2>errors &&
+ test_path_is_dir newfile &&
+ grep "Updating .newfile. would lose untracked files in it" errors
+ )
+'
+
+test_done
diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh
index 1ec7cb57c7..516c95ea0e 100755
--- a/t/t3001-ls-files-others-exclude.sh
+++ b/t/t3001-ls-files-others-exclude.sh
@@ -292,6 +292,11 @@ EOF
test_cmp expect actual
'
+test_expect_success 'ls-files with "**" patterns and --directory' '
+ # Expectation same as previous test
+ git ls-files --directory -o -i --exclude "**/a.1" >actual &&
+ test_cmp expect actual
+'
test_expect_success 'ls-files with "**" patterns and no slashes' '
git ls-files -o -i --exclude "one**a.1" >actual &&
diff --git a/t/t3003-ls-files-exclude.sh b/t/t3003-ls-files-exclude.sh
index d5ec333131..c41c4f046a 100755
--- a/t/t3003-ls-files-exclude.sh
+++ b/t/t3003-ls-files-exclude.sh
@@ -29,11 +29,11 @@ test_expect_success 'add file to gitignore' '
'
check_all_output
-test_expect_success 'ls-files -i lists only tracked-but-ignored files' '
+test_expect_success 'ls-files -i -c lists only tracked-but-ignored files' '
echo content >other-file &&
git add other-file &&
echo file >expect &&
- git ls-files -i --exclude-standard >output &&
+ git ls-files -i -c --exclude-standard >output &&
test_cmp expect output
'
diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh
index 891d4d7cb9..56ea4bda13 100755
--- a/t/t3070-wildmatch.sh
+++ b/t/t3070-wildmatch.sh
@@ -4,6 +4,11 @@ test_description='wildmatch tests'
. ./test-lib.sh
+# Disable expensive chain-lint tests; all of the tests in this script
+# are variants of a few trivial test-tool invocations, and there are a lot of
+# them.
+GIT_TEST_CHAIN_LINT_HARDER_DEFAULT=0
+
should_create_test_file() {
file=$1
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index cc4b10236e..e575ffb4ff 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -1272,6 +1272,19 @@ test_expect_success 'attempt to delete a branch merged to its base' '
test_must_fail git branch -d my10
'
+test_expect_success 'branch --delete --force removes dangling branch' '
+ git checkout main &&
+ test_commit unstable &&
+ hash=$(git rev-parse HEAD) &&
+ objpath=$(echo $hash | sed -e "s|^..|.git/objects/&/|") &&
+ git branch --no-track dangling &&
+ mv $objpath $objpath.x &&
+ test_when_finished "mv $objpath.x $objpath" &&
+ git branch --delete --force dangling &&
+ git for-each-ref refs/heads/dangling >actual &&
+ test_must_be_empty actual
+'
+
test_expect_success 'use --edit-description' '
write_script editor <<-\EOF &&
echo "New contents" >"$1"
diff --git a/t/t3202-show-branch-octopus.sh b/t/t3202-show-branch-octopus.sh
deleted file mode 100755
index 5cb0126cfe..0000000000
--- a/t/t3202-show-branch-octopus.sh
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/bin/sh
-
-test_description='test show-branch with more than 8 heads'
-
-GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
-export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-
-. ./test-lib.sh
-
-numbers="1 2 3 4 5 6 7 8 9 10"
-
-test_expect_success 'setup' '
-
- > file &&
- git add file &&
- test_tick &&
- git commit -m initial &&
-
- for i in $numbers
- do
- git checkout -b branch$i main &&
- > file$i &&
- git add file$i &&
- test_tick &&
- git commit -m branch$i || return 1
- done
-
-'
-
-cat > expect << EOF
-! [branch1] branch1
- ! [branch2] branch2
- ! [branch3] branch3
- ! [branch4] branch4
- ! [branch5] branch5
- ! [branch6] branch6
- ! [branch7] branch7
- ! [branch8] branch8
- ! [branch9] branch9
- * [branch10] branch10
-----------
- * [branch10] branch10
- + [branch9] branch9
- + [branch8] branch8
- + [branch7] branch7
- + [branch6] branch6
- + [branch5] branch5
- + [branch4] branch4
- + [branch3] branch3
- + [branch2] branch2
-+ [branch1] branch1
-+++++++++* [branch10^] initial
-EOF
-
-test_expect_success 'show-branch with more than 8 branches' '
-
- git show-branch $(for i in $numbers; do echo branch$i; done) > out &&
- test_cmp expect out
-
-'
-
-test_expect_success 'show-branch with showbranch.default' '
- for i in $numbers; do
- git config --add showbranch.default branch$i
- done &&
- git show-branch >out &&
- test_cmp expect out
-'
-
-test_done
diff --git a/t/t3202-show-branch.sh b/t/t3202-show-branch.sh
new file mode 100755
index 0000000000..ad9902a06b
--- /dev/null
+++ b/t/t3202-show-branch.sh
@@ -0,0 +1,149 @@
+#!/bin/sh
+
+test_description='test show-branch'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ test_commit initial &&
+ for i in $(test_seq 1 10)
+ do
+ git checkout -b branch$i initial &&
+ test_commit --no-tag branch$i
+ done &&
+ git for-each-ref \
+ --sort=version:refname \
+ --format="%(refname:strip=2)" \
+ "refs/heads/branch*" >branches.sorted &&
+ sed "s/^> //" >expect <<-\EOF
+ > ! [branch1] branch1
+ > ! [branch2] branch2
+ > ! [branch3] branch3
+ > ! [branch4] branch4
+ > ! [branch5] branch5
+ > ! [branch6] branch6
+ > ! [branch7] branch7
+ > ! [branch8] branch8
+ > ! [branch9] branch9
+ > * [branch10] branch10
+ > ----------
+ > * [branch10] branch10
+ > + [branch9] branch9
+ > + [branch8] branch8
+ > + [branch7] branch7
+ > + [branch6] branch6
+ > + [branch5] branch5
+ > + [branch4] branch4
+ > + [branch3] branch3
+ > + [branch2] branch2
+ > + [branch1] branch1
+ > +++++++++* [branch10^] initial
+ EOF
+'
+
+test_expect_success 'show-branch with more than 8 branches' '
+ git show-branch $(cat branches.sorted) >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'show-branch with showbranch.default' '
+ for branch in $(cat branches.sorted)
+ do
+ test_config showbranch.default $branch --add
+ done &&
+ git show-branch >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'show-branch --color output' '
+ sed "s/^> //" >expect <<-\EOF &&
+ > <RED>!<RESET> [branch1] branch1
+ > <GREEN>!<RESET> [branch2] branch2
+ > <YELLOW>!<RESET> [branch3] branch3
+ > <BLUE>!<RESET> [branch4] branch4
+ > <MAGENTA>!<RESET> [branch5] branch5
+ > <CYAN>!<RESET> [branch6] branch6
+ > <BOLD;RED>!<RESET> [branch7] branch7
+ > <BOLD;GREEN>!<RESET> [branch8] branch8
+ > <BOLD;YELLOW>!<RESET> [branch9] branch9
+ > <BOLD;BLUE>*<RESET> [branch10] branch10
+ > ----------
+ > <BOLD;BLUE>*<RESET> [branch10] branch10
+ > <BOLD;YELLOW>+<RESET> [branch9] branch9
+ > <BOLD;GREEN>+<RESET> [branch8] branch8
+ > <BOLD;RED>+<RESET> [branch7] branch7
+ > <CYAN>+<RESET> [branch6] branch6
+ > <MAGENTA>+<RESET> [branch5] branch5
+ > <BLUE>+<RESET> [branch4] branch4
+ > <YELLOW>+<RESET> [branch3] branch3
+ > <GREEN>+<RESET> [branch2] branch2
+ > <RED>+<RESET> [branch1] branch1
+ > <RED>+<RESET><GREEN>+<RESET><YELLOW>+<RESET><BLUE>+<RESET><MAGENTA>+<RESET><CYAN>+<RESET><BOLD;RED>+<RESET><BOLD;GREEN>+<RESET><BOLD;YELLOW>+<RESET><BOLD;BLUE>*<RESET> [branch10^] initial
+ EOF
+ git show-branch --color=always $(cat branches.sorted) >actual.raw &&
+ test_decode_color <actual.raw >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'show branch --remotes' '
+ cat >expect.err <<-\EOF &&
+ No revs to be shown.
+ EOF
+ git show-branch -r 2>actual.err >actual.out &&
+ test_cmp expect.err actual.err &&
+ test_must_be_empty actual.out
+'
+
+test_expect_success 'setup show branch --list' '
+ sed "s/^> //" >expect <<-\EOF
+ > [branch1] branch1
+ > [branch2] branch2
+ > [branch3] branch3
+ > [branch4] branch4
+ > [branch5] branch5
+ > [branch6] branch6
+ > [branch7] branch7
+ > [branch8] branch8
+ > [branch9] branch9
+ > * [branch10] branch10
+ EOF
+'
+
+test_expect_success 'show branch --list' '
+ git show-branch --list $(cat branches.sorted) >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'show branch --list has no --color output' '
+ git show-branch --color=always --list $(cat branches.sorted) >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'show branch --merge-base with one argument' '
+ for branch in $(cat branches.sorted)
+ do
+ git rev-parse $branch >expect &&
+ git show-branch --merge-base $branch >actual &&
+ test_cmp expect actual
+ done
+'
+
+test_expect_success 'show branch --merge-base with two arguments' '
+ for branch in $(cat branches.sorted)
+ do
+ git rev-parse initial >expect &&
+ git show-branch --merge-base initial $branch >actual &&
+ test_cmp expect actual
+ done
+'
+
+test_expect_success 'show branch --merge-base with N arguments' '
+ git rev-parse initial >expect &&
+ git show-branch --merge-base $(cat branches.sorted) >actual &&
+ test_cmp expect actual &&
+
+ git merge-base $(cat branches.sorted) >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index 5325b9f67a..6e94c6db7b 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -340,6 +340,10 @@ test_expect_success 'git branch --format option' '
test_cmp expect actual
'
+test_expect_success 'git branch with --format=%(rest) must fail' '
+ test_must_fail git branch --format="%(rest)" >actual
+'
+
test_expect_success 'worktree colors correct' '
cat >expect <<-EOF &&
* <GREEN>(HEAD detached from fromtag)<RESET>
diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh
index 3b7cdc56ec..577f32dc71 100755
--- a/t/t3210-pack-refs.sh
+++ b/t/t3210-pack-refs.sh
@@ -253,7 +253,7 @@ test_expect_success SYMLINKS 'pack symlinked packed-refs' '
git for-each-ref >all-refs-packed &&
test_cmp all-refs-before all-refs-packed &&
test -h .git/packed-refs &&
- test "$(readlink .git/packed-refs)" = "my-deviant-packed-refs"
+ test "$(test_readlink .git/packed-refs)" = "my-deviant-packed-refs"
'
test_done
diff --git a/t/t3320-notes-merge-worktrees.sh b/t/t3320-notes-merge-worktrees.sh
index 052516e6c6..6b2d507f3e 100755
--- a/t/t3320-notes-merge-worktrees.sh
+++ b/t/t3320-notes-merge-worktrees.sh
@@ -46,8 +46,9 @@ test_expect_success 'create some new worktrees' '
test_expect_success 'merge z into y fails and sets NOTES_MERGE_REF' '
git config core.notesRef refs/notes/y &&
test_must_fail git notes merge z &&
- echo "ref: refs/notes/y" >expect &&
- test_cmp expect .git/NOTES_MERGE_REF
+ echo "refs/notes/y" >expect &&
+ git symbolic-ref NOTES_MERGE_REF >actual &&
+ test_cmp expect actual
'
test_expect_success 'merge z into y while mid-merge in another workdir fails' '
@@ -57,7 +58,7 @@ test_expect_success 'merge z into y while mid-merge in another workdir fails' '
test_must_fail git notes merge z 2>err &&
test_i18ngrep "a notes merge into refs/notes/y is already in-progress at" err
) &&
- test_path_is_missing .git/worktrees/worktree/NOTES_MERGE_REF
+ test_must_fail git -C worktree symbolic-ref NOTES_MERGE_REF
'
test_expect_success 'merge z into x while mid-merge on y succeeds' '
@@ -68,8 +69,9 @@ test_expect_success 'merge z into x while mid-merge on y succeeds' '
test_i18ngrep "Automatic notes merge failed" out &&
grep -v "A notes merge into refs/notes/x is already in-progress in" out
) &&
- echo "ref: refs/notes/x" >expect &&
- test_cmp expect .git/worktrees/worktree2/NOTES_MERGE_REF
+ echo "refs/notes/x" >expect &&
+ git -C worktree2 symbolic-ref NOTES_MERGE_REF >actual &&
+ test_cmp expect actual
'
test_done
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 0bb88aa982..23dbd3c82e 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -406,4 +406,14 @@ test_expect_success 'refuse to switch to branch checked out elsewhere' '
test_i18ngrep "already checked out" err
'
+test_expect_success MINGW,SYMLINKS_WINDOWS 'rebase when .git/logs is a symlink' '
+ git checkout main &&
+ mv .git/logs actual_logs &&
+ cmd //c "mklink /D .git\logs ..\actual_logs" &&
+ git rebase -f HEAD^ &&
+ test -L .git/logs &&
+ rm .git/logs &&
+ mv actual_logs .git/logs
+'
+
test_done
diff --git a/t/t3403-rebase-skip.sh b/t/t3403-rebase-skip.sh
index e26762d0b2..f6e4864497 100755
--- a/t/t3403-rebase-skip.sh
+++ b/t/t3403-rebase-skip.sh
@@ -20,6 +20,7 @@ test_expect_success setup '
git add hello &&
git commit -m "hello" &&
git branch skip-reference &&
+ git tag hello &&
echo world >> hello &&
git commit -a -m "hello world" &&
@@ -36,7 +37,8 @@ test_expect_success setup '
test_tick &&
GIT_AUTHOR_NAME="Another Author" \
GIT_AUTHOR_EMAIL="another.author@example.com" \
- git commit --amend --no-edit -m amended-goodbye &&
+ git commit --amend --no-edit -m amended-goodbye \
+ --reset-author &&
test_tick &&
git tag amended-goodbye &&
@@ -51,7 +53,7 @@ test_expect_success setup '
'
test_expect_success 'rebase with git am -3 (default)' '
- test_must_fail git rebase main
+ test_must_fail git rebase --apply main
'
test_expect_success 'rebase --skip can not be used with other options' '
@@ -95,6 +97,13 @@ test_expect_success 'moved back to branch correctly' '
test_debug 'gitk --all & sleep 1'
+test_expect_success 'skipping final pick removes .git/MERGE_MSG' '
+ test_must_fail git rebase --onto hello reverted-goodbye^ \
+ reverted-goodbye &&
+ git rebase --skip &&
+ test_path_is_missing .git/MERGE_MSG
+'
+
test_expect_success 'correct advice upon picking empty commit' '
test_when_finished "git rebase --abort" &&
test_must_fail git rebase -i --onto goodbye \
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 66bcbbf952..12eb226957 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -297,6 +297,7 @@ test_expect_success 'abort with error when new base cannot be checked out' '
output &&
test_i18ngrep "file1" output &&
test_path_is_missing .git/rebase-merge &&
+ rm file1 &&
git reset --hard HEAD^
'
@@ -351,82 +352,6 @@ test_expect_success 'retain authorship when squashing' '
git show HEAD | grep "^Author: Twerp Snog"
'
-test_expect_success REBASE_P '-p handles "no changes" gracefully' '
- HEAD=$(git rev-parse HEAD) &&
- git rebase -i -p HEAD^ &&
- git update-index --refresh &&
- git diff-files --quiet &&
- git diff-index --quiet --cached HEAD -- &&
- test $HEAD = $(git rev-parse HEAD)
-'
-
-test_expect_failure REBASE_P 'exchange two commits with -p' '
- git checkout H &&
- (
- set_fake_editor &&
- FAKE_LINES="2 1" git rebase -i -p HEAD~2
- ) &&
- test H = $(git cat-file commit HEAD^ | sed -ne \$p) &&
- test G = $(git cat-file commit HEAD | sed -ne \$p)
-'
-
-test_expect_success REBASE_P 'preserve merges with -p' '
- git checkout -b to-be-preserved primary^ &&
- : > unrelated-file &&
- git add unrelated-file &&
- test_tick &&
- git commit -m "unrelated" &&
- git checkout -b another-branch primary &&
- echo B > file1 &&
- test_tick &&
- git commit -m J file1 &&
- test_tick &&
- git merge to-be-preserved &&
- echo C > file1 &&
- test_tick &&
- git commit -m K file1 &&
- echo D > file1 &&
- test_tick &&
- git commit -m L1 file1 &&
- git checkout HEAD^ &&
- echo 1 > unrelated-file &&
- test_tick &&
- git commit -m L2 unrelated-file &&
- test_tick &&
- git merge another-branch &&
- echo E > file1 &&
- test_tick &&
- git commit -m M file1 &&
- git checkout -b to-be-rebased &&
- test_tick &&
- git rebase -i -p --onto branch1 primary &&
- git update-index --refresh &&
- git diff-files --quiet &&
- git diff-index --quiet --cached HEAD -- &&
- test_cmp_rev HEAD~6 branch1 &&
- test_cmp_rev HEAD~4^2 to-be-preserved &&
- test_cmp_rev HEAD^^2^ HEAD^^^ &&
- test $(git show HEAD~5:file1) = B &&
- test $(git show HEAD~3:file1) = C &&
- test $(git show HEAD:file1) = E &&
- test $(git show HEAD:unrelated-file) = 1
-'
-
-test_expect_success REBASE_P 'edit ancestor with -p' '
- (
- set_fake_editor &&
- 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 &&
- git rebase --continue &&
- git update-index --refresh &&
- git diff-files --quiet &&
- git diff-index --quiet --cached HEAD -- &&
- test $(git show HEAD:unrelated-file) = 2
-'
-
test_expect_success '--continue tries to commit' '
git reset --hard D &&
test_tick &&
@@ -839,6 +764,19 @@ test_expect_success 'reword' '
git show HEAD~2 | grep "C changed"
'
+test_expect_success 'no uncommited changes when rewording the todo list is reloaded' '
+ git checkout E &&
+ test_when_finished "git checkout @{-1}" &&
+ (
+ set_fake_editor &&
+ GIT_SEQUENCE_EDITOR="\"$PWD/fake-editor.sh\"" &&
+ export GIT_SEQUENCE_EDITOR &&
+ set_reword_editor &&
+ FAKE_LINES="reword 1 reword 2" git rebase -i C
+ ) &&
+ check_reworded_commits D E
+'
+
test_expect_success 'rebase -i can copy notes' '
git config notes.rewrite.rebase true &&
git config notes.rewriteRef "refs/notes/*" &&
diff --git a/t/t3407-rebase-abort.sh b/t/t3407-rebase-abort.sh
index 7c381fbc89..ebbaed147a 100755
--- a/t/t3407-rebase-abort.sh
+++ b/t/t3407-rebase-abort.sh
@@ -7,77 +7,77 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
-### Test that we handle space characters properly
-work_dir="$(pwd)/test dir"
-
test_expect_success setup '
- mkdir -p "$work_dir" &&
- cd "$work_dir" &&
- git init &&
- echo a > a &&
- git add a &&
- git commit -m a &&
+ test_commit a a a &&
git branch to-rebase &&
- echo b > a &&
- git commit -a -m b &&
- echo c > a &&
- git commit -a -m c &&
+ test_commit --annotate b a b &&
+ test_commit --annotate c a c &&
git checkout to-rebase &&
- echo d > a &&
- git commit -a -m "merge should fail on this" &&
- echo e > a &&
- git commit -a -m "merge should fail on this, too" &&
- git branch pre-rebase
+ test_commit "merge should fail on this" a d d &&
+ test_commit --annotate "merge should fail on this, too" a e pre-rebase
'
+# Check that HEAD is equal to "pre-rebase" and the current branch is
+# "to-rebase"
+check_head() {
+ test_cmp_rev HEAD pre-rebase^{commit} &&
+ test "$(git symbolic-ref HEAD)" = refs/heads/to-rebase
+}
+
testrebase() {
type=$1
- dotest=$2
+ state_dir=$2
test_expect_success "rebase$type --abort" '
- cd "$work_dir" &&
# Clean up the state from the previous one
git reset --hard pre-rebase &&
test_must_fail git rebase$type main &&
- test_path_is_dir "$dotest" &&
+ test_path_is_dir "$state_dir" &&
git rebase --abort &&
- test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase) &&
- test ! -d "$dotest"
+ check_head &&
+ test_path_is_missing "$state_dir"
'
test_expect_success "rebase$type --abort after --skip" '
- cd "$work_dir" &&
# Clean up the state from the previous one
git reset --hard pre-rebase &&
test_must_fail git rebase$type main &&
- test_path_is_dir "$dotest" &&
+ test_path_is_dir "$state_dir" &&
test_must_fail git rebase --skip &&
- test $(git rev-parse HEAD) = $(git rev-parse main) &&
+ test_cmp_rev HEAD main &&
git rebase --abort &&
- test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase) &&
- test ! -d "$dotest"
+ check_head &&
+ test_path_is_missing "$state_dir"
'
test_expect_success "rebase$type --abort after --continue" '
- cd "$work_dir" &&
# Clean up the state from the previous one
git reset --hard pre-rebase &&
test_must_fail git rebase$type main &&
- test_path_is_dir "$dotest" &&
+ test_path_is_dir "$state_dir" &&
echo c > a &&
echo d >> a &&
git add a &&
test_must_fail git rebase --continue &&
- test $(git rev-parse HEAD) != $(git rev-parse main) &&
+ test_cmp_rev ! HEAD main &&
+ git rebase --abort &&
+ check_head &&
+ test_path_is_missing "$state_dir"
+ '
+
+ test_expect_success "rebase$type --abort when checking out a tag" '
+ test_when_finished "git symbolic-ref HEAD refs/heads/to-rebase" &&
+ git reset --hard a -- &&
+ test_must_fail git rebase$type --onto b c pre-rebase &&
+ test_cmp_rev HEAD b^{commit} &&
git rebase --abort &&
- test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase) &&
- test ! -d "$dotest"
+ test_cmp_rev HEAD pre-rebase^{commit} &&
+ ! git symbolic-ref HEAD
'
test_expect_success "rebase$type --abort does not update reflog" '
- cd "$work_dir" &&
# Clean up the state from the previous one
git reset --hard pre-rebase &&
git reflog show to-rebase > reflog_before &&
@@ -89,7 +89,6 @@ testrebase() {
'
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 main &&
@@ -97,33 +96,21 @@ testrebase() {
test_must_fail git rebase --abort -v &&
git rebase --abort
'
+
+ test_expect_success "rebase$type --quit" '
+ test_when_finished "git symbolic-ref HEAD refs/heads/to-rebase" &&
+ # Clean up the state from the previous one
+ git reset --hard pre-rebase &&
+ test_must_fail git rebase$type main &&
+ test_path_is_dir $state_dir &&
+ head_before=$(git rev-parse HEAD) &&
+ git rebase --quit &&
+ test_cmp_rev HEAD $head_before &&
+ test_path_is_missing .git/rebase-apply
+ '
}
testrebase " --apply" .git/rebase-apply
testrebase " --merge" .git/rebase-merge
-test_expect_success 'rebase --apply --quit' '
- cd "$work_dir" &&
- # Clean up the state from the previous one
- git reset --hard pre-rebase &&
- test_must_fail git rebase --apply main &&
- test_path_is_dir .git/rebase-apply &&
- head_before=$(git rev-parse HEAD) &&
- git rebase --quit &&
- test $(git rev-parse HEAD) = $head_before &&
- test ! -d .git/rebase-apply
-'
-
-test_expect_success 'rebase --merge --quit' '
- cd "$work_dir" &&
- # Clean up the state from the previous one
- git reset --hard pre-rebase &&
- test_must_fail git rebase --merge main &&
- test_path_is_dir .git/rebase-merge &&
- head_before=$(git rev-parse HEAD) &&
- git rebase --quit &&
- test $(git rev-parse HEAD) = $head_before &&
- test ! -d .git/rebase-merge
-'
-
test_done
diff --git a/t/t3408-rebase-multi-line.sh b/t/t3408-rebase-multi-line.sh
index ab0960e6d9..cde3562e3a 100755
--- a/t/t3408-rebase-multi-line.sh
+++ b/t/t3408-rebase-multi-line.sh
@@ -55,14 +55,4 @@ test_expect_success rebase '
test_cmp expect actual
'
-test_expect_success REBASE_P rebasep '
-
- git checkout side-merge &&
- git rebase -p side &&
- git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
- git cat-file commit side-merge-original | sed -e "1,/^\$/d" >expect &&
- test_cmp expect actual
-
-'
-
test_done
diff --git a/t/t3409-rebase-preserve-merges.sh b/t/t3409-rebase-preserve-merges.sh
deleted file mode 100755
index ec8062a66a..0000000000
--- a/t/t3409-rebase-preserve-merges.sh
+++ /dev/null
@@ -1,130 +0,0 @@
-#!/bin/sh
-#
-# Copyright(C) 2008 Stephen Habermann & Andreas Ericsson
-#
-test_description='git rebase -p should preserve merges
-
-Run "git rebase -p" and check that merges are properly carried along
-'
-GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
-export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-
-. ./test-lib.sh
-
-if ! test_have_prereq REBASE_P; then
- skip_all='skipping git rebase -p tests, as asked for'
- test_done
-fi
-
-GIT_AUTHOR_EMAIL=bogus_email_address
-export GIT_AUTHOR_EMAIL
-
-# Clone 2 (conflicting merge):
-#
-# A1--A2--B3 <-- origin/main
-# \ \
-# B1------M <-- topic
-# \
-# B2 <-- origin/topic
-#
-# Clone 3 (no-ff merge):
-#
-# A1--A2--B3 <-- origin/main
-# \
-# B1------M <-- topic
-# \ /
-# \--A3 <-- topic2
-# \
-# B2 <-- origin/topic
-#
-# Clone 4 (same as Clone 3)
-
-test_expect_success 'setup for merge-preserving rebase' \
- 'echo First > A &&
- git add A &&
- git commit -m "Add A1" &&
- git checkout -b topic &&
- echo Second > B &&
- git add B &&
- git commit -m "Add B1" &&
- git checkout -f main &&
- echo Third >> A &&
- git commit -a -m "Modify A2" &&
- echo Fifth > B &&
- git add B &&
- git commit -m "Add different B" &&
-
- git clone ./. clone2 &&
- (
- cd clone2 &&
- git checkout -b topic origin/topic &&
- test_must_fail git merge origin/main &&
- echo Resolved >B &&
- git add B &&
- git commit -m "Merge origin/main 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 clone ./. clone4 &&
- (
- cd clone4 &&
- 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"
-'
-
-test_expect_success '--continue works after a conflict' '
- (
- cd clone2 &&
- git fetch &&
- test_must_fail git rebase -p origin/topic &&
- test 2 = $(git ls-files B | wc -l) &&
- echo Resolved again > B &&
- test_must_fail git rebase --continue &&
- grep "^@@@ " .git/rebase-merge/patch &&
- git add B &&
- git rebase --continue &&
- test 1 = $(git rev-list --all --pretty=oneline | grep "Modify A" | wc -l) &&
- test 1 = $(git rev-list --all --pretty=oneline | grep "Add different" | wc -l) &&
- test 1 = $(git rev-list --all --pretty=oneline | grep "Merge origin" | wc -l)
- )
-'
-
-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 ignores merge.log config' '
- (
- cd clone4 &&
- git fetch &&
- git -c merge.log=1 rebase -p origin/topic &&
- echo >expected &&
- git log --format="%b" -1 >current &&
- test_cmp expected current
- )
-'
-
-test_done
diff --git a/t/t3410-rebase-preserve-dropped-merges.sh b/t/t3410-rebase-preserve-dropped-merges.sh
deleted file mode 100755
index 2e29866993..0000000000
--- a/t/t3410-rebase-preserve-dropped-merges.sh
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2008 Stephen Haberman
-#
-
-test_description='git rebase preserve merges
-
-This test runs git rebase with preserve merges and ensures commits
-dropped by the --cherry-pick flag have their childrens parents
-rewritten.
-'
-. ./test-lib.sh
-
-if ! test_have_prereq REBASE_P; then
- skip_all='skipping git rebase -p tests, as asked for'
- test_done
-fi
-
-# set up two branches like this:
-#
-# A - B - C - D - E
-# \
-# F - G - H
-# \
-# I
-#
-# where B, D and G touch the same file.
-
-test_expect_success 'setup' '
- test_commit A file1 &&
- test_commit B file1 1 &&
- test_commit C file2 &&
- test_commit D file1 2 &&
- test_commit E file3 &&
- git checkout A &&
- test_commit F file4 &&
- test_commit G file1 3 &&
- test_commit H file5 &&
- git checkout F &&
- test_commit I file6
-'
-
-# A - B - C - D - E
-# \ \ \
-# F - G - H -- L \ --> L
-# \ | \
-# I -- G2 -- J -- K I -- K
-# G2 = same changes as G
-test_expect_success 'skip same-resolution merges with -p' '
- git checkout H &&
- test_must_fail git merge E &&
- test_commit L file1 23 &&
- git checkout I &&
- test_commit G2 file1 3 &&
- test_must_fail git merge E &&
- test_commit J file1 23 &&
- test_commit K file7 file7 &&
- git rebase -i -p L &&
- test $(git rev-parse HEAD^^) = $(git rev-parse L) &&
- test "23" = "$(cat file1)" &&
- test "I" = "$(cat file6)" &&
- test "file7" = "$(cat file7)"
-'
-
-# A - B - C - D - E
-# \ \ \
-# F - G - H -- L2 \ --> L2
-# \ | \
-# I -- G3 --- J2 -- K2 I -- G3 -- K2
-# G2 = different changes as G
-test_expect_success 'keep different-resolution merges with -p' '
- git checkout H &&
- test_must_fail git merge E &&
- test_commit L2 file1 23 &&
- git checkout I &&
- test_commit G3 file1 4 &&
- test_must_fail git merge E &&
- test_commit J2 file1 24 &&
- test_commit K2 file7 file7 &&
- test_must_fail git rebase -i -p L2 &&
- echo 234 > file1 &&
- git add file1 &&
- git rebase --continue &&
- test $(git rev-parse HEAD^^^) = $(git rev-parse L2) &&
- test "234" = "$(cat file1)" &&
- test "I" = "$(cat file6)" &&
- test "file7" = "$(cat file7)"
-'
-
-test_done
diff --git a/t/t3411-rebase-preserve-around-merges.sh b/t/t3411-rebase-preserve-around-merges.sh
deleted file mode 100755
index fb45e7bf7b..0000000000
--- a/t/t3411-rebase-preserve-around-merges.sh
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2008 Stephen Haberman
-#
-
-test_description='git rebase preserve merges
-
-This test runs git rebase with -p and tries to squash a commit from after
-a merge to before the merge.
-'
-. ./test-lib.sh
-
-if ! test_have_prereq REBASE_P; then
- skip_all='skipping git rebase -p tests, as asked for'
- test_done
-fi
-
-. "$TEST_DIRECTORY"/lib-rebase.sh
-
-set_fake_editor
-
-# set up two branches like this:
-#
-# A1 - B1 - D1 - E1 - F1
-# \ /
-# -- C1 --
-
-test_expect_success 'setup' '
- test_commit A1 &&
- test_commit B1 &&
- test_commit C1 &&
- git reset --hard B1 &&
- test_commit D1 &&
- test_merge E1 C1 &&
- test_commit F1
-'
-
-# Should result in:
-#
-# A1 - B1 - D2 - E2
-# \ /
-# -- C1 --
-#
-test_expect_success 'squash F1 into D1' '
- 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
-'
-
-# Start with:
-#
-# A1 - B1 - D2 - E2
-# \
-# G1 ---- L1 ---- M1
-# \ /
-# H1 -- J1 -- K1
-# \ /
-# -- I1 --
-#
-# And rebase G1..M1 onto E2
-
-test_expect_success 'rebase two levels of merge' '
- git checkout A1 &&
- test_commit G1 &&
- test_commit H1 &&
- test_commit I1 &&
- git checkout -b branch3 H1 &&
- test_commit J1 &&
- test_merge K1 I1 &&
- git checkout -b branch2 G1 &&
- test_commit L1 &&
- test_merge M1 K1 &&
- GIT_EDITOR=: git rebase -i -p E2 &&
- test "$(git rev-parse HEAD~3)" = "$(git rev-parse E2)" &&
- test "$(git rev-parse HEAD~2)" = "$(git rev-parse HEAD^2^2~2)" &&
- test "$(git rev-parse HEAD^2^1^1)" = "$(git rev-parse HEAD^2^2^1)"
-'
-
-test_done
diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
index fda62c65bd..19c6f4acbf 100755
--- a/t/t3412-rebase-root.sh
+++ b/t/t3412-rebase-root.sh
@@ -89,17 +89,6 @@ test_expect_success 'pre-rebase got correct input (4)' '
test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,work4
'
-test_expect_success REBASE_P 'rebase -i -p with linear history' '
- git checkout -b work5 other &&
- git rebase -i -p --root --onto main &&
- git log --pretty=tformat:"%s" > rebased5 &&
- test_cmp expect rebased5
-'
-
-test_expect_success REBASE_P 'pre-rebase got correct input (5)' '
- test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,
-'
-
test_expect_success 'set up merge history' '
git checkout other^ &&
git checkout -b side &&
@@ -123,13 +112,6 @@ commit work6~4
1
EOF
-test_expect_success REBASE_P 'rebase -i -p with merge' '
- git checkout -b work6 other &&
- git rebase -i -p --root --onto main &&
- log_with_names work6 > rebased6 &&
- test_cmp expect-side rebased6
-'
-
test_expect_success 'set up second root and merge' '
git symbolic-ref HEAD refs/heads/third &&
rm .git/index &&
@@ -158,13 +140,6 @@ commit work7~5
1
EOF
-test_expect_success REBASE_P 'rebase -i -p with two roots' '
- git checkout -b work7 other &&
- git rebase -i -p --root --onto main &&
- log_with_names work7 > rebased7 &&
- test_cmp expect-third rebased7
-'
-
test_expect_success 'setup pre-rebase hook that fails' '
mkdir -p .git/hooks &&
cat >.git/hooks/pre-rebase <<EOF &&
@@ -264,21 +239,9 @@ commit conflict3~6
1
EOF
-test_expect_success REBASE_P 'rebase -i -p --root with conflict (first part)' '
- git checkout -b conflict3 other &&
- test_must_fail git rebase -i -p --root --onto main &&
- git ls-files -u | grep "B$"
-'
-
test_expect_success 'fix the conflict' '
echo 3 > B &&
git add B
'
-test_expect_success REBASE_P 'rebase -i -p --root with conflict (second part)' '
- git rebase --continue &&
- log_with_names conflict3 >out &&
- test_cmp expect-conflict-p out
-'
-
test_done
diff --git a/t/t3414-rebase-preserve-onto.sh b/t/t3414-rebase-preserve-onto.sh
deleted file mode 100755
index 72e04b5386..0000000000
--- a/t/t3414-rebase-preserve-onto.sh
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2009 Greg Price
-#
-
-test_description='git rebase -p should respect --onto
-
-In a rebase with --onto, we should rewrite all the commits that
-aren'"'"'t on top of $ONTO, even if they are on top of $UPSTREAM.
-'
-. ./test-lib.sh
-
-if ! test_have_prereq REBASE_P; then
- skip_all='skipping git rebase -p tests, as asked for'
- test_done
-fi
-
-. "$TEST_DIRECTORY"/lib-rebase.sh
-
-# Set up branches like this:
-# A1---B1---E1---F1---G1
-# \ \ /
-# \ \--C1---D1--/
-# H1
-
-test_expect_success 'setup' '
- test_commit A1 &&
- test_commit B1 &&
- test_commit C1 &&
- test_commit D1 &&
- git reset --hard B1 &&
- test_commit E1 &&
- test_commit F1 &&
- test_merge G1 D1 &&
- git reset --hard A1 &&
- test_commit H1
-'
-
-# Now rebase merge G1 from both branches' base B1, both should move:
-# A1---B1---E1---F1---G1
-# \ \ /
-# \ \--C1---D1--/
-# \
-# H1---E2---F2---G2
-# \ /
-# \--C2---D2--/
-
-test_expect_success 'rebase from B1 onto H1' '
- git checkout G1 &&
- git rebase -p --onto H1 B1 &&
- test "$(git rev-parse HEAD^1^1^1)" = "$(git rev-parse H1)" &&
- test "$(git rev-parse HEAD^2^1^1)" = "$(git rev-parse H1)"
-'
-
-# On the other hand if rebase from E1 which is within one branch,
-# then the other branch stays:
-# A1---B1---E1---F1---G1
-# \ \ /
-# \ \--C1---D1--/
-# \ \
-# H1-----F3-----G3
-
-test_expect_success 'rebase from E1 onto H1' '
- git checkout G1 &&
- git rebase -p --onto H1 E1 &&
- test "$(git rev-parse HEAD^1^1)" = "$(git rev-parse H1)" &&
- test "$(git rev-parse HEAD^2)" = "$(git rev-parse D1)"
-'
-
-# And the same if we rebase from a commit in the second-parent branch.
-# A1---B1---E1---F1----G1
-# \ \ \ /
-# \ \--C1---D1-\-/
-# \ \
-# H1------D3------G4
-
-test_expect_success 'rebase from C1 onto H1' '
- git checkout G1 &&
- git rev-list --first-parent --pretty=oneline C1..G1 &&
- git rebase -p --onto H1 C1 &&
- test "$(git rev-parse HEAD^2^1)" = "$(git rev-parse H1)" &&
- test "$(git rev-parse HEAD^1)" = "$(git rev-parse F1)"
-'
-
-test_done
diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh
index 0838f4e798..22eca73aa3 100755
--- a/t/t3418-rebase-continue.sh
+++ b/t/t3418-rebase-continue.sh
@@ -21,7 +21,7 @@ test_expect_success 'setup' '
git checkout main
'
-test_expect_success 'interactive rebase --continue works with touched file' '
+test_expect_success 'merge based rebase --continue with works with touched file' '
rm -fr .git/rebase-* &&
git reset --hard &&
git checkout main &&
@@ -31,12 +31,22 @@ test_expect_success 'interactive rebase --continue works with touched file' '
git rebase --continue
'
-test_expect_success 'non-interactive rebase --continue works with touched file' '
+test_expect_success 'merge based rebase --continue removes .git/MERGE_MSG' '
+ git checkout -f --detach topic &&
+
+ test_must_fail git rebase --onto main HEAD^ &&
+ git read-tree --reset -u HEAD &&
+ test_path_is_file .git/MERGE_MSG &&
+ git rebase --continue &&
+ test_path_is_missing .git/MERGE_MSG
+'
+
+test_expect_success 'apply based rebase --continue works with touched file' '
rm -fr .git/rebase-* &&
git reset --hard &&
git checkout main &&
- test_must_fail git rebase --onto main main topic &&
+ test_must_fail git rebase --apply --onto main main topic &&
echo "Resolved" >F2 &&
git add F2 &&
test-tool chmtime =-60 F1 &&
@@ -109,20 +119,6 @@ test_expect_success 'rebase -i --continue handles merge strategy and options' '
test -f funny.was.run
'
-test_expect_success REBASE_P 'rebase passes merge strategy options correctly' '
- rm -fr .git/rebase-* &&
- git reset --hard commit-new-file-F3-on-topic-branch &&
- test_commit theirs-to-merge &&
- git reset --hard HEAD^ &&
- test_commit some-commit &&
- test_tick &&
- git merge --no-ff theirs-to-merge &&
- FAKE_LINES="1 edit 2 3" git rebase -i -f -p -m \
- -s recursive --strategy-option=theirs HEAD~2 &&
- test_commit force-change &&
- git rebase --continue
-'
-
test_expect_success 'rebase -r passes merge strategy options correctly' '
rm -fr .git/rebase-* &&
git reset --hard commit-new-file-F3-on-topic-branch &&
@@ -254,11 +250,10 @@ test_rerere_autoupdate () {
'
}
-test_rerere_autoupdate
+test_rerere_autoupdate --apply
test_rerere_autoupdate -m
GIT_SEQUENCE_EDITOR=: && export GIT_SEQUENCE_EDITOR
test_rerere_autoupdate -i
-test_have_prereq !REBASE_P || test_rerere_autoupdate --preserve-merges
unset GIT_SEQUENCE_EDITOR
test_expect_success 'the todo command "break" works' '
@@ -282,12 +277,35 @@ test_expect_success '--reschedule-failed-exec' '
test_i18ngrep "has been rescheduled" err
'
-test_expect_success 'rebase.reschedulefailedexec only affects `rebase -i`' '
- test_config rebase.reschedulefailedexec true &&
+test_expect_success 'rebase.rescheduleFailedExec only affects `rebase -i`' '
+ test_config rebase.rescheduleFailedExec true &&
test_must_fail git rebase -x false HEAD^ &&
grep "^exec false" .git/rebase-merge/git-rebase-todo &&
git rebase --abort &&
git rebase HEAD^
'
+test_expect_success 'rebase.rescheduleFailedExec=true & --no-reschedule-failed-exec' '
+ test_when_finished "git rebase --abort" &&
+ test_config rebase.rescheduleFailedExec true &&
+ test_must_fail git rebase -x false --no-reschedule-failed-exec HEAD~2 &&
+ test_must_fail git rebase --continue 2>err &&
+ ! grep "has been rescheduled" err
+'
+
+test_expect_success 'new rebase.rescheduleFailedExec=true setting in an ongoing rebase is ignored' '
+ test_when_finished "git rebase --abort" &&
+ test_must_fail git rebase -x false HEAD~2 &&
+ test_config rebase.rescheduleFailedExec true &&
+ test_must_fail git rebase --continue 2>err &&
+ ! grep "has been rescheduled" err
+'
+
+test_expect_success 'there is no --no-reschedule-failed-exec in an ongoing rebase' '
+ test_when_finished "git rebase --abort" &&
+ test_must_fail git rebase -x false HEAD~2 &&
+ test_expect_code 129 git rebase --continue --no-reschedule-failed-exec &&
+ test_expect_code 129 git rebase --edit-todo --no-reschedule-failed-exec
+'
+
test_done
diff --git a/t/t3421-rebase-topology-linear.sh b/t/t3421-rebase-topology-linear.sh
index 4a9204b4b6..62d86d557d 100755
--- a/t/t3421-rebase-topology-linear.sh
+++ b/t/t3421-rebase-topology-linear.sh
@@ -29,7 +29,6 @@ test_run_rebase () {
test_run_rebase success --apply
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase success -p
test_expect_success 'setup branches and remote tracking' '
git tag -l >tags &&
@@ -53,7 +52,6 @@ test_run_rebase () {
test_run_rebase success --apply
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase success -p
test_run_rebase () {
result=$1
@@ -70,7 +68,6 @@ test_run_rebase success --apply
test_run_rebase success --fork-point
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase failure -p
test_run_rebase () {
result=$1
@@ -87,7 +84,6 @@ test_run_rebase success --apply
test_run_rebase success --fork-point
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase success -p
test_run_rebase () {
result=$1
@@ -102,7 +98,6 @@ test_run_rebase success --apply
test_run_rebase success --fork-point
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase success -p
# f
# /
@@ -142,7 +137,6 @@ test_run_rebase () {
test_run_rebase success --apply
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase success -p
test_run_rebase () {
result=$1
@@ -157,7 +151,6 @@ test_run_rebase () {
test_run_rebase success --apply
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase success -p
test_run_rebase () {
result=$1
@@ -172,7 +165,6 @@ test_run_rebase () {
test_run_rebase success --apply
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase success -p
test_run_rebase () {
result=$1
@@ -187,7 +179,6 @@ test_run_rebase () {
test_run_rebase success --apply
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase success -p
# a---b---c---j!
# \
@@ -215,7 +206,6 @@ test_run_rebase () {
test_run_rebase failure --apply
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase failure -p
test_run_rebase () {
result=$1
@@ -229,7 +219,6 @@ test_run_rebase () {
}
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase success -p
test_run_rebase () {
result=$1
@@ -243,7 +232,6 @@ test_run_rebase () {
}
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase success -p
test_run_rebase success --rebase-merges
# m
@@ -283,7 +271,6 @@ test_run_rebase () {
test_run_rebase success --apply
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase success -p
test_run_rebase () {
result=$1
@@ -298,7 +285,6 @@ test_run_rebase () {
test_run_rebase success --apply
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase failure -p
test_run_rebase () {
result=$1
@@ -313,7 +299,6 @@ test_run_rebase () {
test_run_rebase success --apply
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase success -p
test_run_rebase () {
result=$1
@@ -329,7 +314,6 @@ test_run_rebase () {
test_run_rebase success --apply
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase failure -p
test_run_rebase () {
result=$1
@@ -344,7 +328,6 @@ test_run_rebase () {
test_run_rebase success --apply
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase failure -p
test_run_rebase () {
result=$1
@@ -358,7 +341,6 @@ test_run_rebase () {
test_run_rebase success ''
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase failure -p
test_run_rebase () {
result=$1
@@ -373,6 +355,5 @@ test_run_rebase () {
test_run_rebase success ''
test_run_rebase success -m
test_run_rebase success -i
-test_have_prereq !REBASE_P || test_run_rebase success -p
test_done
diff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh
index c8234062c6..eb0a3d9d48 100755
--- a/t/t3422-rebase-incompatible-options.sh
+++ b/t/t3422-rebase-incompatible-options.sh
@@ -63,15 +63,4 @@ test_rebase_am_only () {
test_rebase_am_only --whitespace=fix
test_rebase_am_only -C4
-test_expect_success REBASE_P '--preserve-merges incompatible with --signoff' '
- git checkout B^0 &&
- test_must_fail git rebase --preserve-merges --signoff A
-'
-
-test_expect_success REBASE_P \
- '--preserve-merges incompatible with --rebase-merges' '
- git checkout B^0 &&
- test_must_fail git rebase --preserve-merges --rebase-merges A
-'
-
test_done
diff --git a/t/t3425-rebase-topology-merges.sh b/t/t3425-rebase-topology-merges.sh
index e42faa44e7..63acc1ea4d 100755
--- a/t/t3425-rebase-topology-merges.sh
+++ b/t/t3425-rebase-topology-merges.sh
@@ -106,155 +106,4 @@ test_run_rebase success 'd n o e' --apply
test_run_rebase success 'd n o e' -m
test_run_rebase success 'd n o e' -i
-if ! test_have_prereq REBASE_P; then
- skip_all='skipping git rebase -p tests, as asked for'
- test_done
-fi
-
-test_expect_success "rebase -p is no-op in non-linear history" "
- reset_rebase &&
- git rebase -p d w &&
- test_cmp_rev w HEAD
-"
-
-test_expect_success "rebase -p is no-op when base inside second parent" "
- reset_rebase &&
- git rebase -p e w &&
- test_cmp_rev w HEAD
-"
-
-test_expect_failure "rebase -p --root on non-linear history is a no-op" "
- reset_rebase &&
- git rebase -p --root w &&
- test_cmp_rev w HEAD
-"
-
-test_expect_success "rebase -p re-creates merge from side branch" "
- reset_rebase &&
- git rebase -p z w &&
- test_cmp_rev z HEAD^ &&
- test_cmp_rev w^2 HEAD^2
-"
-
-test_expect_success "rebase -p re-creates internal merge" "
- reset_rebase &&
- git rebase -p c w &&
- test_cmp_rev c HEAD~4 &&
- test_cmp_rev HEAD^2^ HEAD~3 &&
- test_revision_subjects 'd n e o w' HEAD~3 HEAD~2 HEAD^2 HEAD^ HEAD
-"
-
-test_expect_success "rebase -p can re-create two branches on onto" "
- reset_rebase &&
- git rebase -p --onto c d w &&
- test_cmp_rev c HEAD~3 &&
- test_cmp_rev c HEAD^2^ &&
- test_revision_subjects 'n e o w' HEAD~2 HEAD^2 HEAD^ HEAD
-"
-
-# f
-# /
-# a---b---c---g---h
-# \
-# d---gp--i
-# \ \
-# e-------u
-#
-# gp = cherry-picked g
-# h = reverted g
-test_expect_success 'setup of non-linear-history for patch-equivalence tests' '
- git checkout e &&
- test_merge u i
-'
-
-test_expect_success "rebase -p re-creates history around dropped commit matching upstream" "
- reset_rebase &&
- git rebase -p h u &&
- test_cmp_rev h HEAD~3 &&
- test_cmp_rev HEAD^2^ HEAD~2 &&
- test_revision_subjects 'd i e u' HEAD~2 HEAD^2 HEAD^ HEAD
-"
-
-test_expect_success "rebase -p --onto in merged history drops patches in upstream" "
- reset_rebase &&
- git rebase -p --onto f h u &&
- test_cmp_rev f HEAD~3 &&
- test_cmp_rev HEAD^2^ HEAD~2 &&
- test_revision_subjects 'd i e u' HEAD~2 HEAD^2 HEAD^ HEAD
-"
-
-test_expect_success "rebase -p --onto in merged history does not drop patches in onto" "
- reset_rebase &&
- git rebase -p --onto h f u &&
- test_cmp_rev h HEAD~3 &&
- test_cmp_rev HEAD^2~2 HEAD~2 &&
- test_revision_subjects 'd gp i e u' HEAD~2 HEAD^2^ HEAD^2 HEAD^ HEAD
-"
-
-# a---b---c---g---h
-# \
-# d---gp--s
-# \ \ /
-# \ X
-# \ / \
-# e---t
-#
-# gp = cherry-picked g
-# h = reverted g
-test_expect_success 'setup of non-linear-history for dropping whole side' '
- git checkout gp &&
- test_merge s e &&
- git checkout e &&
- test_merge t gp
-'
-
-test_expect_failure "rebase -p drops merge commit when entire first-parent side is dropped" "
- reset_rebase &&
- git rebase -p h s &&
- test_cmp_rev h HEAD~2 &&
- test_linear_range 'd e' h..
-"
-
-test_expect_success "rebase -p drops merge commit when entire second-parent side is dropped" "
- reset_rebase &&
- git rebase -p h t &&
- test_cmp_rev h HEAD~2 &&
- test_linear_range 'd e' h..
-"
-
-# a---b---c
-# \
-# d---e
-# \ \
-# n---r
-# \
-# o
-#
-# r = tree-same with n
-test_expect_success 'setup of non-linear-history for empty commits' '
- git checkout n &&
- git merge --no-commit e &&
- git reset n . &&
- git commit -m r &&
- git reset --hard &&
- git clean -f &&
- git tag r
-'
-
-test_expect_success "rebase -p re-creates empty internal merge commit" "
- reset_rebase &&
- git rebase -p c r &&
- test_cmp_rev c HEAD~3 &&
- test_cmp_rev HEAD^2^ HEAD~2 &&
- test_revision_subjects 'd e n r' HEAD~2 HEAD^2 HEAD^ HEAD
-"
-
-test_expect_success "rebase -p re-creates empty merge commit" "
- reset_rebase &&
- git rebase -p o r &&
- test_cmp_rev e HEAD^2 &&
- test_cmp_rev o HEAD^ &&
- test_revision_subjects 'r' HEAD
-"
-
test_done
diff --git a/t/t3427-rebase-subtree.sh b/t/t3427-rebase-subtree.sh
index e78c7e3796..48b76f8232 100755
--- a/t/t3427-rebase-subtree.sh
+++ b/t/t3427-rebase-subtree.sh
@@ -36,11 +36,10 @@ commit_message() {
# where the root commit adds three files: topic_1.t, topic_2.t and topic_3.t.
#
# This commit history is then rebased onto `topic_3` with the
-# `-Xsubtree=files_subtree` option in three different ways:
+# `-Xsubtree=files_subtree` option in two different ways:
#
-# 1. using `--preserve-merges`
-# 2. using `--preserve-merges` and --keep-empty
-# 3. without specifying a rebase backend
+# 1. without specifying a rebase backend
+# 2. using the `--rebase-merges` backend
test_expect_success 'setup' '
test_commit README &&
@@ -69,25 +68,6 @@ test_expect_success 'setup' '
git commit -m "Empty commit" --allow-empty
'
-# FAILURE: Does not preserve topic_4.
-test_expect_failure REBASE_P 'Rebase -Xsubtree --preserve-merges --onto commit' '
- reset_rebase &&
- git checkout -b rebase-preserve-merges to-rebase &&
- git rebase -Xsubtree=files_subtree --preserve-merges --onto files-main main &&
- verbose test "$(commit_message HEAD~)" = "topic_4" &&
- verbose test "$(commit_message HEAD)" = "files_subtree/topic_5"
-'
-
-# FAILURE: Does not preserve topic_4.
-test_expect_failure REBASE_P 'Rebase -Xsubtree --keep-empty --preserve-merges --onto commit' '
- reset_rebase &&
- git checkout -b rebase-keep-empty to-rebase &&
- git rebase -Xsubtree=files_subtree --keep-empty --preserve-merges --onto files-main main &&
- verbose test "$(commit_message HEAD~2)" = "topic_4" &&
- verbose test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
- verbose test "$(commit_message HEAD)" = "Empty commit"
-'
-
test_expect_success 'Rebase -Xsubtree --empty=ask --onto commit' '
reset_rebase &&
git checkout -b rebase-onto to-rebase &&
diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh
index 6748070df5..43c82d9a33 100755
--- a/t/t3430-rebase-merges.sh
+++ b/t/t3430-rebase-merges.sh
@@ -172,19 +172,39 @@ test_expect_success 'failed `merge <branch>` does not crash' '
grep "^Merge branch ${SQ}G${SQ}$" .git/rebase-merge/message
'
-test_expect_success 'fast-forward merge -c still rewords' '
- git checkout -b fast-forward-merge-c H &&
+test_expect_success 'merge -c commits before rewording and reloads todo-list' '
+ cat >script-from-scratch <<-\EOF &&
+ merge -c E B
+ merge -c H G
+ EOF
+
+ git checkout -b merge-c H &&
(
- set_fake_editor &&
- FAKE_COMMIT_MESSAGE=edited \
- GIT_SEQUENCE_EDITOR="echo merge -c H G >" \
- git rebase -ir @^
+ set_reword_editor &&
+ GIT_SEQUENCE_EDITOR="\"$PWD/replace-editor.sh\"" \
+ git rebase -i -r D
) &&
- echo edited >expected &&
- git log --pretty=format:%B -1 >actual &&
- test_cmp expected actual
+ check_reworded_commits E H
'
+test_expect_success 'merge -c rewords when a strategy is given' '
+ git checkout -b merge-c-with-strategy H &&
+ write_script git-merge-override <<-\EOF &&
+ echo overridden$1 >G.t
+ git add G.t
+ EOF
+
+ PATH="$PWD:$PATH" \
+ GIT_SEQUENCE_EDITOR="echo merge -c H G >" \
+ GIT_EDITOR="echo edited >>" \
+ git rebase --no-ff -ir -s override -Xxopt E &&
+ test_write_lines overridden--xopt >expect &&
+ test_cmp expect G.t &&
+ test_write_lines H "" edited "" >expect &&
+ git log --format=%B -1 >actual &&
+ test_cmp expect actual
+
+'
test_expect_success 'with a branch tip that was cherry-picked already' '
git checkout -b already-upstream main &&
base="$(git rev-parse --verify HEAD)" &&
diff --git a/t/t3435-rebase-gpg-sign.sh b/t/t3435-rebase-gpg-sign.sh
index ec10766858..5f8ba2c739 100755
--- a/t/t3435-rebase-gpg-sign.sh
+++ b/t/t3435-rebase-gpg-sign.sh
@@ -65,6 +65,7 @@ test_rebase_gpg_sign ! true -i --gpg-sign --no-gpg-sign
test_rebase_gpg_sign false -i --no-gpg-sign --gpg-sign
test_expect_failure 'rebase -p --no-gpg-sign override commit.gpgsign' '
+ test_when_finished "git clean -f" &&
git reset --hard merged &&
git config commit.gpgsign true &&
git rebase -p --no-gpg-sign --onto=one fork-point main &&
diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh
index 9d100cd188..4b5b607673 100755
--- a/t/t3501-revert-cherry-pick.sh
+++ b/t/t3501-revert-cherry-pick.sh
@@ -158,4 +158,20 @@ test_expect_success 'cherry-pick works with dirty renamed file' '
grep -q "^modified$" renamed
'
+test_expect_success 'advice from failed revert' '
+ test_commit --no-tag "add dream" dream dream &&
+ dream_oid=$(git rev-parse --short HEAD) &&
+ cat <<-EOF >expected &&
+ error: could not revert $dream_oid... add dream
+ hint: After resolving the conflicts, mark them with
+ hint: "git add/rm <pathspec>", then run
+ hint: "git revert --continue".
+ hint: You can instead skip this commit with "git revert --skip".
+ hint: To abort and get back to the state before "git revert",
+ hint: run "git revert --abort".
+ EOF
+ test_commit --append --no-tag "double-add dream" dream dream &&
+ test_must_fail git revert HEAD^ 2>actual &&
+ test_cmp expected actual
+'
test_done
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index 014001b8f3..979e843c65 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -47,20 +47,23 @@ test_expect_success 'failed cherry-pick does not advance HEAD' '
test "$head" = "$newhead"
'
-test_expect_success 'advice from failed cherry-pick' "
+test_expect_success 'advice from failed cherry-pick' '
pristine_detach initial &&
- picked=\$(git rev-parse --short picked) &&
+ 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'
+ error: could not apply $picked... picked
+ hint: After resolving the conflicts, mark them with
+ hint: "git add/rm <pathspec>", then run
+ hint: "git cherry-pick --continue".
+ hint: You can instead skip this commit with "git cherry-pick --skip".
+ hint: To abort and get back to the state before "git cherry-pick",
+ hint: run "git cherry-pick --abort".
EOF
test_must_fail git cherry-pick picked 2>actual &&
test_cmp expected actual
-"
+'
test_expect_success 'advice from failed cherry-pick --no-commit' "
pristine_detach initial &&
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 49010aa946..3b0fa66c33 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -238,6 +238,7 @@ test_expect_success 'allow skipping commit but not abort for a new history' '
'
test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '
+ test_when_finished "rm unrelated" &&
pristine_detach initial &&
git rm --cached unrelated &&
git commit -m "untrack unrelated" &&
diff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh
index 74cd96e582..8bfe3ed246 100755
--- a/t/t3513-revert-submodule.sh
+++ b/t/t3513-revert-submodule.sh
@@ -14,7 +14,7 @@ test_description='revert can handle submodules'
git_revert () {
git status -su >expect &&
ls -1pR * >>expect &&
- tar cf "$TRASH_DIRECTORY/tmp.tar" * &&
+ "$TAR" cf "$TRASH_DIRECTORY/tmp.tar" * &&
may_only_be_test_must_fail "$2" &&
$2 git checkout "$1" &&
if test -n "$2"
@@ -23,7 +23,7 @@ git_revert () {
fi &&
git revert HEAD &&
rm -rf * &&
- tar xf "$TRASH_DIRECTORY/tmp.tar" &&
+ "$TAR" xf "$TRASH_DIRECTORY/tmp.tar" &&
git status -su >actual &&
ls -1pR * >>actual &&
test_cmp expect actual &&
diff --git a/t/t3602-rm-sparse-checkout.sh b/t/t3602-rm-sparse-checkout.sh
new file mode 100755
index 0000000000..ecce497a9c
--- /dev/null
+++ b/t/t3602-rm-sparse-checkout.sh
@@ -0,0 +1,108 @@
+#!/bin/sh
+
+test_description='git rm in sparse checked out working trees'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' "
+ mkdir -p sub/dir &&
+ touch a b c sub/d sub/dir/e &&
+ git add -A &&
+ git commit -m files &&
+
+ cat >sparse_error_header <<-EOF &&
+ The following paths and/or pathspecs matched paths that exist
+ outside of your sparse-checkout definition, so will not be
+ updated in the index:
+ EOF
+
+ cat >sparse_hint <<-EOF &&
+ hint: If you intend to update such entries, try one of the following:
+ hint: * Use the --sparse option.
+ hint: * Disable or modify the sparsity rules.
+ hint: Disable this message with \"git config advice.updateSparsePath false\"
+ EOF
+
+ echo b | cat sparse_error_header - >sparse_entry_b_error &&
+ cat sparse_entry_b_error sparse_hint >b_error_and_hint
+"
+
+for opt in "" -f --dry-run
+do
+ test_expect_success "rm${opt:+ $opt} does not remove sparse entries" '
+ git sparse-checkout set a &&
+ test_must_fail git rm $opt b 2>stderr &&
+ test_cmp b_error_and_hint stderr &&
+ git ls-files --error-unmatch b
+ '
+done
+
+test_expect_success 'recursive rm does not remove sparse entries' '
+ git reset --hard &&
+ git sparse-checkout set sub/dir &&
+ test_must_fail git rm -r sub &&
+ git rm --sparse -r sub &&
+ git status --porcelain -uno >actual &&
+ cat >expected <<-\EOF &&
+ D sub/d
+ D sub/dir/e
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'recursive rm --sparse removes sparse entries' '
+ git reset --hard &&
+ git sparse-checkout set "sub/dir" &&
+ git rm --sparse -r sub &&
+ git status --porcelain -uno >actual &&
+ cat >expected <<-\EOF &&
+ D sub/d
+ D sub/dir/e
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'rm obeys advice.updateSparsePath' '
+ git reset --hard &&
+ git sparse-checkout set a &&
+ test_must_fail git -c advice.updateSparsePath=false rm b 2>stderr &&
+ test_cmp sparse_entry_b_error stderr
+'
+
+test_expect_success 'do not advice about sparse entries when they do not match the pathspec' '
+ git reset --hard &&
+ git sparse-checkout set a &&
+ test_must_fail git rm nonexistent 2>stderr &&
+ grep "fatal: pathspec .nonexistent. did not match any files" stderr &&
+ ! grep -F -f sparse_error_header stderr
+'
+
+test_expect_success 'do not warn about sparse entries when pathspec matches dense entries' '
+ git reset --hard &&
+ git sparse-checkout set a &&
+ git rm "[ba]" 2>stderr &&
+ test_must_be_empty stderr &&
+ git ls-files --error-unmatch b &&
+ test_must_fail git ls-files --error-unmatch a
+'
+
+test_expect_success 'do not warn about sparse entries with --ignore-unmatch' '
+ git reset --hard &&
+ git sparse-checkout set a &&
+ git rm --ignore-unmatch b 2>stderr &&
+ test_must_be_empty stderr &&
+ git ls-files --error-unmatch b
+'
+
+test_expect_success 'refuse to rm a non-skip-worktree path outside sparse cone' '
+ git reset --hard &&
+ git sparse-checkout set a &&
+ git update-index --no-skip-worktree b &&
+ test_must_fail git rm b 2>stderr &&
+ test_cmp b_error_and_hint stderr &&
+ git rm --sparse b 2>stderr &&
+ test_must_be_empty stderr &&
+ test_path_is_missing b
+'
+
+test_done
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index b3b122ff97..4086e1ebbc 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -196,6 +196,12 @@ test_expect_success 'git add --refresh with pathspec' '
grep baz actual
'
+test_expect_success 'git add --refresh correctly reports no match error' "
+ echo \"fatal: pathspec ':(icase)nonexistent' did not match any files\" >expect &&
+ test_must_fail git add --refresh ':(icase)nonexistent' 2>actual &&
+ test_cmp expect actual
+"
+
test_expect_success POSIXPERM,SANITY 'git add should fail atomically upon an unreadable file' '
git reset --hard &&
date >foo1 &&
@@ -343,6 +349,10 @@ test_expect_success 'git add --dry-run --ignore-missing of non-existing file out
test_cmp expect.err actual.err
'
+test_expect_success 'git add --dry-run --interactive should fail' '
+ test_must_fail git add --dry-run --interactive
+'
+
test_expect_success 'git add empty string should fail' '
test_must_fail git add ""
'
diff --git a/t/t3705-add-sparse-checkout.sh b/t/t3705-add-sparse-checkout.sh
new file mode 100755
index 0000000000..5b904988d4
--- /dev/null
+++ b/t/t3705-add-sparse-checkout.sh
@@ -0,0 +1,217 @@
+#!/bin/sh
+
+test_description='git add in sparse checked out working trees'
+
+. ./test-lib.sh
+
+SPARSE_ENTRY_BLOB=""
+
+# Optionally take a printf format string to write to the sparse_entry file
+setup_sparse_entry () {
+ # 'sparse_entry' might already be in the index with the skip-worktree
+ # bit set. Remove it so that the subsequent git add can update it.
+ git update-index --force-remove sparse_entry &&
+ if test $# -eq 1
+ then
+ printf "$1" >sparse_entry
+ else
+ >sparse_entry
+ fi &&
+ git add sparse_entry &&
+ git update-index --skip-worktree sparse_entry &&
+ git commit --allow-empty -m "ensure sparse_entry exists at HEAD" &&
+ SPARSE_ENTRY_BLOB=$(git rev-parse :sparse_entry)
+}
+
+test_sparse_entry_unchanged () {
+ echo "100644 $SPARSE_ENTRY_BLOB 0 sparse_entry" >expected &&
+ git ls-files --stage sparse_entry >actual &&
+ test_cmp expected actual
+}
+
+setup_gitignore () {
+ test_when_finished rm -f .gitignore &&
+ cat >.gitignore <<-EOF
+ *
+ !/sparse_entry
+ EOF
+}
+
+test_sparse_entry_unstaged () {
+ git diff --staged -- sparse_entry >diff &&
+ test_must_be_empty diff
+}
+
+test_expect_success 'setup' "
+ cat >sparse_error_header <<-EOF &&
+ The following paths and/or pathspecs matched paths that exist
+ outside of your sparse-checkout definition, so will not be
+ updated in the index:
+ EOF
+
+ cat >sparse_hint <<-EOF &&
+ hint: If you intend to update such entries, try one of the following:
+ hint: * Use the --sparse option.
+ hint: * Disable or modify the sparsity rules.
+ hint: Disable this message with \"git config advice.updateSparsePath false\"
+ EOF
+
+ echo sparse_entry | cat sparse_error_header - >sparse_entry_error &&
+ cat sparse_entry_error sparse_hint >error_and_hint
+"
+
+test_expect_success 'git add does not remove sparse entries' '
+ setup_sparse_entry &&
+ rm sparse_entry &&
+ test_must_fail git add sparse_entry 2>stderr &&
+ test_sparse_entry_unstaged &&
+ test_cmp error_and_hint stderr &&
+ test_sparse_entry_unchanged
+'
+
+test_expect_success 'git add -A does not remove sparse entries' '
+ setup_sparse_entry &&
+ rm sparse_entry &&
+ setup_gitignore &&
+ git add -A 2>stderr &&
+ test_must_be_empty stderr &&
+ test_sparse_entry_unchanged
+'
+
+test_expect_success 'git add . does not remove sparse entries' '
+ setup_sparse_entry &&
+ rm sparse_entry &&
+ setup_gitignore &&
+ test_must_fail git add . 2>stderr &&
+ test_sparse_entry_unstaged &&
+
+ cat sparse_error_header >expect &&
+ echo . >>expect &&
+ cat sparse_hint >>expect &&
+
+ test_cmp expect stderr &&
+ test_sparse_entry_unchanged
+'
+
+for opt in "" -f -u --ignore-removal --dry-run
+do
+ test_expect_success "git add${opt:+ $opt} does not update sparse entries" '
+ setup_sparse_entry &&
+ echo modified >sparse_entry &&
+ test_must_fail git add $opt sparse_entry 2>stderr &&
+ test_sparse_entry_unstaged &&
+ test_cmp error_and_hint stderr &&
+ test_sparse_entry_unchanged
+ '
+done
+
+test_expect_success 'git add --refresh does not update sparse entries' '
+ setup_sparse_entry &&
+ git ls-files --debug sparse_entry | grep mtime >before &&
+ test-tool chmtime -60 sparse_entry &&
+ test_must_fail git add --refresh sparse_entry 2>stderr &&
+ test_sparse_entry_unstaged &&
+ test_cmp error_and_hint stderr &&
+ git ls-files --debug sparse_entry | grep mtime >after &&
+ test_cmp before after
+'
+
+test_expect_success 'git add --chmod does not update sparse entries' '
+ setup_sparse_entry &&
+ test_must_fail git add --chmod=+x sparse_entry 2>stderr &&
+ test_sparse_entry_unstaged &&
+ test_cmp error_and_hint stderr &&
+ test_sparse_entry_unchanged &&
+ ! test -x sparse_entry
+'
+
+test_expect_success 'git add --renormalize does not update sparse entries' '
+ test_config core.autocrlf false &&
+ setup_sparse_entry "LINEONE\r\nLINETWO\r\n" &&
+ echo "sparse_entry text=auto" >.gitattributes &&
+ test_must_fail git add --renormalize sparse_entry 2>stderr &&
+ test_sparse_entry_unstaged &&
+ test_cmp error_and_hint stderr &&
+ test_sparse_entry_unchanged
+'
+
+test_expect_success 'git add --dry-run --ignore-missing warn on sparse path' '
+ setup_sparse_entry &&
+ rm sparse_entry &&
+ test_must_fail git add --dry-run --ignore-missing sparse_entry 2>stderr &&
+ test_sparse_entry_unstaged &&
+ test_cmp error_and_hint stderr &&
+ test_sparse_entry_unchanged
+'
+
+test_expect_success 'do not advice about sparse entries when they do not match the pathspec' '
+ setup_sparse_entry &&
+ test_must_fail git add nonexistent 2>stderr &&
+ grep "fatal: pathspec .nonexistent. did not match any files" stderr &&
+ ! grep -F -f sparse_error_header stderr
+'
+
+test_expect_success 'do not warn when pathspec matches dense entries' '
+ setup_sparse_entry &&
+ echo modified >sparse_entry &&
+ >dense_entry &&
+ git add "*_entry" 2>stderr &&
+ test_must_be_empty stderr &&
+ test_sparse_entry_unchanged &&
+ git ls-files --error-unmatch dense_entry
+'
+
+test_expect_success 'git add fails outside of sparse-checkout definition' '
+ test_when_finished git sparse-checkout disable &&
+ test_commit a &&
+ git sparse-checkout init &&
+ git sparse-checkout set a &&
+ echo >>sparse_entry &&
+
+ git update-index --no-skip-worktree sparse_entry &&
+ test_must_fail git add sparse_entry &&
+ test_sparse_entry_unstaged &&
+
+ test_must_fail git add --chmod=+x sparse_entry &&
+ test_sparse_entry_unstaged &&
+
+ test_must_fail git add --renormalize sparse_entry &&
+ test_sparse_entry_unstaged &&
+
+ # Avoid munging CRLFs to avoid an error message
+ git -c core.autocrlf=input add --sparse sparse_entry 2>stderr &&
+ test_must_be_empty stderr &&
+ test-tool read-cache --table >actual &&
+ grep "^100644 blob.*sparse_entry\$" actual &&
+
+ git add --sparse --chmod=+x sparse_entry 2>stderr &&
+ test_must_be_empty stderr &&
+ test-tool read-cache --table >actual &&
+ grep "^100755 blob.*sparse_entry\$" actual &&
+
+ git reset &&
+
+ # This will print a message over stderr on Windows.
+ git add --sparse --renormalize sparse_entry &&
+ git status --porcelain >actual &&
+ grep "^M sparse_entry\$" actual
+'
+
+test_expect_success 'add obeys advice.updateSparsePath' '
+ setup_sparse_entry &&
+ test_must_fail git -c advice.updateSparsePath=false add sparse_entry 2>stderr &&
+ test_sparse_entry_unstaged &&
+ test_cmp sparse_entry_error stderr
+
+'
+
+test_expect_success 'add allows sparse entries with --sparse' '
+ git sparse-checkout set a &&
+ echo modified >sparse_entry &&
+ test_must_fail git add sparse_entry &&
+ test_sparse_entry_unchanged &&
+ git add --sparse sparse_entry 2>stderr &&
+ test_must_be_empty stderr
+'
+
+test_done
diff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh
index 6275c98523..0544d58a6e 100755
--- a/t/t3800-mktag.sh
+++ b/t/t3800-mktag.sh
@@ -12,15 +12,93 @@ test_description='git mktag: tag object verify test'
# given in the expect.pat file.
check_verify_failure () {
- test_expect_success "$1" "
- test_must_fail git mktag <tag.sig 2>message &&
- grep '$2' message &&
- if test '$3' != '--no-strict'
+ subject=$1 &&
+ message=$2 &&
+ shift 2 &&
+
+ no_strict= &&
+ fsck_obj_ok= &&
+ no_strict= &&
+ while test $# != 0
+ do
+ case "$1" in
+ --no-strict)
+ no_strict=yes
+ ;;
+ --fsck-obj-ok)
+ fsck_obj_ok=yes
+ ;;
+ esac &&
+ shift
+ done &&
+
+ test_expect_success "fail with [--[no-]strict]: $subject" '
+ test_must_fail git mktag <tag.sig 2>err &&
+ if test -z "$no_strict"
then
- test_must_fail git mktag --no-strict <tag.sig 2>message.no-strict &&
- grep '$2' message.no-strict
+ test_must_fail git mktag <tag.sig 2>err2 &&
+ test_cmp err err2
+ else
+ git mktag --no-strict <tag.sig
fi
- "
+ '
+
+ test_expect_success "setup: $subject" '
+ tag_ref=refs/tags/bad_tag &&
+
+ # Reset any leftover state from the last $subject
+ rm -rf bad-tag &&
+
+ git init --bare bad-tag &&
+ bad_tag=$(git -C bad-tag hash-object -t tag -w --stdin --literally <tag.sig)
+ '
+
+ test_expect_success "hash-object & fsck unreachable: $subject" '
+ if test -n "$fsck_obj_ok"
+ then
+ git -C bad-tag fsck
+ else
+ test_must_fail git -C bad-tag fsck
+ fi
+ '
+
+ test_expect_success "update-ref & fsck reachable: $subject" '
+ # Make sure the earlier test created it for us
+ git rev-parse "$bad_tag" &&
+
+ # The update-ref of the bad content will fail, do it
+ # anyway to see if it segfaults
+ test_might_fail git -C bad-tag update-ref "$tag_ref" "$bad_tag" &&
+
+ # Manually create the broken, we cannot do it with
+ # update-ref
+ echo "$bad_tag" >"bad-tag/$tag_ref" &&
+
+ # Unlike fsck-ing unreachable content above, this
+ # will always fail.
+ test_must_fail git -C bad-tag fsck
+ '
+
+ test_expect_success "for-each-ref: $subject" '
+ # Make sure the earlier test created it for us
+ git rev-parse "$bad_tag" &&
+
+ echo "$bad_tag" >"bad-tag/$tag_ref" &&
+
+ printf "%s tag\t%s\n" "$bad_tag" "$tag_ref" >expected &&
+ git -C bad-tag for-each-ref "$tag_ref" >actual &&
+ test_cmp expected actual &&
+
+ test_must_fail git -C bad-tag for-each-ref --format="%(*objectname)"
+ '
+
+ test_expect_success "fast-export & fast-import: $subject" '
+ # Make sure the earlier test created it for us
+ git rev-parse "$bad_tag" &&
+
+ test_must_fail git -C bad-tag fast-export --all &&
+ test_must_fail git -C bad-tag fast-export "$bad_tag"
+ '
}
test_expect_mktag_success() {
@@ -167,7 +245,8 @@ tagger . <> 0 +0000
EOF
check_verify_failure 'verify object (hash/type) check -- correct type, nonexisting object' \
- '^fatal: could not read tagged object'
+ '^fatal: could not read tagged object' \
+ --fsck-obj-ok
cat >tag.sig <<EOF
object $head
@@ -200,7 +279,8 @@ tagger . <> 0 +0000
EOF
check_verify_failure 'verify object (hash/type) check -- mismatched type, valid object' \
- '^fatal: object.*tagged as.*tree.*but is.*commit'
+ '^fatal: object.*tagged as.*tree.*but is.*commit' \
+ --fsck-obj-ok
############################################################
# 9.5. verify object (hash/type) check -- replacement
@@ -229,7 +309,8 @@ tagger . <> 0 +0000
EOF
check_verify_failure 'verify object (hash/type) check -- mismatched type, valid object' \
- '^fatal: object.*tagged as.*tree.*but is.*blob'
+ '^fatal: object.*tagged as.*tree.*but is.*blob' \
+ --fsck-obj-ok
############################################################
# 10. verify tag-name check
@@ -243,7 +324,9 @@ tagger . <> 0 +0000
EOF
check_verify_failure 'verify tag-name check' \
- '^error:.* badTagName:' '--no-strict'
+ '^error:.* badTagName:' \
+ --no-strict \
+ --fsck-obj-ok
############################################################
# 11. tagger line label check #1
@@ -257,7 +340,9 @@ This is filler
EOF
check_verify_failure '"tagger" line label check #1' \
- '^error:.* missingTaggerEntry:' '--no-strict'
+ '^error:.* missingTaggerEntry:' \
+ --no-strict \
+ --fsck-obj-ok
############################################################
# 12. tagger line label check #2
@@ -272,7 +357,9 @@ This is filler
EOF
check_verify_failure '"tagger" line label check #2' \
- '^error:.* missingTaggerEntry:' '--no-strict'
+ '^error:.* missingTaggerEntry:' \
+ --no-strict \
+ --fsck-obj-ok
############################################################
# 13. allow missing tag author name like fsck
@@ -301,7 +388,9 @@ tagger T A Gger <
EOF
check_verify_failure 'disallow malformed tagger' \
- '^error:.* badEmail:' '--no-strict'
+ '^error:.* badEmail:' \
+ --no-strict \
+ --fsck-obj-ok
############################################################
# 15. allow empty tag email
@@ -425,7 +514,9 @@ this line should not be here
EOF
check_verify_failure 'detect invalid header entry' \
- '^error:.* extraHeaderEntry:' '--no-strict'
+ '^error:.* extraHeaderEntry:' \
+ --no-strict \
+ --fsck-obj-ok
test_expect_success 'invalid header entry config & fsck' '
test_must_fail git mktag <tag.sig &&
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 5f282ecf61..f0a82be9de 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -859,7 +859,7 @@ test_expect_success 'setup stash with index and worktree changes' '
git stash
'
-test_expect_success 'stash list implies --first-parent -m' '
+test_expect_success 'stash list -p shows simple diff' '
cat >expect <<-EOF &&
stash@{0}
@@ -1307,4 +1307,62 @@ test_expect_success 'stash -c stash.useBuiltin=false warning ' '
test_must_be_empty err
'
+test_expect_success 'git stash succeeds despite directory/file change' '
+ test_create_repo directory_file_switch_v1 &&
+ (
+ cd directory_file_switch_v1 &&
+ test_commit init &&
+
+ test_write_lines this file has some words >filler &&
+ git add filler &&
+ git commit -m filler &&
+
+ git rm filler &&
+ mkdir filler &&
+ echo contents >filler/file &&
+ git stash push
+ )
+'
+
+test_expect_success 'git stash can pop file -> directory saved changes' '
+ test_create_repo directory_file_switch_v2 &&
+ (
+ cd directory_file_switch_v2 &&
+ test_commit init &&
+
+ test_write_lines this file has some words >filler &&
+ git add filler &&
+ git commit -m filler &&
+
+ git rm filler &&
+ mkdir filler &&
+ echo contents >filler/file &&
+ cp filler/file expect &&
+ git stash push --include-untracked &&
+ git stash apply --index &&
+ test_cmp expect filler/file
+ )
+'
+
+test_expect_success 'git stash can pop directory -> file saved changes' '
+ test_create_repo directory_file_switch_v3 &&
+ (
+ cd directory_file_switch_v3 &&
+ test_commit init &&
+
+ mkdir filler &&
+ test_write_lines some words >filler/file1 &&
+ test_write_lines and stuff >filler/file2 &&
+ git add filler &&
+ git commit -m filler &&
+
+ git rm -rf filler &&
+ echo contents >filler &&
+ cp filler expect &&
+ git stash push --include-untracked &&
+ git stash apply --index &&
+ test_cmp expect filler
+ )
+'
+
test_done
diff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh
index c59bcffabb..5390eec4e3 100755
--- a/t/t3905-stash-include-untracked.sh
+++ b/t/t3905-stash-include-untracked.sh
@@ -333,6 +333,8 @@ test_expect_success 'stash show --include-untracked shows untracked files' '
git stash show -p --include-untracked >actual &&
test_cmp expect actual &&
git stash show --include-untracked -p >actual &&
+ test_cmp expect actual &&
+ git -c stash.showIncludeUntracked=true stash show -p >actual &&
test_cmp expect actual
'
@@ -367,7 +369,7 @@ test_expect_success 'stash show --only-untracked only shows untracked files' '
test_cmp expect actual
'
-test_expect_success 'stash show --no-include-untracked cancels --{include,show}-untracked' '
+test_expect_success 'stash show --no-include-untracked cancels --{include,only}-untracked' '
git reset --hard &&
git clean -xf &&
>untracked &&
@@ -405,6 +407,21 @@ test_expect_success 'stash show --include-untracked errors on duplicate files' '
test_i18ngrep "worktree and untracked commit have duplicate entries: tracked" err
'
+test_expect_success 'stash show --{include,only}-untracked on stashes without untracked entries' '
+ git reset --hard &&
+ git clean -xf &&
+ >tracked &&
+ git add tracked &&
+ git stash &&
+
+ git stash show >expect &&
+ git stash show --include-untracked >actual &&
+ test_cmp expect actual &&
+
+ git stash show --only-untracked >actual &&
+ test_must_be_empty actual
+'
+
test_expect_success 'stash -u ignores sub-repository' '
test_when_finished "rm -rf sub-repo" &&
git init sub-repo &&
diff --git a/t/t3920-crlf-messages.sh b/t/t3920-crlf-messages.sh
index 70ddce3a2e..a8ad5462d9 100755
--- a/t/t3920-crlf-messages.sh
+++ b/t/t3920-crlf-messages.sh
@@ -64,7 +64,7 @@ test_crlf_subject_body_and_contents() {
while test -n "${atoms}"
do
set ${atoms} && atom=$1 && shift && atoms="$*" &&
- set ${files} && file=$1 && shift && files="$*" &&
+ set ${files} && file=$1 && shift && files="$*" &&
test_expect_success "${command}: --format='%${atom}' works with messages using CRLF" "
rm -f expect &&
for ref in ${LIB_CRLF_BRANCHES}
diff --git a/t/t4006-diff-mode.sh b/t/t4006-diff-mode.sh
index 275ce5fa15..6cdee2a216 100755
--- a/t/t4006-diff-mode.sh
+++ b/t/t4006-diff-mode.sh
@@ -26,10 +26,8 @@ test_expect_success 'chmod' '
'
test_expect_success 'prepare binary file' '
- git commit -m rezrov &&
- printf "\00\01\02\03\04\05\06" >binbin &&
- git add binbin &&
- git commit -m binbin
+ git commit -m one &&
+ test_commit --printf two binbin "\00\01\02\03\04\05\06"
'
test_expect_success '--stat output after text chmod' '
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 6cca8b84a6..28683d059d 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -65,7 +65,7 @@ test_expect_success setup '
export GIT_AUTHOR_DATE GIT_COMMITTER_DATE &&
git checkout master &&
- git pull -s ours . side &&
+ git pull -s ours --no-rebase . side &&
GIT_AUTHOR_DATE="2006-06-26 00:05:00 +0000" &&
GIT_COMMITTER_DATE="2006-06-26 00:05:00 +0000" &&
@@ -293,6 +293,7 @@ diff-tree --stat initial mode
diff-tree --summary initial mode
diff-tree master
+diff-tree -m master
diff-tree -p master
diff-tree -p -m master
diff-tree -c master
@@ -337,6 +338,8 @@ log -m -p --first-parent master
log -m -p master
log --cc -m -p master
log -c -m -p master
+log -m --raw master
+log -m --stat master
log -SF master
log -S F master
log -SF -p master
@@ -452,6 +455,58 @@ diff-tree --stat --compact-summary initial mode
diff-tree -R --stat --compact-summary initial mode
EOF
+test_expect_success 'log -m matches pure log' '
+ git log master >result &&
+ process_diffs result >expected &&
+ git log -m >result &&
+ process_diffs result >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'log --diff-merges=on matches --diff-merges=separate' '
+ git log -p --diff-merges=separate master >result &&
+ process_diffs result >expected &&
+ git log -p --diff-merges=on master >result &&
+ process_diffs result >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'deny wrong log.diffMerges config' '
+ test_config log.diffMerges wrong-value &&
+ test_expect_code 128 git log
+'
+
+test_expect_success 'git config log.diffMerges first-parent' '
+ git log -p --diff-merges=first-parent master >result &&
+ process_diffs result >expected &&
+ test_config log.diffMerges first-parent &&
+ git log -p --diff-merges=on master >result &&
+ process_diffs result >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'git config log.diffMerges first-parent vs -m' '
+ git log -p --diff-merges=first-parent master >result &&
+ process_diffs result >expected &&
+ test_config log.diffMerges first-parent &&
+ git log -p -m master >result &&
+ process_diffs result >actual &&
+ test_cmp expected actual
+'
+
+# -m in "git diff-index" means "match missing", that differs
+# from its meaning in "git diff". Let's check it in diff-index.
+# The line in the output for removed file should disappear when
+# we provide -m in diff-index.
+test_expect_success 'git diff-index -m' '
+ rm -f file1 &&
+ git diff-index HEAD >without-m &&
+ lines_count=$(wc -l <without-m) &&
+ git diff-index -m HEAD >with-m &&
+ git restore file1 &&
+ test_line_count = $((lines_count - 1)) with-m
+'
+
test_expect_success 'log -S requires an argument' '
test_must_fail git log -S
'
diff --git a/t/t4013/diff.diff-tree_-m_master b/t/t4013/diff.diff-tree_-m_master
new file mode 100644
index 0000000000..6d0a2207fb
--- /dev/null
+++ b/t/t4013/diff.diff-tree_-m_master
@@ -0,0 +1,11 @@
+$ git diff-tree -m master
+59d314ad6f356dd08601a4cd5e530381da3e3c64
+:040000 040000 65f5c9dd60ce3b2b3324b618ac7accf8d912c113 0564e026437809817a64fff393079714b6dd4628 M dir
+:100644 100644 b414108e81e5091fe0974a1858b4d0d22b107f70 10a8a9f3657f91a156b9f0184ed79a20adef9f7f M file0
+59d314ad6f356dd08601a4cd5e530381da3e3c64
+:040000 040000 f977ed46ae6873c1c30ab878e15a4accedc3618b 0564e026437809817a64fff393079714b6dd4628 M dir
+:100644 100644 f4615da674c09df322d6ba8d6b21ecfb1b1ba510 10a8a9f3657f91a156b9f0184ed79a20adef9f7f M file0
+:000000 100644 0000000000000000000000000000000000000000 b1e67221afe8461efd244b487afca22d46b95eb8 A file1
+:100644 000000 01e79c32a8c99c557f0757da7cb6d65b3414466d 0000000000000000000000000000000000000000 D file2
+:100644 000000 7289e35bff32727c08dda207511bec138fdb9ea5 0000000000000000000000000000000000000000 D file3
+$
diff --git a/t/t4013/diff.log_-m_--raw_master b/t/t4013/diff.log_-m_--raw_master
new file mode 100644
index 0000000000..cd2ecc4628
--- /dev/null
+++ b/t/t4013/diff.log_-m_--raw_master
@@ -0,0 +1,61 @@
+$ git log -m --raw master
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+:100644 100644 cead32e... 992913c... M dir/sub
+:100644 100644 b414108... 10a8a9f... M file0
+
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+:100644 100644 7289e35... 992913c... M dir/sub
+:100644 100644 f4615da... 10a8a9f... M file0
+:000000 100644 0000000... b1e6722... A file1
+:100644 000000 01e79c3... 0000000... D file2
+:100644 000000 7289e35... 0000000... D file3
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+
+:100644 100644 35d242b... 7289e35... M dir/sub
+:100644 100644 01e79c3... f4615da... M file0
+:000000 100644 0000000... 7289e35... A file3
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+
+:100644 100644 8422d40... cead32e... M dir/sub
+:000000 100644 0000000... b1e6722... A file1
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+
+ This is the second commit.
+
+:100644 100644 35d242b... 8422d40... M dir/sub
+:100644 100644 01e79c3... b414108... M file0
+:100644 000000 01e79c3... 0000000... D file2
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+$
diff --git a/t/t4013/diff.log_-m_--stat_master b/t/t4013/diff.log_-m_--stat_master
new file mode 100644
index 0000000000..c7db084fd9
--- /dev/null
+++ b/t/t4013/diff.log_-m_--stat_master
@@ -0,0 +1,66 @@
+$ git log -m --stat master
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+ dir/sub | 2 ++
+ file0 | 3 +++
+ 2 files changed, 5 insertions(+)
+
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+ dir/sub | 4 ++++
+ file0 | 3 +++
+ file1 | 3 +++
+ file2 | 3 ---
+ file3 | 4 ----
+ 5 files changed, 10 insertions(+), 7 deletions(-)
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+)
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+
+ dir/sub | 2 ++
+ file1 | 3 +++
+ 2 files changed, 5 insertions(+)
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+
+ This is the second commit.
+
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 ---
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+$
diff --git a/t/t4018/java-class-member-function b/t/t4018/java-class-member-function
index 298bc7a71b..3b95f68b3b 100644
--- a/t/t4018/java-class-member-function
+++ b/t/t4018/java-class-member-function
@@ -3,6 +3,10 @@ public class Beer
int special;
public static void main(String RIGHT[])
{
+ someMethodCall();
+ someOtherMethod("17")
+ .doThat();
+ // Whatever
System.out.print("ChangeMe");
}
}
diff --git a/t/t4018/java-enum-constant b/t/t4018/java-enum-constant
new file mode 100644
index 0000000000..a1931c8379
--- /dev/null
+++ b/t/t4018/java-enum-constant
@@ -0,0 +1,6 @@
+private enum RIGHT {
+ ONE,
+ TWO,
+ THREE,
+ ChangeMe
+}
diff --git a/t/t4018/java-method-return-generic-bounded b/t/t4018/java-method-return-generic-bounded
new file mode 100644
index 0000000000..66dd78c379
--- /dev/null
+++ b/t/t4018/java-method-return-generic-bounded
@@ -0,0 +1,9 @@
+class MyExample {
+ public <T extends Bar & Foo<T>, R> Map<T, R[]> foo(String[] RIGHT) {
+ someMethodCall();
+ someOtherMethod()
+ .doThat();
+ // Whatever...
+ return (List<T>) Arrays.asList("ChangeMe");
+ }
+}
diff --git a/t/t4018/java-method-return-generic-wildcard b/t/t4018/java-method-return-generic-wildcard
new file mode 100644
index 0000000000..96e9e5f2c1
--- /dev/null
+++ b/t/t4018/java-method-return-generic-wildcard
@@ -0,0 +1,9 @@
+class MyExample {
+ public List<? extends Comparable> foo(String[] RIGHT) {
+ someMethodCall();
+ someOtherMethod()
+ .doThat();
+ // Whatever...
+ return Arrays.asList("ChangeMe");
+ }
+}
diff --git a/t/t4018/java-nested-field b/t/t4018/java-nested-field
new file mode 100644
index 0000000000..d92d3ec688
--- /dev/null
+++ b/t/t4018/java-nested-field
@@ -0,0 +1,6 @@
+class MyExample {
+ private static class RIGHT {
+ // change an inner class field
+ String inner = "ChangeMe";
+ }
+}
diff --git a/t/t4018/php-enum b/t/t4018/php-enum
new file mode 100644
index 0000000000..91a69c1a2b
--- /dev/null
+++ b/t/t4018/php-enum
@@ -0,0 +1,4 @@
+enum RIGHT: string
+{
+ case Foo = 'ChangeMe';
+}
diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
index c906320b60..a39a626664 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -26,12 +26,8 @@ EOF
chmod +x hexdump
test_expect_success 'setup binary file with history' '
- printf "\\0\\n" >file &&
- git add file &&
- git commit -m one &&
- printf "\\01\\n" >>file &&
- git add file &&
- git commit -m two
+ test_commit --printf one file "\\0\\n" &&
+ test_commit --printf --append two file "\\01\\n"
'
test_expect_success 'file is considered binary by porcelain' '
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index ee7721ab91..561c582d16 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -184,6 +184,11 @@ test_expect_success 'word diff with a regular expression' '
word_diff --color-words="[a-z]+"
'
+test_expect_success 'word diff with zero length matches' '
+ cp expect.letter-runs-are-words expect &&
+ word_diff --color-words="[a-z${LF}]*"
+'
+
test_expect_success 'set up a diff driver' '
git config diff.testdriver.wordRegex "[^[:space:]]" &&
cat <<-\EOF >.gitattributes
diff --git a/t/t4045-diff-relative.sh b/t/t4045-diff-relative.sh
index 61ba5f707f..fab351b48a 100755
--- a/t/t4045-diff-relative.sh
+++ b/t/t4045-diff-relative.sh
@@ -162,4 +162,57 @@ check_diff_relative_option subdir file2 true --no-relative --relative
check_diff_relative_option . file2 false --no-relative --relative=subdir
check_diff_relative_option . file2 true --no-relative --relative=subdir
+test_expect_success 'setup diff --relative unmerged' '
+ test_commit zero file0 &&
+ test_commit base subdir/file0 &&
+ git switch -c br1 &&
+ test_commit one file0 &&
+ test_commit sub1 subdir/file0 &&
+ git switch -c br2 base &&
+ test_commit two file0 &&
+ git switch -c br3 &&
+ test_commit sub3 subdir/file0
+'
+
+test_expect_success 'diff --relative without change in subdir' '
+ git switch br2 &&
+ test_when_finished "git merge --abort" &&
+ test_must_fail git merge one &&
+ git -C subdir diff --relative >out &&
+ test_must_be_empty out &&
+ git -C subdir diff --relative --name-only >out &&
+ test_must_be_empty out
+'
+
+test_expect_success 'diff --relative --name-only with change in subdir' '
+ git switch br3 &&
+ test_when_finished "git merge --abort" &&
+ test_must_fail git merge sub1 &&
+ test_write_lines file0 file0 >expected &&
+ git -C subdir diff --relative --name-only >out &&
+ test_cmp expected out
+'
+
+test_expect_failure 'diff --relative with change in subdir' '
+ git switch br3 &&
+ br1_blob=$(git rev-parse --short --verify br1:subdir/file0) &&
+ br3_blob=$(git rev-parse --short --verify br3:subdir/file0) &&
+ test_when_finished "git merge --abort" &&
+ test_must_fail git merge br1 &&
+ cat >expected <<-EOF &&
+ diff --cc file0
+ index $br3_blob,$br1_blob..0000000
+ --- a/file0
+ +++ b/file0
+ @@@ -1,1 -1,1 +1,5 @@@
+ ++<<<<<<< HEAD
+ +sub3
+ ++=======
+ + sub1
+ ++>>>>>>> br1
+ EOF
+ git -C subdir diff --relative >out &&
+ test_cmp expected out
+'
+
test_done
diff --git a/t/t4060-diff-submodule-option-diff-format.sh b/t/t4060-diff-submodule-option-diff-format.sh
index dc7b242697..d86e38abd8 100755
--- a/t/t4060-diff-submodule-option-diff-format.sh
+++ b/t/t4060-diff-submodule-option-diff-format.sh
@@ -361,7 +361,6 @@ test_expect_success 'typechanged submodule(submodule->blob)' '
rm -f sm1 &&
test_create_repo sm1 &&
head6=$(add_file sm1 foo6 foo7)
-fullhead6=$(cd sm1; git rev-parse --verify HEAD)
test_expect_success 'nonexistent commit' '
git diff-index -p --submodule=diff HEAD >actual &&
cat >expected <<-EOF &&
@@ -704,10 +703,26 @@ test_expect_success 'path filter' '
diff_cmp expected actual
'
-commit_file sm2
+cat >.gitmodules <<-EOF
+[submodule "sm2"]
+ path = sm2
+ url = bogus_url
+EOF
+git add .gitmodules
+commit_file sm2 .gitmodules
+
test_expect_success 'given commit' '
git diff-index -p --submodule=diff HEAD^ >actual &&
cat >expected <<-EOF &&
+ diff --git a/.gitmodules b/.gitmodules
+ new file mode 100644
+ index 1234567..89abcde
+ --- /dev/null
+ +++ b/.gitmodules
+ @@ -0,0 +1,3 @@
+ +[submodule "sm2"]
+ +path = sm2
+ +url = bogus_url
Submodule sm1 $head7...0000000 (submodule deleted)
Submodule sm2 0000000...$head9 (new submodule)
diff --git a/sm2/foo8 b/sm2/foo8
@@ -729,15 +744,21 @@ test_expect_success 'given commit' '
'
test_expect_success 'setup .git file for sm2' '
- (cd sm2 &&
- REAL="$(pwd)/../.real" &&
- mv .git "$REAL" &&
- echo "gitdir: $REAL" >.git)
+ git submodule absorbgitdirs sm2
'
test_expect_success 'diff --submodule=diff with .git file' '
git diff --submodule=diff HEAD^ >actual &&
cat >expected <<-EOF &&
+ diff --git a/.gitmodules b/.gitmodules
+ new file mode 100644
+ index 1234567..89abcde
+ --- /dev/null
+ +++ b/.gitmodules
+ @@ -0,0 +1,3 @@
+ +[submodule "sm2"]
+ +path = sm2
+ +url = bogus_url
Submodule sm1 $head7...0000000 (submodule deleted)
Submodule sm2 0000000...$head9 (new submodule)
diff --git a/sm2/foo8 b/sm2/foo8
@@ -758,9 +779,67 @@ test_expect_success 'diff --submodule=diff with .git file' '
diff_cmp expected actual
'
+mv sm2 sm2-bak
+
+test_expect_success 'deleted submodule with .git file' '
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 $head7...0000000 (submodule deleted)
+ Submodule sm2 $head9...0000000 (submodule deleted)
+ diff --git a/sm2/foo8 b/sm2/foo8
+ deleted file mode 100644
+ index 1234567..89abcde
+ --- a/sm2/foo8
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -foo8
+ diff --git a/sm2/foo9 b/sm2/foo9
+ deleted file mode 100644
+ index 1234567..89abcde
+ --- a/sm2/foo9
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -foo9
+ EOF
+ diff_cmp expected actual
+'
+
+echo submodule-to-blob>sm2
+
+test_expect_success 'typechanged(submodule->blob) submodule with .git file' '
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 $head7...0000000 (submodule deleted)
+ Submodule sm2 $head9...0000000 (submodule deleted)
+ diff --git a/sm2/foo8 b/sm2/foo8
+ deleted file mode 100644
+ index 1234567..89abcde
+ --- a/sm2/foo8
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -foo8
+ diff --git a/sm2/foo9 b/sm2/foo9
+ deleted file mode 100644
+ index 1234567..89abcde
+ --- a/sm2/foo9
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -foo9
+ diff --git a/sm2 b/sm2
+ new file mode 100644
+ index 1234567..89abcde
+ --- /dev/null
+ +++ b/sm2
+ @@ -0,0 +1 @@
+ +submodule-to-blob
+ EOF
+ diff_cmp expected actual
+'
+
+rm sm2
+mv sm2-bak sm2
+
test_expect_success 'setup nested submodule' '
- git submodule add -f ./sm2 &&
- git commit -a -m "add sm2" &&
git -C sm2 submodule add ../sm2 nested &&
git -C sm2 commit -a -m "nested sub" &&
head10=$(git -C sm2 rev-parse --short --verify HEAD)
@@ -791,6 +870,7 @@ test_expect_success 'diff --submodule=diff with moved nested submodule HEAD' '
test_expect_success 'diff --submodule=diff recurses into nested submodules' '
cat >expected <<-EOF &&
+ Submodule sm1 $head7...0000000 (submodule deleted)
Submodule sm2 contains modified content
Submodule sm2 $head9..$head10:
diff --git a/sm2/.gitmodules b/sm2/.gitmodules
@@ -830,4 +910,67 @@ test_expect_success 'diff --submodule=diff recurses into nested submodules' '
diff_cmp expected actual
'
+(cd sm2; commit_file nested)
+commit_file sm2
+head12=$(cd sm2; git rev-parse --short --verify HEAD)
+
+mv sm2 sm2-bak
+
+test_expect_success 'diff --submodule=diff recurses into deleted nested submodules' '
+ cat >expected <<-EOF &&
+ Submodule sm1 $head7...0000000 (submodule deleted)
+ Submodule sm2 $head12...0000000 (submodule deleted)
+ diff --git a/sm2/.gitmodules b/sm2/.gitmodules
+ deleted file mode 100644
+ index 3a816b8..0000000
+ --- a/sm2/.gitmodules
+ +++ /dev/null
+ @@ -1,3 +0,0 @@
+ -[submodule "nested"]
+ - path = nested
+ - url = ../sm2
+ diff --git a/sm2/foo8 b/sm2/foo8
+ deleted file mode 100644
+ index db9916b..0000000
+ --- a/sm2/foo8
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -foo8
+ diff --git a/sm2/foo9 b/sm2/foo9
+ deleted file mode 100644
+ index 9c3b4f6..0000000
+ --- a/sm2/foo9
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -foo9
+ Submodule nested $head11...0000000 (submodule deleted)
+ diff --git a/sm2/nested/file b/sm2/nested/file
+ deleted file mode 100644
+ index ca281f5..0000000
+ --- a/sm2/nested/file
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -nested content
+ diff --git a/sm2/nested/foo8 b/sm2/nested/foo8
+ deleted file mode 100644
+ index db9916b..0000000
+ --- a/sm2/nested/foo8
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -foo8
+ diff --git a/sm2/nested/foo9 b/sm2/nested/foo9
+ deleted file mode 100644
+ index 9c3b4f6..0000000
+ --- a/sm2/nested/foo9
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -foo9
+ EOF
+ git diff --submodule=diff >actual 2>err &&
+ test_must_be_empty err &&
+ diff_cmp expected actual
+'
+
+mv sm2-bak sm2
+
test_done
diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh
index fad6d3f542..d370ecfe0d 100755
--- a/t/t4103-apply-binary.sh
+++ b/t/t4103-apply-binary.sh
@@ -158,4 +158,27 @@ test_expect_success 'apply binary -p0 diff' '
test -z "$(git diff --name-status binary -- file3)"
'
+test_expect_success 'reject truncated binary diff' '
+ do_reset &&
+
+ # this length is calculated to get us very close to
+ # the 8192-byte strbuf we will use to read in the patch.
+ test-tool genrandom foo 6205 >file1 &&
+ git diff --binary >patch &&
+
+ # truncate the patch at the second "literal" line,
+ # but exclude the trailing newline. We must use perl
+ # for this, since tools like "sed" cannot reliably
+ # produce output without the trailing newline.
+ perl -pe "
+ if (/^literal/ && \$count++ >= 1) {
+ chomp;
+ print;
+ exit 0;
+ }
+ " <patch >patch.trunc &&
+
+ do_reset &&
+ test_must_fail git apply patch.trunc
+'
test_done
diff --git a/t/t4108-apply-threeway.sh b/t/t4108-apply-threeway.sh
index 65147efdea..cc3aa3314a 100755
--- a/t/t4108-apply-threeway.sh
+++ b/t/t4108-apply-threeway.sh
@@ -230,4 +230,49 @@ test_expect_success 'apply with --3way --cached and conflicts' '
test_cmp expect.diff actual.diff
'
+test_expect_success 'apply binary file patch' '
+ git reset --hard main &&
+ cp "$TEST_DIRECTORY/test-binary-1.png" bin.png &&
+ git add bin.png &&
+ git commit -m "add binary file" &&
+
+ cp "$TEST_DIRECTORY/test-binary-2.png" bin.png &&
+
+ git diff --binary >bin.diff &&
+ git reset --hard &&
+
+ # Apply must succeed.
+ git apply bin.diff
+'
+
+test_expect_success 'apply binary file patch with 3way' '
+ git reset --hard main &&
+ cp "$TEST_DIRECTORY/test-binary-1.png" bin.png &&
+ git add bin.png &&
+ git commit -m "add binary file" &&
+
+ cp "$TEST_DIRECTORY/test-binary-2.png" bin.png &&
+
+ git diff --binary >bin.diff &&
+ git reset --hard &&
+
+ # Apply must succeed.
+ git apply --3way --index bin.diff
+'
+
+test_expect_success 'apply full-index patch with 3way' '
+ git reset --hard main &&
+ cp "$TEST_DIRECTORY/test-binary-1.png" bin.png &&
+ git add bin.png &&
+ git commit -m "add binary file" &&
+
+ cp "$TEST_DIRECTORY/test-binary-2.png" bin.png &&
+
+ git diff --full-index >bin.diff &&
+ git reset --hard &&
+
+ # Apply must succeed.
+ git apply --3way --index bin.diff
+'
+
test_done
diff --git a/t/t4151-am-abort.sh b/t/t4151-am-abort.sh
index 9d8d3c72e7..2374151662 100755
--- a/t/t4151-am-abort.sh
+++ b/t/t4151-am-abort.sh
@@ -23,7 +23,13 @@ test_expect_success setup '
test_tick &&
git commit -a -m $i || return 1
done &&
+ git branch changes &&
git format-patch --no-numbered initial &&
+ git checkout -b conflicting initial &&
+ echo different >>file-1 &&
+ echo whatever >new-file &&
+ git add file-1 new-file &&
+ git commit -m different &&
git checkout -b side initial &&
echo local change >file-2-expect
'
@@ -191,4 +197,37 @@ test_expect_success 'am --abort leaves index stat info alone' '
git diff-files --exit-code --quiet
'
+test_expect_success 'git am --abort return failed exit status when it fails' '
+ test_when_finished "rm -rf file-2/ && git reset --hard && git am --abort" &&
+ git checkout changes &&
+ git format-patch -1 --stdout conflicting >changes.mbox &&
+ test_must_fail git am --3way changes.mbox &&
+
+ git rm file-2 &&
+ mkdir file-2 &&
+ echo precious >file-2/somefile &&
+ test_must_fail git am --abort &&
+ test_path_is_dir file-2/
+'
+
+test_expect_success 'git am --abort cleans relevant files' '
+ git checkout changes &&
+ git format-patch -1 --stdout conflicting >changes.mbox &&
+ test_must_fail git am --3way changes.mbox &&
+
+ test_path_is_file new-file &&
+ echo further changes >>file-1 &&
+ echo change other file >>file-2 &&
+
+ # Abort, and expect the files touched by am to be reverted
+ git am --abort &&
+
+ test_path_is_missing new-file &&
+
+ # Files not involved in am operation are left modified
+ git diff --name-only changes >actual &&
+ test_write_lines file-2 >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index 350cfa3593..9dfead936b 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -1834,14 +1834,24 @@ test_expect_success 'log --graph --no-walk is forbidden' '
test_must_fail git log --graph --no-walk
'
-test_expect_success 'log diagnoses bogus HEAD' '
+test_expect_success 'log on empty repo fails' '
git init empty &&
+ test_when_finished "rm -rf empty" &&
test_must_fail git -C empty log 2>stderr &&
- test_i18ngrep does.not.have.any.commits stderr &&
+ test_i18ngrep does.not.have.any.commits stderr
+'
+
+test_expect_success REFFILES 'log diagnoses bogus HEAD hash' '
+ git init empty &&
+ test_when_finished "rm -rf empty" &&
echo 1234abcd >empty/.git/refs/heads/main &&
test_must_fail git -C empty log 2>stderr &&
- test_i18ngrep broken stderr &&
- echo "ref: refs/heads/invalid.lock" >empty/.git/HEAD &&
+ test_i18ngrep broken stderr
+'
+
+test_expect_success 'log diagnoses bogus HEAD symref' '
+ git init empty &&
+ git --git-dir empty/.git symbolic-ref HEAD refs/heads/invalid.lock &&
test_must_fail git -C empty log 2>stderr &&
test_i18ngrep broken stderr &&
test_must_fail git -C empty log --default totally-bogus 2>stderr &&
@@ -1905,6 +1915,20 @@ test_expect_success '--exclude-promisor-objects does not BUG-crash' '
test_must_fail git log --exclude-promisor-objects source-a
'
+test_expect_success 'log --decorate includes all levels of tag annotated tags' '
+ git checkout -b branch &&
+ git commit --allow-empty -m "new commit" &&
+ git tag lightweight HEAD &&
+ git tag -m annotated annotated HEAD &&
+ git tag -m double-0 double-0 HEAD &&
+ git tag -m double-1 double-1 double-0 &&
+ cat >expect <<-\EOF &&
+ HEAD -> branch, tag: lightweight, tag: double-1, tag: double-0, tag: annotated
+ EOF
+ git log -1 --format="%D" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'log --end-of-options' '
git update-ref refs/heads/--source HEAD &&
git log --end-of-options --source >actual &&
diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh
index d8e7374234..0b2d21ec55 100755
--- a/t/t4203-mailmap.sh
+++ b/t/t4203-mailmap.sh
@@ -959,7 +959,7 @@ test_expect_success SYMLINKS 'symlinks not respected in-tree' '
test_when_finished "rm .mailmap" &&
ln -s map .mailmap &&
git log -1 --format=%aE >actual &&
- echo "orig@example.com" >expect&&
+ echo "orig@example.com" >expect &&
test_cmp expect actual
'
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index cabdf7d57a..5865daa8f8 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -525,20 +525,25 @@ test_expect_success 'strbuf_utf8_replace() not producing NUL' '
! grep Q actual
'
-# ISO strict date format
-test_expect_success 'ISO and ISO-strict date formats display the same values' '
- git log --format=%ai%n%ci |
- sed -e "s/ /T/; s/ //; s/..\$/:&/" >expected &&
+# --date=[XXX] and corresponding %a[X] %c[X] format equivalency
+test_expect_success '--date=iso-strict %ad%cd is the same as %aI%cI' '
+ git log --format=%ad%n%cd --date=iso-strict >expected &&
git log --format=%aI%n%cI >actual &&
test_cmp expected actual
'
-test_expect_success 'short date' '
+test_expect_success '--date=short %ad%cd is the same as %as%cs' '
git log --format=%ad%n%cd --date=short >expected &&
git log --format=%as%n%cs >actual &&
test_cmp expected actual
'
+test_expect_success '--date=human %ad%cd is the same as %ah%ch' '
+ git log --format=%ad%n%cd --date=human >expected &&
+ git log --format=%ah%n%ch >actual &&
+ test_cmp expected actual
+'
+
# get new digests (with no abbreviations)
test_expect_success 'set up log decoration tests' '
head1=$(git rev-parse --verify HEAD~0) &&
@@ -983,7 +988,7 @@ test_expect_success '%(describe) vs git describe' '
test_expect_success '%(describe:match=...) vs git describe --match ...' '
test_when_finished "git tag -d tag-match" &&
- git tag -a -m tagged tag-match&&
+ git tag -a -m tagged tag-match &&
git describe --match "*-match" >expect &&
git log -1 --format="%(describe:match=*-match)" >actual &&
test_cmp expect actual
diff --git a/t/t4209-log-pickaxe.sh b/t/t4209-log-pickaxe.sh
index 5d06f5f45e..75795d0b49 100755
--- a/t/t4209-log-pickaxe.sh
+++ b/t/t4209-log-pickaxe.sh
@@ -55,6 +55,43 @@ test_expect_success setup '
git rev-parse --verify HEAD >expect_second
'
+test_expect_success 'usage' '
+ test_expect_code 129 git log -S 2>err &&
+ test_i18ngrep "switch.*requires a value" err &&
+
+ test_expect_code 129 git log -G 2>err &&
+ test_i18ngrep "switch.*requires a value" err &&
+
+ test_expect_code 128 git log -Gregex -Sstring 2>err &&
+ grep "mutually exclusive" err &&
+
+ test_expect_code 128 git log -Gregex --find-object=HEAD 2>err &&
+ grep "mutually exclusive" err &&
+
+ test_expect_code 128 git log -Sstring --find-object=HEAD 2>err &&
+ grep "mutually exclusive" err &&
+
+ test_expect_code 128 git log --pickaxe-all --find-object=HEAD 2>err &&
+ grep "mutually exclusive" err
+'
+
+test_expect_success 'usage: --pickaxe-regex' '
+ test_expect_code 128 git log -Gregex --pickaxe-regex 2>err &&
+ grep "mutually exclusive" err
+'
+
+test_expect_success 'usage: --no-pickaxe-regex' '
+ cat >expect <<-\EOF &&
+ fatal: unrecognized argument: --no-pickaxe-regex
+ EOF
+
+ test_expect_code 128 git log -Sstring --no-pickaxe-regex 2>actual &&
+ test_cmp expect actual &&
+
+ test_expect_code 128 git log -Gstring --no-pickaxe-regex 2>err &&
+ test_cmp expect actual
+'
+
test_log expect_initial --grep initial
test_log expect_nomatch --grep InItial
test_log_icase expect_initial --grep InItial
@@ -106,38 +143,83 @@ test_expect_success 'log -S --no-textconv (missing textconv tool)' '
rm .gitattributes
'
+test_expect_success 'setup log -[GS] plain & regex' '
+ test_create_repo GS-plain &&
+ test_commit -C GS-plain --append A data.txt "a" &&
+ test_commit -C GS-plain --append B data.txt "a a" &&
+ test_commit -C GS-plain --append C data.txt "b" &&
+ test_commit -C GS-plain --append D data.txt "[b]" &&
+ test_commit -C GS-plain E data.txt "" &&
+
+ # We also include E, the deletion commit
+ git -C GS-plain log --grep="[ABE]" >A-to-B-then-E-log &&
+ git -C GS-plain log --grep="[CDE]" >C-to-D-then-E-log &&
+ git -C GS-plain log --grep="[DE]" >D-then-E-log &&
+ git -C GS-plain log >full-log
+'
+
+test_expect_success 'log -G trims diff new/old [-+]' '
+ git -C GS-plain log -G"[+-]a" >log &&
+ test_must_be_empty log &&
+ git -C GS-plain log -G"^a" >log &&
+ test_cmp log A-to-B-then-E-log
+'
+
+test_expect_success 'log -S<pat> is not a regex, but -S<pat> --pickaxe-regex is' '
+ git -C GS-plain log -S"a" >log &&
+ test_cmp log A-to-B-then-E-log &&
+
+ git -C GS-plain log -S"[a]" >log &&
+ test_must_be_empty log &&
+
+ git -C GS-plain log -S"[a]" --pickaxe-regex >log &&
+ test_cmp log A-to-B-then-E-log &&
+
+ git -C GS-plain log -S"[b]" >log &&
+ test_cmp log D-then-E-log &&
+
+ git -C GS-plain log -S"[b]" --pickaxe-regex >log &&
+ test_cmp log C-to-D-then-E-log
+'
+
test_expect_success 'setup log -[GS] binary & --text' '
- git checkout --orphan GS-binary-and-text &&
- git read-tree --empty &&
- printf "a\na\0a\n" >data.bin &&
- git add data.bin &&
- git commit -m "create binary file" data.bin &&
- printf "a\na\0a\n" >>data.bin &&
- git commit -m "modify binary file" data.bin &&
- git rm data.bin &&
- git commit -m "delete binary file" data.bin &&
- git log >full-log
+ test_create_repo GS-bin-txt &&
+ test_commit -C GS-bin-txt --printf A data.bin "a\na\0a\n" &&
+ test_commit -C GS-bin-txt --append --printf B data.bin "a\na\0a\n" &&
+ test_commit -C GS-bin-txt C data.bin "" &&
+ git -C GS-bin-txt log >full-log
'
test_expect_success 'log -G ignores binary files' '
- git log -Ga >log &&
+ git -C GS-bin-txt log -Ga >log &&
test_must_be_empty log
'
test_expect_success 'log -G looks into binary files with -a' '
- git log -a -Ga >log &&
+ git -C GS-bin-txt log -a -Ga >log &&
test_cmp log full-log
'
test_expect_success 'log -G looks into binary files with textconv filter' '
- test_when_finished "rm .gitattributes" &&
- echo "* diff=bin" >.gitattributes &&
- git -c diff.bin.textconv=cat log -Ga >log &&
+ test_when_finished "rm GS-bin-txt/.gitattributes" &&
+ (
+ cd GS-bin-txt &&
+ echo "* diff=bin" >.gitattributes &&
+ git -c diff.bin.textconv=cat log -Ga >../log
+ ) &&
test_cmp log full-log
'
test_expect_success 'log -S looks into binary files' '
- git log -Sa >log &&
+ git -C GS-bin-txt log -Sa >log &&
+ test_cmp log full-log
+'
+
+test_expect_success 'log -S --pickaxe-regex looks into binary files' '
+ git -C GS-bin-txt log --pickaxe-regex -Sa >log &&
+ test_cmp log full-log &&
+
+ git -C GS-bin-txt log --pickaxe-regex -S"[a]" >log &&
test_cmp log full-log
'
diff --git a/t/t4210-log-i18n.sh b/t/t4210-log-i18n.sh
index d2dfcf164e..0141f36e33 100755
--- a/t/t4210-log-i18n.sh
+++ b/t/t4210-log-i18n.sh
@@ -131,4 +131,11 @@ do
fi
done
+test_expect_success 'log shows warning when conversion fails' '
+ enc=this-encoding-does-not-exist &&
+ git log -1 --encoding=$enc 2>err &&
+ echo "warning: unable to reencode commit to ${SQ}${enc}${SQ}" >expect &&
+ test_cmp expect err
+'
+
test_done
diff --git a/t/t4258-am-quoted-cr.sh b/t/t4258-am-quoted-cr.sh
new file mode 100755
index 0000000000..201915b45a
--- /dev/null
+++ b/t/t4258-am-quoted-cr.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+test_description='test am --quoted-cr=<action>'
+
+. ./test-lib.sh
+
+DATA="$TEST_DIRECTORY/t4258"
+
+test_expect_success 'setup' '
+ test_write_lines one two three >text &&
+ test_commit one text &&
+ test_write_lines one owt three >text &&
+ test_commit two text
+'
+
+test_expect_success 'am warn if quoted-cr is found' '
+ git reset --hard one &&
+ test_must_fail git am "$DATA/mbox" 2>err &&
+ grep "quoted CRLF detected" err
+'
+
+test_expect_success 'am --quoted-cr=strip' '
+ test_might_fail git am --abort &&
+ git reset --hard one &&
+ git am --quoted-cr=strip "$DATA/mbox" &&
+ git diff --exit-code HEAD two
+'
+
+test_expect_success 'am with config mailinfo.quotedCr=strip' '
+ test_might_fail git am --abort &&
+ git reset --hard one &&
+ test_config mailinfo.quotedCr strip &&
+ git am "$DATA/mbox" &&
+ git diff --exit-code HEAD two
+'
+
+test_done
diff --git a/t/t4258/mbox b/t/t4258/mbox
new file mode 100644
index 0000000000..c62819f3d2
--- /dev/null
+++ b/t/t4258/mbox
@@ -0,0 +1,12 @@
+From: A U Thor <mail@example.com>
+To: list@example.org
+Subject: [PATCH v2] sample
+Date: Mon, 3 Aug 2020 22:40:55 +0700
+Message-Id: <msg-id@example.com>
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: base64
+
+VGhpcyBpcyBjb21taXQgbWVzc2FnZS4NCi0tLQ0KIHRleHQgfCAyICstDQogMSBmaWxlIGNoYW5n
+ZWQsIDEgaW5zZXJ0aW9uKCspLCAxIGRlbGV0aW9uKC0pDQoNCmRpZmYgLS1naXQgYS90ZXh0IGIv
+dGV4dA0KaW5kZXggNTYyNmFiZi4uZjcxOWVmZCAxMDA2NDQNCi0tLSBhL3RleHQNCisrKyBiL3Rl
+eHQNCkBAIC0xICsxIEBADQotb25lDQordHdvDQotLSANCjIuMzEuMQoK
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index 7204799a0b..2c88d1c159 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -111,25 +111,34 @@ test_expect_success 'setup' '
EOF
'
-test_expect_success \
- 'populate workdir' \
- 'mkdir a &&
- echo simple textfile >a/a &&
- ten=0123456789 && hundred=$ten$ten$ten$ten$ten$ten$ten$ten$ten$ten &&
- echo long filename >a/four$hundred &&
- mkdir a/bin &&
- test-tool genrandom "frotz" 500000 >a/bin/sh &&
- printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile1 &&
- printf "A not substituted O" >a/substfile2 &&
- if test_have_prereq SYMLINKS; then
- ln -s a a/l1
- else
- printf %s a > a/l1
- fi &&
- (p=long_path_to_a_file && cd a &&
- for depth in 1 2 3 4 5; do mkdir $p && cd $p; done &&
- echo text >file_with_long_path) &&
- (cd a && find .) | sort >a.lst'
+test_expect_success 'populate workdir' '
+ mkdir a &&
+ echo simple textfile >a/a &&
+ ten=0123456789 &&
+ hundred="$ten$ten$ten$ten$ten$ten$ten$ten$ten$ten" &&
+ echo long filename >"a/four$hundred" &&
+ mkdir a/bin &&
+ test-tool genrandom "frotz" 500000 >a/bin/sh &&
+ printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile1 &&
+ printf "A not substituted O" >a/substfile2 &&
+ if test_have_prereq SYMLINKS
+ then
+ ln -s a a/l1
+ else
+ printf %s a >a/l1
+ fi &&
+ (
+ p=long_path_to_a_file &&
+ cd a &&
+ for depth in 1 2 3 4 5
+ do
+ mkdir $p &&
+ cd $p
+ done &&
+ echo text >file_with_long_path
+ ) &&
+ (cd a && find .) | sort >a.lst
+'
test_expect_success \
'add ignored file' \
@@ -147,18 +156,18 @@ test_expect_success 'setup export-subst' '
>a/substfile1
'
-test_expect_success \
- 'create bare clone' \
- 'git clone --bare . bare.git &&
- cp .git/info/attributes bare.git/info/attributes'
+test_expect_success 'create bare clone' '
+ git clone --bare . bare.git &&
+ cp .git/info/attributes bare.git/info/attributes
+'
-test_expect_success \
- 'remove ignored file' \
- 'rm a/ignored'
+test_expect_success 'remove ignored file' '
+ rm a/ignored
+'
-test_expect_success \
- 'git archive' \
- 'git archive HEAD >b.tar'
+test_expect_success 'git archive' '
+ git archive HEAD >b.tar
+'
check_tar b
@@ -194,26 +203,28 @@ check_added with_untracked2 untracked one/untracked
check_added with_untracked2 untracked two/untracked
test_expect_success 'git archive on large files' '
- test_config core.bigfilethreshold 1 &&
- git archive HEAD >b3.tar &&
- test_cmp_bin b.tar b3.tar
+ test_config core.bigfilethreshold 1 &&
+ git archive HEAD >b3.tar &&
+ test_cmp_bin b.tar b3.tar
'
-test_expect_success \
- 'git archive in a bare repo' \
- '(cd bare.git && git archive HEAD) >b3.tar'
+test_expect_success 'git archive in a bare repo' '
+ git --git-dir bare.git archive HEAD >b3.tar
+'
-test_expect_success \
- 'git archive vs. the same in a bare repo' \
- 'test_cmp_bin b.tar b3.tar'
+test_expect_success 'git archive vs. the same in a bare repo' '
+ test_cmp_bin b.tar b3.tar
+'
-test_expect_success 'git archive with --output' \
- 'git archive --output=b4.tar HEAD &&
- test_cmp_bin b.tar b4.tar'
+test_expect_success 'git archive with --output' '
+ git archive --output=b4.tar HEAD &&
+ test_cmp_bin b.tar b4.tar
+'
-test_expect_success 'git archive --remote' \
- 'git archive --remote=. HEAD >b5.tar &&
- test_cmp_bin b.tar b5.tar'
+test_expect_success 'git archive --remote' '
+ git archive --remote=. HEAD >b5.tar &&
+ test_cmp_bin b.tar b5.tar
+'
test_expect_success 'git archive --remote with configured remote' '
git config remote.foo.url . &&
@@ -224,18 +235,19 @@ test_expect_success 'git archive --remote with configured remote' '
test_cmp_bin b.tar b5-nick.tar
'
-test_expect_success \
- 'validate file modification time' \
- 'mkdir extract &&
- "$TAR" xf b.tar -C extract a/a &&
- test-tool chmtime --get extract/a/a >b.mtime &&
- echo "1117231200" >expected.mtime &&
- test_cmp expected.mtime b.mtime'
+test_expect_success 'validate file modification time' '
+ mkdir extract &&
+ "$TAR" xf b.tar -C extract a/a &&
+ test-tool chmtime --get extract/a/a >b.mtime &&
+ echo "1117231200" >expected.mtime &&
+ test_cmp expected.mtime b.mtime
+'
-test_expect_success \
- 'git get-tar-commit-id' \
- 'git get-tar-commit-id <b.tar >b.commitid &&
- test_cmp .git/$(git symbolic-ref HEAD) b.commitid'
+test_expect_success 'git get-tar-commit-id' '
+ git get-tar-commit-id <b.tar >actual &&
+ git rev-parse HEAD >expect &&
+ test_cmp expect actual
+'
test_expect_success 'git archive with --output, override inferred format' '
git archive --format=tar --output=d4.zip HEAD &&
diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh
index 147e616533..141b29f031 100755
--- a/t/t5100-mailinfo.sh
+++ b/t/t5100-mailinfo.sh
@@ -228,4 +228,44 @@ test_expect_success 'mailinfo handles unusual header whitespace' '
test_cmp expect actual
'
+check_quoted_cr_mail () {
+ mail="$1" && shift &&
+ git mailinfo -u "$@" "$mail.msg" "$mail.patch" \
+ <"$mail" >"$mail.info" 2>"$mail.err" &&
+ test_cmp "$mail-expected.msg" "$mail.msg" &&
+ test_cmp "$mail-expected.patch" "$mail.patch" &&
+ test_cmp "$DATA/quoted-cr-info" "$mail.info"
+}
+
+test_expect_success 'split base64 email with quoted-cr' '
+ mkdir quoted-cr &&
+ git mailsplit -oquoted-cr "$DATA/quoted-cr.mbox" >quoted-cr/last &&
+ test $(cat quoted-cr/last) = 2
+'
+
+test_expect_success 'mailinfo warn CR in base64 encoded email' '
+ sed -e "s/%%$//" -e "s/%%/$(printf \\015)/g" "$DATA/quoted-cr-msg" \
+ >quoted-cr/0001-expected.msg &&
+ sed "s/%%/$(printf \\015)/g" "$DATA/quoted-cr-msg" \
+ >quoted-cr/0002-expected.msg &&
+ sed -e "s/%%$//" -e "s/%%/$(printf \\015)/g" "$DATA/quoted-cr-patch" \
+ >quoted-cr/0001-expected.patch &&
+ sed "s/%%/$(printf \\015)/g" "$DATA/quoted-cr-patch" \
+ >quoted-cr/0002-expected.patch &&
+ check_quoted_cr_mail quoted-cr/0001 &&
+ test_must_be_empty quoted-cr/0001.err &&
+ check_quoted_cr_mail quoted-cr/0002 &&
+ grep "quoted CRLF detected" quoted-cr/0002.err &&
+ check_quoted_cr_mail quoted-cr/0001 --quoted-cr=nowarn &&
+ test_must_be_empty quoted-cr/0001.err &&
+ check_quoted_cr_mail quoted-cr/0002 --quoted-cr=nowarn &&
+ test_must_be_empty quoted-cr/0002.err &&
+ cp quoted-cr/0001-expected.msg quoted-cr/0002-expected.msg &&
+ cp quoted-cr/0001-expected.patch quoted-cr/0002-expected.patch &&
+ check_quoted_cr_mail quoted-cr/0001 --quoted-cr=strip &&
+ test_must_be_empty quoted-cr/0001.err &&
+ check_quoted_cr_mail quoted-cr/0002 --quoted-cr=strip &&
+ test_must_be_empty quoted-cr/0002.err
+'
+
test_done
diff --git a/t/t5100/quoted-cr-info b/t/t5100/quoted-cr-info
new file mode 100644
index 0000000000..dab2228b70
--- /dev/null
+++ b/t/t5100/quoted-cr-info
@@ -0,0 +1,5 @@
+Author: A U Thor
+Email: mail@example.com
+Subject: sample
+Date: Mon, 3 Aug 2020 22:40:55 +0700
+
diff --git a/t/t5100/quoted-cr-msg b/t/t5100/quoted-cr-msg
new file mode 100644
index 0000000000..89b05a0784
--- /dev/null
+++ b/t/t5100/quoted-cr-msg
@@ -0,0 +1,2 @@
+On different distro, %%pytest is suffixed with different patterns.%%
+%%
diff --git a/t/t5100/quoted-cr-patch b/t/t5100/quoted-cr-patch
new file mode 100644
index 0000000000..65b13eeef7
--- /dev/null
+++ b/t/t5100/quoted-cr-patch
@@ -0,0 +1,22 @@
+---%%
+ configure | 2 +-%%
+ 1 file changed, 1 insertion(+), 1 deletion(-)%%
+%%
+diff --git a/configure b/configure%%
+index db3538b3..f7c1c095 100755%%
+--- a/configure%%
++++ b/configure%%
+@@ -814,7 +814,7 @@ if [ $have_python3 -eq 1 ]; then%%
+ printf "%%Checking for python3 pytest (>= 3.0)... "%%
+ conf=$(mktemp)%%
+ printf "[pytest]\nminversion=3.0\n" > $conf%%
+- if pytest-3 -c $conf --version >/dev/null 2>&1; then%%
++ if "$python" -m pytest -c $conf --version >/dev/null 2>&1; then%%
+ printf "Yes.\n"%%
+ have_python3_pytest=1%%
+ else%%
+-- %%
+2.28.0%%
+_______________________________________________
+example mailing list -- list@example.org
+To unsubscribe send an email to list-leave@example.org
diff --git a/t/t5100/quoted-cr.mbox b/t/t5100/quoted-cr.mbox
new file mode 100644
index 0000000000..909021bb7a
--- /dev/null
+++ b/t/t5100/quoted-cr.mbox
@@ -0,0 +1,47 @@
+From nobody Mon Sep 17 00:00:00 2001
+From: A U Thor <mail@example.com>
+To: list@example.org
+Subject: [PATCH v2] sample
+Date: Mon, 3 Aug 2020 22:40:55 +0700
+Message-Id: <msg-id@example.com>
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: base64
+
+T24gZGlmZmVyZW50IGRpc3RybywgDXB5dGVzdCBpcyBzdWZmaXhlZCB3aXRoIGRpZmZlcmVudCBw
+YXR0ZXJucy4KCi0tLQogY29uZmlndXJlIHwgMiArLQogMSBmaWxlIGNoYW5nZWQsIDEgaW5zZXJ0
+aW9uKCspLCAxIGRlbGV0aW9uKC0pCgpkaWZmIC0tZ2l0IGEvY29uZmlndXJlIGIvY29uZmlndXJl
+CmluZGV4IGRiMzUzOGIzLi5mN2MxYzA5NSAxMDA3NTUKLS0tIGEvY29uZmlndXJlCisrKyBiL2Nv
+bmZpZ3VyZQpAQCAtODE0LDcgKzgxNCw3IEBAIGlmIFsgJGhhdmVfcHl0aG9uMyAtZXEgMSBdOyB0
+aGVuCiAgICAgcHJpbnRmICINQ2hlY2tpbmcgZm9yIHB5dGhvbjMgcHl0ZXN0ICg+PSAzLjApLi4u
+ICIKICAgICBjb25mPSQobWt0ZW1wKQogICAgIHByaW50ZiAiW3B5dGVzdF1cbm1pbnZlcnNpb249
+My4wXG4iID4gJGNvbmYKLSAgICBpZiBweXRlc3QtMyAtYyAkY29uZiAtLXZlcnNpb24gPi9kZXYv
+bnVsbCAyPiYxOyB0aGVuCisgICAgaWYgIiRweXRob24iIC1tIHB5dGVzdCAtYyAkY29uZiAtLXZl
+cnNpb24gPi9kZXYvbnVsbCAyPiYxOyB0aGVuCiAgICAgICAgIHByaW50ZiAiWWVzLlxuIgogICAg
+ICAgICBoYXZlX3B5dGhvbjNfcHl0ZXN0PTEKICAgICBlbHNlCi0tIAoyLjI4LjAKX19fX19fX19f
+X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KZXhhbXBsZSBtYWlsaW5nIGxp
+c3QgLS0gbGlzdEBleGFtcGxlLm9yZwpUbyB1bnN1YnNjcmliZSBzZW5kIGFuIGVtYWlsIHRvIGxp
+c3QtbGVhdmVAZXhhbXBsZS5vcmcK
+
+From nobody Mon Sep 17 00:00:00 2001
+From: A U Thor <mail@example.com>
+To: list@example.org
+Subject: [PATCH v2] sample
+Date: Mon, 3 Aug 2020 22:40:55 +0700
+Message-Id: <msg-id2@example.com>
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: base64
+
+T24gZGlmZmVyZW50IGRpc3RybywgDXB5dGVzdCBpcyBzdWZmaXhlZCB3aXRoIGRpZmZlcmVudCBw
+YXR0ZXJucy4NCg0KLS0tDQogY29uZmlndXJlIHwgMiArLQ0KIDEgZmlsZSBjaGFuZ2VkLCAxIGlu
+c2VydGlvbigrKSwgMSBkZWxldGlvbigtKQ0KDQpkaWZmIC0tZ2l0IGEvY29uZmlndXJlIGIvY29u
+ZmlndXJlDQppbmRleCBkYjM1MzhiMy4uZjdjMWMwOTUgMTAwNzU1DQotLS0gYS9jb25maWd1cmUN
+CisrKyBiL2NvbmZpZ3VyZQ0KQEAgLTgxNCw3ICs4MTQsNyBAQCBpZiBbICRoYXZlX3B5dGhvbjMg
+LWVxIDEgXTsgdGhlbg0KICAgICBwcmludGYgIg1DaGVja2luZyBmb3IgcHl0aG9uMyBweXRlc3Qg
+KD49IDMuMCkuLi4gIg0KICAgICBjb25mPSQobWt0ZW1wKQ0KICAgICBwcmludGYgIltweXRlc3Rd
+XG5taW52ZXJzaW9uPTMuMFxuIiA+ICRjb25mDQotICAgIGlmIHB5dGVzdC0zIC1jICRjb25mIC0t
+dmVyc2lvbiA+L2Rldi9udWxsIDI+JjE7IHRoZW4NCisgICAgaWYgIiRweXRob24iIC1tIHB5dGVz
+dCAtYyAkY29uZiAtLXZlcnNpb24gPi9kZXYvbnVsbCAyPiYxOyB0aGVuDQogICAgICAgICBwcmlu
+dGYgIlllcy5cbiINCiAgICAgICAgIGhhdmVfcHl0aG9uM19weXRlc3Q9MQ0KICAgICBlbHNlDQot
+LSANCjIuMjguMA0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f
+X18KZXhhbXBsZSBtYWlsaW5nIGxpc3QgLS0gbGlzdEBleGFtcGxlLm9yZwpUbyB1bnN1YnNjcmli
+ZSBzZW5kIGFuIGVtYWlsIHRvIGxpc3QtbGVhdmVAZXhhbXBsZS5vcmcK
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 2fc5e68250..e13a884207 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -8,125 +8,195 @@ test_description='git pack-object
'
. ./test-lib.sh
-TRASH=$(pwd)
+test_expect_success 'setup' '
+ rm -f .git/index* &&
+ perl -e "print \"a\" x 4096;" >a &&
+ perl -e "print \"b\" x 4096;" >b &&
+ perl -e "print \"c\" x 4096;" >c &&
+ test-tool genrandom "seed a" 2097152 >a_big &&
+ test-tool genrandom "seed b" 2097152 >b_big &&
+ git update-index --add a a_big b b_big c &&
+ cat c >d && echo foo >>d && git update-index --add d &&
+ tree=$(git write-tree) &&
+ commit=$(git commit-tree $tree </dev/null) &&
+ {
+ echo $tree &&
+ echo $commit &&
+ git ls-tree $tree | sed -e "s/.* \\([0-9a-f]*\\) .*/\\1/"
+ } >obj-list &&
+ {
+ git diff-tree --root -p $commit &&
+ while read object
+ do
+ t=$(git cat-file -t $object) &&
+ git cat-file $t $object || return 1
+ done <obj-list
+ } >expect
+'
-test_expect_success \
- 'setup' \
- 'rm -f .git/index* &&
- perl -e "print \"a\" x 4096;" > a &&
- perl -e "print \"b\" x 4096;" > b &&
- perl -e "print \"c\" x 4096;" > c &&
- test-tool genrandom "seed a" 2097152 > a_big &&
- test-tool genrandom "seed b" 2097152 > b_big &&
- git update-index --add a a_big b b_big c &&
- cat c >d && echo foo >>d && git update-index --add d &&
- tree=$(git write-tree) &&
- commit=$(git commit-tree $tree </dev/null) && {
- echo $tree &&
- echo $commit &&
- git ls-tree $tree | sed -e "s/.* \\([0-9a-f]*\\) .*/\\1/"
- } >obj-list && {
- git diff-tree --root -p $commit &&
- while read object
- do
- t=$(git cat-file -t $object) &&
- git cat-file $t $object || return 1
- done <obj-list
- } >expect'
+test_expect_success 'setup pack-object <stdin' '
+ git init pack-object-stdin &&
+ test_commit -C pack-object-stdin one &&
+ test_commit -C pack-object-stdin two
-test_expect_success \
- 'pack without delta' \
- 'packname_1=$(git pack-objects --window=0 test-1 <obj-list)'
+'
-test_expect_success \
- 'pack-objects with bogus arguments' \
- 'test_must_fail git pack-objects --window=0 test-1 blah blah <obj-list'
+test_expect_success 'pack-object <stdin parsing: basic [|--revs]' '
+ cat >in <<-EOF &&
+ $(git -C pack-object-stdin rev-parse one)
+ EOF
-rm -fr .git2
-mkdir .git2
+ git -C pack-object-stdin pack-objects basic-stdin <in &&
+ idx=$(echo pack-object-stdin/basic-stdin-*.idx) &&
+ git show-index <"$idx" >actual &&
+ test_line_count = 1 actual &&
-test_expect_success \
- 'unpack without delta' \
- "GIT_OBJECT_DIRECTORY=.git2/objects &&
- export GIT_OBJECT_DIRECTORY &&
- git init &&
- git unpack-objects -n <test-1-${packname_1}.pack &&
- git unpack-objects <test-1-${packname_1}.pack"
+ git -C pack-object-stdin pack-objects --revs basic-stdin-revs <in &&
+ idx=$(echo pack-object-stdin/basic-stdin-revs-*.idx) &&
+ git show-index <"$idx" >actual &&
+ test_line_count = 3 actual
+'
-unset GIT_OBJECT_DIRECTORY
-cd "$TRASH/.git2"
+test_expect_success 'pack-object <stdin parsing: [|--revs] bad line' '
+ cat >in <<-EOF &&
+ $(git -C pack-object-stdin rev-parse one)
+ garbage
+ $(git -C pack-object-stdin rev-parse two)
+ EOF
+
+ sed "s/^> //g" >err.expect <<-EOF &&
+ fatal: expected object ID, got garbage:
+ > garbage
+
+ EOF
+ test_must_fail git -C pack-object-stdin pack-objects bad-line-stdin <in 2>err.actual &&
+ test_cmp err.expect err.actual &&
+
+ cat >err.expect <<-EOF &&
+ fatal: bad revision '"'"'garbage'"'"'
+ EOF
+ test_must_fail git -C pack-object-stdin pack-objects --revs bad-line-stdin-revs <in 2>err.actual &&
+ test_cmp err.expect err.actual
+'
-test_expect_success \
- 'check unpack without delta' \
- '(cd ../.git && find objects -type f -print) |
- while read path
- do
- cmp $path ../.git/$path || {
- echo $path differs.
- return 1
- }
- done'
-cd "$TRASH"
+test_expect_success 'pack-object <stdin parsing: [|--revs] empty line' '
+ cat >in <<-EOF &&
+ $(git -C pack-object-stdin rev-parse one)
-test_expect_success \
- 'pack with REF_DELTA' \
- 'pwd &&
- packname_2=$(git pack-objects test-2 <obj-list)'
+ $(git -C pack-object-stdin rev-parse two)
+ EOF
-rm -fr .git2
-mkdir .git2
+ sed -e "s/^> //g" -e "s/Z$//g" >err.expect <<-EOF &&
+ fatal: expected object ID, got garbage:
+ > Z
-test_expect_success \
- 'unpack with REF_DELTA' \
- 'GIT_OBJECT_DIRECTORY=.git2/objects &&
- export GIT_OBJECT_DIRECTORY &&
- git init &&
- git unpack-objects -n <test-2-${packname_2}.pack &&
- git unpack-objects <test-2-${packname_2}.pack'
-
-unset GIT_OBJECT_DIRECTORY
-cd "$TRASH/.git2"
-test_expect_success \
- 'check unpack with REF_DELTA' \
- '(cd ../.git && find objects -type f -print) |
- while read path
- do
- cmp $path ../.git/$path || {
- echo $path differs.
- return 1
- }
- done'
-cd "$TRASH"
+ EOF
+ test_must_fail git -C pack-object-stdin pack-objects empty-line-stdin <in 2>err.actual &&
+ test_cmp err.expect err.actual &&
-test_expect_success \
- 'pack with OFS_DELTA' \
- 'pwd &&
- packname_3=$(git pack-objects --delta-base-offset test-3 <obj-list)'
+ git -C pack-object-stdin pack-objects --revs empty-line-stdin-revs <in &&
+ idx=$(echo pack-object-stdin/empty-line-stdin-revs-*.idx) &&
+ git show-index <"$idx" >actual &&
+ test_line_count = 3 actual
+'
-rm -fr .git2
-mkdir .git2
+test_expect_success 'pack-object <stdin parsing: [|--revs] with --stdin' '
+ cat >in <<-EOF &&
+ $(git -C pack-object-stdin rev-parse one)
+ $(git -C pack-object-stdin rev-parse two)
+ EOF
+
+ # There is the "--stdin-packs is incompatible with --revs"
+ # test below, but we should make sure that the revision.c
+ # --stdin is not picked up
+ cat >err.expect <<-EOF &&
+ fatal: disallowed abbreviated or ambiguous option '"'"'stdin'"'"'
+ EOF
+ test_must_fail git -C pack-object-stdin pack-objects stdin-with-stdin-option --stdin <in 2>err.actual &&
+ test_cmp err.expect err.actual &&
+
+ test_must_fail git -C pack-object-stdin pack-objects --stdin --revs stdin-with-stdin-option-revs 2>err.actual <in &&
+ test_cmp err.expect err.actual
+'
-test_expect_success \
- 'unpack with OFS_DELTA' \
- 'GIT_OBJECT_DIRECTORY=.git2/objects &&
- export GIT_OBJECT_DIRECTORY &&
- git init &&
- git unpack-objects -n <test-3-${packname_3}.pack &&
- git unpack-objects <test-3-${packname_3}.pack'
-
-unset GIT_OBJECT_DIRECTORY
-cd "$TRASH/.git2"
-test_expect_success \
- 'check unpack with OFS_DELTA' \
- '(cd ../.git && find objects -type f -print) |
- while read path
- do
- cmp $path ../.git/$path || {
- echo $path differs.
- return 1
- }
- done'
-cd "$TRASH"
+test_expect_success 'pack-object <stdin parsing: --stdin-packs handles garbage' '
+ cat >in <<-EOF &&
+ $(git -C pack-object-stdin rev-parse one)
+ $(git -C pack-object-stdin rev-parse two)
+ EOF
+
+ # That we get "two" and not "one" has to do with OID
+ # ordering. It happens to be the same here under SHA-1 and
+ # SHA-256. See commentary in pack-objects.c
+ cat >err.expect <<-EOF &&
+ fatal: could not find pack '"'"'$(git -C pack-object-stdin rev-parse two)'"'"'
+ EOF
+ test_must_fail git \
+ -C pack-object-stdin \
+ pack-objects stdin-with-stdin-option --stdin-packs \
+ <in 2>err.actual &&
+ test_cmp err.expect err.actual
+'
+
+# usage: check_deltas <stderr_from_pack_objects> <cmp_op> <nr_deltas>
+# e.g.: check_deltas stderr -gt 0
+check_deltas() {
+ deltas=$(perl -lne '/delta (\d+)/ and print $1' "$1") &&
+ shift &&
+ if ! test "$deltas" "$@"
+ then
+ echo >&2 "unexpected number of deltas (compared $delta $*)"
+ return 1
+ fi
+}
+
+test_expect_success 'pack without delta' '
+ packname_1=$(git pack-objects --progress --window=0 test-1 \
+ <obj-list 2>stderr) &&
+ check_deltas stderr = 0
+'
+
+test_expect_success 'pack-objects with bogus arguments' '
+ test_must_fail git pack-objects --window=0 test-1 blah blah <obj-list
+'
+
+check_unpack () {
+ test_when_finished "rm -rf git2" &&
+ git init --bare git2 &&
+ git -C git2 unpack-objects -n <"$1".pack &&
+ git -C git2 unpack-objects <"$1".pack &&
+ (cd .git && find objects -type f -print) |
+ while read path
+ do
+ cmp git2/$path .git/$path || {
+ echo $path differs.
+ return 1
+ }
+ done
+}
+
+test_expect_success 'unpack without delta' '
+ check_unpack test-1-${packname_1}
+'
+
+test_expect_success 'pack with REF_DELTA' '
+ packname_2=$(git pack-objects --progress test-2 <obj-list 2>stderr) &&
+ check_deltas stderr -gt 0
+'
+
+test_expect_success 'unpack with REF_DELTA' '
+ check_unpack test-2-${packname_2}
+'
+
+test_expect_success 'pack with OFS_DELTA' '
+ packname_3=$(git pack-objects --progress --delta-base-offset test-3 \
+ <obj-list 2>stderr) &&
+ check_deltas stderr -gt 0
+'
+
+test_expect_success 'unpack with OFS_DELTA' '
+ check_unpack test-3-${packname_3}
+'
test_expect_success 'compare delta flavors' '
perl -e '\''
@@ -135,55 +205,33 @@ test_expect_success 'compare delta flavors' '
'\'' test-2-$packname_2.pack test-3-$packname_3.pack
'
-rm -fr .git2
-mkdir .git2
+check_use_objects () {
+ test_when_finished "rm -rf git2" &&
+ git init --bare git2 &&
+ cp "$1".pack "$1".idx git2/objects/pack &&
+ (
+ cd git2 &&
+ git diff-tree --root -p $commit &&
+ while read object
+ do
+ t=$(git cat-file -t $object) &&
+ git cat-file $t $object || exit 1
+ done
+ ) <obj-list >current &&
+ cmp expect current
+}
-test_expect_success \
- 'use packed objects' \
- 'GIT_OBJECT_DIRECTORY=.git2/objects &&
- export GIT_OBJECT_DIRECTORY &&
- git init &&
- cp test-1-${packname_1}.pack test-1-${packname_1}.idx .git2/objects/pack && {
- git diff-tree --root -p $commit &&
- while read object
- do
- t=$(git cat-file -t $object) &&
- git cat-file $t $object || return 1
- done <obj-list
- } >current &&
- cmp expect current'
+test_expect_success 'use packed objects' '
+ check_use_objects test-1-${packname_1}
+'
-test_expect_success \
- 'use packed deltified (REF_DELTA) objects' \
- 'GIT_OBJECT_DIRECTORY=.git2/objects &&
- export GIT_OBJECT_DIRECTORY &&
- rm -f .git2/objects/pack/test-* &&
- cp test-2-${packname_2}.pack test-2-${packname_2}.idx .git2/objects/pack && {
- git diff-tree --root -p $commit &&
- while read object
- do
- t=$(git cat-file -t $object) &&
- git cat-file $t $object || return 1
- done <obj-list
- } >current &&
- cmp expect current'
+test_expect_success 'use packed deltified (REF_DELTA) objects' '
+ check_use_objects test-2-${packname_2}
+'
-test_expect_success \
- 'use packed deltified (OFS_DELTA) objects' \
- 'GIT_OBJECT_DIRECTORY=.git2/objects &&
- export GIT_OBJECT_DIRECTORY &&
- rm -f .git2/objects/pack/test-* &&
- cp test-3-${packname_3}.pack test-3-${packname_3}.idx .git2/objects/pack && {
- git diff-tree --root -p $commit &&
- while read object
- do
- t=$(git cat-file -t $object) &&
- git cat-file $t $object || return 1
- done <obj-list
- } >current &&
- cmp expect current'
-
-unset GIT_OBJECT_DIRECTORY
+test_expect_success 'use packed deltified (OFS_DELTA) objects' '
+ check_use_objects test-3-${packname_3}
+'
test_expect_success 'survive missing objects/pack directory' '
(
@@ -669,4 +717,9 @@ test_expect_success '--stdin-packs with broken links' '
)
'
+test_expect_success 'negative window clamps to 0' '
+ git pack-objects --progress --window=-1 neg-window <obj-list 2>stderr &&
+ check_deltas stderr = 0
+'
+
test_done
diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh
index b447ce56a9..8ae314af58 100755
--- a/t/t5304-prune.sh
+++ b/t/t5304-prune.sh
@@ -22,30 +22,25 @@ add_blob() {
}
test_expect_success setup '
-
- : > file &&
+ >file &&
git add file &&
test_tick &&
git commit -m initial &&
git gc
-
'
test_expect_success 'prune stale packs' '
-
orig_pack=$(echo .git/objects/pack/*.pack) &&
- : > .git/objects/tmp_1.pack &&
- : > .git/objects/tmp_2.pack &&
+ >.git/objects/tmp_1.pack &&
+ >.git/objects/tmp_2.pack &&
test-tool chmtime =-86501 .git/objects/tmp_1.pack &&
git prune --expire 1.day &&
test_path_is_file $orig_pack &&
test_path_is_file .git/objects/tmp_2.pack &&
test_path_is_missing .git/objects/tmp_1.pack
-
'
test_expect_success 'prune --expire' '
-
add_blob &&
git prune --expire=1.hour.ago &&
verbose test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
@@ -54,11 +49,9 @@ test_expect_success 'prune --expire' '
git prune --expire 1.day &&
verbose test $before = $(git count-objects | sed "s/ .*//") &&
test_path_is_missing $BLOB_FILE
-
'
test_expect_success 'gc: implicit prune --expire' '
-
add_blob &&
test-tool chmtime =-$((2*$week-30)) $BLOB_FILE &&
git gc &&
@@ -68,123 +61,98 @@ test_expect_success 'gc: implicit prune --expire' '
git gc &&
verbose test $before = $(git count-objects | sed "s/ .*//") &&
test_path_is_missing $BLOB_FILE
-
'
test_expect_success 'gc: refuse to start with invalid gc.pruneExpire' '
-
git config gc.pruneExpire invalid &&
test_must_fail git gc
-
'
test_expect_success 'gc: start with ok gc.pruneExpire' '
-
git config gc.pruneExpire 2.days.ago &&
git gc
-
'
test_expect_success 'prune: prune nonsense parameters' '
-
test_must_fail git prune garbage &&
test_must_fail git prune --- &&
test_must_fail git prune --no-such-option
-
'
test_expect_success 'prune: prune unreachable heads' '
-
git config core.logAllRefUpdates false &&
- mv .git/logs .git/logs.old &&
- : > file2 &&
+ >file2 &&
git add file2 &&
git commit -m temporary &&
tmp_head=$(git rev-list -1 HEAD) &&
git reset HEAD^ &&
+ git reflog expire --all &&
git prune &&
test_must_fail git reset $tmp_head --
-
'
test_expect_success 'prune: do not prune detached HEAD with no reflog' '
-
git checkout --detach --quiet &&
git commit --allow-empty -m "detached commit" &&
- # verify that there is no reflogs
- # (should be removed and disabled by previous test)
- test_path_is_missing .git/logs &&
+ git reflog expire --all &&
git prune -n >prune_actual &&
test_must_be_empty prune_actual
-
'
test_expect_success 'prune: prune former HEAD after checking out branch' '
-
head_oid=$(git rev-parse HEAD) &&
git checkout --quiet main &&
+ git reflog expire --all &&
git prune -v >prune_actual &&
grep "$head_oid" prune_actual
-
'
test_expect_success 'prune: do not prune heads listed as an argument' '
-
- : > file2 &&
+ >file2 &&
git add file2 &&
git commit -m temporary &&
tmp_head=$(git rev-list -1 HEAD) &&
git reset HEAD^ &&
git prune -- $tmp_head &&
git reset $tmp_head --
-
'
test_expect_success 'gc --no-prune' '
-
add_blob &&
test-tool chmtime =-$((5001*$day)) $BLOB_FILE &&
git config gc.pruneExpire 2.days.ago &&
git gc --no-prune &&
verbose test 1 = $(git count-objects | sed "s/ .*//") &&
test_path_is_file $BLOB_FILE
-
'
test_expect_success 'gc respects gc.pruneExpire' '
-
git config gc.pruneExpire 5002.days.ago &&
git gc &&
test_path_is_file $BLOB_FILE &&
git config gc.pruneExpire 5000.days.ago &&
git gc &&
test_path_is_missing $BLOB_FILE
-
'
test_expect_success 'gc --prune=<date>' '
-
add_blob &&
test-tool chmtime =-$((5001*$day)) $BLOB_FILE &&
git gc --prune=5002.days.ago &&
test_path_is_file $BLOB_FILE &&
git gc --prune=5000.days.ago &&
test_path_is_missing $BLOB_FILE
-
'
test_expect_success 'gc --prune=never' '
-
add_blob &&
git gc --prune=never &&
test_path_is_file $BLOB_FILE &&
git gc --prune=now &&
test_path_is_missing $BLOB_FILE
-
'
test_expect_success 'gc respects gc.pruneExpire=never' '
-
git config gc.pruneExpire never &&
add_blob &&
git gc &&
@@ -192,17 +160,14 @@ test_expect_success 'gc respects gc.pruneExpire=never' '
git config gc.pruneExpire now &&
git gc &&
test_path_is_missing $BLOB_FILE
-
'
test_expect_success 'prune --expire=never' '
-
add_blob &&
git prune --expire=never &&
test_path_is_file $BLOB_FILE &&
git prune &&
test_path_is_missing $BLOB_FILE
-
'
test_expect_success 'gc: prune old objects after local clone' '
@@ -222,16 +187,16 @@ test_expect_success 'gc: prune old objects after local clone' '
test_expect_success 'garbage report in count-objects -v' '
test_when_finished "rm -f .git/objects/pack/fake*" &&
test_when_finished "rm -f .git/objects/pack/foo*" &&
- : >.git/objects/pack/foo &&
- : >.git/objects/pack/foo.bar &&
- : >.git/objects/pack/foo.keep &&
- : >.git/objects/pack/foo.pack &&
- : >.git/objects/pack/fake.bar &&
- : >.git/objects/pack/fake.keep &&
- : >.git/objects/pack/fake.pack &&
- : >.git/objects/pack/fake.idx &&
- : >.git/objects/pack/fake2.keep &&
- : >.git/objects/pack/fake3.idx &&
+ >.git/objects/pack/foo &&
+ >.git/objects/pack/foo.bar &&
+ >.git/objects/pack/foo.keep &&
+ >.git/objects/pack/foo.pack &&
+ >.git/objects/pack/fake.bar &&
+ >.git/objects/pack/fake.keep &&
+ >.git/objects/pack/fake.pack &&
+ >.git/objects/pack/fake.idx &&
+ >.git/objects/pack/fake2.keep &&
+ >.git/objects/pack/fake3.idx &&
git count-objects -v 2>stderr &&
grep "index file .git/objects/pack/fake.idx is too small" stderr &&
grep "^warning:" stderr | sort >actual &&
@@ -250,12 +215,12 @@ EOF
test_expect_success 'clean pack garbage with gc' '
test_when_finished "rm -f .git/objects/pack/fake*" &&
test_when_finished "rm -f .git/objects/pack/foo*" &&
- : >.git/objects/pack/foo.keep &&
- : >.git/objects/pack/foo.pack &&
- : >.git/objects/pack/fake.idx &&
- : >.git/objects/pack/fake2.keep &&
- : >.git/objects/pack/fake2.idx &&
- : >.git/objects/pack/fake3.keep &&
+ >.git/objects/pack/foo.keep &&
+ >.git/objects/pack/foo.pack &&
+ >.git/objects/pack/fake.idx &&
+ >.git/objects/pack/fake2.keep &&
+ >.git/objects/pack/fake2.idx &&
+ >.git/objects/pack/fake3.keep &&
git gc &&
git count-objects -v 2>stderr &&
grep "^warning:" stderr | sort >actual &&
@@ -326,6 +291,7 @@ test_expect_success 'prune: handle HEAD reflog in multiple worktrees' '
cat ../expected >blob &&
git add blob &&
git commit -m "second commit in third" &&
+ git clean -f && # Remove untracked left behind by deleting index
git reset --hard HEAD^
) &&
git prune --expire=now &&
@@ -352,4 +318,20 @@ test_expect_success 'trivial prune with bitmaps enabled' '
test_must_fail git cat-file -e $blob
'
+test_expect_success 'old reachable-from-recent retained with bitmaps' '
+ git repack -adb &&
+ to_drop=$(echo bitmap-from-recent-1 | git hash-object -w --stdin) &&
+ test-tool chmtime -86400 .git/objects/$(test_oid_to_path $to_drop) &&
+ to_save=$(echo bitmap-from-recent-2 | git hash-object -w --stdin) &&
+ test-tool chmtime -86400 .git/objects/$(test_oid_to_path $to_save) &&
+ tree=$(printf "100644 blob $to_save\tfile\n" | git mktree) &&
+ test-tool chmtime -86400 .git/objects/$(test_oid_to_path $tree) &&
+ commit=$(echo foo | git commit-tree $tree) &&
+ git prune --expire=12.hours.ago &&
+ git cat-file -e $commit &&
+ git cat-file -e $tree &&
+ git cat-file -e $to_save &&
+ test_must_fail git cat-file -e $to_drop
+'
+
test_done
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index b02838750e..673baa5c3c 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -8,6 +8,10 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. "$TEST_DIRECTORY"/lib-bundle.sh
. "$TEST_DIRECTORY"/lib-bitmap.sh
+# t5310 deals only with single-pack bitmaps, so don't write MIDX bitmaps in
+# their place.
+GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
+
objpath () {
echo ".git/objects/$(echo "$1" | sed -e 's|\(..\)|\1/|')"
}
@@ -25,93 +29,10 @@ has_any () {
grep -Ff "$1" "$2"
}
-# To ensure the logic for "maximal commits" is exercised, make
-# the repository a bit more complicated.
-#
-# other second
-# * *
-# (99 commits) (99 commits)
-# * *
-# |\ /|
-# | * octo-other octo-second * |
-# |/|\_________ ____________/|\|
-# | \ \/ __________/ |
-# | | ________/\ / |
-# * |/ * merge-right *
-# | _|__________/ \____________ |
-# |/ | \|
-# (l1) * * merge-left * (r1)
-# | / \________________________ |
-# |/ \|
-# (l2) * * (r2)
-# \___________________________ |
-# \|
-# * (base)
-#
-# We only push bits down the first-parent history, which
-# makes some of these commits unimportant!
-#
-# The important part for the maximal commit algorithm is how
-# the bitmasks are extended. Assuming starting bit positions
-# for second (bit 0) and other (bit 1), the bitmasks at the
-# end should be:
-#
-# second: 1 (maximal, selected)
-# other: 01 (maximal, selected)
-# (base): 11 (maximal)
-#
-# This complicated history was important for a previous
-# version of the walk that guarantees never walking a
-# commit multiple times. That goal might be important
-# again, so preserve this complicated case. For now, this
-# test will guarantee that the bitmaps are computed
-# correctly, even with the repeat calculations.
-
-test_expect_success 'setup repo with moderate-sized history' '
- test_commit_bulk --id=file 10 &&
- git branch -M second &&
- git checkout -b other HEAD~5 &&
- test_commit_bulk --id=side 10 &&
-
- # add complicated history setup, including merges and
- # ambiguous merge-bases
-
- git checkout -b merge-left other~2 &&
- git merge second~2 -m "merge-left" &&
-
- git checkout -b merge-right second~1 &&
- git merge other~1 -m "merge-right" &&
-
- git checkout -b octo-second second &&
- git merge merge-left merge-right -m "octopus-second" &&
-
- git checkout -b octo-other other &&
- git merge merge-left merge-right -m "octopus-other" &&
-
- git checkout other &&
- git merge octo-other -m "pull octopus" &&
-
- git checkout second &&
- git merge octo-second -m "pull octopus" &&
-
- # Remove these branches so they are not selected
- # as bitmap tips
- git branch -D merge-left &&
- git branch -D merge-right &&
- git branch -D octo-other &&
- git branch -D octo-second &&
-
- # add padding to make these merges less interesting
- # and avoid having them selected for bitmaps
- test_commit_bulk --id=file 100 &&
- git checkout other &&
- test_commit_bulk --id=side 100 &&
- git checkout second &&
-
- bitmaptip=$(git rev-parse second) &&
- blob=$(echo tagged-blob | git hash-object -w --stdin) &&
- git tag tagged-blob $blob &&
- git config repack.writebitmaps true
+setup_bitmap_history
+
+test_expect_success 'setup writing bitmaps during repack' '
+ git config repack.writeBitmaps true
'
test_expect_success 'full repack creates bitmaps' '
@@ -123,109 +44,7 @@ test_expect_success 'full repack creates bitmaps' '
grep "\"key\":\"num_maximal_commits\",\"value\":\"107\"" trace
'
-test_expect_success 'rev-list --test-bitmap verifies bitmaps' '
- git rev-list --test-bitmap HEAD
-'
-
-rev_list_tests_head () {
- test_expect_success "counting commits via bitmap ($state, $branch)" '
- git rev-list --count $branch >expect &&
- git rev-list --use-bitmap-index --count $branch >actual &&
- test_cmp expect actual
- '
-
- test_expect_success "counting partial commits via bitmap ($state, $branch)" '
- git rev-list --count $branch~5..$branch >expect &&
- git rev-list --use-bitmap-index --count $branch~5..$branch >actual &&
- test_cmp expect actual
- '
-
- test_expect_success "counting commits with limit ($state, $branch)" '
- git rev-list --count -n 1 $branch >expect &&
- git rev-list --use-bitmap-index --count -n 1 $branch >actual &&
- test_cmp expect actual
- '
-
- test_expect_success "counting non-linear history ($state, $branch)" '
- git rev-list --count other...second >expect &&
- git rev-list --use-bitmap-index --count other...second >actual &&
- test_cmp expect actual
- '
-
- test_expect_success "counting commits with limiting ($state, $branch)" '
- git rev-list --count $branch -- 1.t >expect &&
- git rev-list --use-bitmap-index --count $branch -- 1.t >actual &&
- test_cmp expect actual
- '
-
- test_expect_success "counting objects via bitmap ($state, $branch)" '
- git rev-list --count --objects $branch >expect &&
- git rev-list --use-bitmap-index --count --objects $branch >actual &&
- test_cmp expect actual
- '
-
- test_expect_success "enumerate commits ($state, $branch)" '
- git rev-list --use-bitmap-index $branch >actual &&
- git rev-list $branch >expect &&
- test_bitmap_traversal --no-confirm-bitmaps expect actual
- '
-
- test_expect_success "enumerate --objects ($state, $branch)" '
- git rev-list --objects --use-bitmap-index $branch >actual &&
- git rev-list --objects $branch >expect &&
- test_bitmap_traversal expect actual
- '
-
- test_expect_success "bitmap --objects handles non-commit objects ($state, $branch)" '
- git rev-list --objects --use-bitmap-index $branch tagged-blob >actual &&
- grep $blob actual
- '
-}
-
-rev_list_tests () {
- state=$1
-
- for branch in "second" "other"
- do
- rev_list_tests_head
- done
-}
-
-rev_list_tests 'full bitmap'
-
-test_expect_success 'clone from bitmapped repository' '
- git clone --no-local --bare . clone.git &&
- git rev-parse HEAD >expect &&
- git --git-dir=clone.git rev-parse HEAD >actual &&
- test_cmp expect actual
-'
-
-test_expect_success 'partial clone from bitmapped repository' '
- test_config uploadpack.allowfilter true &&
- git clone --no-local --bare --filter=blob:none . partial-clone.git &&
- (
- cd partial-clone.git &&
- pack=$(echo objects/pack/*.pack) &&
- git verify-pack -v "$pack" >have &&
- awk "/blob/ { print \$1 }" <have >blobs &&
- # we expect this single blob because of the direct ref
- git rev-parse refs/tags/tagged-blob >expect &&
- test_cmp expect blobs
- )
-'
-
-test_expect_success 'setup further non-bitmapped commits' '
- test_commit_bulk --id=further 10
-'
-
-rev_list_tests 'partial bitmap'
-
-test_expect_success 'fetch (partial bitmap)' '
- git --git-dir=clone.git fetch origin second:second &&
- git rev-parse HEAD >expect &&
- git --git-dir=clone.git rev-parse HEAD >actual &&
- test_cmp expect actual
-'
+basic_bitmap_tests
test_expect_success 'incremental repack fails when bitmaps are requested' '
test_commit more-1 &&
@@ -461,40 +280,6 @@ test_expect_success 'truncated bitmap fails gracefully (cache)' '
test_i18ngrep corrupted.bitmap.index stderr
'
-test_expect_success 'enumerating progress counts pack-reused objects' '
- count=$(git rev-list --objects --all --count) &&
- git repack -adb &&
-
- # check first with only reused objects; confirm that our progress
- # showed the right number, and also that we did pack-reuse as expected.
- # Check only the final "done" line of the meter (there may be an
- # arbitrary number of intermediate lines ending with CR).
- GIT_PROGRESS_DELAY=0 \
- git pack-objects --all --stdout --progress \
- </dev/null >/dev/null 2>stderr &&
- grep "Enumerating objects: $count, done" stderr &&
- grep "pack-reused $count" stderr &&
-
- # now the same but with one non-reused object
- git commit --allow-empty -m "an extra commit object" &&
- GIT_PROGRESS_DELAY=0 \
- git pack-objects --all --stdout --progress \
- </dev/null >/dev/null 2>stderr &&
- grep "Enumerating objects: $((count+1)), done" stderr &&
- grep "pack-reused $count" stderr
-'
-
-# have_delta <obj> <expected_base>
-#
-# Note that because this relies on cat-file, it might find _any_ copy of an
-# object in the repository. The caller is responsible for making sure
-# there's only one (e.g., via "repack -ad", or having just fetched a copy).
-have_delta () {
- echo $2 >expect &&
- echo $1 | git cat-file --batch-check="%(deltabase)" >actual &&
- test_cmp expect actual
-}
-
# Create a state of history with these properties:
#
# - refs that allow a client to fetch some new history, while sharing some old
diff --git a/t/t5312-prune-corruption.sh b/t/t5312-prune-corruption.sh
index 11423b3cb2..ea889c088a 100755
--- a/t/t5312-prune-corruption.sh
+++ b/t/t5312-prune-corruption.sh
@@ -7,6 +7,9 @@ if we see, for example, a ref with a bogus name, it is OK either to
bail out or to proceed using it as a reachable tip, but it is _not_
OK to proceed as if it did not exist. Otherwise we might silently
delete objects that cannot be recovered.
+
+Note that we do assert command failure in these cases, because that is
+what currently happens. If that changes, these tests should be revisited.
'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
@@ -18,39 +21,58 @@ test_expect_success 'disable reflogs' '
git reflog expire --expire=all --all
'
+create_bogus_ref () {
+ test_when_finished 'rm -f .git/refs/heads/bogus..name' &&
+ echo $bogus >.git/refs/heads/bogus..name
+}
+
test_expect_success 'create history reachable only from a bogus-named ref' '
test_tick && git commit --allow-empty -m main &&
base=$(git rev-parse HEAD) &&
test_tick && git commit --allow-empty -m bogus &&
bogus=$(git rev-parse HEAD) &&
git cat-file commit $bogus >saved &&
- echo $bogus >.git/refs/heads/bogus..name &&
git reset --hard HEAD^
'
test_expect_success 'pruning does not drop bogus object' '
test_when_finished "git hash-object -w -t commit saved" &&
- test_might_fail git prune --expire=now &&
- verbose git cat-file -e $bogus
+ create_bogus_ref &&
+ test_must_fail git prune --expire=now &&
+ git cat-file -e $bogus
'
test_expect_success 'put bogus object into pack' '
git tag reachable $bogus &&
git repack -ad &&
git tag -d reachable &&
- verbose git cat-file -e $bogus
+ git cat-file -e $bogus
+'
+
+test_expect_success 'non-destructive repack bails on bogus ref' '
+ create_bogus_ref &&
+ test_must_fail git repack -adk
'
+test_expect_success 'GIT_REF_PARANOIA=0 overrides safety' '
+ create_bogus_ref &&
+ GIT_REF_PARANOIA=0 git repack -adk
+'
+
+
test_expect_success 'destructive repack keeps packed object' '
- test_might_fail git repack -Ad --unpack-unreachable=now &&
- verbose git cat-file -e $bogus &&
- test_might_fail git repack -ad &&
- verbose git cat-file -e $bogus
+ create_bogus_ref &&
+ test_must_fail git repack -Ad --unpack-unreachable=now &&
+ git cat-file -e $bogus &&
+ test_must_fail git repack -ad &&
+ git cat-file -e $bogus
'
-# subsequent tests will have different corruptions
-test_expect_success 'clean up bogus ref' '
- rm .git/refs/heads/bogus..name
+test_expect_success 'destructive repack not confused by dangling symref' '
+ test_when_finished "git symbolic-ref -d refs/heads/dangling" &&
+ git symbolic-ref refs/heads/dangling refs/heads/does-not-exist &&
+ git repack -ad &&
+ test_must_fail git cat-file -e $bogus
'
# We create two new objects here, "one" and "two". Our
@@ -77,8 +99,8 @@ test_expect_success 'create history with missing tip commit' '
test_expect_success 'pruning with a corrupted tip does not drop history' '
test_when_finished "git hash-object -w -t commit saved" &&
- test_might_fail git prune --expire=now &&
- verbose git cat-file -e $recoverable
+ test_must_fail git prune --expire=now &&
+ git cat-file -e $recoverable
'
test_expect_success 'pack-refs does not silently delete broken loose ref' '
diff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh
index a8c1bc0f66..759169d074 100755
--- a/t/t5316-pack-delta-depth.sh
+++ b/t/t5316-pack-delta-depth.sh
@@ -69,6 +69,7 @@ test_expect_success 'create series of packs' '
max_chain() {
git index-pack --verify-stat-only "$1" >output &&
perl -lne '
+ BEGIN { $len = 0 }
/chain length = (\d+)/ and $len = $1;
END { print $len }
' output
@@ -94,4 +95,18 @@ test_expect_success '--depth limits depth' '
test_cmp expect actual
'
+test_expect_success '--depth=0 disables deltas' '
+ pack=$(git pack-objects --all --depth=0 </dev/null pack) &&
+ echo 0 >expect &&
+ max_chain pack-$pack.pack >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'negative depth disables deltas' '
+ pack=$(git pack-objects --all --depth=-1 </dev/null pack) &&
+ echo 0 >expect &&
+ max_chain pack-$pack.pack >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index af88f805aa..295c5bd94d 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -5,6 +5,25 @@ test_description='commit graph'
GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=0
+test_expect_success 'usage' '
+ test_expect_code 129 git commit-graph write blah 2>err &&
+ test_expect_code 129 git commit-graph write verify
+'
+
+test_expect_success 'usage shown without sub-command' '
+ test_expect_code 129 git commit-graph 2>err &&
+ ! grep error: err
+'
+
+test_expect_success 'usage shown with an error on unknown sub-command' '
+ cat >expect <<-\EOF &&
+ error: unrecognized subcommand: unknown
+ EOF
+ test_expect_code 129 git commit-graph unknown 2>stderr &&
+ grep error stderr >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'setup full repo' '
mkdir full &&
cd "$TRASH_DIRECTORY/full" &&
diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index 5641d158df..a3c72b68f7 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -168,18 +168,33 @@ test_expect_success 'write midx with two packs' '
compare_results_with_midx "two packs"
+test_expect_success 'write midx with --stdin-packs' '
+ rm -fr $objdir/pack/multi-pack-index &&
+
+ idx="$(find $objdir/pack -name "test-2-*.idx")" &&
+ basename "$idx" >in &&
+
+ git multi-pack-index write --stdin-packs <in &&
+
+ test-tool read-midx $objdir | grep "\.idx$" >packs &&
+
+ test_cmp packs in
+'
+
+compare_results_with_midx "mixed mode (one pack + extra)"
+
test_expect_success 'write progress off for redirected stderr' '
git multi-pack-index --object-dir=$objdir write 2>err &&
test_line_count = 0 err
'
test_expect_success 'write force progress on for stderr' '
- GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir --progress write 2>err &&
+ GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir write --progress 2>err &&
test_file_not_empty err
'
test_expect_success 'write with the --no-progress option' '
- GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir --no-progress write 2>err &&
+ GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir write --no-progress 2>err &&
test_line_count = 0 err
'
@@ -201,6 +216,34 @@ test_expect_success 'write midx with twelve packs' '
compare_results_with_midx "twelve packs"
+test_expect_success 'multi-pack-index *.rev cleanup with --object-dir' '
+ git init repo &&
+ git clone -s repo alternate &&
+
+ test_when_finished "rm -rf repo alternate" &&
+
+ (
+ cd repo &&
+ test_commit base &&
+ git repack -d
+ ) &&
+
+ ours="alternate/.git/objects/pack/multi-pack-index-123.rev" &&
+ theirs="repo/.git/objects/pack/multi-pack-index-abc.rev" &&
+ touch "$ours" "$theirs" &&
+
+ (
+ cd alternate &&
+ git multi-pack-index --object-dir ../repo/.git/objects write
+ ) &&
+
+ # writing a midx in "repo" should not remove the .rev file in the
+ # alternate
+ test_path_is_file repo/.git/objects/pack/multi-pack-index &&
+ test_path_is_file $ours &&
+ test_path_is_missing $theirs
+'
+
test_expect_success 'warn on improper hash version' '
git init --object-format=sha1 sha1 &&
(
@@ -277,6 +320,23 @@ test_expect_success 'midx picks objects from preferred pack' '
)
'
+test_expect_success 'preferred packs must be non-empty' '
+ test_when_finished rm -rf preferred.git &&
+ git init preferred.git &&
+ (
+ cd preferred.git &&
+
+ test_commit base &&
+ git repack -ad &&
+
+ empty="$(git pack-objects $objdir/pack/pack </dev/null)" &&
+
+ test_must_fail git multi-pack-index write \
+ --preferred-pack=pack-$empty.pack 2>err &&
+ grep "with no objects" err
+ )
+'
+
test_expect_success 'verify multi-pack-index success' '
git multi-pack-index verify --object-dir=$objdir
'
@@ -410,18 +470,31 @@ test_expect_success 'git-fsck incorrect offset' '
"git -c core.multipackindex=true fsck"
'
+test_expect_success 'corrupt MIDX is not reused' '
+ corrupt_midx_and_verify $MIDX_BYTE_OFFSET "\377" $objdir \
+ "incorrect object offset" &&
+ git multi-pack-index write 2>err &&
+ test_i18ngrep checksum.mismatch err &&
+ git multi-pack-index verify
+'
+
+test_expect_success 'verify incorrect checksum' '
+ pos=$(($(wc -c <$objdir/pack/multi-pack-index) - 1)) &&
+ corrupt_midx_and_verify $pos "\377" $objdir "incorrect checksum"
+'
+
test_expect_success 'repack progress off for redirected stderr' '
GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir repack 2>err &&
test_line_count = 0 err
'
test_expect_success 'repack force progress on for stderr' '
- GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir --progress repack 2>err &&
+ GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir repack --progress 2>err &&
test_file_not_empty err
'
test_expect_success 'repack with the --no-progress option' '
- GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir --no-progress repack 2>err &&
+ GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir repack --no-progress 2>err &&
test_line_count = 0 err
'
@@ -474,7 +547,8 @@ test_expect_success 'repack preserves multi-pack-index when creating packs' '
compare_results_with_midx "after repack"
test_expect_success 'multi-pack-index and pack-bitmap' '
- git -c repack.writeBitmaps=true repack -ad &&
+ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
+ git -c repack.writeBitmaps=true repack -ad &&
git multi-pack-index write &&
git rev-list --test-bitmap HEAD
'
@@ -524,7 +598,15 @@ test_expect_success 'force some 64-bit offsets with pack-objects' '
idx64=objects64/pack/test-64-$pack64.idx &&
chmod u+w $idx64 &&
corrupt_data $idx64 $(test_oid idxoff) "\02" &&
- midx64=$(git multi-pack-index --object-dir=objects64 write) &&
+ # objects64 is not a real repository, but can serve as an alternate
+ # anyway so we can write a MIDX into it
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+ ( cd ../objects64 && pwd ) >.git/objects/info/alternates &&
+ midx64=$(git multi-pack-index --object-dir=../objects64 write)
+ ) &&
midx_read_expect 1 63 5 objects64 " large-offsets"
'
@@ -605,7 +687,7 @@ test_expect_success 'expire progress off for redirected stderr' '
test_expect_success 'expire force progress on for stderr' '
(
cd dup &&
- GIT_PROGRESS_DELAY=0 git multi-pack-index --progress expire 2>err &&
+ GIT_PROGRESS_DELAY=0 git multi-pack-index expire --progress 2>err &&
test_file_not_empty err
)
'
@@ -613,7 +695,7 @@ test_expect_success 'expire force progress on for stderr' '
test_expect_success 'expire with the --no-progress option' '
(
cd dup &&
- GIT_PROGRESS_DELAY=0 git multi-pack-index --no-progress expire 2>err &&
+ GIT_PROGRESS_DELAY=0 git multi-pack-index expire --no-progress 2>err &&
test_line_count = 0 err
)
'
@@ -824,4 +906,14 @@ test_expect_success 'load reverse index when missing .idx, .pack' '
)
'
+test_expect_success 'usage shown without sub-command' '
+ test_expect_code 129 git multi-pack-index 2>err &&
+ ! test_i18ngrep "unrecognized subcommand" err
+'
+
+test_expect_success 'complains when run outside of a repository' '
+ nongit test_must_fail git multi-pack-index write 2>err &&
+ grep "not a git repository" err
+'
+
test_done
diff --git a/t/t5323-pack-redundant.sh b/t/t5323-pack-redundant.sh
index 8b01793845..8dbbcc5e51 100755
--- a/t/t5323-pack-redundant.sh
+++ b/t/t5323-pack-redundant.sh
@@ -114,9 +114,9 @@ test_expect_success 'setup main repo' '
create_commits_in "$main_repo" A B C D E F G H I J K L M N O P Q R
'
-test_expect_success 'master: pack-redundant works with no packfile' '
+test_expect_success 'main: pack-redundant works with no packfile' '
(
- cd "$master_repo" &&
+ cd "$main_repo" &&
cat >expect <<-EOF &&
fatal: Zero packs found!
EOF
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
new file mode 100755
index 0000000000..e187f90f29
--- /dev/null
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -0,0 +1,398 @@
+#!/bin/sh
+
+test_description='exercise basic multi-pack bitmap functionality'
+. ./test-lib.sh
+. "${TEST_DIRECTORY}/lib-bitmap.sh"
+
+# We'll be writing our own midx and bitmaps, so avoid getting confused by the
+# automatic ones.
+GIT_TEST_MULTI_PACK_INDEX=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
+
+objdir=.git/objects
+midx=$objdir/pack/multi-pack-index
+
+# midx_pack_source <obj>
+midx_pack_source () {
+ test-tool read-midx --show-objects .git/objects | grep "^$1 " | cut -f2
+}
+
+setup_bitmap_history
+
+test_expect_success 'enable core.multiPackIndex' '
+ git config core.multiPackIndex true
+'
+
+test_expect_success 'create single-pack midx with bitmaps' '
+ git repack -ad &&
+ git multi-pack-index write --bitmap &&
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+ test_path_is_file $midx-$(midx_checksum $objdir).rev
+'
+
+basic_bitmap_tests
+
+test_expect_success 'create new additional packs' '
+ for i in $(test_seq 1 16)
+ do
+ test_commit "$i" &&
+ git repack -d || return 1
+ done &&
+
+ git checkout -b other2 HEAD~8 &&
+ for i in $(test_seq 1 8)
+ do
+ test_commit "side-$i" &&
+ git repack -d || return 1
+ done &&
+ git checkout second
+'
+
+test_expect_success 'create multi-pack midx with bitmaps' '
+ git multi-pack-index write --bitmap &&
+
+ ls $objdir/pack/pack-*.pack >packs &&
+ test_line_count = 25 packs &&
+
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+ test_path_is_file $midx-$(midx_checksum $objdir).rev
+'
+
+basic_bitmap_tests
+
+test_expect_success '--no-bitmap is respected when bitmaps exist' '
+ git multi-pack-index write --bitmap &&
+
+ test_commit respect--no-bitmap &&
+ git repack -d &&
+
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+ test_path_is_file $midx-$(midx_checksum $objdir).rev &&
+
+ git multi-pack-index write --no-bitmap &&
+
+ test_path_is_file $midx &&
+ test_path_is_missing $midx-$(midx_checksum $objdir).bitmap &&
+ test_path_is_missing $midx-$(midx_checksum $objdir).rev
+'
+
+test_expect_success 'setup midx with base from later pack' '
+ # Write a and b so that "a" is a delta on top of base "b", since Git
+ # prefers to delete contents out of a base rather than add to a shorter
+ # object.
+ test_seq 1 128 >a &&
+ test_seq 1 130 >b &&
+
+ git add a b &&
+ git commit -m "initial commit" &&
+
+ a=$(git rev-parse HEAD:a) &&
+ b=$(git rev-parse HEAD:b) &&
+
+ # In the first pack, "a" is stored as a delta to "b".
+ p1=$(git pack-objects .git/objects/pack/pack <<-EOF
+ $a
+ $b
+ EOF
+ ) &&
+
+ # In the second pack, "a" is missing, and "b" is not a delta nor base to
+ # any other object.
+ p2=$(git pack-objects .git/objects/pack/pack <<-EOF
+ $b
+ $(git rev-parse HEAD)
+ $(git rev-parse HEAD^{tree})
+ EOF
+ ) &&
+
+ git prune-packed &&
+ # Use the second pack as the preferred source, so that "b" occurs
+ # earlier in the MIDX object order, rendering "a" unusable for pack
+ # reuse.
+ git multi-pack-index write --bitmap --preferred-pack=pack-$p2.idx &&
+
+ have_delta $a $b &&
+ test $(midx_pack_source $a) != $(midx_pack_source $b)
+'
+
+rev_list_tests 'full bitmap with backwards delta'
+
+test_expect_success 'clone with bitmaps enabled' '
+ git clone --no-local --bare . clone-reverse-delta.git &&
+ test_when_finished "rm -fr clone-reverse-delta.git" &&
+
+ git rev-parse HEAD >expect &&
+ git --git-dir=clone-reverse-delta.git rev-parse HEAD >actual &&
+ test_cmp expect actual
+'
+
+bitmap_reuse_tests() {
+ from=$1
+ to=$2
+
+ test_expect_success "setup pack reuse tests ($from -> $to)" '
+ rm -fr repo &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit_bulk 16 &&
+ git tag old-tip &&
+
+ git config core.multiPackIndex true &&
+ if test "MIDX" = "$from"
+ then
+ git repack -Ad &&
+ git multi-pack-index write --bitmap
+ else
+ git repack -Adb
+ fi
+ )
+ '
+
+ test_expect_success "build bitmap from existing ($from -> $to)" '
+ (
+ cd repo &&
+ test_commit_bulk --id=further 16 &&
+ git tag new-tip &&
+
+ if test "MIDX" = "$to"
+ then
+ git repack -d &&
+ git multi-pack-index write --bitmap
+ else
+ git repack -Adb
+ fi
+ )
+ '
+
+ test_expect_success "verify resulting bitmaps ($from -> $to)" '
+ (
+ cd repo &&
+ git for-each-ref &&
+ git rev-list --test-bitmap refs/tags/old-tip &&
+ git rev-list --test-bitmap refs/tags/new-tip
+ )
+ '
+}
+
+bitmap_reuse_tests 'pack' 'MIDX'
+bitmap_reuse_tests 'MIDX' 'pack'
+bitmap_reuse_tests 'MIDX' 'MIDX'
+
+test_expect_success 'missing object closure fails gracefully' '
+ rm -fr repo &&
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit loose &&
+ test_commit packed &&
+
+ # Do not pass "--revs"; we want a pack without the "loose"
+ # commit.
+ git pack-objects $objdir/pack/pack <<-EOF &&
+ $(git rev-parse packed)
+ EOF
+
+ test_must_fail git multi-pack-index write --bitmap 2>err &&
+ grep "doesn.t have full closure" err &&
+ test_path_is_missing $midx
+ )
+'
+
+test_expect_success 'setup partial bitmaps' '
+ test_commit packed &&
+ git repack &&
+ test_commit loose &&
+ git multi-pack-index write --bitmap 2>err &&
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+ test_path_is_file $midx-$(midx_checksum $objdir).rev
+'
+
+basic_bitmap_tests HEAD~
+
+test_expect_success 'removing a MIDX clears stale bitmaps' '
+ rm -fr repo &&
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+ test_commit base &&
+ git repack &&
+ git multi-pack-index write --bitmap &&
+
+ # Write a MIDX and bitmap; remove the MIDX but leave the bitmap.
+ stale_bitmap=$midx-$(midx_checksum $objdir).bitmap &&
+ stale_rev=$midx-$(midx_checksum $objdir).rev &&
+ rm $midx &&
+
+ # Then write a new MIDX.
+ test_commit new &&
+ git repack &&
+ git multi-pack-index write --bitmap &&
+
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+ test_path_is_file $midx-$(midx_checksum $objdir).rev &&
+ test_path_is_missing $stale_bitmap &&
+ test_path_is_missing $stale_rev
+ )
+'
+
+test_expect_success 'pack.preferBitmapTips' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit_bulk --message="%s" 103 &&
+
+ git log --format="%H" >commits.raw &&
+ sort <commits.raw >commits &&
+
+ git log --format="create refs/tags/%s %H" HEAD >refs &&
+ git update-ref --stdin <refs &&
+
+ git multi-pack-index write --bitmap &&
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+ test_path_is_file $midx-$(midx_checksum $objdir).rev &&
+
+ test-tool bitmap list-commits | sort >bitmaps &&
+ comm -13 bitmaps commits >before &&
+ test_line_count = 1 before &&
+
+ perl -ne "printf(\"create refs/tags/include/%d \", $.); print" \
+ <before | git update-ref --stdin &&
+
+ rm -fr $midx-$(midx_checksum $objdir).bitmap &&
+ rm -fr $midx-$(midx_checksum $objdir).rev &&
+ rm -fr $midx &&
+
+ git -c pack.preferBitmapTips=refs/tags/include \
+ multi-pack-index write --bitmap &&
+ test-tool bitmap list-commits | sort >bitmaps &&
+ comm -13 bitmaps commits >after &&
+
+ ! test_cmp before after
+ )
+'
+
+test_expect_success 'writing a bitmap with --refs-snapshot' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit one &&
+ test_commit two &&
+
+ git rev-parse one >snapshot &&
+
+ git repack -ad &&
+
+ # First, write a MIDX which see both refs/tags/one and
+ # refs/tags/two (causing both of those commits to receive
+ # bitmaps).
+ git multi-pack-index write --bitmap &&
+
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+
+ test-tool bitmap list-commits | sort >bitmaps &&
+ grep "$(git rev-parse one)" bitmaps &&
+ grep "$(git rev-parse two)" bitmaps &&
+
+ rm -fr $midx-$(midx_checksum $objdir).bitmap &&
+ rm -fr $midx-$(midx_checksum $objdir).rev &&
+ rm -fr $midx &&
+
+ # Then again, but with a refs snapshot which only sees
+ # refs/tags/one.
+ git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
+
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+
+ test-tool bitmap list-commits | sort >bitmaps &&
+ grep "$(git rev-parse one)" bitmaps &&
+ ! grep "$(git rev-parse two)" bitmaps
+ )
+'
+
+test_expect_success 'write a bitmap with --refs-snapshot (preferred tips)' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit_bulk --message="%s" 103 &&
+
+ git log --format="%H" >commits.raw &&
+ sort <commits.raw >commits &&
+
+ git log --format="create refs/tags/%s %H" HEAD >refs &&
+ git update-ref --stdin <refs &&
+
+ git multi-pack-index write --bitmap &&
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+
+ test-tool bitmap list-commits | sort >bitmaps &&
+ comm -13 bitmaps commits >before &&
+ test_line_count = 1 before &&
+
+ (
+ grep -vf before commits.raw &&
+ # mark missing commits as preferred
+ sed "s/^/+/" before
+ ) >snapshot &&
+
+ rm -fr $midx-$(midx_checksum $objdir).bitmap &&
+ rm -fr $midx-$(midx_checksum $objdir).rev &&
+ rm -fr $midx &&
+
+ git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
+ test-tool bitmap list-commits | sort >bitmaps &&
+ comm -13 bitmaps commits >after &&
+
+ ! test_cmp before after
+ )
+'
+
+test_expect_success 'hash-cache values are propagated from pack bitmaps' '
+ rm -fr repo &&
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit base &&
+ test_commit base2 &&
+ git repack -adb &&
+
+ test-tool bitmap dump-hashes >pack.raw &&
+ test_file_not_empty pack.raw &&
+ sort pack.raw >pack.hashes &&
+
+ test_commit new &&
+ git repack &&
+ git multi-pack-index write --bitmap &&
+
+ test-tool bitmap dump-hashes >midx.raw &&
+ sort midx.raw >midx.hashes &&
+
+ # ensure that every namehash in the pack bitmap can be found in
+ # the midx bitmap (i.e., that there are no oid-namehash pairs
+ # unique to the pack bitmap).
+ comm -23 pack.hashes midx.hashes >dropped.hashes &&
+ test_must_be_empty dropped.hashes
+ )
+'
+
+test_done
diff --git a/t/t5406-remote-rejects.sh b/t/t5406-remote-rejects.sh
index ff06f99649..5c509db6fc 100755
--- a/t/t5406-remote-rejects.sh
+++ b/t/t5406-remote-rejects.sh
@@ -5,7 +5,6 @@ test_description='remote push rejects are reported by client'
. ./test-lib.sh
test_expect_success 'setup' '
- mkdir .git/hooks &&
write_script .git/hooks/update <<-\EOF &&
exit 1
EOF
diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index 5bb23cc3a4..6da8d760e2 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -20,8 +20,6 @@ test_expect_success 'setup' '
git checkout main
'
-mkdir .git/hooks
-
cat >.git/hooks/post-rewrite <<EOF
#!/bin/sh
echo \$@ > "$TRASH_DIRECTORY"/post-rewrite.args
diff --git a/t/t5409-colorize-remote-messages.sh b/t/t5409-colorize-remote-messages.sh
index 5d8f401d8e..9f1a483f42 100755
--- a/t/t5409-colorize-remote-messages.sh
+++ b/t/t5409-colorize-remote-messages.sh
@@ -5,7 +5,6 @@ test_description='remote messages are colorized on the client'
. ./test-lib.sh
test_expect_success 'setup' '
- mkdir .git/hooks &&
write_script .git/hooks/update <<-\EOF &&
echo error: error
echo ERROR: also highlighted
diff --git a/t/t5411/common-functions.sh b/t/t5411/common-functions.sh
index 6694858e18..3c747782c1 100644
--- a/t/t5411/common-functions.sh
+++ b/t/t5411/common-functions.sh
@@ -6,50 +6,44 @@
# NOTE: Never calling this function from a subshell since variable
# assignments will disappear when subshell exits.
create_commits_in () {
- repo="$1" &&
- if ! parent=$(git -C "$repo" rev-parse HEAD^{} --)
- then
- parent=
- fi &&
- T=$(git -C "$repo" write-tree) &&
+ repo="$1" && test -d "$repo" ||
+ error "Repository $repo does not exist."
shift &&
while test $# -gt 0
do
name=$1 &&
- test_tick &&
- if test -z "$parent"
- then
- oid=$(echo $name | git -C "$repo" commit-tree $T)
- else
- oid=$(echo $name | git -C "$repo" commit-tree -p $parent $T)
- fi &&
- eval $name=$oid &&
- parent=$oid &&
- shift ||
- return 1
- done &&
- git -C "$repo" update-ref refs/heads/main $oid
+ shift &&
+ test_commit -C "$repo" --no-tag "$name" &&
+ eval $name=$(git -C "$repo" rev-parse HEAD)
+ done
+}
+
+get_abbrev_oid () {
+ oid=$1 &&
+ suffix=${oid#???????} &&
+ oid=${oid%$suffix} &&
+ if test -n "$oid"
+ then
+ echo "$oid"
+ else
+ echo "undefined-oid"
+ fi
}
# Format the output of git-push, git-show-ref and other commands to make a
# user-friendly and stable text. We can easily prepare the expect text
-# without having to worry about future changes of the commit ID and spaces
+# without having to worry about changes of the commit ID (full or abbrev.)
# of the output. Single quotes are replaced with double quotes, because
# it is boring to prepare unquoted single quotes in expect text. We also
# remove some locale error messages. The emitted human-readable errors are
# redundant to the more machine-readable output the tests already assert.
make_user_friendly_and_stable_output () {
sed \
- -e "s/ *\$//" \
- -e "s/ */ /g" \
-e "s/'/\"/g" \
- -e "s/ / /g" \
- -e "s/$A/<COMMIT-A>/g" \
- -e "s/$B/<COMMIT-B>/g" \
- -e "s/$TAG/<TAG-v123>/g" \
+ -e "s/$(get_abbrev_oid $A)[0-9a-f]*/<COMMIT-A>/g" \
+ -e "s/$(get_abbrev_oid $B)[0-9a-f]*/<COMMIT-B>/g" \
+ -e "s/$(get_abbrev_oid $TAG)[0-9a-f]*/<TAG-v123>/g" \
-e "s/$ZERO_OID/<ZERO-OID>/g" \
- -e "s/$(echo $A | cut -c1-7)[0-9a-f]*/<OID-A>/g" \
- -e "s/$(echo $B | cut -c1-7)[0-9a-f]*/<OID-B>/g" \
-e "s#To $URL_PREFIX/upstream.git#To <URL/of/upstream.git>#" \
-e "/^error: / d"
}
@@ -59,6 +53,10 @@ filter_out_user_friendly_and_stable_output () {
sed -n ${1+"$@"}
}
+format_and_save_expect () {
+ sed -e 's/^> //' -e 's/Z$//' >expect
+}
+
test_cmp_refs () {
indir=
if test "$1" = "-C"
diff --git a/t/t5411/once-0010-report-status-v1.sh b/t/t5411/once-0010-report-status-v1.sh
index 1233a46eac..297b10925d 100644
--- a/t/t5411/once-0010-report-status-v1.sh
+++ b/t/t5411/once-0010-report-status-v1.sh
@@ -28,10 +28,10 @@ test_expect_success "proc-receive: report status v1" '
if test -z "$GIT_DEFAULT_HASH" || test "$GIT_DEFAULT_HASH" = "sha1"
then
printf "%s %s refs/heads/main\0report-status\n" \
- $A $B | packetize
+ $A $B | packetize_raw
else
printf "%s %s refs/heads/main\0report-status object-format=$GIT_DEFAULT_HASH\n" \
- $A $B | packetize
+ $A $B | packetize_raw
fi &&
printf "%s %s refs/for/main/topic1\n" \
$ZERO_OID $A | packetize &&
diff --git a/t/t5411/test-0000-standard-git-push.sh b/t/t5411/test-0000-standard-git-push.sh
index e1e0175c12..ce64bb660b 100644
--- a/t/t5411/test-0000-standard-git-push.sh
+++ b/t/t5411/test-0000-standard-git-push.sh
@@ -7,16 +7,16 @@ test_expect_success "git-push ($PROTOCOL)" '
HEAD:refs/heads/next \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/main
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- remote: # post-receive hook
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/main
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- To <URL/of/upstream.git>
- <OID-A>..<OID-B> <COMMIT-B> -> main
- * [new branch] HEAD -> next
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/main Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/main Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > To <URL/of/upstream.git>
+ > <COMMIT-A>..<COMMIT-B> <COMMIT-B> -> main
+ > * [new branch] HEAD -> next
EOF
test_cmp expect actual &&
@@ -38,10 +38,10 @@ test_expect_success "git-push --atomic ($PROTOCOL)" '
-e "/^To / { p; }" \
-e "/^ ! / { p; }" \
<out-$test_count >actual &&
- cat >expect <<-EOF &&
- To <URL/of/upstream.git>
- ! [rejected] main -> main (non-fast-forward)
- ! [rejected] <COMMIT-B> -> next (atomic push failed)
+ format_and_save_expect <<-EOF &&
+ > To <URL/of/upstream.git>
+ > ! [rejected] main -> main (non-fast-forward)
+ > ! [rejected] <COMMIT-B> -> next (atomic push failed)
EOF
test_cmp expect actual &&
@@ -63,14 +63,14 @@ test_expect_success "non-fast-forward git-push ($PROTOCOL)" '
$B:refs/heads/next \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/next
- remote: # post-receive hook
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/next
- To <URL/of/upstream.git>
- <OID-A>..<OID-B> <COMMIT-B> -> next
- ! [rejected] main -> main (non-fast-forward)
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/next Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/next Z
+ > To <URL/of/upstream.git>
+ > <COMMIT-A>..<COMMIT-B> <COMMIT-B> -> next
+ > ! [rejected] main -> main (non-fast-forward)
EOF
test_cmp expect actual &&
@@ -92,25 +92,25 @@ test_expect_success "git-push -f ($PROTOCOL)" '
HEAD:refs/heads/a/b/c \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <COMMIT-B> <COMMIT-A> refs/heads/main
- remote: pre-receive< <COMMIT-B> <ZERO-OID> refs/heads/next
- remote: pre-receive< <ZERO-OID> <TAG-v123> refs/tags/v123
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/review/main/topic
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/a/b/c
- remote: # post-receive hook
- remote: post-receive< <COMMIT-B> <COMMIT-A> refs/heads/main
- remote: post-receive< <COMMIT-B> <ZERO-OID> refs/heads/next
- remote: post-receive< <ZERO-OID> <TAG-v123> refs/tags/v123
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/review/main/topic
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/a/b/c
- To <URL/of/upstream.git>
- + <OID-B>...<OID-A> main -> main (forced update)
- - [deleted] next
- * [new tag] v123 -> v123
- * [new reference] main -> refs/review/main/topic
- * [new branch] HEAD -> a/b/c
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <COMMIT-B> <COMMIT-A> refs/heads/main Z
+ > remote: pre-receive< <COMMIT-B> <ZERO-OID> refs/heads/next Z
+ > remote: pre-receive< <ZERO-OID> <TAG-v123> refs/tags/v123 Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/review/main/topic Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/a/b/c Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-B> <COMMIT-A> refs/heads/main Z
+ > remote: post-receive< <COMMIT-B> <ZERO-OID> refs/heads/next Z
+ > remote: post-receive< <ZERO-OID> <TAG-v123> refs/tags/v123 Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/review/main/topic Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/a/b/c Z
+ > To <URL/of/upstream.git>
+ > + <COMMIT-B>...<COMMIT-A> main -> main (forced update)
+ > - [deleted] next
+ > * [new tag] v123 -> v123
+ > * [new reference] main -> refs/review/main/topic
+ > * [new branch] HEAD -> a/b/c
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0001-standard-git-push--porcelain.sh b/t/t5411/test-0001-standard-git-push--porcelain.sh
index bcbda72341..373ec3d865 100644
--- a/t/t5411/test-0001-standard-git-push--porcelain.sh
+++ b/t/t5411/test-0001-standard-git-push--porcelain.sh
@@ -7,17 +7,17 @@ test_expect_success "git-push ($PROTOCOL/porcelain)" '
HEAD:refs/heads/next \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/main
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- remote: # post-receive hook
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/main
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- To <URL/of/upstream.git>
- <COMMIT-B>:refs/heads/main <OID-A>..<OID-B>
- * HEAD:refs/heads/next [new branch]
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/main Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/main Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > To <URL/of/upstream.git>
+ > <COMMIT-B>:refs/heads/main <COMMIT-A>..<COMMIT-B>
+ > * HEAD:refs/heads/next [new branch]
+ > Done
EOF
test_cmp expect actual &&
@@ -38,12 +38,12 @@ test_expect_success "git-push --atomic ($PROTOCOL/porcelain)" '
filter_out_user_friendly_and_stable_output \
-e "s/^# GETTEXT POISON #//" \
-e "/^To / { p; }" \
- -e "/^! / { p; }" \
+ -e "/^!/ { p; }" \
<out-$test_count >actual &&
- cat >expect <<-EOF &&
- To <URL/of/upstream.git>
- ! refs/heads/main:refs/heads/main [rejected] (non-fast-forward)
- ! <COMMIT-B>:refs/heads/next [rejected] (atomic push failed)
+ format_and_save_expect <<-EOF &&
+ > To <URL/of/upstream.git>
+ > ! refs/heads/main:refs/heads/main [rejected] (non-fast-forward)
+ > ! <COMMIT-B>:refs/heads/next [rejected] (atomic push failed)
EOF
test_cmp expect actual &&
@@ -65,15 +65,15 @@ test_expect_success "non-fast-forward git-push ($PROTOCOL/porcelain)" '
$B:refs/heads/next \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/next
- remote: # post-receive hook
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/next
- To <URL/of/upstream.git>
- <COMMIT-B>:refs/heads/next <OID-A>..<OID-B>
- ! refs/heads/main:refs/heads/main [rejected] (non-fast-forward)
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/next Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/next Z
+ > To <URL/of/upstream.git>
+ > <COMMIT-B>:refs/heads/next <COMMIT-A>..<COMMIT-B>
+ > ! refs/heads/main:refs/heads/main [rejected] (non-fast-forward)
+ > Done
EOF
test_cmp expect actual &&
@@ -95,26 +95,26 @@ test_expect_success "git-push -f ($PROTOCOL/porcelain)" '
HEAD:refs/heads/a/b/c \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <COMMIT-B> <COMMIT-A> refs/heads/main
- remote: pre-receive< <COMMIT-B> <ZERO-OID> refs/heads/next
- remote: pre-receive< <ZERO-OID> <TAG-v123> refs/tags/v123
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/review/main/topic
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/a/b/c
- remote: # post-receive hook
- remote: post-receive< <COMMIT-B> <COMMIT-A> refs/heads/main
- remote: post-receive< <COMMIT-B> <ZERO-OID> refs/heads/next
- remote: post-receive< <ZERO-OID> <TAG-v123> refs/tags/v123
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/review/main/topic
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/a/b/c
- To <URL/of/upstream.git>
- + refs/heads/main:refs/heads/main <OID-B>...<OID-A> (forced update)
- - :refs/heads/next [deleted]
- * refs/tags/v123:refs/tags/v123 [new tag]
- * refs/heads/main:refs/review/main/topic [new reference]
- * HEAD:refs/heads/a/b/c [new branch]
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <COMMIT-B> <COMMIT-A> refs/heads/main Z
+ > remote: pre-receive< <COMMIT-B> <ZERO-OID> refs/heads/next Z
+ > remote: pre-receive< <ZERO-OID> <TAG-v123> refs/tags/v123 Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/review/main/topic Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/a/b/c Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-B> <COMMIT-A> refs/heads/main Z
+ > remote: post-receive< <COMMIT-B> <ZERO-OID> refs/heads/next Z
+ > remote: post-receive< <ZERO-OID> <TAG-v123> refs/tags/v123 Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/review/main/topic Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/a/b/c Z
+ > To <URL/of/upstream.git>
+ > + refs/heads/main:refs/heads/main <COMMIT-B>...<COMMIT-A> (forced update)
+ > - :refs/heads/next [deleted]
+ > * refs/tags/v123:refs/tags/v123 [new tag]
+ > * refs/heads/main:refs/review/main/topic [new reference]
+ > * HEAD:refs/heads/a/b/c [new branch]
+ > Done
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0003-pre-receive-declined--porcelain.sh b/t/t5411/test-0003-pre-receive-declined--porcelain.sh
index e9c9db5d1f..2393b04ad9 100644
--- a/t/t5411/test-0003-pre-receive-declined--porcelain.sh
+++ b/t/t5411/test-0003-pre-receive-declined--porcelain.sh
@@ -14,10 +14,10 @@ test_expect_success "git-push is declined ($PROTOCOL/porcelain)" '
HEAD:refs/heads/next \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- To <URL/of/upstream.git>
- ! <COMMIT-B>:refs/heads/main [remote rejected] (pre-receive hook declined)
- ! HEAD:refs/heads/next [remote rejected] (pre-receive hook declined)
+ format_and_save_expect <<-EOF &&
+ > To <URL/of/upstream.git>
+ > ! <COMMIT-B>:refs/heads/main [remote rejected] (pre-receive hook declined)
+ > ! HEAD:refs/heads/next [remote rejected] (pre-receive hook declined)
Done
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0011-no-hook-error.sh b/t/t5411/test-0011-no-hook-error.sh
index 3ef136e6ef..d35002b1f0 100644
--- a/t/t5411/test-0011-no-hook-error.sh
+++ b/t/t5411/test-0011-no-hook-error.sh
@@ -7,16 +7,16 @@ test_expect_success "proc-receive: no hook, fail to push special ref ($PROTOCOL)
HEAD:refs/for/main/topic \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: error: cannot find hook "proc-receive"
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- To <URL/of/upstream.git>
- * [new branch] HEAD -> next
- ! [remote rejected] HEAD -> refs/for/main/topic (fail to run proc-receive hook)
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: error: cannot find hook "proc-receive" Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > To <URL/of/upstream.git>
+ > * [new branch] HEAD -> next
+ > ! [remote rejected] HEAD -> refs/for/main/topic (fail to run proc-receive hook)
EOF
test_cmp expect actual &&
@@ -41,16 +41,16 @@ test_expect_success "proc-receive: no hook, all failed for atomic push ($PROTOCO
HEAD:next \
HEAD:refs/for/main/topic >out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/main
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: error: cannot find hook "proc-receive"
- To <URL/of/upstream.git>
- ! [remote rejected] <COMMIT-B> -> main (fail to run proc-receive hook)
- ! [remote rejected] HEAD -> next (fail to run proc-receive hook)
- ! [remote rejected] HEAD -> refs/for/main/topic (fail to run proc-receive hook)
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/main Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: error: cannot find hook "proc-receive" Z
+ > To <URL/of/upstream.git>
+ > ! [remote rejected] <COMMIT-B> -> main (fail to run proc-receive hook)
+ > ! [remote rejected] HEAD -> next (fail to run proc-receive hook)
+ > ! [remote rejected] HEAD -> refs/for/main/topic (fail to run proc-receive hook)
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0012-no-hook-error--porcelain.sh b/t/t5411/test-0012-no-hook-error--porcelain.sh
index 19f66fbd7d..04468b5018 100644
--- a/t/t5411/test-0012-no-hook-error--porcelain.sh
+++ b/t/t5411/test-0012-no-hook-error--porcelain.sh
@@ -7,16 +7,16 @@ test_expect_success "proc-receive: no hook, fail to push special ref ($PROTOCOL/
HEAD:refs/for/main/topic \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: error: cannot find hook "proc-receive"
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- To <URL/of/upstream.git>
- * HEAD:refs/heads/next [new branch]
- ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook)
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: error: cannot find hook "proc-receive" Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > To <URL/of/upstream.git>
+ > * HEAD:refs/heads/next [new branch]
+ > ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook)
Done
EOF
test_cmp expect actual &&
@@ -42,17 +42,17 @@ test_expect_success "proc-receive: no hook, all failed for atomic push ($PROTOCO
HEAD:next \
HEAD:refs/for/main/topic >out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/main
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: error: cannot find hook "proc-receive"
- To <URL/of/upstream.git>
- ! <COMMIT-B>:refs/heads/main [remote rejected] (fail to run proc-receive hook)
- ! HEAD:refs/heads/next [remote rejected] (fail to run proc-receive hook)
- ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook)
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/main Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: error: cannot find hook "proc-receive" Z
+ > To <URL/of/upstream.git>
+ > ! <COMMIT-B>:refs/heads/main [remote rejected] (fail to run proc-receive hook)
+ > ! HEAD:refs/heads/next [remote rejected] (fail to run proc-receive hook)
+ > ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook)
+ > Done
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0013-bad-protocol.sh b/t/t5411/test-0013-bad-protocol.sh
index 095e613f6f..c08a00ded2 100644
--- a/t/t5411/test-0013-bad-protocol.sh
+++ b/t/t5411/test-0013-bad-protocol.sh
@@ -29,8 +29,8 @@ test_expect_success "proc-receive: bad protocol (unknown version, $PROTOCOL)" '
# message ("remote: fatal: the remote end hung up unexpectedly") which
# is different from the remote HTTP server with different locale settings.
grep "^remote: error:" <actual >actual-error &&
- cat >expect <<-EOF &&
- remote: error: proc-receive version "2" is not supported
+ format_and_save_expect <<-EOF &&
+ > remote: error: proc-receive version "2" is not supported Z
EOF
test_cmp expect actual-error &&
@@ -208,17 +208,17 @@ test_expect_success "proc-receive: bad protocol (no report, $PROTOCOL)" '
HEAD:refs/heads/next \
HEAD:refs/for/main/topic >out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- To <URL/of/upstream.git>
- * [new branch] HEAD -> next
- ! [remote rejected] HEAD -> refs/for/main/topic (proc-receive failed to report status)
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > To <URL/of/upstream.git>
+ > * [new branch] HEAD -> next
+ > ! [remote rejected] HEAD -> refs/for/main/topic (proc-receive failed to report status)
EOF
test_cmp expect actual &&
@@ -251,15 +251,15 @@ test_expect_success "proc-receive: bad protocol (no ref, $PROTOCOL)" '
HEAD:refs/for/main/topic\
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok
- remote: error: proc-receive reported incomplete status line: "ok"
- To <URL/of/upstream.git>
- ! [remote rejected] HEAD -> refs/for/main/topic (proc-receive failed to report status)
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok Z
+ > remote: error: proc-receive reported incomplete status line: "ok" Z
+ > To <URL/of/upstream.git>
+ > ! [remote rejected] HEAD -> refs/for/main/topic (proc-receive failed to report status)
EOF
test_cmp expect actual &&
@@ -284,15 +284,15 @@ test_expect_success "proc-receive: bad protocol (unknown status, $PROTOCOL)" '
HEAD:refs/for/main/topic \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> xx refs/for/main/topic
- remote: error: proc-receive reported bad status "xx" on ref "refs/for/main/topic"
- To <URL/of/upstream.git>
- ! [remote rejected] HEAD -> refs/for/main/topic (proc-receive failed to report status)
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> xx refs/for/main/topic Z
+ > remote: error: proc-receive reported bad status "xx" on ref "refs/for/main/topic" Z
+ > To <URL/of/upstream.git>
+ > ! [remote rejected] HEAD -> refs/for/main/topic (proc-receive failed to report status)
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0014-bad-protocol--porcelain.sh b/t/t5411/test-0014-bad-protocol--porcelain.sh
index a44649789c..3eaa597e0f 100644
--- a/t/t5411/test-0014-bad-protocol--porcelain.sh
+++ b/t/t5411/test-0014-bad-protocol--porcelain.sh
@@ -20,7 +20,7 @@ test_expect_success "proc-receive: bad protocol (unknown version, $PROTOCOL/porc
<actual >actual-report &&
cat >expect <<-EOF &&
To <URL/of/upstream.git>
- ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook)
+ ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook)
Done
EOF
test_cmp expect actual-report &&
@@ -29,8 +29,8 @@ test_expect_success "proc-receive: bad protocol (unknown version, $PROTOCOL/porc
# message ("remote: fatal: the remote end hung up unexpectedly") which
# is different from the remote HTTP server with different locale settings.
grep "^remote: error:" <actual >actual-error &&
- cat >expect <<-EOF &&
- remote: error: proc-receive version "2" is not supported
+ format_and_save_expect <<-EOF &&
+ > remote: error: proc-receive version "2" is not supported Z
EOF
test_cmp expect actual-error &&
@@ -58,7 +58,7 @@ test_expect_success "proc-receive: bad protocol (hook --die-read-version, $PROTO
<out-$test_count >actual &&
cat >expect <<-EOF &&
To <URL/of/upstream.git>
- ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook)
+ ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook)
Done
EOF
test_cmp expect actual &&
@@ -89,7 +89,7 @@ test_expect_success "proc-receive: bad protocol (hook --die-write-version, $PROT
<out-$test_count >actual &&
cat >expect <<-EOF &&
To <URL/of/upstream.git>
- ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook)
+ ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook)
Done
EOF
test_cmp expect actual &&
@@ -120,7 +120,7 @@ test_expect_success "proc-receive: bad protocol (hook --die-read-commands, $PROT
<out-$test_count >actual &&
cat >expect <<-EOF &&
To <URL/of/upstream.git>
- ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook)
+ ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook)
Done
EOF
test_cmp expect actual &&
@@ -152,7 +152,7 @@ test_expect_success "proc-receive: bad protocol (hook --die-read-push-options, $
<out-$test_count >actual &&
cat >expect <<-EOF &&
To <URL/of/upstream.git>
- ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook)
+ ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook)
Done
EOF
test_cmp expect actual &&
@@ -182,7 +182,7 @@ test_expect_success "proc-receive: bad protocol (hook --die-write-report, $PROTO
<out-$test_count >actual &&
cat >expect <<-EOF &&
To <URL/of/upstream.git>
- ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook)
+ ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook)
Done
EOF
test_cmp expect actual &&
@@ -208,18 +208,18 @@ test_expect_success "proc-receive: bad protocol (no report, $PROTOCOL/porcelain)
HEAD:refs/heads/next \
HEAD:refs/for/main/topic >out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- To <URL/of/upstream.git>
- * HEAD:refs/heads/next [new branch]
- ! HEAD:refs/for/main/topic [remote rejected] (proc-receive failed to report status)
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > To <URL/of/upstream.git>
+ > * HEAD:refs/heads/next [new branch]
+ > ! HEAD:refs/for/main/topic [remote rejected] (proc-receive failed to report status)
+ > Done
EOF
test_cmp expect actual &&
@@ -251,16 +251,16 @@ test_expect_success "proc-receive: bad protocol (no ref, $PROTOCOL/porcelain)" '
HEAD:refs/for/main/topic\
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok
- remote: error: proc-receive reported incomplete status line: "ok"
- To <URL/of/upstream.git>
- ! HEAD:refs/for/main/topic [remote rejected] (proc-receive failed to report status)
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok Z
+ > remote: error: proc-receive reported incomplete status line: "ok" Z
+ > To <URL/of/upstream.git>
+ > ! HEAD:refs/for/main/topic [remote rejected] (proc-receive failed to report status)
+ > Done
EOF
test_cmp expect actual &&
@@ -285,16 +285,16 @@ test_expect_success "proc-receive: bad protocol (unknown status, $PROTOCOL/porce
HEAD:refs/for/main/topic \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> xx refs/for/main/topic
- remote: error: proc-receive reported bad status "xx" on ref "refs/for/main/topic"
- To <URL/of/upstream.git>
- ! HEAD:refs/for/main/topic [remote rejected] (proc-receive failed to report status)
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> xx refs/for/main/topic Z
+ > remote: error: proc-receive reported bad status "xx" on ref "refs/for/main/topic" Z
+ > To <URL/of/upstream.git>
+ > ! HEAD:refs/for/main/topic [remote rejected] (proc-receive failed to report status)
+ > Done
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0020-report-ng.sh b/t/t5411/test-0020-report-ng.sh
index ad2c8f6535..e915dbc28d 100644
--- a/t/t5411/test-0020-report-ng.sh
+++ b/t/t5411/test-0020-report-ng.sh
@@ -14,14 +14,14 @@ test_expect_success "proc-receive: fail to update (ng, no message, $PROTOCOL)" '
HEAD:refs/for/main/topic \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ng refs/for/main/topic
- To <URL/of/upstream.git>
- ! [remote rejected] HEAD -> refs/for/main/topic (failed)
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ng refs/for/main/topic Z
+ > To <URL/of/upstream.git>
+ > ! [remote rejected] HEAD -> refs/for/main/topic (failed)
EOF
test_cmp expect actual &&
@@ -46,14 +46,14 @@ test_expect_success "proc-receive: fail to update (ng, with message, $PROTOCOL)"
HEAD:refs/for/main/topic \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ng refs/for/main/topic error msg
- To <URL/of/upstream.git>
- ! [remote rejected] HEAD -> refs/for/main/topic (error msg)
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ng refs/for/main/topic error msg Z
+ > To <URL/of/upstream.git>
+ > ! [remote rejected] HEAD -> refs/for/main/topic (error msg)
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0021-report-ng--porcelain.sh b/t/t5411/test-0021-report-ng--porcelain.sh
index d8ae9d3414..2a392e099b 100644
--- a/t/t5411/test-0021-report-ng--porcelain.sh
+++ b/t/t5411/test-0021-report-ng--porcelain.sh
@@ -14,15 +14,15 @@ test_expect_success "proc-receive: fail to update (ng, no message, $PROTOCOL/por
HEAD:refs/for/main/topic \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ng refs/for/main/topic
- To <URL/of/upstream.git>
- ! HEAD:refs/for/main/topic [remote rejected] (failed)
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ng refs/for/main/topic Z
+ > To <URL/of/upstream.git>
+ > ! HEAD:refs/for/main/topic [remote rejected] (failed)
+ > Done
EOF
test_cmp expect actual &&
@@ -47,15 +47,15 @@ test_expect_success "proc-receive: fail to update (ng, with message, $PROTOCOL/p
HEAD:refs/for/main/topic \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ng refs/for/main/topic error msg
- To <URL/of/upstream.git>
- ! HEAD:refs/for/main/topic [remote rejected] (error msg)
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ng refs/for/main/topic error msg Z
+ > To <URL/of/upstream.git>
+ > ! HEAD:refs/for/main/topic [remote rejected] (error msg)
+ > Done
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0022-report-unexpect-ref.sh b/t/t5411/test-0022-report-unexpect-ref.sh
index dbed467186..f7a494bdb9 100644
--- a/t/t5411/test-0022-report-unexpect-ref.sh
+++ b/t/t5411/test-0022-report-unexpect-ref.sh
@@ -15,19 +15,19 @@ test_expect_success "proc-receive: report unexpected ref ($PROTOCOL)" '
HEAD:refs/for/main/topic \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/main
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/heads/main
- remote: error: proc-receive reported status on unexpected ref: refs/heads/main
- remote: # post-receive hook
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/main
- To <URL/of/upstream.git>
- <OID-A>..<OID-B> <COMMIT-B> -> main
- ! [remote rejected] HEAD -> refs/for/main/topic (proc-receive failed to report status)
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/main Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/heads/main Z
+ > remote: error: proc-receive reported status on unexpected ref: refs/heads/main Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/main Z
+ > To <URL/of/upstream.git>
+ > <COMMIT-A>..<COMMIT-B> <COMMIT-B> -> main
+ > ! [remote rejected] HEAD -> refs/for/main/topic (proc-receive failed to report status)
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0023-report-unexpect-ref--porcelain.sh b/t/t5411/test-0023-report-unexpect-ref--porcelain.sh
index e89096fa13..63c479e975 100644
--- a/t/t5411/test-0023-report-unexpect-ref--porcelain.sh
+++ b/t/t5411/test-0023-report-unexpect-ref--porcelain.sh
@@ -15,20 +15,20 @@ test_expect_success "proc-receive: report unexpected ref ($PROTOCOL/porcelain)"
HEAD:refs/for/main/topic \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/main
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/heads/main
- remote: error: proc-receive reported status on unexpected ref: refs/heads/main
- remote: # post-receive hook
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/main
- To <URL/of/upstream.git>
- <COMMIT-B>:refs/heads/main <OID-A>..<OID-B>
- ! HEAD:refs/for/main/topic [remote rejected] (proc-receive failed to report status)
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/main Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/heads/main Z
+ > remote: error: proc-receive reported status on unexpected ref: refs/heads/main Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/main Z
+ > To <URL/of/upstream.git>
+ > <COMMIT-B>:refs/heads/main <COMMIT-A>..<COMMIT-B>
+ > ! HEAD:refs/for/main/topic [remote rejected] (proc-receive failed to report status)
+ > Done
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0024-report-unknown-ref.sh b/t/t5411/test-0024-report-unknown-ref.sh
index 77204244b8..af055aa086 100644
--- a/t/t5411/test-0024-report-unknown-ref.sh
+++ b/t/t5411/test-0024-report-unknown-ref.sh
@@ -14,15 +14,15 @@ test_expect_success "proc-receive: report unknown reference ($PROTOCOL)" '
HEAD:refs/for/a/b/c/my/topic \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/my/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/my/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: error: proc-receive reported status on unknown ref: refs/for/main/topic
- To <URL/of/upstream.git>
- ! [remote rejected] HEAD -> refs/for/a/b/c/my/topic (proc-receive failed to report status)
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/my/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/my/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: error: proc-receive reported status on unknown ref: refs/for/main/topic Z
+ > To <URL/of/upstream.git>
+ > ! [remote rejected] HEAD -> refs/for/a/b/c/my/topic (proc-receive failed to report status)
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0025-report-unknown-ref--porcelain.sh b/t/t5411/test-0025-report-unknown-ref--porcelain.sh
index eeb1ce6b2c..99601ca321 100644
--- a/t/t5411/test-0025-report-unknown-ref--porcelain.sh
+++ b/t/t5411/test-0025-report-unknown-ref--porcelain.sh
@@ -14,16 +14,16 @@ test_expect_success "proc-receive: report unknown reference ($PROTOCOL/porcelain
HEAD:refs/for/a/b/c/my/topic \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/my/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/my/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: error: proc-receive reported status on unknown ref: refs/for/main/topic
- To <URL/of/upstream.git>
- ! HEAD:refs/for/a/b/c/my/topic [remote rejected] (proc-receive failed to report status)
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/my/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/my/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: error: proc-receive reported status on unknown ref: refs/for/main/topic Z
+ > To <URL/of/upstream.git>
+ > ! HEAD:refs/for/a/b/c/my/topic [remote rejected] (proc-receive failed to report status)
+ > Done
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0026-push-options.sh b/t/t5411/test-0026-push-options.sh
index 1ec2cb95bc..fec5f95793 100644
--- a/t/t5411/test-0026-push-options.sh
+++ b/t/t5411/test-0026-push-options.sh
@@ -52,19 +52,19 @@ test_expect_success "proc-receive: ignore push-options for version 0 ($PROTOCOL)
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- To <URL/of/upstream.git>
- * [new branch] HEAD -> next
- * [new reference] HEAD -> refs/for/main/topic
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > To <URL/of/upstream.git>
+ > * [new branch] HEAD -> next
+ > * [new reference] HEAD -> refs/for/main/topic
EOF
test_cmp expect actual &&
@@ -101,22 +101,22 @@ test_expect_success "proc-receive: push with options ($PROTOCOL)" '
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive: atomic push_options
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive< issue=123
- remote: proc-receive< reviewer=user1
- remote: proc-receive> ok refs/for/main/topic
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- To <URL/of/upstream.git>
- * [new branch] HEAD -> next
- * [new reference] HEAD -> refs/for/main/topic
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive: atomic push_options Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive< issue=123 Z
+ > remote: proc-receive< reviewer=user1 Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > To <URL/of/upstream.git>
+ > * [new branch] HEAD -> next
+ > * [new reference] HEAD -> refs/for/main/topic
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0027-push-options--porcelain.sh b/t/t5411/test-0027-push-options--porcelain.sh
index 447fbfec0c..8fb75a8789 100644
--- a/t/t5411/test-0027-push-options--porcelain.sh
+++ b/t/t5411/test-0027-push-options--porcelain.sh
@@ -54,20 +54,20 @@ test_expect_success "proc-receive: ignore push-options for version 0 ($PROTOCOL/
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- To <URL/of/upstream.git>
- * HEAD:refs/heads/next [new branch]
- * HEAD:refs/for/main/topic [new reference]
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > To <URL/of/upstream.git>
+ > * HEAD:refs/heads/next [new branch]
+ > * HEAD:refs/for/main/topic [new reference]
+ > Done
EOF
test_cmp expect actual &&
@@ -105,23 +105,23 @@ test_expect_success "proc-receive: push with options ($PROTOCOL/porcelain)" '
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive: atomic push_options
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive< issue=123
- remote: proc-receive< reviewer=user1
- remote: proc-receive> ok refs/for/main/topic
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- To <URL/of/upstream.git>
- * HEAD:refs/heads/next [new branch]
- * HEAD:refs/for/main/topic [new reference]
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive: atomic push_options Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive< issue=123 Z
+ > remote: proc-receive< reviewer=user1 Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > To <URL/of/upstream.git>
+ > * HEAD:refs/heads/next [new branch]
+ > * HEAD:refs/for/main/topic [new reference]
+ > Done
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0030-report-ok.sh b/t/t5411/test-0030-report-ok.sh
index 8acb4f204f..a3a6278213 100644
--- a/t/t5411/test-0030-report-ok.sh
+++ b/t/t5411/test-0030-report-ok.sh
@@ -14,16 +14,16 @@ test_expect_success "proc-receive: ok ($PROTOCOL)" '
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- To <URL/of/upstream.git>
- * [new reference] HEAD -> refs/for/main/topic
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > To <URL/of/upstream.git>
+ > * [new reference] HEAD -> refs/for/main/topic
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0031-report-ok--porcelain.sh b/t/t5411/test-0031-report-ok--porcelain.sh
index a967718046..0e175388b6 100644
--- a/t/t5411/test-0031-report-ok--porcelain.sh
+++ b/t/t5411/test-0031-report-ok--porcelain.sh
@@ -14,17 +14,17 @@ test_expect_success "proc-receive: ok ($PROTOCOL/porcelain)" '
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- To <URL/of/upstream.git>
- * HEAD:refs/for/main/topic [new reference]
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > To <URL/of/upstream.git>
+ > * HEAD:refs/for/main/topic [new reference]
+ > Done
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0032-report-with-options.sh b/t/t5411/test-0032-report-with-options.sh
index 437ade012d..988a4302a6 100644
--- a/t/t5411/test-0032-report-with-options.sh
+++ b/t/t5411/test-0032-report-with-options.sh
@@ -15,16 +15,16 @@ test_expect_success "proc-receive: report option without matching ok ($PROTOCOL)
HEAD:refs/for/main/topic \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> option refname refs/pull/123/head
- remote: proc-receive> option old-oid <COMMIT-B>
- remote: error: proc-receive reported "option" without a matching "ok/ng" directive
- To <URL/of/upstream.git>
- ! [remote rejected] HEAD -> refs/for/main/topic (proc-receive failed to report status)
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/pull/123/head Z
+ > remote: proc-receive> option old-oid <COMMIT-B> Z
+ > remote: error: proc-receive reported "option" without a matching "ok/ng" directive Z
+ > To <URL/of/upstream.git>
+ > ! [remote rejected] HEAD -> refs/for/main/topic (proc-receive failed to report status)
EOF
test_cmp expect actual
'
@@ -46,17 +46,17 @@ test_expect_success "proc-receive: report option refname ($PROTOCOL)" '
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/pull/123/head
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head
- To <URL/of/upstream.git>
- * [new reference] HEAD -> refs/pull/123/head
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/pull/123/head Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head Z
+ > To <URL/of/upstream.git>
+ > * [new reference] HEAD -> refs/pull/123/head
EOF
test_cmp expect actual
'
@@ -78,18 +78,18 @@ test_expect_success "proc-receive: report option refname and forced-update ($PRO
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/pull/123/head
- remote: proc-receive> option forced-update
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head
- To <URL/of/upstream.git>
- * [new reference] HEAD -> refs/pull/123/head
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/pull/123/head Z
+ > remote: proc-receive> option forced-update Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head Z
+ > To <URL/of/upstream.git>
+ > * [new reference] HEAD -> refs/pull/123/head
EOF
test_cmp expect actual
'
@@ -112,18 +112,18 @@ test_expect_success "proc-receive: report option refname and old-oid ($PROTOCOL)
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/pull/123/head
- remote: proc-receive> option old-oid <COMMIT-B>
- remote: # post-receive hook
- remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/123/head
- To <URL/of/upstream.git>
- <OID-B>..<OID-A> HEAD -> refs/pull/123/head
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/pull/123/head Z
+ > remote: proc-receive> option old-oid <COMMIT-B> Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/123/head Z
+ > To <URL/of/upstream.git>
+ > <COMMIT-B>..<COMMIT-A> HEAD -> refs/pull/123/head
EOF
test_cmp expect actual
'
@@ -145,17 +145,17 @@ test_expect_success "proc-receive: report option old-oid ($PROTOCOL)" '
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option old-oid <COMMIT-B>
- remote: # post-receive hook
- remote: post-receive< <COMMIT-B> <COMMIT-A> refs/for/main/topic
- To <URL/of/upstream.git>
- <OID-B>..<OID-A> HEAD -> refs/for/main/topic
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option old-oid <COMMIT-B> Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-B> <COMMIT-A> refs/for/main/topic Z
+ > To <URL/of/upstream.git>
+ > <COMMIT-B>..<COMMIT-A> HEAD -> refs/for/main/topic
EOF
test_cmp expect actual
'
@@ -178,18 +178,18 @@ test_expect_success "proc-receive: report option old-oid and new-oid ($PROTOCOL)
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option old-oid <COMMIT-A>
- remote: proc-receive> option new-oid <COMMIT-B>
- remote: # post-receive hook
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/main/topic
- To <URL/of/upstream.git>
- <OID-A>..<OID-B> HEAD -> refs/for/main/topic
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option old-oid <COMMIT-A> Z
+ > remote: proc-receive> option new-oid <COMMIT-B> Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/main/topic Z
+ > To <URL/of/upstream.git>
+ > <COMMIT-A>..<COMMIT-B> HEAD -> refs/for/main/topic
EOF
test_cmp expect actual
'
@@ -219,31 +219,31 @@ test_expect_success "proc-receive: report with multiple rewrites ($PROTOCOL)" '
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/a/b/c/topic
- remote: proc-receive> ok refs/for/next/topic
- remote: proc-receive> option refname refs/pull/123/head
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/pull/124/head
- remote: proc-receive> option old-oid <COMMIT-B>
- remote: proc-receive> option forced-update
- remote: proc-receive> option new-oid <COMMIT-A>
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
- remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/124/head
- To <URL/of/upstream.git>
- * [new reference] HEAD -> refs/pull/123/head
- * [new reference] HEAD -> refs/for/a/b/c/topic
- + <OID-B>...<OID-A> HEAD -> refs/pull/124/head (forced update)
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/a/b/c/topic Z
+ > remote: proc-receive> ok refs/for/next/topic Z
+ > remote: proc-receive> option refname refs/pull/123/head Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/pull/124/head Z
+ > remote: proc-receive> option old-oid <COMMIT-B> Z
+ > remote: proc-receive> option forced-update Z
+ > remote: proc-receive> option new-oid <COMMIT-A> Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic Z
+ > remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/124/head Z
+ > To <URL/of/upstream.git>
+ > * [new reference] HEAD -> refs/pull/123/head
+ > * [new reference] HEAD -> refs/for/a/b/c/topic
+ > + <COMMIT-B>...<COMMIT-A> HEAD -> refs/pull/124/head (forced update)
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0033-report-with-options--porcelain.sh b/t/t5411/test-0033-report-with-options--porcelain.sh
index 11486720ee..daacb3d69d 100644
--- a/t/t5411/test-0033-report-with-options--porcelain.sh
+++ b/t/t5411/test-0033-report-with-options--porcelain.sh
@@ -15,17 +15,17 @@ test_expect_success "proc-receive: report option without matching ok ($PROTOCOL/
HEAD:refs/for/main/topic \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> option refname refs/pull/123/head
- remote: proc-receive> option old-oid <COMMIT-B>
- remote: error: proc-receive reported "option" without a matching "ok/ng" directive
- To <URL/of/upstream.git>
- ! HEAD:refs/for/main/topic [remote rejected] (proc-receive failed to report status)
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/pull/123/head Z
+ > remote: proc-receive> option old-oid <COMMIT-B> Z
+ > remote: error: proc-receive reported "option" without a matching "ok/ng" directive Z
+ > To <URL/of/upstream.git>
+ > ! HEAD:refs/for/main/topic [remote rejected] (proc-receive failed to report status)
+ > Done
EOF
test_cmp expect actual
'
@@ -47,18 +47,18 @@ test_expect_success "proc-receive: report option refname ($PROTOCOL/porcelain)"
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/pull/123/head
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head
- To <URL/of/upstream.git>
- * HEAD:refs/pull/123/head [new reference]
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/pull/123/head Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head Z
+ > To <URL/of/upstream.git>
+ > * HEAD:refs/pull/123/head [new reference]
+ > Done
EOF
test_cmp expect actual
'
@@ -81,19 +81,19 @@ test_expect_success "proc-receive: report option refname and forced-update ($PRO
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/pull/123/head
- remote: proc-receive> option forced-update
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head
- To <URL/of/upstream.git>
- * HEAD:refs/pull/123/head [new reference]
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/pull/123/head Z
+ > remote: proc-receive> option forced-update Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head Z
+ > To <URL/of/upstream.git>
+ > * HEAD:refs/pull/123/head [new reference]
+ > Done
EOF
test_cmp expect actual
'
@@ -116,19 +116,19 @@ test_expect_success "proc-receive: report option refname and old-oid ($PROTOCOL/
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/pull/123/head
- remote: proc-receive> option old-oid <COMMIT-B>
- remote: # post-receive hook
- remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/123/head
- To <URL/of/upstream.git>
- HEAD:refs/pull/123/head <OID-B>..<OID-A>
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/pull/123/head Z
+ > remote: proc-receive> option old-oid <COMMIT-B> Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/123/head Z
+ > To <URL/of/upstream.git>
+ > HEAD:refs/pull/123/head <COMMIT-B>..<COMMIT-A>
+ > Done
EOF
test_cmp expect actual
'
@@ -150,18 +150,18 @@ test_expect_success "proc-receive: report option old-oid ($PROTOCOL/porcelain)"
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option old-oid <COMMIT-B>
- remote: # post-receive hook
- remote: post-receive< <COMMIT-B> <COMMIT-A> refs/for/main/topic
- To <URL/of/upstream.git>
- HEAD:refs/for/main/topic <OID-B>..<OID-A>
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option old-oid <COMMIT-B> Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-B> <COMMIT-A> refs/for/main/topic Z
+ > To <URL/of/upstream.git>
+ > HEAD:refs/for/main/topic <COMMIT-B>..<COMMIT-A>
+ > Done
EOF
test_cmp expect actual
'
@@ -184,19 +184,19 @@ test_expect_success "proc-receive: report option old-oid and new-oid ($PROTOCOL/
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option old-oid <COMMIT-A>
- remote: proc-receive> option new-oid <COMMIT-B>
- remote: # post-receive hook
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/main/topic
- To <URL/of/upstream.git>
- HEAD:refs/for/main/topic <OID-A>..<OID-B>
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option old-oid <COMMIT-A> Z
+ > remote: proc-receive> option new-oid <COMMIT-B> Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/main/topic Z
+ > To <URL/of/upstream.git>
+ > HEAD:refs/for/main/topic <COMMIT-A>..<COMMIT-B>
+ > Done
EOF
test_cmp expect actual
'
@@ -227,32 +227,32 @@ test_expect_success "proc-receive: report with multiple rewrites ($PROTOCOL/porc
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/a/b/c/topic
- remote: proc-receive> ok refs/for/next/topic
- remote: proc-receive> option refname refs/pull/123/head
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/pull/124/head
- remote: proc-receive> option old-oid <COMMIT-B>
- remote: proc-receive> option forced-update
- remote: proc-receive> option new-oid <COMMIT-A>
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
- remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/124/head
- To <URL/of/upstream.git>
- * HEAD:refs/pull/123/head [new reference]
- * HEAD:refs/for/a/b/c/topic [new reference]
- + HEAD:refs/pull/124/head <OID-B>...<OID-A> (forced update)
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/a/b/c/topic Z
+ > remote: proc-receive> ok refs/for/next/topic Z
+ > remote: proc-receive> option refname refs/pull/123/head Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/pull/124/head Z
+ > remote: proc-receive> option old-oid <COMMIT-B> Z
+ > remote: proc-receive> option forced-update Z
+ > remote: proc-receive> option new-oid <COMMIT-A> Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic Z
+ > remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/124/head Z
+ > To <URL/of/upstream.git>
+ > * HEAD:refs/pull/123/head [new reference]
+ > * HEAD:refs/for/a/b/c/topic [new reference]
+ > + HEAD:refs/pull/124/head <COMMIT-B>...<COMMIT-A> (forced update)
+ > Done
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0034-report-ft.sh b/t/t5411/test-0034-report-ft.sh
index 6e0d08b327..73a47d1ffd 100644
--- a/t/t5411/test-0034-report-ft.sh
+++ b/t/t5411/test-0034-report-ft.sh
@@ -15,17 +15,17 @@ test_expect_success "proc-receive: fall throught, let receive-pack to execute ($
$B:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-B> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-B> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option fall-through
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-B> refs/for/main/topic
- To <URL/of/upstream.git>
- * [new reference] <COMMIT-B> -> refs/for/main/topic
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-B> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-B> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option fall-through Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-B> refs/for/main/topic Z
+ > To <URL/of/upstream.git>
+ > * [new reference] <COMMIT-B> -> refs/for/main/topic
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0035-report-ft--porcelain.sh b/t/t5411/test-0035-report-ft--porcelain.sh
index 81bae9f2ec..c350201107 100644
--- a/t/t5411/test-0035-report-ft--porcelain.sh
+++ b/t/t5411/test-0035-report-ft--porcelain.sh
@@ -15,18 +15,18 @@ test_expect_success "proc-receive: fall throught, let receive-pack to execute ($
$B:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-B> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-B> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option fall-through
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-B> refs/for/main/topic
- To <URL/of/upstream.git>
- * <COMMIT-B>:refs/for/main/topic [new reference]
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-B> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-B> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option fall-through Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-B> refs/for/main/topic Z
+ > To <URL/of/upstream.git>
+ > * <COMMIT-B>:refs/for/main/topic [new reference]
+ > Done
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh b/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh
index be9b18b2b6..8c8a6c16e1 100644
--- a/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh
+++ b/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh
@@ -39,30 +39,30 @@ test_expect_success "proc-receive: multiple rewrite for one ref, no refname for
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option old-oid <COMMIT-A>
- remote: proc-receive> option new-oid <COMMIT-B>
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/changes/24/124/1
- remote: proc-receive> option old-oid <ZERO-OID>
- remote: proc-receive> option new-oid <COMMIT-A>
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/changes/25/125/1
- remote: proc-receive> option old-oid <COMMIT-A>
- remote: proc-receive> option new-oid <COMMIT-B>
- remote: # post-receive hook
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/main/topic
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/changes/24/124/1
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/changes/25/125/1
- To <URL/of/upstream.git>
- <OID-A>..<OID-B> HEAD -> refs/for/main/topic
- * [new reference] HEAD -> refs/changes/24/124/1
- <OID-A>..<OID-B> HEAD -> refs/changes/25/125/1
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option old-oid <COMMIT-A> Z
+ > remote: proc-receive> option new-oid <COMMIT-B> Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/changes/24/124/1 Z
+ > remote: proc-receive> option old-oid <ZERO-OID> Z
+ > remote: proc-receive> option new-oid <COMMIT-A> Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/changes/25/125/1 Z
+ > remote: proc-receive> option old-oid <COMMIT-A> Z
+ > remote: proc-receive> option new-oid <COMMIT-B> Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/main/topic Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/changes/24/124/1 Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/changes/25/125/1 Z
+ > To <URL/of/upstream.git>
+ > <COMMIT-A>..<COMMIT-B> HEAD -> refs/for/main/topic
+ > * [new reference] HEAD -> refs/changes/24/124/1
+ > <COMMIT-A>..<COMMIT-B> HEAD -> refs/changes/25/125/1
EOF
test_cmp expect actual &&
@@ -113,31 +113,31 @@ test_expect_success "proc-receive: multiple rewrites for one ref, no refname for
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/changes/24/124/1
- remote: proc-receive> option old-oid <ZERO-OID>
- remote: proc-receive> option new-oid <COMMIT-A>
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option old-oid <COMMIT-A>
- remote: proc-receive> option new-oid <COMMIT-B>
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/changes/25/125/1
- remote: proc-receive> option old-oid <COMMIT-B>
- remote: proc-receive> option new-oid <COMMIT-A>
- remote: proc-receive> option forced-update
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/changes/24/124/1
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/main/topic
- remote: post-receive< <COMMIT-B> <COMMIT-A> refs/changes/25/125/1
- To <URL/of/upstream.git>
- * [new reference] HEAD -> refs/changes/24/124/1
- <OID-A>..<OID-B> HEAD -> refs/for/main/topic
- + <OID-B>...<OID-A> HEAD -> refs/changes/25/125/1 (forced update)
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/changes/24/124/1 Z
+ > remote: proc-receive> option old-oid <ZERO-OID> Z
+ > remote: proc-receive> option new-oid <COMMIT-A> Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option old-oid <COMMIT-A> Z
+ > remote: proc-receive> option new-oid <COMMIT-B> Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/changes/25/125/1 Z
+ > remote: proc-receive> option old-oid <COMMIT-B> Z
+ > remote: proc-receive> option new-oid <COMMIT-A> Z
+ > remote: proc-receive> option forced-update Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/changes/24/124/1 Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/main/topic Z
+ > remote: post-receive< <COMMIT-B> <COMMIT-A> refs/changes/25/125/1 Z
+ > To <URL/of/upstream.git>
+ > * [new reference] HEAD -> refs/changes/24/124/1
+ > <COMMIT-A>..<COMMIT-B> HEAD -> refs/for/main/topic
+ > + <COMMIT-B>...<COMMIT-A> HEAD -> refs/changes/25/125/1 (forced update)
EOF
test_cmp expect actual &&
@@ -182,23 +182,23 @@ test_expect_success "proc-receive: multiple rewrites for one ref ($PROTOCOL)" '
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/changes/23/123/1
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/changes/24/124/2
- remote: proc-receive> option old-oid <COMMIT-A>
- remote: proc-receive> option new-oid <COMMIT-B>
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/changes/23/123/1
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/changes/24/124/2
- To <URL/of/upstream.git>
- * [new reference] HEAD -> refs/changes/23/123/1
- <OID-A>..<OID-B> HEAD -> refs/changes/24/124/2
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/changes/23/123/1 Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/changes/24/124/2 Z
+ > remote: proc-receive> option old-oid <COMMIT-A> Z
+ > remote: proc-receive> option new-oid <COMMIT-B> Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/changes/23/123/1 Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/changes/24/124/2 Z
+ > To <URL/of/upstream.git>
+ > * [new reference] HEAD -> refs/changes/23/123/1
+ > <COMMIT-A>..<COMMIT-B> HEAD -> refs/changes/24/124/2
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh b/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh
index 95fb89c031..bc44810f33 100644
--- a/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh
+++ b/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh
@@ -24,31 +24,31 @@ test_expect_success "proc-receive: multiple rewrite for one ref, no refname for
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option old-oid <COMMIT-A>
- remote: proc-receive> option new-oid <COMMIT-B>
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/changes/24/124/1
- remote: proc-receive> option old-oid <ZERO-OID>
- remote: proc-receive> option new-oid <COMMIT-A>
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/changes/25/125/1
- remote: proc-receive> option old-oid <COMMIT-A>
- remote: proc-receive> option new-oid <COMMIT-B>
- remote: # post-receive hook
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/main/topic
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/changes/24/124/1
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/changes/25/125/1
- To <URL/of/upstream.git>
- HEAD:refs/for/main/topic <OID-A>..<OID-B>
- * HEAD:refs/changes/24/124/1 [new reference]
- HEAD:refs/changes/25/125/1 <OID-A>..<OID-B>
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option old-oid <COMMIT-A> Z
+ > remote: proc-receive> option new-oid <COMMIT-B> Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/changes/24/124/1 Z
+ > remote: proc-receive> option old-oid <ZERO-OID> Z
+ > remote: proc-receive> option new-oid <COMMIT-A> Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/changes/25/125/1 Z
+ > remote: proc-receive> option old-oid <COMMIT-A> Z
+ > remote: proc-receive> option new-oid <COMMIT-B> Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/main/topic Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/changes/24/124/1 Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/changes/25/125/1 Z
+ > To <URL/of/upstream.git>
+ > HEAD:refs/for/main/topic <COMMIT-A>..<COMMIT-B>
+ > * HEAD:refs/changes/24/124/1 [new reference]
+ > HEAD:refs/changes/25/125/1 <COMMIT-A>..<COMMIT-B>
+ > Done
EOF
test_cmp expect actual &&
@@ -84,32 +84,32 @@ test_expect_success "proc-receive: multiple rewrites for one ref, no refname for
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/changes/24/124/1
- remote: proc-receive> option old-oid <ZERO-OID>
- remote: proc-receive> option new-oid <COMMIT-A>
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option old-oid <COMMIT-A>
- remote: proc-receive> option new-oid <COMMIT-B>
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/changes/25/125/1
- remote: proc-receive> option old-oid <COMMIT-B>
- remote: proc-receive> option new-oid <COMMIT-A>
- remote: proc-receive> option forced-update
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/changes/24/124/1
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/main/topic
- remote: post-receive< <COMMIT-B> <COMMIT-A> refs/changes/25/125/1
- To <URL/of/upstream.git>
- * HEAD:refs/changes/24/124/1 [new reference]
- HEAD:refs/for/main/topic <OID-A>..<OID-B>
- + HEAD:refs/changes/25/125/1 <OID-B>...<OID-A> (forced update)
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/changes/24/124/1 Z
+ > remote: proc-receive> option old-oid <ZERO-OID> Z
+ > remote: proc-receive> option new-oid <COMMIT-A> Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option old-oid <COMMIT-A> Z
+ > remote: proc-receive> option new-oid <COMMIT-B> Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/changes/25/125/1 Z
+ > remote: proc-receive> option old-oid <COMMIT-B> Z
+ > remote: proc-receive> option new-oid <COMMIT-A> Z
+ > remote: proc-receive> option forced-update Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/changes/24/124/1 Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/main/topic Z
+ > remote: post-receive< <COMMIT-B> <COMMIT-A> refs/changes/25/125/1 Z
+ > To <URL/of/upstream.git>
+ > * HEAD:refs/changes/24/124/1 [new reference]
+ > HEAD:refs/for/main/topic <COMMIT-A>..<COMMIT-B>
+ > + HEAD:refs/changes/25/125/1 <COMMIT-B>...<COMMIT-A> (forced update)
+ > Done
EOF
test_cmp expect actual &&
@@ -139,24 +139,24 @@ test_expect_success "proc-receive: multiple rewrites for one ref ($PROTOCOL/porc
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/changes/23/123/1
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/changes/24/124/2
- remote: proc-receive> option old-oid <COMMIT-A>
- remote: proc-receive> option new-oid <COMMIT-B>
- remote: # post-receive hook
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/changes/23/123/1
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/changes/24/124/2
- To <URL/of/upstream.git>
- * HEAD:refs/changes/23/123/1 [new reference]
- HEAD:refs/changes/24/124/2 <OID-A>..<OID-B>
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/changes/23/123/1 Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/changes/24/124/2 Z
+ > remote: proc-receive> option old-oid <COMMIT-A> Z
+ > remote: proc-receive> option new-oid <COMMIT-B> Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/changes/23/123/1 Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/changes/24/124/2 Z
+ > To <URL/of/upstream.git>
+ > * HEAD:refs/changes/23/123/1 [new reference]
+ > HEAD:refs/changes/24/124/2 <COMMIT-A>..<COMMIT-B>
+ > Done
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0038-report-mixed-refs.sh b/t/t5411/test-0038-report-mixed-refs.sh
index 5e005299cc..e63fe7ba11 100644
--- a/t/t5411/test-0038-report-mixed-refs.sh
+++ b/t/t5411/test-0038-report-mixed-refs.sh
@@ -26,43 +26,43 @@ test_expect_success "proc-receive: report update of mixed refs ($PROTOCOL)" '
HEAD:refs/for/next/topic3 \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/main
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/bar
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/baz
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic2
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic1
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/foo
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic3
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic2
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic1
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic3
- remote: proc-receive> ok refs/for/next/topic2
- remote: proc-receive> ng refs/for/next/topic1 fail to call Web API
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/for/main/topic
- remote: proc-receive> option old-oid <COMMIT-A>
- remote: proc-receive> option new-oid <COMMIT-B>
- remote: # post-receive hook
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/main
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/bar
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/baz
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic2
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/foo
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/main/topic
- To <URL/of/upstream.git>
- <OID-A>..<OID-B> <COMMIT-B> -> main
- * [new branch] HEAD -> bar
- * [new branch] HEAD -> baz
- * [new reference] HEAD -> refs/for/next/topic2
- * [new branch] HEAD -> foo
- <OID-A>..<OID-B> HEAD -> refs/for/main/topic
- ! [remote rejected] HEAD -> refs/for/next/topic1 (fail to call Web API)
- ! [remote rejected] HEAD -> refs/for/next/topic3 (proc-receive failed to report status)
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/main Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/bar Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/baz Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic2 Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic1 Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/foo Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic3 Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic2 Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic1 Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic3 Z
+ > remote: proc-receive> ok refs/for/next/topic2 Z
+ > remote: proc-receive> ng refs/for/next/topic1 fail to call Web API Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/for/main/topic Z
+ > remote: proc-receive> option old-oid <COMMIT-A> Z
+ > remote: proc-receive> option new-oid <COMMIT-B> Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/main Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/bar Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/baz Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic2 Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/foo Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/main/topic Z
+ > To <URL/of/upstream.git>
+ > <COMMIT-A>..<COMMIT-B> <COMMIT-B> -> main
+ > * [new branch] HEAD -> bar
+ > * [new branch] HEAD -> baz
+ > * [new reference] HEAD -> refs/for/next/topic2
+ > * [new branch] HEAD -> foo
+ > <COMMIT-A>..<COMMIT-B> HEAD -> refs/for/main/topic
+ > ! [remote rejected] HEAD -> refs/for/next/topic1 (fail to call Web API)
+ > ! [remote rejected] HEAD -> refs/for/next/topic3 (proc-receive failed to report status)
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0039-report-mixed-refs--porcelain.sh b/t/t5411/test-0039-report-mixed-refs--porcelain.sh
index 8f891c5385..99d17b73af 100644
--- a/t/t5411/test-0039-report-mixed-refs--porcelain.sh
+++ b/t/t5411/test-0039-report-mixed-refs--porcelain.sh
@@ -26,44 +26,44 @@ test_expect_success "proc-receive: report update of mixed refs ($PROTOCOL/porcel
HEAD:refs/for/next/topic3 \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/main
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/bar
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/baz
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic2
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic1
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/foo
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic3
- remote: # proc-receive hook
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic2
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic1
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic3
- remote: proc-receive> ok refs/for/next/topic2
- remote: proc-receive> ng refs/for/next/topic1 fail to call Web API
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/for/main/topic
- remote: proc-receive> option old-oid <COMMIT-A>
- remote: proc-receive> option new-oid <COMMIT-B>
- remote: # post-receive hook
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/main
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/bar
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/baz
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic2
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/foo
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/main/topic
- To <URL/of/upstream.git>
- <COMMIT-B>:refs/heads/main <OID-A>..<OID-B>
- * HEAD:refs/heads/bar [new branch]
- * HEAD:refs/heads/baz [new branch]
- * HEAD:refs/for/next/topic2 [new reference]
- * HEAD:refs/heads/foo [new branch]
- HEAD:refs/for/main/topic <OID-A>..<OID-B>
- ! HEAD:refs/for/next/topic1 [remote rejected] (fail to call Web API)
- ! HEAD:refs/for/next/topic3 [remote rejected] (proc-receive failed to report status)
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/main Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/bar Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/baz Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic2 Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic1 Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/foo Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic3 Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic2 Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic1 Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic3 Z
+ > remote: proc-receive> ok refs/for/next/topic2 Z
+ > remote: proc-receive> ng refs/for/next/topic1 fail to call Web API Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/for/main/topic Z
+ > remote: proc-receive> option old-oid <COMMIT-A> Z
+ > remote: proc-receive> option new-oid <COMMIT-B> Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/main Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/bar Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/baz Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic2 Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/foo Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/main/topic Z
+ > To <URL/of/upstream.git>
+ > <COMMIT-B>:refs/heads/main <COMMIT-A>..<COMMIT-B>
+ > * HEAD:refs/heads/bar [new branch]
+ > * HEAD:refs/heads/baz [new branch]
+ > * HEAD:refs/for/next/topic2 [new reference]
+ > * HEAD:refs/heads/foo [new branch]
+ > HEAD:refs/for/main/topic <COMMIT-A>..<COMMIT-B>
+ > ! HEAD:refs/for/next/topic1 [remote rejected] (fail to call Web API)
+ > ! HEAD:refs/for/next/topic3 [remote rejected] (proc-receive failed to report status)
+ > Done
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0040-process-all-refs.sh b/t/t5411/test-0040-process-all-refs.sh
index fdcdcc7c2e..2f405adefa 100644
--- a/t/t5411/test-0040-process-all-refs.sh
+++ b/t/t5411/test-0040-process-all-refs.sh
@@ -50,46 +50,46 @@ test_expect_success "proc-receive: process all refs ($PROTOCOL)" '
HEAD:refs/for/next/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
- remote: pre-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
- remote: pre-receive< <COMMIT-B> <COMMIT-A> refs/heads/main
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
- remote: # proc-receive hook
- remote: proc-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
- remote: proc-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
- remote: proc-receive< <COMMIT-B> <COMMIT-A> refs/heads/main
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
- remote: proc-receive> ok refs/heads/main
- remote: proc-receive> option fall-through
- remote: proc-receive> ok refs/heads/foo
- remote: proc-receive> option fall-through
- remote: proc-receive> ok refs/heads/bar
- remote: proc-receive> option fall-through
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/pull/123/head
- remote: proc-receive> option old-oid <COMMIT-A>
- remote: proc-receive> option new-oid <COMMIT-B>
- remote: proc-receive> ok refs/for/next/topic
- remote: proc-receive> option refname refs/pull/124/head
- remote: proc-receive> option old-oid <COMMIT-B>
- remote: proc-receive> option new-oid <COMMIT-A>
- remote: proc-receive> option forced-update
- remote: # post-receive hook
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
- remote: post-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
- remote: post-receive< <COMMIT-B> <COMMIT-A> refs/heads/main
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/pull/123/head
- remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/124/head
- To <URL/of/upstream.git>
- <OID-A>..<OID-B> <COMMIT-B> -> bar
- - [deleted] foo
- + <OID-B>...<OID-A> HEAD -> main (forced update)
- <OID-A>..<OID-B> HEAD -> refs/pull/123/head
- + <OID-B>...<OID-A> HEAD -> refs/pull/124/head (forced update)
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar Z
+ > remote: pre-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo Z
+ > remote: pre-receive< <COMMIT-B> <COMMIT-A> refs/heads/main Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar Z
+ > remote: proc-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo Z
+ > remote: proc-receive< <COMMIT-B> <COMMIT-A> refs/heads/main Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic Z
+ > remote: proc-receive> ok refs/heads/main Z
+ > remote: proc-receive> option fall-through Z
+ > remote: proc-receive> ok refs/heads/foo Z
+ > remote: proc-receive> option fall-through Z
+ > remote: proc-receive> ok refs/heads/bar Z
+ > remote: proc-receive> option fall-through Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/pull/123/head Z
+ > remote: proc-receive> option old-oid <COMMIT-A> Z
+ > remote: proc-receive> option new-oid <COMMIT-B> Z
+ > remote: proc-receive> ok refs/for/next/topic Z
+ > remote: proc-receive> option refname refs/pull/124/head Z
+ > remote: proc-receive> option old-oid <COMMIT-B> Z
+ > remote: proc-receive> option new-oid <COMMIT-A> Z
+ > remote: proc-receive> option forced-update Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar Z
+ > remote: post-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo Z
+ > remote: post-receive< <COMMIT-B> <COMMIT-A> refs/heads/main Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/pull/123/head Z
+ > remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/124/head Z
+ > To <URL/of/upstream.git>
+ > <COMMIT-A>..<COMMIT-B> <COMMIT-B> -> bar
+ > - [deleted] foo
+ > + <COMMIT-B>...<COMMIT-A> HEAD -> main (forced update)
+ > <COMMIT-A>..<COMMIT-B> HEAD -> refs/pull/123/head
+ > + <COMMIT-B>...<COMMIT-A> HEAD -> refs/pull/124/head (forced update)
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0041-process-all-refs--porcelain.sh b/t/t5411/test-0041-process-all-refs--porcelain.sh
index 73b35fe0aa..c88405792e 100644
--- a/t/t5411/test-0041-process-all-refs--porcelain.sh
+++ b/t/t5411/test-0041-process-all-refs--porcelain.sh
@@ -50,47 +50,47 @@ test_expect_success "proc-receive: process all refs ($PROTOCOL/porcelain)" '
HEAD:refs/for/next/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
- remote: pre-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
- remote: pre-receive< <COMMIT-B> <COMMIT-A> refs/heads/main
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
- remote: # proc-receive hook
- remote: proc-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
- remote: proc-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
- remote: proc-receive< <COMMIT-B> <COMMIT-A> refs/heads/main
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
- remote: proc-receive> ok refs/heads/main
- remote: proc-receive> option fall-through
- remote: proc-receive> ok refs/heads/foo
- remote: proc-receive> option fall-through
- remote: proc-receive> ok refs/heads/bar
- remote: proc-receive> option fall-through
- remote: proc-receive> ok refs/for/main/topic
- remote: proc-receive> option refname refs/pull/123/head
- remote: proc-receive> option old-oid <COMMIT-A>
- remote: proc-receive> option new-oid <COMMIT-B>
- remote: proc-receive> ok refs/for/next/topic
- remote: proc-receive> option refname refs/pull/124/head
- remote: proc-receive> option old-oid <COMMIT-B>
- remote: proc-receive> option new-oid <COMMIT-A>
- remote: proc-receive> option forced-update
- remote: # post-receive hook
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
- remote: post-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
- remote: post-receive< <COMMIT-B> <COMMIT-A> refs/heads/main
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/pull/123/head
- remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/124/head
- To <URL/of/upstream.git>
- <COMMIT-B>:refs/heads/bar <OID-A>..<OID-B>
- - :refs/heads/foo [deleted]
- + HEAD:refs/heads/main <OID-B>...<OID-A> (forced update)
- HEAD:refs/pull/123/head <OID-A>..<OID-B>
- + HEAD:refs/pull/124/head <OID-B>...<OID-A> (forced update)
- Done
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar Z
+ > remote: pre-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo Z
+ > remote: pre-receive< <COMMIT-B> <COMMIT-A> refs/heads/main Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar Z
+ > remote: proc-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo Z
+ > remote: proc-receive< <COMMIT-B> <COMMIT-A> refs/heads/main Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic Z
+ > remote: proc-receive> ok refs/heads/main Z
+ > remote: proc-receive> option fall-through Z
+ > remote: proc-receive> ok refs/heads/foo Z
+ > remote: proc-receive> option fall-through Z
+ > remote: proc-receive> ok refs/heads/bar Z
+ > remote: proc-receive> option fall-through Z
+ > remote: proc-receive> ok refs/for/main/topic Z
+ > remote: proc-receive> option refname refs/pull/123/head Z
+ > remote: proc-receive> option old-oid <COMMIT-A> Z
+ > remote: proc-receive> option new-oid <COMMIT-B> Z
+ > remote: proc-receive> ok refs/for/next/topic Z
+ > remote: proc-receive> option refname refs/pull/124/head Z
+ > remote: proc-receive> option old-oid <COMMIT-B> Z
+ > remote: proc-receive> option new-oid <COMMIT-A> Z
+ > remote: proc-receive> option forced-update Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar Z
+ > remote: post-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo Z
+ > remote: post-receive< <COMMIT-B> <COMMIT-A> refs/heads/main Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/pull/123/head Z
+ > remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/124/head Z
+ > To <URL/of/upstream.git>
+ > <COMMIT-B>:refs/heads/bar <COMMIT-A>..<COMMIT-B>
+ > - :refs/heads/foo [deleted]
+ > + HEAD:refs/heads/main <COMMIT-B>...<COMMIT-A> (forced update)
+ > HEAD:refs/pull/123/head <COMMIT-A>..<COMMIT-B>
+ > + HEAD:refs/pull/124/head <COMMIT-B>...<COMMIT-A> (forced update)
+ > Done
EOF
test_cmp expect actual &&
diff --git a/t/t5411/test-0050-proc-receive-refs-with-modifiers.sh b/t/t5411/test-0050-proc-receive-refs-with-modifiers.sh
index 7214647ada..31989f0185 100644
--- a/t/t5411/test-0050-proc-receive-refs-with-modifiers.sh
+++ b/t/t5411/test-0050-proc-receive-refs-with-modifiers.sh
@@ -29,25 +29,25 @@ test_expect_success "proc-receive: update branch and new tag ($PROTOCOL)" '
$B:refs/heads/main \
v123 >out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/main
- remote: pre-receive< <ZERO-OID> <TAG-v123> refs/tags/v123
- remote: # proc-receive hook
- remote: proc-receive< <COMMIT-A> <COMMIT-B> refs/heads/main
- remote: proc-receive< <ZERO-OID> <TAG-v123> refs/tags/v123
- remote: proc-receive> ok refs/heads/main
- remote: proc-receive> option refname refs/pull/123/head
- remote: proc-receive> option old-oid <COMMIT-A>
- remote: proc-receive> option new-oid <COMMIT-B>
- remote: proc-receive> ok refs/tags/v123
- remote: proc-receive> option refname refs/pull/124/head
- remote: # post-receive hook
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/pull/123/head
- remote: post-receive< <ZERO-OID> <TAG-v123> refs/pull/124/head
- To <URL/of/upstream.git>
- <OID-A>..<OID-B> <COMMIT-B> -> refs/pull/123/head
- * [new reference] v123 -> refs/pull/124/head
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/main Z
+ > remote: pre-receive< <ZERO-OID> <TAG-v123> refs/tags/v123 Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <COMMIT-A> <COMMIT-B> refs/heads/main Z
+ > remote: proc-receive< <ZERO-OID> <TAG-v123> refs/tags/v123 Z
+ > remote: proc-receive> ok refs/heads/main Z
+ > remote: proc-receive> option refname refs/pull/123/head Z
+ > remote: proc-receive> option old-oid <COMMIT-A> Z
+ > remote: proc-receive> option new-oid <COMMIT-B> Z
+ > remote: proc-receive> ok refs/tags/v123 Z
+ > remote: proc-receive> option refname refs/pull/124/head Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/pull/123/head Z
+ > remote: post-receive< <ZERO-OID> <TAG-v123> refs/pull/124/head Z
+ > To <URL/of/upstream.git>
+ > <COMMIT-A>..<COMMIT-B> <COMMIT-B> -> refs/pull/123/head
+ > * [new reference] v123 -> refs/pull/124/head
EOF
test_cmp expect actual &&
@@ -93,32 +93,32 @@ test_expect_success "proc-receive: create/delete branch, and delete tag ($PROTOC
$A:refs/heads/next \
:refs/tags/v123 >out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- remote: # pre-receive hook
- remote: pre-receive< <COMMIT-A> <ZERO-OID> refs/heads/main
- remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/topic
- remote: pre-receive< <TAG-v123> <ZERO-OID> refs/tags/v123
- remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- remote: # proc-receive hook
- remote: proc-receive< <COMMIT-A> <ZERO-OID> refs/heads/main
- remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
- remote: proc-receive> ok refs/heads/main
- remote: proc-receive> option refname refs/pull/123/head
- remote: proc-receive> option old-oid <COMMIT-A>
- remote: proc-receive> option new-oid <ZERO-OID>
- remote: proc-receive> ok refs/heads/next
- remote: proc-receive> option refname refs/pull/124/head
- remote: proc-receive> option new-oid <COMMIT-A>
- remote: # post-receive hook
- remote: post-receive< <COMMIT-A> <ZERO-OID> refs/pull/123/head
- remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/topic
- remote: post-receive< <TAG-v123> <ZERO-OID> refs/tags/v123
- remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/124/head
- To <URL/of/upstream.git>
- - [deleted] refs/pull/123/head
- <OID-A>..<OID-B> <COMMIT-B> -> topic
- - [deleted] v123
- * [new reference] <COMMIT-A> -> refs/pull/124/head
+ format_and_save_expect <<-EOF &&
+ > remote: # pre-receive hook Z
+ > remote: pre-receive< <COMMIT-A> <ZERO-OID> refs/heads/main Z
+ > remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/topic Z
+ > remote: pre-receive< <TAG-v123> <ZERO-OID> refs/tags/v123 Z
+ > remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > remote: # proc-receive hook Z
+ > remote: proc-receive< <COMMIT-A> <ZERO-OID> refs/heads/main Z
+ > remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/heads/next Z
+ > remote: proc-receive> ok refs/heads/main Z
+ > remote: proc-receive> option refname refs/pull/123/head Z
+ > remote: proc-receive> option old-oid <COMMIT-A> Z
+ > remote: proc-receive> option new-oid <ZERO-OID> Z
+ > remote: proc-receive> ok refs/heads/next Z
+ > remote: proc-receive> option refname refs/pull/124/head Z
+ > remote: proc-receive> option new-oid <COMMIT-A> Z
+ > remote: # post-receive hook Z
+ > remote: post-receive< <COMMIT-A> <ZERO-OID> refs/pull/123/head Z
+ > remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/topic Z
+ > remote: post-receive< <TAG-v123> <ZERO-OID> refs/tags/v123 Z
+ > remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/124/head Z
+ > To <URL/of/upstream.git>
+ > - [deleted] refs/pull/123/head
+ > <COMMIT-A>..<COMMIT-B> <COMMIT-B> -> topic
+ > - [deleted] v123
+ > * [new reference] <COMMIT-A> -> refs/pull/124/head
EOF
test_cmp expect actual &&
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index c7b392794b..e6e3c8f552 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -182,7 +182,7 @@ test_expect_success 'rename errors out early when deleting non-existent branch'
)
'
-test_expect_success 'rename errors out early when when new name is invalid' '
+test_expect_success 'rename errors out early when new name is invalid' '
test_config remote.foo.vcs bar &&
echo "fatal: '\''invalid...name'\'' is not a valid remote name" >expect &&
test_must_fail git remote rename foo invalid...name 2>actual &&
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index e83b2a6506..a0faf0dd94 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -1214,6 +1214,19 @@ test_expect_success '--negotiation-tip understands abbreviated SHA-1' '
check_negotiation_tip
'
+test_expect_success '--negotiation-tip rejects missing OIDs' '
+ setup_negotiation_tip server server 0 &&
+ test_must_fail git -C client fetch \
+ --negotiation-tip=alpha_1 \
+ --negotiation-tip=$(test_oid zero) \
+ origin alpha_s beta_s 2>err &&
+ cat >fatal-expect <<-EOF &&
+ fatal: the object $(test_oid zero) does not exist
+EOF
+ grep fatal: err >fatal-actual &&
+ test_cmp fatal-expect fatal-actual
+'
+
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index f11742ed59..8212ca56dc 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -191,6 +191,44 @@ test_expect_success 'fetch with pushInsteadOf (should not rewrite)' '
)
'
+grep_wrote () {
+ object_count=$1
+ file_name=$2
+ grep 'write_pack_file/wrote.*"value":"'$1'"' $2
+}
+
+test_expect_success 'push with negotiation' '
+ # Without negotiation
+ mk_empty testrepo &&
+ git push testrepo $the_first_commit:refs/remotes/origin/first_commit &&
+ test_commit -C testrepo unrelated_commit &&
+ git -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&
+ echo now pushing without negotiation &&
+ GIT_TRACE2_EVENT="$(pwd)/event" git -c protocol.version=2 push testrepo refs/heads/main:refs/remotes/origin/main &&
+ grep_wrote 5 event && # 2 commits, 2 trees, 1 blob
+
+ # Same commands, but with negotiation
+ rm event &&
+ mk_empty testrepo &&
+ git push testrepo $the_first_commit:refs/remotes/origin/first_commit &&
+ test_commit -C testrepo unrelated_commit &&
+ git -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&
+ GIT_TRACE2_EVENT="$(pwd)/event" git -c protocol.version=2 -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main &&
+ grep_wrote 2 event # 1 commit, 1 tree
+'
+
+test_expect_success 'push with negotiation proceeds anyway even if negotiation fails' '
+ rm event &&
+ mk_empty testrepo &&
+ git push testrepo $the_first_commit:refs/remotes/origin/first_commit &&
+ test_commit -C testrepo unrelated_commit &&
+ git -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&
+ GIT_TEST_PROTOCOL_VERSION=0 GIT_TRACE2_EVENT="$(pwd)/event" \
+ git -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main 2>err &&
+ grep_wrote 5 event && # 2 commits, 2 trees, 1 blob
+ test_i18ngrep "push negotiation failed" err
+'
+
test_expect_success 'push without wildcard' '
mk_empty testrepo &&
@@ -624,10 +662,10 @@ test_expect_success 'push does not update local refs on failure' '
test_expect_success 'allow deleting an invalid remote ref' '
- mk_test testrepo heads/main &&
+ mk_test testrepo heads/branch &&
rm -f testrepo/.git/objects/??/* &&
- git push testrepo :refs/heads/main &&
- (cd testrepo && test_must_fail git rev-parse --verify refs/heads/main)
+ git push testrepo :refs/heads/branch &&
+ (cd testrepo && test_must_fail git rev-parse --verify refs/heads/branch)
'
@@ -668,25 +706,26 @@ test_expect_success 'pushing valid refs triggers post-receive and post-update ho
'
test_expect_success 'deleting dangling ref triggers hooks with correct args' '
- mk_test_with_hooks testrepo heads/main &&
+ mk_test_with_hooks testrepo heads/branch &&
+ orig=$(git -C testrepo rev-parse refs/heads/branch) &&
rm -f testrepo/.git/objects/??/* &&
- git push testrepo :refs/heads/main &&
+ git push testrepo :refs/heads/branch &&
(
cd testrepo/.git &&
cat >pre-receive.expect <<-EOF &&
- $ZERO_OID $ZERO_OID refs/heads/main
+ $orig $ZERO_OID refs/heads/branch
EOF
cat >update.expect <<-EOF &&
- refs/heads/main $ZERO_OID $ZERO_OID
+ refs/heads/branch $orig $ZERO_OID
EOF
cat >post-receive.expect <<-EOF &&
- $ZERO_OID $ZERO_OID refs/heads/main
+ $orig $ZERO_OID refs/heads/branch
EOF
cat >post-update.expect <<-EOF &&
- refs/heads/main
+ refs/heads/branch
EOF
test_cmp pre-receive.expect pre-receive.actual &&
@@ -1732,5 +1771,4 @@ test_expect_success 'denyCurrentBranch and worktrees' '
git -C cloned push origin HEAD:new-wt &&
test_must_fail git -C cloned push --delete origin new-wt
'
-
test_done
diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh
index a09411327f..93ecfcdd24 100755
--- a/t/t5520-pull.sh
+++ b/t/t5520-pull.sh
@@ -136,12 +136,12 @@ test_expect_success 'the default remote . should not break explicit pull' '
git reset --hard HEAD^ &&
echo file >expect &&
test_cmp expect file &&
- git pull . second &&
+ git pull --no-rebase . second &&
echo modified >expect &&
test_cmp expect file &&
git reflog -1 >reflog.actual &&
sed "s/^[0-9a-f][0-9a-f]*/OBJID/" reflog.actual >reflog.fuzzy &&
- echo "OBJID HEAD@{0}: pull . second: Fast-forward" >reflog.expected &&
+ echo "OBJID HEAD@{0}: pull --no-rebase . second: Fast-forward" >reflog.expected &&
test_cmp reflog.expected reflog.fuzzy
'
@@ -226,7 +226,7 @@ test_expect_success 'fail if the index has unresolved entries' '
test_commit modified2 file &&
git ls-files -u >unmerged &&
test_must_be_empty unmerged &&
- test_must_fail git pull . second &&
+ test_must_fail git pull --no-rebase . second &&
git ls-files -u >unmerged &&
test_file_not_empty unmerged &&
cp file expected &&
@@ -409,37 +409,37 @@ test_expect_success 'pull --rebase --no-autostash & rebase.autostash unset' '
test_expect_success 'pull succeeds with dirty working directory and merge.autostash set' '
test_config merge.autostash true &&
- test_pull_autostash 2
+ test_pull_autostash 2 --no-rebase
'
test_expect_success 'pull --autostash & merge.autostash=true' '
test_config merge.autostash true &&
- test_pull_autostash 2 --autostash
+ test_pull_autostash 2 --autostash --no-rebase
'
test_expect_success 'pull --autostash & merge.autostash=false' '
test_config merge.autostash false &&
- test_pull_autostash 2 --autostash
+ test_pull_autostash 2 --autostash --no-rebase
'
test_expect_success 'pull --autostash & merge.autostash unset' '
test_unconfig merge.autostash &&
- test_pull_autostash 2 --autostash
+ test_pull_autostash 2 --autostash --no-rebase
'
test_expect_success 'pull --no-autostash & merge.autostash=true' '
test_config merge.autostash true &&
- test_pull_autostash_fail --no-autostash
+ test_pull_autostash_fail --no-autostash --no-rebase
'
test_expect_success 'pull --no-autostash & merge.autostash=false' '
test_config merge.autostash false &&
- test_pull_autostash_fail --no-autostash
+ test_pull_autostash_fail --no-autostash --no-rebase
'
test_expect_success 'pull --no-autostash & merge.autostash unset' '
test_unconfig merge.autostash &&
- test_pull_autostash_fail --no-autostash
+ test_pull_autostash_fail --no-autostash --no-rebase
'
test_expect_success 'pull.rebase' '
@@ -546,15 +546,6 @@ test_expect_success 'pull.rebase=1 is treated as true and flattens keep-merge' '
test_cmp expect actual
'
-test_expect_success REBASE_P \
- 'pull.rebase=preserve rebases and merges keep-merge' '
- git reset --hard before-preserve-rebase &&
- test_config pull.rebase preserve &&
- git pull . copy &&
- test_cmp_rev HEAD^^ copy &&
- test_cmp_rev HEAD^2 keep-merge
-'
-
test_expect_success 'pull.rebase=interactive' '
write_script "$TRASH_DIRECTORY/fake-editor" <<-\EOF &&
echo I was here >fake.out &&
@@ -598,7 +589,7 @@ test_expect_success '--rebase=false create a new merge commit' '
test_expect_success '--rebase=true rebases and flattens keep-merge' '
git reset --hard before-preserve-rebase &&
- test_config pull.rebase preserve &&
+ test_config pull.rebase merges &&
git pull --rebase=true . copy &&
test_cmp_rev HEAD^^ copy &&
echo file3 >expect &&
@@ -606,23 +597,14 @@ test_expect_success '--rebase=true rebases and flattens keep-merge' '
test_cmp expect actual
'
-test_expect_success REBASE_P \
- '--rebase=preserve rebases and merges keep-merge' '
- git reset --hard before-preserve-rebase &&
- test_config pull.rebase true &&
- git pull --rebase=preserve . copy &&
- test_cmp_rev HEAD^^ copy &&
- test_cmp_rev HEAD^2 keep-merge
-'
-
test_expect_success '--rebase=invalid fails' '
git reset --hard before-preserve-rebase &&
test_must_fail git pull --rebase=invalid . copy
'
-test_expect_success '--rebase overrides pull.rebase=preserve and flattens keep-merge' '
+test_expect_success '--rebase overrides pull.rebase=merges and flattens keep-merge' '
git reset --hard before-preserve-rebase &&
- test_config pull.rebase preserve &&
+ test_config pull.rebase merges &&
git pull --rebase . copy &&
test_cmp_rev HEAD^^ copy &&
echo file3 >expect &&
@@ -746,14 +728,8 @@ test_expect_success 'pull --rebase fails on corrupt HEAD' '
'
test_expect_success 'setup for detecting upstreamed changes' '
- mkdir src &&
- (
- cd src &&
- git init &&
- printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" > stuff &&
- git add stuff &&
- git commit -m "Initial revision"
- ) &&
+ test_create_repo src &&
+ test_commit -C src --printf one stuff "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" &&
git clone src dst &&
(
cd src &&
diff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh
index 63a688bdbf..7601c919fd 100755
--- a/t/t5521-pull-options.sh
+++ b/t/t5521-pull-options.sh
@@ -113,7 +113,7 @@ test_expect_success 'git pull --force' '
git pull two &&
test_commit A &&
git branch -f origin &&
- git pull --all --force
+ git pull --no-rebase --all --force
)
'
@@ -179,7 +179,7 @@ test_expect_success 'git pull --allow-unrelated-histories' '
(
cd dst &&
test_must_fail git pull ../src side &&
- git pull --allow-unrelated-histories ../src side
+ git pull --no-rebase --allow-unrelated-histories ../src side
)
'
diff --git a/t/t5524-pull-msg.sh b/t/t5524-pull-msg.sh
index c278adaa5a..b2be3605f5 100755
--- a/t/t5524-pull-msg.sh
+++ b/t/t5524-pull-msg.sh
@@ -28,7 +28,7 @@ test_expect_success setup '
test_expect_success pull '
(
cd cloned &&
- git pull --log &&
+ git pull --no-rebase --log &&
git log -2 &&
git cat-file commit HEAD >result &&
grep Dollar result
@@ -41,7 +41,7 @@ test_expect_success '--log=1 limits shortlog length' '
git reset --hard HEAD^ &&
test "$(cat afile)" = original &&
test "$(cat bfile)" = added &&
- git pull --log=1 &&
+ git pull --no-rebase --log=1 &&
git log -3 &&
git cat-file commit HEAD >result &&
grep Dollar result &&
diff --git a/t/t5548-push-porcelain.sh b/t/t5548-push-porcelain.sh
index 5a761f3642..f11ff57e54 100755
--- a/t/t5548-push-porcelain.sh
+++ b/t/t5548-push-porcelain.sh
@@ -14,29 +14,28 @@ test_description='Test git push porcelain output'
# NOTE: Never calling this function from a subshell since variable
# assignments will disappear when subshell exits.
create_commits_in () {
- repo="$1" &&
- if ! parent=$(git -C "$repo" rev-parse HEAD^{} --)
- then
- parent=
- fi &&
- T=$(git -C "$repo" write-tree) &&
+ repo="$1" && test -d "$repo" ||
+ error "Repository $repo does not exist."
shift &&
while test $# -gt 0
do
name=$1 &&
- test_tick &&
- if test -z "$parent"
- then
- oid=$(echo $name | git -C "$repo" commit-tree $T)
- else
- oid=$(echo $name | git -C "$repo" commit-tree -p $parent $T)
- fi &&
- eval $name=$oid &&
- parent=$oid &&
- shift ||
- return 1
- done &&
- git -C "$repo" update-ref refs/heads/main $oid
+ shift &&
+ test_commit -C "$repo" --no-tag "$name" &&
+ eval $name=$(git -C "$repo" rev-parse HEAD)
+ done
+}
+
+get_abbrev_oid () {
+ oid=$1 &&
+ suffix=${oid#???????} &&
+ oid=${oid%$suffix} &&
+ if test -n "$oid"
+ then
+ echo "$oid"
+ else
+ echo "undefined-oid"
+ fi
}
# Format the output of git-push, git-show-ref and other commands to make a
@@ -45,17 +44,16 @@ create_commits_in () {
# of the output.
make_user_friendly_and_stable_output () {
sed \
- -e "s/ *\$//" \
- -e "s/ */ /g" \
- -e "s/ / /g" \
- -e "s/$A/<COMMIT-A>/g" \
- -e "s/$B/<COMMIT-B>/g" \
+ -e "s/$(get_abbrev_oid $A)[0-9a-f]*/<COMMIT-A>/g" \
+ -e "s/$(get_abbrev_oid $B)[0-9a-f]*/<COMMIT-B>/g" \
-e "s/$ZERO_OID/<ZERO-OID>/g" \
- -e "s/$(echo $A | cut -c1-7)[0-9a-f]*/<OID-A>/g" \
- -e "s/$(echo $B | cut -c1-7)[0-9a-f]*/<OID-B>/g" \
-e "s#To $URL_PREFIX/upstream.git#To <URL/of/upstream.git>#"
}
+format_and_save_expect () {
+ sed -e 's/^> //' -e 's/Z$//' >expect
+}
+
setup_upstream_and_workbench () {
# Upstream after setup : main(B) foo(A) bar(A) baz(A)
# Workbench after setup : main(A)
@@ -111,14 +109,14 @@ run_git_push_porcelain_output_test() {
next
) >out &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
- To <URL/of/upstream.git>
- = refs/heads/baz:refs/heads/baz [up to date]
- <COMMIT-B>:refs/heads/bar <OID-A>..<OID-B>
- - :refs/heads/foo [deleted]
- + refs/heads/main:refs/heads/main <OID-B>...<OID-A> (forced update)
- * refs/heads/next:refs/heads/next [new branch]
- Done
+ format_and_save_expect <<-EOF &&
+ > To <URL/of/upstream.git>
+ > = refs/heads/baz:refs/heads/baz [up to date]
+ > <COMMIT-B>:refs/heads/bar <COMMIT-A>..<COMMIT-B>
+ > - :refs/heads/foo [deleted]
+ > + refs/heads/main:refs/heads/main <COMMIT-B>...<COMMIT-A> (forced update)
+ > * refs/heads/next:refs/heads/next [new branch]
+ > Done
EOF
test_cmp expect actual &&
@@ -148,12 +146,12 @@ run_git_push_porcelain_output_test() {
next
) >out &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
+ format_and_save_expect <<-EOF &&
To <URL/of/upstream.git>
- = refs/heads/next:refs/heads/next [up to date]
- ! refs/heads/bar:refs/heads/bar [rejected] (non-fast-forward)
- ! (delete):refs/heads/baz [rejected] (atomic push failed)
- ! refs/heads/main:refs/heads/main [rejected] (atomic push failed)
+ > = refs/heads/next:refs/heads/next [up to date]
+ > ! refs/heads/bar:refs/heads/bar [rejected] (non-fast-forward)
+ > ! (delete):refs/heads/baz [rejected] (atomic push failed)
+ > ! refs/heads/main:refs/heads/main [rejected] (atomic push failed)
Done
EOF
test_cmp expect actual &&
@@ -168,6 +166,7 @@ run_git_push_porcelain_output_test() {
EOF
test_cmp expect actual
'
+
test_expect_success "prepare pre-receive hook ($PROTOCOL)" '
write_script "$upstream/hooks/pre-receive" <<-EOF
exit 1
@@ -189,12 +188,12 @@ run_git_push_porcelain_output_test() {
next
) >out &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
+ format_and_save_expect <<-EOF &&
To <URL/of/upstream.git>
- = refs/heads/next:refs/heads/next [up to date]
- ! refs/heads/bar:refs/heads/bar [remote rejected] (pre-receive hook declined)
- ! :refs/heads/baz [remote rejected] (pre-receive hook declined)
- ! refs/heads/main:refs/heads/main [remote rejected] (pre-receive hook declined)
+ > = refs/heads/next:refs/heads/next [up to date]
+ > ! refs/heads/bar:refs/heads/bar [remote rejected] (pre-receive hook declined)
+ > ! :refs/heads/baz [remote rejected] (pre-receive hook declined)
+ > ! refs/heads/main:refs/heads/main [remote rejected] (pre-receive hook declined)
Done
EOF
test_cmp expect actual &&
@@ -227,12 +226,12 @@ run_git_push_porcelain_output_test() {
next
) >out &&
make_user_friendly_and_stable_output <out >actual &&
- cat >expect <<-EOF &&
+ format_and_save_expect <<-EOF &&
To <URL/of/upstream.git>
- = refs/heads/next:refs/heads/next [up to date]
- - :refs/heads/baz [deleted]
- refs/heads/main:refs/heads/main <OID-A>..<OID-B>
- ! refs/heads/bar:refs/heads/bar [rejected] (non-fast-forward)
+ > = refs/heads/next:refs/heads/next [up to date]
+ > - :refs/heads/baz [deleted]
+ > refs/heads/main:refs/heads/main <COMMIT-A>..<COMMIT-B>
+ > ! refs/heads/bar:refs/heads/bar [rejected] (non-fast-forward)
Done
EOF
test_cmp expect actual &&
diff --git a/t/t5549-fetch-push-http.sh b/t/t5549-fetch-push-http.sh
new file mode 100755
index 0000000000..2cdebcb735
--- /dev/null
+++ b/t/t5549-fetch-push-http.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+test_description='fetch/push functionality using the HTTP protocol'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-httpd.sh
+start_httpd
+
+SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server"
+URI="$HTTPD_URL/smart/server"
+
+grep_wrote () {
+ object_count=$1
+ file_name=$2
+ grep 'write_pack_file/wrote.*"value":"'$1'"' $2
+}
+
+setup_client_and_server () {
+ git init client &&
+ test_when_finished 'rm -rf client' &&
+ test_commit -C client first_commit &&
+ test_commit -C client second_commit &&
+
+ git init "$SERVER" &&
+ test_when_finished 'rm -rf "$SERVER"' &&
+ test_config -C "$SERVER" http.receivepack true &&
+ test_commit -C "$SERVER" unrelated_commit &&
+ git -C client push "$URI" first_commit:refs/remotes/origin/first_commit &&
+ git -C "$SERVER" config receive.hideRefs refs/remotes/origin/first_commit
+}
+
+test_expect_success 'push without negotiation (for comparing object counts with the next test)' '
+ setup_client_and_server &&
+
+ GIT_TRACE2_EVENT="$(pwd)/event" git -C client -c protocol.version=2 \
+ push "$URI" refs/heads/main:refs/remotes/origin/main &&
+ test_when_finished "rm -f event" &&
+ grep_wrote 6 event # 2 commits, 2 trees, 2 blobs
+'
+
+test_expect_success 'push with negotiation' '
+ setup_client_and_server &&
+
+ GIT_TRACE2_EVENT="$(pwd)/event" git -C client -c protocol.version=2 -c push.negotiate=1 \
+ push "$URI" refs/heads/main:refs/remotes/origin/main &&
+ test_when_finished "rm -f event" &&
+ grep_wrote 3 event # 1 commit, 1 tree, 1 blob
+'
+
+test_expect_success 'push with negotiation proceeds anyway even if negotiation fails' '
+ setup_client_and_server &&
+
+ # Use protocol v0 to make negotiation fail (because protocol v0 does
+ # not support the "wait-for-done" capability, which is required for
+ # push negotiation)
+ GIT_TEST_PROTOCOL_VERSION=0 GIT_TRACE2_EVENT="$(pwd)/event" git -C client -c push.negotiate=1 \
+ push "$URI" refs/heads/main:refs/remotes/origin/main 2>err &&
+ test_when_finished "rm -f event" &&
+ grep_wrote 6 event && # 2 commits, 2 trees, 2 blobs
+
+ cat >warning-expect <<-EOF &&
+ warning: --negotiate-only requires protocol v2
+ warning: push negotiation failed; proceeding anyway with push
+EOF
+ grep warning: err >warning-actual &&
+ test_cmp warning-expect warning-actual
+'
+
+test_done
diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh
index 984dba22af..f92c79c132 100755
--- a/t/t5551-http-fetch-smart.sh
+++ b/t/t5551-http-fetch-smart.sh
@@ -196,8 +196,8 @@ test_expect_success 'GIT_TRACE_CURL redacts auth details' '
# Ensure that there is no "Basic" followed by a base64 string, but that
# the auth details are redacted
- ! grep "Authorization: Basic [0-9a-zA-Z+/]" trace &&
- grep "Authorization: Basic <redacted>" trace
+ ! grep -i "Authorization: Basic [0-9a-zA-Z+/]" trace &&
+ grep -i "Authorization: Basic <redacted>" trace
'
test_expect_success 'GIT_CURL_VERBOSE redacts auth details' '
@@ -208,8 +208,8 @@ test_expect_success 'GIT_CURL_VERBOSE redacts auth details' '
# Ensure that there is no "Basic" followed by a base64 string, but that
# the auth details are redacted
- ! grep "Authorization: Basic [0-9a-zA-Z+/]" trace &&
- grep "Authorization: Basic <redacted>" trace
+ ! grep -i "Authorization: Basic [0-9a-zA-Z+/]" trace &&
+ grep -i "Authorization: Basic <redacted>" trace
'
test_expect_success 'GIT_TRACE_CURL does not redact auth details if GIT_TRACE_REDACT=0' '
@@ -219,7 +219,7 @@ test_expect_success 'GIT_TRACE_CURL does not redact auth details if GIT_TRACE_RE
git clone --bare "$HTTPD_URL/auth/smart/repo.git" redact-auth &&
expect_askpass both user@host &&
- grep "Authorization: Basic [0-9a-zA-Z+/]" trace
+ grep -i "Authorization: Basic [0-9a-zA-Z+/]" trace
'
test_expect_success 'disable dumb http on server' '
@@ -474,10 +474,10 @@ test_expect_success 'cookies are redacted by default' '
GIT_TRACE_CURL=true \
git -c "http.cookieFile=$(pwd)/cookies" clone \
$HTTPD_URL/smart/repo.git clone 2>err &&
- grep "Cookie:.*Foo=<redacted>" err &&
- grep "Cookie:.*Bar=<redacted>" err &&
- ! grep "Cookie:.*Foo=1" err &&
- ! grep "Cookie:.*Bar=2" err
+ grep -i "Cookie:.*Foo=<redacted>" err &&
+ grep -i "Cookie:.*Bar=<redacted>" err &&
+ ! grep -i "Cookie:.*Foo=1" err &&
+ ! grep -i "Cookie:.*Bar=2" err
'
test_expect_success 'empty values of cookies are also redacted' '
@@ -486,7 +486,7 @@ test_expect_success 'empty values of cookies are also redacted' '
GIT_TRACE_CURL=true \
git -c "http.cookieFile=$(pwd)/cookies" clone \
$HTTPD_URL/smart/repo.git clone 2>err &&
- grep "Cookie:.*Foo=<redacted>" err
+ grep -i "Cookie:.*Foo=<redacted>" err
'
test_expect_success 'GIT_TRACE_REDACT=0 disables cookie redaction' '
@@ -496,8 +496,8 @@ test_expect_success 'GIT_TRACE_REDACT=0 disables cookie redaction' '
GIT_TRACE_REDACT=0 GIT_TRACE_CURL=true \
git -c "http.cookieFile=$(pwd)/cookies" clone \
$HTTPD_URL/smart/repo.git clone 2>err &&
- grep "Cookie:.*Foo=1" err &&
- grep "Cookie:.*Bar=2" err
+ grep -i "Cookie:.*Foo=1" err &&
+ grep -i "Cookie:.*Bar=2" err
'
test_expect_success 'GIT_TRACE_CURL_NO_DATA prevents data from being traced' '
@@ -517,4 +517,54 @@ test_expect_success 'server-side error detected' '
test_i18ngrep "server-side error" actual
'
+test_expect_success 'http auth remembers successful credentials' '
+ rm -f .git-credentials &&
+ test_config credential.helper store &&
+
+ # the first request prompts the user...
+ set_askpass user@host pass@host &&
+ git ls-remote "$HTTPD_URL/auth/smart/repo.git" >/dev/null &&
+ expect_askpass both user@host &&
+
+ # ...and the second one uses the stored value rather than
+ # prompting the user.
+ set_askpass bogus-user bogus-pass &&
+ git ls-remote "$HTTPD_URL/auth/smart/repo.git" >/dev/null &&
+ expect_askpass none
+'
+
+test_expect_success 'http auth forgets bogus credentials' '
+ # seed credential store with bogus values. In real life,
+ # this would probably come from a password which worked
+ # for a previous request.
+ rm -f .git-credentials &&
+ test_config credential.helper store &&
+ {
+ echo "url=$HTTPD_URL" &&
+ echo "username=bogus" &&
+ echo "password=bogus"
+ } | git credential approve &&
+
+ # we expect this to use the bogus values and fail, never even
+ # prompting the user...
+ set_askpass user@host pass@host &&
+ test_must_fail git ls-remote "$HTTPD_URL/auth/smart/repo.git" >/dev/null &&
+ expect_askpass none &&
+
+ # ...but now we should have forgotten the bad value, causing
+ # us to prompt the user again.
+ set_askpass user@host pass@host &&
+ git ls-remote "$HTTPD_URL/auth/smart/repo.git" >/dev/null &&
+ expect_askpass both user@host
+'
+
+test_expect_success 'client falls back from v2 to v0 to match server' '
+ GIT_TRACE_PACKET=$PWD/trace \
+ GIT_TEST_PROTOCOL_VERSION=2 \
+ git clone $HTTPD_URL/smart_v0/repo.git repo-v0 &&
+ # check for v0; there the HEAD symref is communicated in the capability
+ # line; v2 uses a different syntax on each ref advertisement line
+ grep symref=HEAD:refs/heads/ trace
+'
+
test_done
diff --git a/t/t5553-set-upstream.sh b/t/t5553-set-upstream.sh
index b1d614ce18..9c12c0f8c3 100755
--- a/t/t5553-set-upstream.sh
+++ b/t/t5553-set-upstream.sh
@@ -108,27 +108,27 @@ test_expect_success 'setup commit on main and other pull' '
test_expect_success 'pull --set-upstream upstream main sets branch main but not other' '
clear_config main other &&
- git pull --set-upstream upstream main &&
+ git pull --no-rebase --set-upstream upstream main &&
check_config main upstream refs/heads/main &&
check_config_missing other
'
test_expect_success 'pull --set-upstream main:other2 does not set the branch other2' '
clear_config other2 &&
- git pull --set-upstream upstream main:other2 &&
+ git pull --no-rebase --set-upstream upstream main:other2 &&
check_config_missing other2
'
test_expect_success 'pull --set-upstream upstream other sets branch main' '
clear_config main other &&
- git pull --set-upstream upstream other &&
+ git pull --no-rebase --set-upstream upstream other &&
check_config main upstream refs/heads/other &&
check_config_missing other
'
test_expect_success 'pull --set-upstream upstream tag does not set the tag' '
clear_config three &&
- git pull --tags --set-upstream upstream three &&
+ git pull --no-rebase --tags --set-upstream upstream three &&
check_config_missing three
'
@@ -144,16 +144,16 @@ test_expect_success 'pull --set-upstream http://nosuchdomain.example.com fails w
test_expect_success 'pull --set-upstream upstream HEAD sets branch HEAD' '
clear_config main other &&
- git pull --set-upstream upstream HEAD &&
+ git pull --no-rebase --set-upstream upstream HEAD &&
check_config main upstream HEAD &&
git checkout other &&
- git pull --set-upstream upstream HEAD &&
+ git pull --no-rebase --set-upstream upstream HEAD &&
check_config other upstream HEAD
'
test_expect_success 'pull --set-upstream upstream with more than one branch does nothing' '
clear_config main three &&
- git pull --set-upstream upstream main three &&
+ git pull --no-rebase --set-upstream upstream main three &&
check_config_missing main &&
check_config_missing three
'
diff --git a/t/t5555-http-smart-common.sh b/t/t5555-http-smart-common.sh
new file mode 100755
index 0000000000..49faf5e283
--- /dev/null
+++ b/t/t5555-http-smart-common.sh
@@ -0,0 +1,161 @@
+#!/bin/sh
+
+test_description='test functionality common to smart fetch & push'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ test_commit --no-tag initial
+'
+
+test_expect_success 'git upload-pack --http-backend-info-refs and --advertise-refs are aliased' '
+ git upload-pack --http-backend-info-refs . >expected 2>err.expected &&
+ git upload-pack --advertise-refs . >actual 2>err.actual &&
+ test_cmp err.expected err.actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'git receive-pack --http-backend-info-refs and --advertise-refs are aliased' '
+ git receive-pack --http-backend-info-refs . >expected 2>err.expected &&
+ git receive-pack --advertise-refs . >actual 2>err.actual &&
+ test_cmp err.expected err.actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'git upload-pack --advertise-refs' '
+ cat >expect <<-EOF &&
+ $(git rev-parse HEAD) HEAD
+ $(git rev-parse HEAD) $(git symbolic-ref HEAD)
+ 0000
+ EOF
+
+ # We only care about GIT_PROTOCOL, not GIT_TEST_PROTOCOL_VERSION
+ sane_unset GIT_PROTOCOL &&
+ GIT_TEST_PROTOCOL_VERSION=2 \
+ git upload-pack --advertise-refs . >out 2>err &&
+
+ test-tool pkt-line unpack <out >actual &&
+ test_must_be_empty err &&
+ test_cmp actual expect &&
+
+ # The --advertise-refs alias works
+ git upload-pack --advertise-refs . >out 2>err &&
+
+ test-tool pkt-line unpack <out >actual &&
+ test_must_be_empty err &&
+ test_cmp actual expect
+'
+
+test_expect_success 'git upload-pack --advertise-refs: v0' '
+ # With no specified protocol
+ cat >expect <<-EOF &&
+ $(git rev-parse HEAD) HEAD
+ $(git rev-parse HEAD) $(git symbolic-ref HEAD)
+ 0000
+ EOF
+
+ git upload-pack --advertise-refs . >out 2>err &&
+ test-tool pkt-line unpack <out >actual &&
+ test_must_be_empty err &&
+ test_cmp actual expect &&
+
+ # With explicit v0
+ GIT_PROTOCOL=version=0 \
+ git upload-pack --advertise-refs . >out 2>err &&
+ test-tool pkt-line unpack <out >actual 2>err &&
+ test_must_be_empty err &&
+ test_cmp actual expect
+
+'
+
+test_expect_success 'git receive-pack --advertise-refs: v0' '
+ # With no specified protocol
+ cat >expect <<-EOF &&
+ $(git rev-parse HEAD) $(git symbolic-ref HEAD)
+ 0000
+ EOF
+
+ git receive-pack --advertise-refs . >out 2>err &&
+ test-tool pkt-line unpack <out >actual &&
+ test_must_be_empty err &&
+ test_cmp actual expect &&
+
+ # With explicit v0
+ GIT_PROTOCOL=version=0 \
+ git receive-pack --advertise-refs . >out 2>err &&
+ test-tool pkt-line unpack <out >actual 2>err &&
+ test_must_be_empty err &&
+ test_cmp actual expect
+
+'
+
+test_expect_success 'git upload-pack --advertise-refs: v1' '
+ # With no specified protocol
+ cat >expect <<-EOF &&
+ version 1
+ $(git rev-parse HEAD) HEAD
+ $(git rev-parse HEAD) $(git symbolic-ref HEAD)
+ 0000
+ EOF
+
+ GIT_PROTOCOL=version=1 \
+ git upload-pack --advertise-refs . >out &&
+
+ test-tool pkt-line unpack <out >actual 2>err &&
+ test_must_be_empty err &&
+ test_cmp actual expect
+'
+
+test_expect_success 'git receive-pack --advertise-refs: v1' '
+ # With no specified protocol
+ cat >expect <<-EOF &&
+ version 1
+ $(git rev-parse HEAD) $(git symbolic-ref HEAD)
+ 0000
+ EOF
+
+ GIT_PROTOCOL=version=1 \
+ git receive-pack --advertise-refs . >out &&
+
+ test-tool pkt-line unpack <out >actual 2>err &&
+ test_must_be_empty err &&
+ test_cmp actual expect
+'
+
+test_expect_success 'git upload-pack --advertise-refs: v2' '
+ cat >expect <<-EOF &&
+ version 2
+ agent=FAKE
+ ls-refs=unborn
+ fetch=shallow wait-for-done
+ server-option
+ object-format=$(test_oid algo)
+ object-info
+ 0000
+ EOF
+
+ GIT_PROTOCOL=version=2 \
+ GIT_USER_AGENT=FAKE \
+ git upload-pack --advertise-refs . >out 2>err &&
+
+ test-tool pkt-line unpack <out >actual &&
+ test_must_be_empty err &&
+ test_cmp actual expect
+'
+
+test_expect_success 'git receive-pack --advertise-refs: v2' '
+ # There is no v2 yet for receive-pack, implicit v0
+ cat >expect <<-EOF &&
+ $(git rev-parse HEAD) $(git symbolic-ref HEAD)
+ 0000
+ EOF
+
+ GIT_PROTOCOL=version=2 \
+ git receive-pack --advertise-refs . >out 2>err &&
+
+ test-tool pkt-line unpack <out >actual &&
+ test_must_be_empty err &&
+ test_cmp actual expect
+'
+
+test_done
diff --git a/t/t5562-http-backend-content-length.sh b/t/t5562-http-backend-content-length.sh
index e5d3d15ba8..05a58069b0 100755
--- a/t/t5562-http-backend-content-length.sh
+++ b/t/t5562-http-backend-content-length.sh
@@ -63,7 +63,7 @@ test_expect_success 'setup' '
hash_next=$(git commit-tree -p HEAD -m next HEAD^{tree}) &&
{
printf "%s %s refs/heads/newbranch\\0report-status object-format=%s\\n" \
- "$ZERO_OID" "$hash_next" "$(test_oid algo)" | packetize &&
+ "$ZERO_OID" "$hash_next" "$(test_oid algo)" | packetize_raw
printf 0000 &&
echo "$hash_next" | git pack-objects --stdout
} >push_body &&
diff --git a/t/t5562/invoke-with-content-length.pl b/t/t5562/invoke-with-content-length.pl
index 0943474af2..718dd9b49d 100644
--- a/t/t5562/invoke-with-content-length.pl
+++ b/t/t5562/invoke-with-content-length.pl
@@ -13,11 +13,6 @@ my $body_data;
defined read($body_fh, $body_data, $body_size) or die "Cannot read $body_filename: $!";
close($body_fh);
-my $exited = 0;
-$SIG{"CHLD"} = sub {
- $exited = 1;
-};
-
# write data
my $pid = open(my $out, "|-", @command);
{
@@ -29,8 +24,13 @@ my $pid = open(my $out, "|-", @command);
}
print $out $body_data or die "Cannot write data: $!";
-sleep 60; # is interrupted by SIGCHLD
-if (!$exited) {
- close($out);
+$SIG{ALRM} = sub {
+ kill 'KILL', $pid;
die "Command did not exit after reading whole body";
+};
+alarm 60;
+
+my $ret = waitpid($pid, 0);
+if ($ret != $pid) {
+ die "confusing return from waitpid: $ret";
}
diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh
index 82c31ab6cd..b87ca06a58 100755
--- a/t/t5570-git-daemon.sh
+++ b/t/t5570-git-daemon.sh
@@ -194,7 +194,7 @@ test_expect_success 'hostname cannot break out of directory' '
test_expect_success FAKENC 'hostname interpolation works after LF-stripping' '
{
- printf "git-upload-pack /interp.git\n\0host=localhost" | packetize
+ printf "git-upload-pack /interp.git\n\0host=localhost" | packetize_raw
printf "0000"
} >input &&
fake_nc "$GIT_DAEMON_HOST_PORT" <input >output &&
diff --git a/t/t5582-fetch-negative-refspec.sh b/t/t5582-fetch-negative-refspec.sh
index e5d2e79ad3..7a80e47c2b 100755
--- a/t/t5582-fetch-negative-refspec.sh
+++ b/t/t5582-fetch-negative-refspec.sh
@@ -105,7 +105,6 @@ test_expect_success "fetch with negative pattern refspec does not expand prefix"
'
test_expect_success "fetch with negative refspec avoids duplicate conflict" '
- cd "$D" &&
(
cd one &&
git branch dups/a &&
diff --git a/t/t5600-clone-fail-cleanup.sh b/t/t5600-clone-fail-cleanup.sh
index 4a1a912e03..34b3df4027 100755
--- a/t/t5600-clone-fail-cleanup.sh
+++ b/t/t5600-clone-fail-cleanup.sh
@@ -35,7 +35,9 @@ test_expect_success 'create a repo to clone' '
'
test_expect_success 'create objects in repo for later corruption' '
- test_commit -C foo file
+ test_commit -C foo file &&
+ git -C foo checkout --detach &&
+ test_commit -C foo detached
'
# source repository given to git clone should be relative to the
@@ -97,4 +99,11 @@ test_expect_success 'failed clone into empty leaves directory (separate, wt)' '
test_dir_is_empty empty-wt
'
+test_expect_success 'transport failure cleans up directory' '
+ test_must_fail git clone --no-local \
+ -u "f() { git-upload-pack \"\$@\"; return 1; }; f" \
+ foo broken-clone &&
+ test_path_is_missing broken-clone
+'
+
test_done
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 329ae599fd..83c24fc97a 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -305,7 +305,8 @@ test_expect_success 'clone from original with relative alternate' '
test_expect_success 'clone checking out a tag' '
git clone --branch=some-tag src dst.tag &&
GIT_DIR=src/.git git rev-parse some-tag >expected &&
- test_cmp expected dst.tag/.git/HEAD &&
+ GIT_DIR=dst.tag/.git git rev-parse HEAD >actual &&
+ test_cmp expected actual &&
GIT_DIR=dst.tag/.git git config remote.origin.fetch >fetch.actual &&
echo "+refs/heads/*:refs/remotes/origin/*" >fetch.expected &&
test_cmp fetch.expected fetch.actual
@@ -762,7 +763,7 @@ test_expect_success 'partial clone using HTTP' '
test_expect_success 'reject cloning shallow repository using HTTP' '
test_when_finished "rm -rf repo" &&
git clone --bare --no-local --depth=1 src "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
- test_must_fail git clone --reject-shallow $HTTPD_URL/smart/repo.git repo 2>err &&
+ test_must_fail git -c protocol.version=2 clone --reject-shallow $HTTPD_URL/smart/repo.git repo 2>err &&
test_i18ngrep -e "source repository is shallow, reject to clone." err &&
git clone --no-reject-shallow $HTTPD_URL/smart/repo.git repo
diff --git a/t/t5604-clone-reference.sh b/t/t5604-clone-reference.sh
index e845d621f6..24340e6d56 100755
--- a/t/t5604-clone-reference.sh
+++ b/t/t5604-clone-reference.sh
@@ -87,7 +87,7 @@ test_expect_success 'updating origin' '
'
test_expect_success 'pulling changes from origin' '
- git -C C pull origin
+ git -C C pull --no-rebase origin
'
# the 2 local objects are commit and tree from the merge
@@ -96,7 +96,7 @@ test_expect_success 'that alternate to origin gets used' '
'
test_expect_success 'pulling changes from origin' '
- git -C D pull origin
+ git -C D pull --no-rebase origin
'
# the 5 local objects are expected; file3 blob, commit in A to add it
diff --git a/t/t5606-clone-options.sh b/t/t5606-clone-options.sh
index 3a595c0f82..d822153e4d 100755
--- a/t/t5606-clone-options.sh
+++ b/t/t5606-clone-options.sh
@@ -16,6 +16,18 @@ test_expect_success 'setup' '
'
+test_expect_success 'submodule.stickyRecursiveClone flag manipulates submodule.recurse value' '
+
+ test_config_global submodule.stickyRecursiveClone true &&
+ git clone --recurse-submodules parent clone_recurse_true &&
+ test_cmp_config -C clone_recurse_true true submodule.recurse &&
+
+ test_config_global submodule.stickyRecursiveClone false &&
+ git clone --recurse-submodules parent clone_recurse_false &&
+ test_expect_code 1 git -C clone_recurse_false config --get submodule.recurse
+
+'
+
test_expect_success 'clone -o' '
git clone -o foo parent clone-o &&
diff --git a/t/t5607-clone-bundle.sh b/t/t5607-clone-bundle.sh
index f4c383cd5c..51705aa86a 100755
--- a/t/t5607-clone-bundle.sh
+++ b/t/t5607-clone-bundle.sh
@@ -29,11 +29,21 @@ test_expect_success '"verify" needs a worktree' '
test_expect_success 'annotated tags can be excluded by rev-list options' '
git bundle create bundle --all --since=7.Apr.2005.15:14:00.-0700 &&
- git ls-remote bundle > output &&
- grep tag output &&
+ cat >expect <<-EOF &&
+ $(git rev-parse HEAD) HEAD
+ $(git rev-parse tag) refs/tags/tag
+ $(git rev-parse main) refs/heads/main
+ EOF
+ git ls-remote bundle >actual &&
+ test_cmp expect actual &&
+
git bundle create bundle --all --since=7.Apr.2005.15:16:00.-0700 &&
- git ls-remote bundle > output &&
- ! grep tag output
+ cat >expect <<-EOF &&
+ $(git rev-parse HEAD) HEAD
+ $(git rev-parse main) refs/heads/main
+ EOF
+ git ls-remote bundle >actual &&
+ test_cmp expect actual
'
test_expect_success 'die if bundle file cannot be created' '
@@ -43,39 +53,66 @@ test_expect_success 'die if bundle file cannot be created' '
test_expect_success 'bundle --stdin' '
echo main | git bundle create stdin-bundle.bdl --stdin &&
- git ls-remote stdin-bundle.bdl >output &&
- grep main output
+ cat >expect <<-EOF &&
+ $(git rev-parse main) refs/heads/main
+ EOF
+ git ls-remote stdin-bundle.bdl >actual &&
+ test_cmp expect actual
'
test_expect_success 'bundle --stdin <rev-list options>' '
echo main | git bundle create hybrid-bundle.bdl --stdin tag &&
- git ls-remote hybrid-bundle.bdl >output &&
- grep main output
+ cat >expect <<-EOF &&
+ $(git rev-parse main) refs/heads/main
+ EOF
+ git ls-remote stdin-bundle.bdl >actual &&
+ test_cmp expect actual
'
test_expect_success 'empty bundle file is rejected' '
- : >empty-bundle &&
+ >empty-bundle &&
test_must_fail git fetch empty-bundle
'
# This triggers a bug in older versions where the resulting line (with
# --pretty=oneline) was longer than a 1024-char buffer.
test_expect_success 'ridiculously long subject in boundary' '
- : >file4 &&
+ >file4 &&
test_tick &&
git add file4 &&
printf "%01200d\n" 0 | git commit -F - &&
test_commit fifth &&
git bundle create long-subject-bundle.bdl HEAD^..HEAD &&
- git bundle list-heads long-subject-bundle.bdl >heads &&
- test -s heads &&
+ cat >expect <<-EOF &&
+ $(git rev-parse main) HEAD
+ EOF
+ git bundle list-heads long-subject-bundle.bdl >actual &&
+ test_cmp expect actual &&
+
git fetch long-subject-bundle.bdl &&
- sed -n "/^-/{p;q;}" long-subject-bundle.bdl >boundary &&
- grep "^-$OID_REGEX " boundary
+
+ algo=$(test_oid algo) &&
+ if test "$algo" != sha1
+ then
+ echo "@object-format=sha256"
+ fi >expect &&
+ cat >>expect <<-EOF &&
+ -$(git log --pretty=format:"%H %s" -1 HEAD^)
+ $(git rev-parse HEAD) HEAD
+ EOF
+
+ if test "$algo" = sha1
+ then
+ head -n 3 long-subject-bundle.bdl
+ else
+ head -n 4 long-subject-bundle.bdl
+ fi | grep -v "^#" >actual &&
+
+ test_cmp expect actual
'
test_expect_success 'prerequisites with an empty commit message' '
- : >file1 &&
+ >file1 &&
git add file1 &&
test_tick &&
git commit --allow-empty-message -m "" &&
@@ -103,7 +140,11 @@ test_expect_success 'fetch SHA-1 from bundle' '
test_expect_success 'git bundle uses expected default format' '
git bundle create bundle HEAD^.. &&
- head -n1 bundle | grep "^# v$(test_oid version) git bundle$"
+ cat >expect <<-EOF &&
+ # v$(test_oid version) git bundle
+ EOF
+ head -n1 bundle >actual &&
+ test_cmp expect actual
'
test_expect_success 'git bundle v3 has expected contents' '
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index 5cb415386e..cf3e82bdf5 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -548,6 +548,14 @@ test_expect_success 'fetch from a partial clone, protocol v2' '
grep "version 2" trace
'
+test_expect_success 'repack does not loosen promisor objects' '
+ rm -rf client trace &&
+ git clone --bare --filter=blob:none "file://$(pwd)/srv.bare" client &&
+ test_when_finished "rm -rf client trace" &&
+ GIT_TRACE2_PERF="$(pwd)/trace" git -C client repack -A -d &&
+ grep "loosen_unused_packed_objects/loosened:0" trace
+'
+
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh
index 509f379d49..aa1827d841 100755
--- a/t/t5701-git-serve.sh
+++ b/t/t5701-git-serve.sh
@@ -16,9 +16,10 @@ test_expect_success 'test capability advertisement' '
version 2
agent=git/$(git version | cut -d" " -f3)
ls-refs=unborn
- fetch=shallow
+ fetch=shallow wait-for-done
server-option
object-format=$(test_oid algo)
+ object-info
0000
EOF
@@ -71,6 +72,37 @@ test_expect_success 'request invalid command' '
test_i18ngrep "invalid command" err
'
+test_expect_success 'request capability as command' '
+ test-tool pkt-line pack >in <<-EOF &&
+ command=agent
+ object-format=$(test_oid algo)
+ 0000
+ EOF
+ test_must_fail test-tool serve-v2 --stateless-rpc 2>err <in &&
+ grep invalid.command.*agent err
+'
+
+test_expect_success 'request command as capability' '
+ test-tool pkt-line pack >in <<-EOF &&
+ command=ls-refs
+ object-format=$(test_oid algo)
+ fetch
+ 0000
+ EOF
+ test_must_fail test-tool serve-v2 --stateless-rpc 2>err <in &&
+ grep unknown.capability err
+'
+
+test_expect_success 'requested command is command=value' '
+ test-tool pkt-line pack >in <<-EOF &&
+ command=ls-refs=whatever
+ object-format=$(test_oid algo)
+ 0000
+ EOF
+ test_must_fail test-tool serve-v2 --stateless-rpc 2>err <in &&
+ grep invalid.command.*ls-refs=whatever err
+'
+
test_expect_success 'wrong object-format' '
test-tool pkt-line pack >in <<-EOF &&
command=fetch
@@ -115,6 +147,19 @@ test_expect_success 'basics of ls-refs' '
test_cmp expect actual
'
+test_expect_success 'ls-refs complains about unknown options' '
+ test-tool pkt-line pack >in <<-EOF &&
+ command=ls-refs
+ object-format=$(test_oid algo)
+ 0001
+ no-such-arg
+ 0000
+ EOF
+
+ test_must_fail test-tool serve-v2 --stateless-rpc 2>err <in &&
+ grep unexpected.line.*no-such-arg err
+'
+
test_expect_success 'basic ref-prefixes' '
test-tool pkt-line pack >in <<-EOF &&
command=ls-refs
@@ -157,6 +202,37 @@ test_expect_success 'refs/heads prefix' '
test_cmp expect actual
'
+test_expect_success 'ignore very large set of prefixes' '
+ # generate a large number of ref-prefixes that we expect
+ # to match nothing; the value here exceeds TOO_MANY_PREFIXES
+ # from ls-refs.c.
+ {
+ echo command=ls-refs &&
+ echo object-format=$(test_oid algo) &&
+ echo 0001 &&
+ perl -le "print \"ref-prefix refs/heads/\$_\" for (1..65536)" &&
+ echo 0000
+ } |
+ test-tool pkt-line pack >in &&
+
+ # and then confirm that we see unmatched prefixes anyway (i.e.,
+ # that the prefix was not applied).
+ cat >expect <<-EOF &&
+ $(git rev-parse HEAD) HEAD
+ $(git rev-parse refs/heads/dev) refs/heads/dev
+ $(git rev-parse refs/heads/main) refs/heads/main
+ $(git rev-parse refs/heads/release) refs/heads/release
+ $(git rev-parse refs/tags/annotated-tag) refs/tags/annotated-tag
+ $(git rev-parse refs/tags/one) refs/tags/one
+ $(git rev-parse refs/tags/two) refs/tags/two
+ 0000
+ EOF
+
+ test-tool serve-v2 --stateless-rpc <in >out &&
+ test-tool pkt-line unpack <out >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'peel parameter' '
test-tool pkt-line pack >in <<-EOF &&
command=ls-refs
@@ -240,4 +316,29 @@ test_expect_success 'unexpected lines are not allowed in fetch request' '
grep "unexpected line: .this-is-not-a-command." err
'
+# Test the basics of object-info
+#
+test_expect_success 'basics of object-info' '
+ test-tool pkt-line pack >in <<-EOF &&
+ command=object-info
+ object-format=$(test_oid algo)
+ 0001
+ size
+ oid $(git rev-parse two:two.t)
+ oid $(git rev-parse two:two.t)
+ 0000
+ EOF
+
+ cat >expect <<-EOF &&
+ size
+ $(git rev-parse two:two.t) $(wc -c <two.t | xargs)
+ $(git rev-parse two:two.t) $(wc -c <two.t | xargs)
+ 0000
+ EOF
+
+ test-tool serve-v2 --stateless-rpc <in >out &&
+ test-tool pkt-line unpack <out >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index 2e1243ca40..d527cf6c49 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -27,9 +27,9 @@ test_expect_success 'list refs with git:// using protocol v2' '
ls-remote --symref "$GIT_DAEMON_URL/parent" >actual &&
# Client requested to use protocol v2
- grep "git> .*\\\0\\\0version=2\\\0$" log &&
+ grep "ls-remote> .*\\\0\\\0version=2\\\0$" log &&
# Server responded using protocol v2
- grep "git< version 2" log &&
+ grep "ls-remote< version 2" log &&
git ls-remote --symref "$GIT_DAEMON_URL/parent" >expect &&
test_cmp expect actual
@@ -151,7 +151,7 @@ test_expect_success 'list refs with file:// using protocol v2' '
ls-remote --symref "file://$(pwd)/file_parent" >actual &&
# Server responded using protocol v2
- grep "git< version 2" log &&
+ grep "ls-remote< version 2" log &&
git ls-remote --symref "file://$(pwd)/file_parent" >expect &&
test_cmp expect actual
@@ -237,6 +237,19 @@ test_expect_success '...but not if explicitly forbidden by config' '
! grep "refs/heads/mydefaultbranch" file_empty_child/.git/HEAD
'
+test_expect_success 'bare clone propagates empty default branch' '
+ test_when_finished "rm -rf file_empty_parent file_empty_child.git" &&
+
+ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= \
+ git -c init.defaultBranch=mydefaultbranch init file_empty_parent &&
+
+ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= \
+ git -c init.defaultBranch=main -c protocol.version=2 \
+ clone --bare \
+ "file://$(pwd)/file_empty_parent" file_empty_child.git &&
+ grep "refs/heads/mydefaultbranch" file_empty_child.git/HEAD
+'
+
test_expect_success 'fetch with file:// using protocol v2' '
test_when_finished "rm -f log" &&
@@ -585,6 +598,65 @@ test_expect_success 'deepen-relative' '
test_cmp expected actual
'
+setup_negotiate_only () {
+ SERVER="$1"
+ URI="$2"
+
+ rm -rf "$SERVER" client
+
+ git init "$SERVER"
+ test_commit -C "$SERVER" one
+ test_commit -C "$SERVER" two
+
+ git clone "$URI" client
+ test_commit -C client three
+}
+
+test_expect_success 'usage: --negotiate-only without --negotiation-tip' '
+ SERVER="server" &&
+ URI="file://$(pwd)/server" &&
+
+ setup_negotiate_only "$SERVER" "$URI" &&
+
+ cat >err.expect <<-\EOF &&
+ fatal: --negotiate-only needs one or more --negotiate-tip=*
+ EOF
+
+ test_must_fail git -c protocol.version=2 -C client fetch \
+ --negotiate-only \
+ origin 2>err.actual &&
+ test_cmp err.expect err.actual
+'
+
+test_expect_success 'file:// --negotiate-only' '
+ SERVER="server" &&
+ URI="file://$(pwd)/server" &&
+
+ setup_negotiate_only "$SERVER" "$URI" &&
+
+ git -c protocol.version=2 -C client fetch \
+ --no-tags \
+ --negotiate-only \
+ --negotiation-tip=$(git -C client rev-parse HEAD) \
+ origin >out &&
+ COMMON=$(git -C "$SERVER" rev-parse two) &&
+ grep "$COMMON" out
+'
+
+test_expect_success 'file:// --negotiate-only with protocol v0' '
+ SERVER="server" &&
+ URI="file://$(pwd)/server" &&
+
+ setup_negotiate_only "$SERVER" "$URI" &&
+
+ test_must_fail git -c protocol.version=0 -C client fetch \
+ --no-tags \
+ --negotiate-only \
+ --negotiation-tip=$(git -C client rev-parse HEAD) \
+ origin 2>err &&
+ test_i18ngrep "negotiate-only requires protocol v2" err
+'
+
# Test protocol v2 with 'http://' transport
#
. "$TEST_DIRECTORY"/lib-httpd.sh
@@ -1035,6 +1107,52 @@ test_expect_success 'packfile-uri with transfer.fsckobjects fails when .gitmodul
test_i18ngrep "disallowed submodule name" err
'
+test_expect_success 'http:// --negotiate-only' '
+ SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
+ URI="$HTTPD_URL/smart/server" &&
+
+ setup_negotiate_only "$SERVER" "$URI" &&
+
+ git -c protocol.version=2 -C client fetch \
+ --no-tags \
+ --negotiate-only \
+ --negotiation-tip=$(git -C client rev-parse HEAD) \
+ origin >out &&
+ COMMON=$(git -C "$SERVER" rev-parse two) &&
+ grep "$COMMON" out
+'
+
+test_expect_success 'http:// --negotiate-only without wait-for-done support' '
+ SERVER="server" &&
+ URI="$HTTPD_URL/one_time_perl/server" &&
+
+ setup_negotiate_only "$SERVER" "$URI" &&
+
+ echo "s/ wait-for-done/ xxxx-xxx-xxxx/" \
+ >"$HTTPD_ROOT_PATH/one-time-perl" &&
+
+ test_must_fail git -c protocol.version=2 -C client fetch \
+ --no-tags \
+ --negotiate-only \
+ --negotiation-tip=$(git -C client rev-parse HEAD) \
+ origin 2>err &&
+ test_i18ngrep "server does not support wait-for-done" err
+'
+
+test_expect_success 'http:// --negotiate-only with protocol v0' '
+ SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
+ URI="$HTTPD_URL/smart/server" &&
+
+ setup_negotiate_only "$SERVER" "$URI" &&
+
+ test_must_fail git -c protocol.version=0 -C client fetch \
+ --no-tags \
+ --negotiate-only \
+ --negotiation-tip=$(git -C client rev-parse HEAD) \
+ origin 2>err &&
+ test_i18ngrep "negotiate-only requires protocol v2" err
+'
+
# DO NOT add non-httpd-specific tests here, because the last part of this
# test script is only executed when httpd is available and enabled.
diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index e9e471621d..220098523a 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -40,6 +40,30 @@ write_command () {
fi
}
+# Write a complete fetch command to stdout, suitable for use with `test-tool
+# pkt-line`. "want-ref", "want", and "have" lines are read from stdin.
+#
+# Examples:
+#
+# write_fetch_command <<-EOF
+# want-ref refs/heads/main
+# have $(git rev-parse a)
+# EOF
+#
+# write_fetch_command <<-EOF
+# want $(git rev-parse b)
+# have $(git rev-parse a)
+# EOF
+#
+write_fetch_command () {
+ write_command fetch &&
+ echo "0001" &&
+ echo "no-progress" &&
+ cat &&
+ echo "done" &&
+ echo "0000"
+}
+
# c(o/foo) d(o/bar)
# \ /
# b e(baz) f(main)
@@ -77,15 +101,11 @@ test_expect_success 'config controls ref-in-want advertisement' '
'
test_expect_success 'invalid want-ref line' '
- test-tool pkt-line pack >in <<-EOF &&
- $(write_command fetch)
- 0001
- no-progress
+ write_fetch_command >pkt <<-EOF &&
want-ref refs/heads/non-existent
- done
- 0000
EOF
+ test-tool pkt-line pack <pkt >in &&
test_must_fail test-tool serve-v2 --stateless-rpc 2>out <in &&
grep "unknown ref" out
'
@@ -97,16 +117,11 @@ test_expect_success 'basic want-ref' '
EOF
git rev-parse f >expected_commits &&
- oid=$(git rev-parse a) &&
- test-tool pkt-line pack >in <<-EOF &&
- $(write_command fetch)
- 0001
- no-progress
+ write_fetch_command >pkt <<-EOF &&
want-ref refs/heads/main
- have $oid
- done
- 0000
+ have $(git rev-parse a)
EOF
+ test-tool pkt-line pack <pkt >in &&
test-tool serve-v2 --stateless-rpc >out <in &&
check_output
@@ -121,17 +136,12 @@ test_expect_success 'multiple want-ref lines' '
EOF
git rev-parse c d >expected_commits &&
- oid=$(git rev-parse b) &&
- test-tool pkt-line pack >in <<-EOF &&
- $(write_command fetch)
- 0001
- no-progress
+ write_fetch_command >pkt <<-EOF &&
want-ref refs/heads/o/foo
want-ref refs/heads/o/bar
- have $oid
- done
- 0000
+ have $(git rev-parse b)
EOF
+ test-tool pkt-line pack <pkt >in &&
test-tool serve-v2 --stateless-rpc >out <in &&
check_output
@@ -144,16 +154,12 @@ test_expect_success 'mix want and want-ref' '
EOF
git rev-parse e f >expected_commits &&
- test-tool pkt-line pack >in <<-EOF &&
- $(write_command fetch)
- 0001
- no-progress
+ write_fetch_command >pkt <<-EOF &&
want-ref refs/heads/main
want $(git rev-parse e)
have $(git rev-parse a)
- done
- 0000
EOF
+ test-tool pkt-line pack <pkt >in &&
test-tool serve-v2 --stateless-rpc >out <in &&
check_output
@@ -166,16 +172,11 @@ test_expect_success 'want-ref with ref we already have commit for' '
EOF
>expected_commits &&
- oid=$(git rev-parse c) &&
- test-tool pkt-line pack >in <<-EOF &&
- $(write_command fetch)
- 0001
- no-progress
+ write_fetch_command >pkt <<-EOF &&
want-ref refs/heads/o/foo
- have $oid
- done
- 0000
+ have $(git rev-parse c)
EOF
+ test-tool pkt-line pack <pkt >in &&
test-tool serve-v2 --stateless-rpc >out <in &&
check_output
@@ -298,6 +299,141 @@ test_expect_success 'fetching with wildcard that matches multiple refs' '
grep "want-ref refs/heads/o/bar" log
'
+REPO="$(pwd)/repo-ns"
+
+test_expect_success 'setup namespaced repo' '
+ (
+ git init -b main "$REPO" &&
+ cd "$REPO" &&
+ test_commit a &&
+ test_commit b &&
+ git checkout a &&
+ test_commit c &&
+ git checkout a &&
+ test_commit d &&
+ git update-ref refs/heads/ns-no b &&
+ git update-ref refs/namespaces/ns/refs/heads/ns-yes c &&
+ git update-ref refs/namespaces/ns/refs/heads/hidden d
+ ) &&
+ git -C "$REPO" config uploadpack.allowRefInWant true
+'
+
+test_expect_success 'with namespace: want-ref is considered relative to namespace' '
+ wanted_ref=refs/heads/ns-yes &&
+
+ oid=$(git -C "$REPO" rev-parse "refs/namespaces/ns/$wanted_ref") &&
+ cat >expected_refs <<-EOF &&
+ $oid $wanted_ref
+ EOF
+ cat >expected_commits <<-EOF &&
+ $oid
+ $(git -C "$REPO" rev-parse a)
+ EOF
+
+ write_fetch_command >pkt <<-EOF &&
+ want-ref $wanted_ref
+ EOF
+ test-tool pkt-line pack <pkt >in &&
+
+ GIT_NAMESPACE=ns test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
+ check_output
+'
+
+test_expect_success 'with namespace: want-ref outside namespace is unknown' '
+ wanted_ref=refs/heads/ns-no &&
+
+ write_fetch_command >pkt <<-EOF &&
+ want-ref $wanted_ref
+ EOF
+ test-tool pkt-line pack <pkt >in &&
+
+ test_must_fail env GIT_NAMESPACE=ns \
+ test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
+ grep "unknown ref" out
+'
+
+# Cross-check refs/heads/ns-no indeed exists
+test_expect_success 'without namespace: want-ref outside namespace succeeds' '
+ wanted_ref=refs/heads/ns-no &&
+
+ oid=$(git -C "$REPO" rev-parse $wanted_ref) &&
+ cat >expected_refs <<-EOF &&
+ $oid $wanted_ref
+ EOF
+ cat >expected_commits <<-EOF &&
+ $oid
+ $(git -C "$REPO" rev-parse a)
+ EOF
+
+ write_fetch_command >pkt <<-EOF &&
+ want-ref $wanted_ref
+ EOF
+ test-tool pkt-line pack <pkt >in &&
+
+ test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
+ check_output
+'
+
+test_expect_success 'with namespace: hideRefs is matched, relative to namespace' '
+ wanted_ref=refs/heads/hidden &&
+ git -C "$REPO" config transfer.hideRefs $wanted_ref &&
+
+ write_fetch_command >pkt <<-EOF &&
+ want-ref $wanted_ref
+ EOF
+ test-tool pkt-line pack <pkt >in &&
+
+ test_must_fail env GIT_NAMESPACE=ns \
+ test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
+ grep "unknown ref" out
+'
+
+# Cross-check refs/heads/hidden indeed exists
+test_expect_success 'with namespace: want-ref succeeds if hideRefs is removed' '
+ wanted_ref=refs/heads/hidden &&
+ git -C "$REPO" config --unset transfer.hideRefs $wanted_ref &&
+
+ oid=$(git -C "$REPO" rev-parse "refs/namespaces/ns/$wanted_ref") &&
+ cat >expected_refs <<-EOF &&
+ $oid $wanted_ref
+ EOF
+ cat >expected_commits <<-EOF &&
+ $oid
+ $(git -C "$REPO" rev-parse a)
+ EOF
+
+ write_fetch_command >pkt <<-EOF &&
+ want-ref $wanted_ref
+ EOF
+ test-tool pkt-line pack <pkt >in &&
+
+ GIT_NAMESPACE=ns test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
+ check_output
+'
+
+test_expect_success 'without namespace: relative hideRefs does not match' '
+ wanted_ref=refs/namespaces/ns/refs/heads/hidden &&
+ git -C "$REPO" config transfer.hideRefs refs/heads/hidden &&
+
+ oid=$(git -C "$REPO" rev-parse $wanted_ref) &&
+ cat >expected_refs <<-EOF &&
+ $oid $wanted_ref
+ EOF
+ cat >expected_commits <<-EOF &&
+ $oid
+ $(git -C "$REPO" rev-parse a)
+ EOF
+
+ write_fetch_command >pkt <<-EOF &&
+ want-ref $wanted_ref
+ EOF
+ test-tool pkt-line pack <pkt >in &&
+
+ test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
+ check_output
+'
+
+
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
diff --git a/t/t5704-protocol-violations.sh b/t/t5704-protocol-violations.sh
index 5c941949b9..bc393d7c31 100755
--- a/t/t5704-protocol-violations.sh
+++ b/t/t5704-protocol-violations.sh
@@ -32,4 +32,19 @@ test_expect_success 'extra delim packet in v2 fetch args' '
test_i18ngrep "expected flush after fetch arguments" err
'
+test_expect_success 'bogus symref in v0 capabilities' '
+ test_commit foo &&
+ oid=$(git rev-parse HEAD) &&
+ dst=refs/heads/foo &&
+ {
+ printf "%s HEAD\0symref object-format=%s symref=HEAD:%s\n" \
+ "$oid" "$GIT_DEFAULT_HASH" "$dst" |
+ test-tool pkt-line pack-raw-stdin &&
+ printf "0000"
+ } >input &&
+ git ls-remote --symref --upload-pack="cat input; read junk;:" . >actual &&
+ printf "ref: %s\tHEAD\n%s\tHEAD\n" "$dst" "$oid" >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t5705-session-id-in-capabilities.sh b/t/t5705-session-id-in-capabilities.sh
index f1d189d5bc..eb8c79aafd 100755
--- a/t/t5705-session-id-in-capabilities.sh
+++ b/t/t5705-session-id-in-capabilities.sh
@@ -73,6 +73,17 @@ do
grep \"key\":\"server-sid\" tr2-client-events &&
grep \"key\":\"client-sid\" tr2-server-events
'
+
+ test_expect_success "client & server log negotiated version (v${PROTO})" '
+ test_when_finished "rm -rf local tr2-client-events tr2-server-events" &&
+ cp -r "$LOCAL_PRISTINE" local &&
+ GIT_TRACE2_EVENT="$(pwd)/tr2-client-events" \
+ git -c protocol.version=$PROTO -C local fetch \
+ --upload-pack "GIT_TRACE2_EVENT=\"$(pwd)/tr2-server-events\" git-upload-pack" \
+ origin &&
+ grep \"key\":\"negotiated-version\",\"value\":\"$PROTO\" tr2-client-events &&
+ grep \"key\":\"negotiated-version\",\"value\":\"$PROTO\" tr2-server-events
+ '
done
test_done
diff --git a/t/t6000-rev-list-misc.sh b/t/t6000-rev-list-misc.sh
index 12def7bcbf..ef849e5bc8 100755
--- a/t/t6000-rev-list-misc.sh
+++ b/t/t6000-rev-list-misc.sh
@@ -169,4 +169,35 @@ test_expect_success 'rev-list --count --objects' '
test_line_count = $count actual
'
+test_expect_success 'rev-list --unsorted-input results in different sorting' '
+ git rev-list --unsorted-input HEAD HEAD~ >first &&
+ git rev-list --unsorted-input HEAD~ HEAD >second &&
+ ! test_cmp first second &&
+ sort first >first.sorted &&
+ sort second >second.sorted &&
+ test_cmp first.sorted second.sorted
+'
+
+test_expect_success 'rev-list --unsorted-input incompatible with --no-walk' '
+ cat >expect <<-EOF &&
+ fatal: --no-walk is incompatible with --unsorted-input
+ EOF
+ test_must_fail git rev-list --unsorted-input --no-walk HEAD 2>error &&
+ test_cmp expect error &&
+ test_must_fail git rev-list --unsorted-input --no-walk=sorted HEAD 2>error &&
+ test_cmp expect error &&
+ test_must_fail git rev-list --unsorted-input --no-walk=unsorted HEAD 2>error &&
+ test_cmp expect error &&
+
+ cat >expect <<-EOF &&
+ fatal: --unsorted-input is incompatible with --no-walk
+ EOF
+ test_must_fail git rev-list --no-walk --unsorted-input HEAD 2>error &&
+ test_cmp expect error &&
+ test_must_fail git rev-list --no-walk=sorted --unsorted-input HEAD 2>error &&
+ test_cmp expect error &&
+ test_must_fail git rev-list --no-walk=unsorted --unsorted-input HEAD 2>error &&
+ test_cmp expect error
+'
+
test_done
diff --git a/t/t6001-rev-list-graft.sh b/t/t6001-rev-list-graft.sh
index 90d93f77fa..7294147334 100755
--- a/t/t6001-rev-list-graft.sh
+++ b/t/t6001-rev-list-graft.sh
@@ -23,7 +23,8 @@ test_expect_success setup '
git commit -a -m "Third in one history." &&
A2=$(git rev-parse --verify HEAD) &&
- rm -f .git/refs/heads/main .git/index &&
+ git update-ref -d refs/heads/main &&
+ rm -f .git/index &&
echo >fileA fileA again &&
echo >subdir/fileB fileB again &&
diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index 35a2f62392..41d0ca00b1 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -41,22 +41,59 @@ test_expect_success 'setup' '
echo "$added_iso88591" | git commit -F - &&
head1=$(git rev-parse --verify HEAD) &&
head1_short=$(git rev-parse --verify --short $head1) &&
+ head1_short4=$(git rev-parse --verify --short=4 $head1) &&
tree1=$(git rev-parse --verify HEAD:) &&
tree1_short=$(git rev-parse --verify --short $tree1) &&
echo "$changed" > foo &&
echo "$changed_iso88591" | git commit -a -F - &&
head2=$(git rev-parse --verify HEAD) &&
head2_short=$(git rev-parse --verify --short $head2) &&
+ head2_short4=$(git rev-parse --verify --short=4 $head2) &&
tree2=$(git rev-parse --verify HEAD:) &&
tree2_short=$(git rev-parse --verify --short $tree2) &&
git config --unset i18n.commitEncoding
'
-# usage: test_format name format_string [failure] <expected_output
+# usage: test_format [argument...] name format_string [failure] <expected_output
test_format () {
+ local args=
+ while true
+ do
+ case "$1" in
+ --*)
+ args="$args $1"
+ shift;;
+ *)
+ break;;
+ esac
+ done
cat >expect.$1
test_expect_${3:-success} "format $1" "
- git rev-list --pretty=format:'$2' main >output.$1 &&
+ git rev-list $args --pretty=format:'$2' main >output.$1 &&
+ test_cmp expect.$1 output.$1
+ "
+}
+
+# usage: test_pretty [argument...] name format_name [failure] <expected_output
+test_pretty () {
+ local args=
+ while true
+ do
+ case "$1" in
+ --*)
+ args="$args $1"
+ shift;;
+ *)
+ break;;
+ esac
+ done
+ cat >expect.$1
+ test_expect_${3:-success} "pretty $1 (without --no-commit-header)" "
+ git rev-list $args --pretty='$2' main >output.$1 &&
+ test_cmp expect.$1 output.$1
+ "
+ test_expect_${3:-success} "pretty $1 (with --no-commit-header)" "
+ git rev-list $args --no-commit-header --pretty='$2' main >output.$1 &&
test_cmp expect.$1 output.$1
"
}
@@ -93,6 +130,20 @@ $head1
$head1_short
EOF
+test_format --no-commit-header hash-no-header %H%n%h <<EOF
+$head2
+$head2_short
+$head1
+$head1_short
+EOF
+
+test_format --abbrev-commit --abbrev=0 --no-commit-header hash-no-header-abbrev %H%n%h <<EOF
+$head2
+$head2_short4
+$head1
+$head1_short4
+EOF
+
test_format tree %T%n%t <<EOF
commit $head2
$tree2
@@ -181,6 +232,31 @@ $added
EOF
+test_format --no-commit-header raw-body-no-header %B <<EOF
+$changed
+
+$added
+
+EOF
+
+test_pretty oneline oneline <<EOF
+$head2 $changed
+$head1 $added
+EOF
+
+test_pretty short short <<EOF
+commit $head2
+Author: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>
+
+ $changed
+
+commit $head1
+Author: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>
+
+ $added
+
+EOF
+
test_expect_success 'basic colors' '
cat >expect <<-EOF &&
commit $head2
diff --git a/t/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh
index 881f72fd44..b13e8a52a9 100755
--- a/t/t6020-bundle-misc.sh
+++ b/t/t6020-bundle-misc.sh
@@ -80,31 +80,46 @@ test_commit_setvar () {
eval $var=$oid
}
+get_abbrev_oid () {
+ oid=$1 &&
+ suffix=${oid#???????} &&
+ oid=${oid%$suffix} &&
+ if test -n "$oid"
+ then
+ echo "$oid"
+ else
+ echo "undefined-oid"
+ fi
+}
+
# Format the output of git commands to make a user-friendly and stable
# text. We can easily prepare the expect text without having to worry
-# about future changes of the commit ID and spaces of the output.
+# about future changes of the commit ID.
make_user_friendly_and_stable_output () {
sed \
- -e "s/${A%${A#???????}}[0-9a-f]*/<COMMIT-A>/g" \
- -e "s/${B%${B#???????}}[0-9a-f]*/<COMMIT-B>/g" \
- -e "s/${C%${C#???????}}[0-9a-f]*/<COMMIT-C>/g" \
- -e "s/${D%${D#???????}}[0-9a-f]*/<COMMIT-D>/g" \
- -e "s/${E%${E#???????}}[0-9a-f]*/<COMMIT-E>/g" \
- -e "s/${F%${F#???????}}[0-9a-f]*/<COMMIT-F>/g" \
- -e "s/${G%${G#???????}}[0-9a-f]*/<COMMIT-G>/g" \
- -e "s/${H%${H#???????}}[0-9a-f]*/<COMMIT-H>/g" \
- -e "s/${I%${I#???????}}[0-9a-f]*/<COMMIT-I>/g" \
- -e "s/${J%${J#???????}}[0-9a-f]*/<COMMIT-J>/g" \
- -e "s/${K%${K#???????}}[0-9a-f]*/<COMMIT-K>/g" \
- -e "s/${L%${L#???????}}[0-9a-f]*/<COMMIT-L>/g" \
- -e "s/${M%${M#???????}}[0-9a-f]*/<COMMIT-M>/g" \
- -e "s/${N%${N#???????}}[0-9a-f]*/<COMMIT-N>/g" \
- -e "s/${O%${O#???????}}[0-9a-f]*/<COMMIT-O>/g" \
- -e "s/${P%${P#???????}}[0-9a-f]*/<COMMIT-P>/g" \
- -e "s/${TAG1%${TAG1#???????}}[0-9a-f]*/<TAG-1>/g" \
- -e "s/${TAG2%${TAG2#???????}}[0-9a-f]*/<TAG-2>/g" \
- -e "s/${TAG3%${TAG3#???????}}[0-9a-f]*/<TAG-3>/g" \
- -e "s/ *\$//"
+ -e "s/$(get_abbrev_oid $A)[0-9a-f]*/<COMMIT-A>/g" \
+ -e "s/$(get_abbrev_oid $B)[0-9a-f]*/<COMMIT-B>/g" \
+ -e "s/$(get_abbrev_oid $C)[0-9a-f]*/<COMMIT-C>/g" \
+ -e "s/$(get_abbrev_oid $D)[0-9a-f]*/<COMMIT-D>/g" \
+ -e "s/$(get_abbrev_oid $E)[0-9a-f]*/<COMMIT-E>/g" \
+ -e "s/$(get_abbrev_oid $F)[0-9a-f]*/<COMMIT-F>/g" \
+ -e "s/$(get_abbrev_oid $G)[0-9a-f]*/<COMMIT-G>/g" \
+ -e "s/$(get_abbrev_oid $H)[0-9a-f]*/<COMMIT-H>/g" \
+ -e "s/$(get_abbrev_oid $I)[0-9a-f]*/<COMMIT-I>/g" \
+ -e "s/$(get_abbrev_oid $J)[0-9a-f]*/<COMMIT-J>/g" \
+ -e "s/$(get_abbrev_oid $K)[0-9a-f]*/<COMMIT-K>/g" \
+ -e "s/$(get_abbrev_oid $L)[0-9a-f]*/<COMMIT-L>/g" \
+ -e "s/$(get_abbrev_oid $M)[0-9a-f]*/<COMMIT-M>/g" \
+ -e "s/$(get_abbrev_oid $N)[0-9a-f]*/<COMMIT-N>/g" \
+ -e "s/$(get_abbrev_oid $O)[0-9a-f]*/<COMMIT-O>/g" \
+ -e "s/$(get_abbrev_oid $P)[0-9a-f]*/<COMMIT-P>/g" \
+ -e "s/$(get_abbrev_oid $TAG1)[0-9a-f]*/<TAG-1>/g" \
+ -e "s/$(get_abbrev_oid $TAG2)[0-9a-f]*/<TAG-2>/g" \
+ -e "s/$(get_abbrev_oid $TAG3)[0-9a-f]*/<TAG-3>/g"
+}
+
+format_and_save_expect () {
+ sed -e 's/Z$//' >expect
}
# (C) (D, pull/1/head, topic/1)
@@ -179,11 +194,11 @@ test_expect_success 'create bundle from special rev: main^!' '
git bundle verify special-rev.bdl |
make_user_friendly_and_stable_output >actual &&
- cat >expect <<-\EOF &&
+ format_and_save_expect <<-\EOF &&
The bundle contains this ref:
<COMMIT-P> refs/heads/main
The bundle requires this ref:
- <COMMIT-O>
+ <COMMIT-O> Z
EOF
test_cmp expect actual &&
@@ -200,12 +215,12 @@ test_expect_success 'create bundle with --max-count option' '
git bundle verify max-count.bdl |
make_user_friendly_and_stable_output >actual &&
- cat >expect <<-\EOF &&
+ format_and_save_expect <<-\EOF &&
The bundle contains these 2 refs:
<COMMIT-P> refs/heads/main
<TAG-1> refs/tags/v1
The bundle requires this ref:
- <COMMIT-O>
+ <COMMIT-O> Z
EOF
test_cmp expect actual &&
@@ -225,7 +240,7 @@ test_expect_success 'create bundle with --since option' '
git bundle verify since.bdl |
make_user_friendly_and_stable_output >actual &&
- cat >expect <<-\EOF &&
+ format_and_save_expect <<-\EOF &&
The bundle contains these 5 refs:
<COMMIT-P> refs/heads/main
<COMMIT-N> refs/heads/release
@@ -233,8 +248,8 @@ test_expect_success 'create bundle with --since option' '
<TAG-3> refs/tags/v3
<COMMIT-P> HEAD
The bundle requires these 2 refs:
- <COMMIT-M>
- <COMMIT-K>
+ <COMMIT-M> Z
+ <COMMIT-K> Z
EOF
test_cmp expect actual &&
@@ -293,13 +308,13 @@ test_expect_success 'create bundle 2 - has prerequisites' '
--stdin \
release <input &&
- cat >expect <<-\EOF &&
+ format_and_save_expect <<-\EOF &&
The bundle contains this ref:
<COMMIT-N> refs/heads/release
The bundle requires these 3 refs:
- <COMMIT-D>
- <COMMIT-E>
- <COMMIT-G>
+ <COMMIT-D> Z
+ <COMMIT-E> Z
+ <COMMIT-G> Z
EOF
git bundle verify 2.bdl |
@@ -317,11 +332,11 @@ test_expect_success 'create bundle 2 - has prerequisites' '
test_expect_success 'fail to verify bundle without prerequisites' '
git init --bare test1.git &&
- cat >expect <<-\EOF &&
+ format_and_save_expect <<-\EOF &&
error: Repository lacks these prerequisite commits:
- error: <COMMIT-D>
- error: <COMMIT-E>
- error: <COMMIT-G>
+ error: <COMMIT-D> Z
+ error: <COMMIT-E> Z
+ error: <COMMIT-G> Z
EOF
test_must_fail git -C test1.git bundle verify ../2.bdl 2>&1 |
@@ -352,13 +367,13 @@ test_expect_success 'create bundle 3 - two refs, same object' '
--stdin \
main HEAD <input &&
- cat >expect <<-\EOF &&
+ format_and_save_expect <<-\EOF &&
The bundle contains these 2 refs:
<COMMIT-P> refs/heads/main
<COMMIT-P> HEAD
The bundle requires these 2 refs:
- <COMMIT-M>
- <COMMIT-K>
+ <COMMIT-M> Z
+ <COMMIT-K> Z
EOF
git bundle verify 3.bdl |
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 32bb66e1ed..1be85d064e 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -922,6 +922,17 @@ test_expect_success 'bisect start takes options and revs in any order' '
test_cmp expected actual
'
+# Bisect is started with --term-new and --term-old arguments,
+# then skip. The HEAD should be changed.
+test_expect_success 'bisect skip works with --term*' '
+ git bisect reset &&
+ git bisect start --term-new=fixed --term-old=unfixed HEAD $HASH1 &&
+ hash_skipped_from=$(git rev-parse --verify HEAD) &&
+ git bisect skip &&
+ hash_skipped_to=$(git rev-parse --verify HEAD) &&
+ test "$hash_skipped_from" != "$hash_skipped_to"
+'
+
test_expect_success 'git bisect reset cleans bisection state properly' '
git bisect reset &&
git bisect start &&
@@ -951,4 +962,22 @@ test_expect_success 'bisect handles annotated tags' '
grep "$bad is the first bad commit" output
'
+test_expect_success 'bisect run fails with exit code equals or greater than 128' '
+ write_script test_script.sh <<-\EOF &&
+ exit 128
+ EOF
+ test_must_fail git bisect run ./test_script.sh &&
+ write_script test_script.sh <<-\EOF &&
+ exit 255
+ EOF
+ test_must_fail git bisect run ./test_script.sh
+'
+
+test_expect_success 'bisect visualize with a filename with dash and space' '
+ echo "My test line" >>"./-hello 2" &&
+ git add -- "./-hello 2" &&
+ git commit --quiet -m "Add test line" -- "./-hello 2" &&
+ git bisect visualize -p -- "-hello 2"
+'
+
test_done
diff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh
index df1eff0fb8..82013fc903 100755
--- a/t/t6041-bisect-submodule.sh
+++ b/t/t6041-bisect-submodule.sh
@@ -8,7 +8,7 @@ test_description='bisect can handle submodules'
git_bisect () {
git status -su >expect &&
ls -1pR * >>expect &&
- tar cf "$TRASH_DIRECTORY/tmp.tar" * &&
+ "$TAR" cf "$TRASH_DIRECTORY/tmp.tar" * &&
GOOD=$(git rev-parse --verify HEAD) &&
may_only_be_test_must_fail "$2" &&
$2 git checkout "$1" &&
@@ -25,7 +25,7 @@ git_bisect () {
git bisect start &&
git bisect good $GOOD &&
rm -rf * &&
- tar xf "$TRASH_DIRECTORY/tmp.tar" &&
+ "$TAR" xf "$TRASH_DIRECTORY/tmp.tar" &&
git status -su >actual &&
ls -1pR * >>actual &&
test_cmp expect actual &&
diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh
index e33d512ec1..2500acc2ef 100755
--- a/t/t6050-replace.sh
+++ b/t/t6050-replace.sh
@@ -132,7 +132,7 @@ tagger T A Gger <> 0 +0000
EOF
test_expect_success 'tag replaced commit' '
- git mktag <tag.sig >.git/refs/tags/mytag
+ git update-ref refs/tags/mytag $(git mktag <tag.sig)
'
test_expect_success '"git fsck" works' '
diff --git a/t/t6112-rev-list-filters-objects.sh b/t/t6112-rev-list-filters-objects.sh
index 31457d13b9..4ade105db3 100755
--- a/t/t6112-rev-list-filters-objects.sh
+++ b/t/t6112-rev-list-filters-objects.sh
@@ -159,6 +159,78 @@ test_expect_success 'verify blob:limit=1m' '
test_must_be_empty observed
'
+# Test object:type=<type> filter.
+
+test_expect_success 'setup object-type' '
+ test_create_repo object-type &&
+ test_commit --no-tag -C object-type message blob &&
+ git -C object-type tag tag -m tag-message
+'
+
+test_expect_success 'verify object:type= fails with invalid type' '
+ test_must_fail git -C object-type rev-list --objects --filter=object:type= HEAD &&
+ test_must_fail git -C object-type rev-list --objects --filter=object:type=invalid HEAD
+'
+
+test_expect_success 'verify object:type=blob prints blob and commit' '
+ git -C object-type rev-parse HEAD >expected &&
+ printf "%s blob\n" $(git -C object-type rev-parse HEAD:blob) >>expected &&
+ git -C object-type rev-list --objects --filter=object:type=blob HEAD >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'verify object:type=tree prints tree and commit' '
+ (
+ git -C object-type rev-parse HEAD &&
+ printf "%s \n" $(git -C object-type rev-parse HEAD^{tree})
+ ) >expected &&
+ git -C object-type rev-list --objects --filter=object:type=tree HEAD >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'verify object:type=commit prints commit' '
+ git -C object-type rev-parse HEAD >expected &&
+ git -C object-type rev-list --objects --filter=object:type=commit HEAD >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'verify object:type=tag prints tag' '
+ (
+ git -C object-type rev-parse HEAD &&
+ printf "%s tag\n" $(git -C object-type rev-parse tag)
+ ) >expected &&
+ git -C object-type rev-list --objects --filter=object:type=tag tag >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'verify object:type=blob prints only blob with --filter-provided-objects' '
+ printf "%s blob\n" $(git -C object-type rev-parse HEAD:blob) >expected &&
+ git -C object-type rev-list --objects \
+ --filter=object:type=blob --filter-provided-objects HEAD >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'verify object:type=tree prints only tree with --filter-provided-objects' '
+ printf "%s \n" $(git -C object-type rev-parse HEAD^{tree}) >expected &&
+ git -C object-type rev-list --objects \
+ --filter=object:type=tree HEAD --filter-provided-objects >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'verify object:type=commit prints only commit with --filter-provided-objects' '
+ git -C object-type rev-parse HEAD >expected &&
+ git -C object-type rev-list --objects \
+ --filter=object:type=commit --filter-provided-objects HEAD >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'verify object:type=tag prints only tag with --filter-provided-objects' '
+ printf "%s tag\n" $(git -C object-type rev-parse tag) >expected &&
+ git -C object-type rev-list --objects \
+ --filter=object:type=tag --filter-provided-objects tag >actual &&
+ test_cmp expected actual
+'
+
# Test sparse:path=<path> filter.
# !!!!
# NOTE: sparse:path filter support has been dropped for security reasons,
diff --git a/t/t6113-rev-list-bitmap-filters.sh b/t/t6113-rev-list-bitmap-filters.sh
index 3f889949ca..4d8e09167e 100755
--- a/t/t6113-rev-list-bitmap-filters.sh
+++ b/t/t6113-rev-list-bitmap-filters.sh
@@ -10,7 +10,8 @@ test_expect_success 'set up bitmapped repo' '
test_commit much-larger-blob-one &&
git repack -adb &&
test_commit two &&
- test_commit much-larger-blob-two
+ test_commit much-larger-blob-two &&
+ git tag tag
'
test_expect_success 'filters fallback to non-bitmap traversal' '
@@ -75,4 +76,69 @@ test_expect_success 'tree:1 filter' '
test_cmp expect actual
'
+test_expect_success 'object:type filter' '
+ git rev-list --objects --filter=object:type=tag tag >expect &&
+ git rev-list --use-bitmap-index \
+ --objects --filter=object:type=tag tag >actual &&
+ test_cmp expect actual &&
+
+ git rev-list --objects --filter=object:type=commit tag >expect &&
+ git rev-list --use-bitmap-index \
+ --objects --filter=object:type=commit tag >actual &&
+ test_bitmap_traversal expect actual &&
+
+ git rev-list --objects --filter=object:type=tree tag >expect &&
+ git rev-list --use-bitmap-index \
+ --objects --filter=object:type=tree tag >actual &&
+ test_bitmap_traversal expect actual &&
+
+ git rev-list --objects --filter=object:type=blob tag >expect &&
+ git rev-list --use-bitmap-index \
+ --objects --filter=object:type=blob tag >actual &&
+ test_bitmap_traversal expect actual
+'
+
+test_expect_success 'object:type filter with --filter-provided-objects' '
+ git rev-list --objects --filter-provided-objects --filter=object:type=tag tag >expect &&
+ git rev-list --use-bitmap-index \
+ --objects --filter-provided-objects --filter=object:type=tag tag >actual &&
+ test_cmp expect actual &&
+
+ git rev-list --objects --filter-provided-objects --filter=object:type=commit tag >expect &&
+ git rev-list --use-bitmap-index \
+ --objects --filter-provided-objects --filter=object:type=commit tag >actual &&
+ test_bitmap_traversal expect actual &&
+
+ git rev-list --objects --filter-provided-objects --filter=object:type=tree tag >expect &&
+ git rev-list --use-bitmap-index \
+ --objects --filter-provided-objects --filter=object:type=tree tag >actual &&
+ test_bitmap_traversal expect actual &&
+
+ git rev-list --objects --filter-provided-objects --filter=object:type=blob tag >expect &&
+ git rev-list --use-bitmap-index \
+ --objects --filter-provided-objects --filter=object:type=blob tag >actual &&
+ test_bitmap_traversal expect actual
+'
+
+test_expect_success 'combine filter' '
+ git rev-list --objects --filter=blob:limit=1000 --filter=object:type=blob tag >expect &&
+ git rev-list --use-bitmap-index \
+ --objects --filter=blob:limit=1000 --filter=object:type=blob tag >actual &&
+ test_bitmap_traversal expect actual
+'
+
+test_expect_success 'combine filter with --filter-provided-objects' '
+ git rev-list --objects --filter-provided-objects --filter=blob:limit=1000 --filter=object:type=blob tag >expect &&
+ git rev-list --use-bitmap-index \
+ --objects --filter-provided-objects --filter=blob:limit=1000 --filter=object:type=blob tag >actual &&
+ test_bitmap_traversal expect actual &&
+
+ git cat-file --batch-check="%(objecttype) %(objectsize)" <actual >objects &&
+ while read objecttype objectsize
+ do
+ test "$objecttype" = blob || return 1
+ test "$objectsize" -le 1000 || return 1
+ done <objects
+'
+
test_done
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index e89b6747be..bae2419150 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -17,103 +17,84 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
check_describe () {
+ indir= &&
+ while test $# != 0
+ do
+ case "$1" in
+ -C)
+ indir="$2"
+ shift
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+ done &&
+ indir=${indir:+"$indir"/} &&
expect="$1"
shift
describe_opts="$@"
test_expect_success "describe $describe_opts" '
- R=$(git describe $describe_opts 2>err.actual) &&
- case "$R" in
- $expect) echo happy ;;
- *) echo "Oops - $R is not $expect" &&
- false ;;
- esac
+ git ${indir:+ -C "$indir"} describe $describe_opts >raw &&
+ sed -e "s/-g[0-9a-f]*\$/-gHASH/" <raw >actual &&
+ echo "$expect" >expect &&
+ test_cmp expect actual
'
}
test_expect_success setup '
+ test_commit initial file one &&
+ test_commit second file two &&
+ test_commit third file three &&
+ test_commit --annotate A file A &&
+ test_commit c file c &&
- test_tick &&
- echo one >file && git add file && git commit -m initial &&
- one=$(git rev-parse HEAD) &&
-
- git describe --always HEAD &&
-
- test_tick &&
- echo two >file && git add file && git commit -m second &&
- two=$(git rev-parse HEAD) &&
-
- test_tick &&
- echo three >file && git add file && git commit -m third &&
-
- test_tick &&
- echo A >file && git add file && git commit -m A &&
- test_tick &&
- git tag -a -m A A &&
-
- test_tick &&
- echo c >file && git add file && git commit -m c &&
- test_tick &&
- git tag c &&
-
- git reset --hard $two &&
- test_tick &&
- echo B >side && git add side && git commit -m B &&
- test_tick &&
- git tag -a -m B B &&
+ git reset --hard second &&
+ test_commit --annotate B side B &&
test_tick &&
git merge -m Merged c &&
merged=$(git rev-parse HEAD) &&
- git reset --hard $two &&
- test_tick &&
- echo D >another && git add another && git commit -m D &&
- test_tick &&
- git tag -a -m D D &&
- test_tick &&
- git tag -a -m R R &&
-
- test_tick &&
- echo DD >another && git commit -a -m another &&
+ git reset --hard second &&
+ test_commit --no-tag D another D &&
test_tick &&
- git tag e &&
+ git tag -a -m R R &&
- test_tick &&
- echo DDD >another && git commit -a -m "yet another" &&
+ test_commit e another DD &&
+ test_commit --no-tag "yet another" another DDD &&
test_tick &&
git merge -m Merged $merged &&
- test_tick &&
- echo X >file && echo X >side && git add file side &&
- git commit -m x
-
+ test_commit --no-tag x file
'
-check_describe A-* HEAD
-check_describe A-* HEAD^
-check_describe R-* HEAD^^
-check_describe A-* HEAD^^2
+check_describe A-8-gHASH HEAD
+check_describe A-7-gHASH HEAD^
+check_describe R-2-gHASH HEAD^^
+check_describe A-3-gHASH HEAD^^2
check_describe B HEAD^^2^
-check_describe R-* HEAD^^^
+check_describe R-1-gHASH HEAD^^^
-check_describe c-* --tags HEAD
-check_describe c-* --tags HEAD^
-check_describe e-* --tags HEAD^^
-check_describe c-* --tags HEAD^^2
+check_describe c-7-gHASH --tags HEAD
+check_describe c-6-gHASH --tags HEAD^
+check_describe e-1-gHASH --tags HEAD^^
+check_describe c-2-gHASH --tags HEAD^^2
check_describe B --tags HEAD^^2^
check_describe e --tags HEAD^^^
check_describe heads/main --all HEAD
-check_describe tags/c-* --all HEAD^
+check_describe tags/c-6-gHASH --all HEAD^
check_describe tags/e --all HEAD^^^
-check_describe B-0-* --long HEAD^^2^
-check_describe A-3-* --long HEAD^^2
+check_describe B-0-gHASH --long HEAD^^2^
+check_describe A-3-gHASH --long HEAD^^2
-check_describe c-7-* --tags
-check_describe e-3-* --first-parent --tags
+check_describe c-7-gHASH --tags
+check_describe e-3-gHASH --first-parent --tags
test_expect_success 'describe --contains defaults to HEAD without commit-ish' '
echo "A^0" >expect &&
@@ -124,20 +105,18 @@ test_expect_success 'describe --contains defaults to HEAD without commit-ish' '
'
check_describe tags/A --all A^0
-test_expect_success 'no warning was displayed for A' '
- test_must_be_empty err.actual
-'
-test_expect_success 'rename tag A to Q locally' '
- mv .git/refs/tags/A .git/refs/tags/Q
-'
-cat - >err.expect <<EOF
-warning: tag 'Q' is externally known as 'A'
-EOF
-check_describe A-* HEAD
-test_expect_success 'warning was displayed for Q' '
- test_cmp err.expect err.actual
-'
+test_expect_success 'renaming tag A to Q locally produces a warning' "
+ git update-ref refs/tags/Q $(git rev-parse refs/tags/A) &&
+ git update-ref -d refs/tags/A &&
+ git describe HEAD 2>err >out &&
+ cat >expected <<-\EOF &&
+ warning: tag 'Q' is externally known as 'A'
+ EOF
+ test_cmp expected err &&
+ grep -E '^A-8-g[0-9a-f]+$' out
+"
+
test_expect_success 'misnamed annotated tag forces long output' '
description=$(git describe --no-long Q^0) &&
expr "$description" : "A-0-g[0-9a-f]*$" &&
@@ -157,50 +136,51 @@ test_expect_success 'abbrev=0 will not break misplaced tag (2)' '
'
test_expect_success 'rename tag Q back to A' '
- mv .git/refs/tags/Q .git/refs/tags/A
+ git update-ref refs/tags/A $(git rev-parse refs/tags/Q) &&
+ git update-ref -d refs/tags/Q
'
test_expect_success 'pack tag refs' 'git pack-refs'
-check_describe A-* HEAD
+check_describe A-8-gHASH HEAD
test_expect_success 'describe works from outside repo using --git-dir' '
git clone --bare "$TRASH_DIRECTORY" "$TRASH_DIRECTORY/bare" &&
git --git-dir "$TRASH_DIRECTORY/bare" describe >out &&
- grep -E "^A-[1-9][0-9]?-g[0-9a-f]+$" out
+ grep -E "^A-8-g[0-9a-f]+$" out
'
-check_describe "A-*[0-9a-f]" --dirty
+check_describe "A-8-gHASH" --dirty
test_expect_success 'describe --dirty with --work-tree' '
(
cd "$TEST_DIRECTORY" &&
git --git-dir "$TRASH_DIRECTORY/.git" --work-tree "$TRASH_DIRECTORY" describe --dirty >"$TRASH_DIRECTORY/out"
) &&
- grep -E "^A-[1-9][0-9]?-g[0-9a-f]+$" out
+ grep -E "^A-8-g[0-9a-f]+$" out
'
test_expect_success 'set-up dirty work tree' '
echo >>file
'
-check_describe "A-*[0-9a-f]-dirty" --dirty
-
test_expect_success 'describe --dirty with --work-tree (dirty)' '
+ git describe --dirty >expected &&
(
cd "$TEST_DIRECTORY" &&
git --git-dir "$TRASH_DIRECTORY/.git" --work-tree "$TRASH_DIRECTORY" describe --dirty >"$TRASH_DIRECTORY/out"
) &&
- grep -E "^A-[1-9][0-9]?-g[0-9a-f]+-dirty$" out
+ grep -E "^A-8-g[0-9a-f]+-dirty$" out &&
+ test_cmp expected out
'
-check_describe "A-*[0-9a-f].mod" --dirty=.mod
-
test_expect_success 'describe --dirty=.mod with --work-tree (dirty)' '
+ git describe --dirty=.mod >expected &&
(
cd "$TEST_DIRECTORY" &&
git --git-dir "$TRASH_DIRECTORY/.git" --work-tree "$TRASH_DIRECTORY" describe --dirty=.mod >"$TRASH_DIRECTORY/out"
) &&
- grep -E "^A-[1-9][0-9]?-g[0-9a-f]+.mod$" out
+ grep -E "^A-8-g[0-9a-f]+.mod$" out &&
+ test_cmp expected out
'
test_expect_success 'describe --dirty HEAD' '
@@ -223,21 +203,21 @@ test_expect_success 'set-up matching pattern tests' '
'
-check_describe "test-annotated-*" --match="test-*"
+check_describe "test-annotated-3-gHASH" --match="test-*"
-check_describe "test1-lightweight-*" --tags --match="test1-*"
+check_describe "test1-lightweight-2-gHASH" --tags --match="test1-*"
-check_describe "test2-lightweight-*" --tags --match="test2-*"
+check_describe "test2-lightweight-1-gHASH" --tags --match="test2-*"
-check_describe "test2-lightweight-*" --long --tags --match="test2-*" HEAD^
+check_describe "test2-lightweight-0-gHASH" --long --tags --match="test2-*" HEAD^
-check_describe "test2-lightweight-*" --long --tags --match="test1-*" --match="test2-*" HEAD^
+check_describe "test2-lightweight-0-gHASH" --long --tags --match="test1-*" --match="test2-*" HEAD^
-check_describe "test2-lightweight-*" --long --tags --match="test1-*" --no-match --match="test2-*" HEAD^
+check_describe "test2-lightweight-0-gHASH" --long --tags --match="test1-*" --no-match --match="test2-*" HEAD^
-check_describe "test1-lightweight-*" --long --tags --match="test1-*" --match="test3-*" HEAD
+check_describe "test1-lightweight-2-gHASH" --long --tags --match="test1-*" --match="test3-*" HEAD
-check_describe "test1-lightweight-*" --long --tags --match="test3-*" --match="test1-*" HEAD
+check_describe "test1-lightweight-2-gHASH" --long --tags --match="test3-*" --match="test1-*" HEAD
test_expect_success 'set-up branches' '
git branch branch_A A &&
@@ -247,11 +227,11 @@ test_expect_success 'set-up branches' '
git update-ref refs/original/original_branch_A test-annotated~2
'
-check_describe "heads/branch_A*" --all --match="branch_*" --exclude="branch_C" HEAD
+check_describe "heads/branch_A-11-gHASH" --all --match="branch_*" --exclude="branch_C" HEAD
-check_describe "remotes/origin/remote_branch_A*" --all --match="origin/remote_branch_*" --exclude="origin/remote_branch_C" HEAD
+check_describe "remotes/origin/remote_branch_A-11-gHASH" --all --match="origin/remote_branch_*" --exclude="origin/remote_branch_C" HEAD
-check_describe "original/original_branch_A*" --all test-annotated~1
+check_describe "original/original_branch_A-6-gHASH" --all test-annotated~1
test_expect_success '--match does not work for other types' '
test_must_fail git describe --all --match="*original_branch_*" test-annotated~1
@@ -506,7 +486,7 @@ test_expect_success 'name-rev covers all conditions while looking at parents' '
# o-----o---o----x
# A
#
-test_expect_success 'describe commits with disjoint bases' '
+test_expect_success 'setup: describe commits with disjoint bases' '
git init disjoint1 &&
(
cd disjoint1 &&
@@ -519,19 +499,19 @@ test_expect_success 'describe commits with disjoint bases' '
git checkout --orphan branch && rm file &&
echo B > file2 && git add file2 && git commit -m B &&
git tag B -a -m B &&
- git merge --no-ff --allow-unrelated-histories main -m x &&
-
- check_describe "A-3-*" HEAD
+ git merge --no-ff --allow-unrelated-histories main -m x
)
'
+check_describe -C disjoint1 "A-3-gHASH" HEAD
+
# B
# o---o---o------------.
# \
# o---o---x
# A
#
-test_expect_success 'describe commits with disjoint bases 2' '
+test_expect_success 'setup: describe commits with disjoint bases 2' '
git init disjoint2 &&
(
cd disjoint2 &&
@@ -545,10 +525,10 @@ test_expect_success 'describe commits with disjoint bases 2' '
echo o >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:01" git commit -m o &&
echo B >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:02" git commit -m B &&
git tag B -a -m B &&
- git merge --no-ff --allow-unrelated-histories main -m x &&
-
- check_describe "B-3-*" HEAD
+ git merge --no-ff --allow-unrelated-histories main -m x
)
'
+check_describe -C disjoint2 "B-3-gHASH" HEAD
+
test_done
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 9e0214076b..80679d5e12 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -59,18 +59,25 @@ test_atom() {
# Automatically test "contents:size" atom after testing "contents"
if test "$2" = "contents"
then
- case $(git cat-file -t "$ref") in
- tag)
- # We cannot use $3 as it expects sanitize_pgp to run
- expect=$(git cat-file tag $ref | tail -n +6 | wc -c) ;;
- tree | blob)
- expect='' ;;
- commit)
- expect=$(printf '%s' "$3" | wc -c) ;;
- esac
- # Leave $expect unquoted to lose possible leading whitespaces
- echo $expect >expected
+ # for commit leg, $3 is changed there
+ expect=$(printf '%s' "$3" | wc -c)
test_expect_${4:-success} $PREREQ "basic atom: $1 contents:size" '
+ type=$(git cat-file -t "$ref") &&
+ case $type in
+ tag)
+ # We cannot use $3 as it expects sanitize_pgp to run
+ git cat-file tag $ref >out &&
+ expect=$(tail -n +6 out | wc -c) &&
+ rm -f out ;;
+ tree | blob)
+ expect="" ;;
+ commit)
+ : "use the calculated expect" ;;
+ *)
+ BUG "unknown object type" ;;
+ esac &&
+ # Leave $expect unquoted to lose possible leading whitespaces
+ echo $expect >expected &&
git for-each-ref --format="%(contents:size)" "$ref" >actual &&
test_cmp expected actual
'
@@ -130,6 +137,8 @@ test_atom head parent:short=10 ''
test_atom head numparent 0
test_atom head object ''
test_atom head type ''
+test_atom head raw "$(git cat-file commit refs/heads/main)
+"
test_atom head '*objectname' ''
test_atom head '*objecttype' ''
test_atom head author 'A U Thor <author@example.com> 1151968724 +0200'
@@ -221,6 +230,15 @@ test_atom tag contents 'Tagging at 1151968727
'
test_atom tag HEAD ' '
+test_expect_success 'basic atom: refs/tags/testtag *raw' '
+ git cat-file commit refs/tags/testtag^{} >expected &&
+ git for-each-ref --format="%(*raw)" refs/tags/testtag >actual &&
+ sanitize_pgp <expected >expected.clean &&
+ echo >>expected.clean &&
+ sanitize_pgp <actual >actual.clean &&
+ test_cmp expected.clean actual.clean
+'
+
test_expect_success 'Check invalid atoms names are errors' '
test_must_fail git for-each-ref --format="%(INVALID)" refs/heads
'
@@ -686,6 +704,15 @@ 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_expect_success GPG 'basic atom: refs/tags/signed-empty raw' '
+ git cat-file tag refs/tags/signed-empty >expected &&
+ git for-each-ref --format="%(raw)" refs/tags/signed-empty >actual &&
+ sanitize_pgp <expected >expected.clean &&
+ echo >>expected.clean &&
+ sanitize_pgp <actual >actual.clean &&
+ test_cmp expected.clean actual.clean
+'
+
test_atom refs/tags/signed-short subject 'subject line'
test_atom refs/tags/signed-short subject:sanitize 'subject-line'
test_atom refs/tags/signed-short contents:subject 'subject line'
@@ -695,6 +722,15 @@ test_atom refs/tags/signed-short contents:signature "$sig"
test_atom refs/tags/signed-short contents "subject line
$sig"
+test_expect_success GPG 'basic atom: refs/tags/signed-short raw' '
+ git cat-file tag refs/tags/signed-short >expected &&
+ git for-each-ref --format="%(raw)" refs/tags/signed-short >actual &&
+ sanitize_pgp <expected >expected.clean &&
+ echo >>expected.clean &&
+ sanitize_pgp <actual >actual.clean &&
+ test_cmp expected.clean actual.clean
+'
+
test_atom refs/tags/signed-long subject 'subject line'
test_atom refs/tags/signed-long subject:sanitize 'subject-line'
test_atom refs/tags/signed-long contents:subject 'subject line'
@@ -708,6 +744,15 @@ test_atom refs/tags/signed-long contents "subject line
body contents
$sig"
+test_expect_success GPG 'basic atom: refs/tags/signed-long raw' '
+ git cat-file tag refs/tags/signed-long >expected &&
+ git for-each-ref --format="%(raw)" refs/tags/signed-long >actual &&
+ sanitize_pgp <expected >expected.clean &&
+ echo >>expected.clean &&
+ sanitize_pgp <actual >actual.clean &&
+ test_cmp expected.clean actual.clean
+'
+
test_expect_success 'set up refs pointing to tree and blob' '
git update-ref refs/mytrees/first refs/heads/main^{tree} &&
git update-ref refs/myblobs/first refs/heads/main:one
@@ -720,6 +765,16 @@ test_atom refs/mytrees/first contents:body ""
test_atom refs/mytrees/first contents:signature ""
test_atom refs/mytrees/first contents ""
+test_expect_success 'basic atom: refs/mytrees/first raw' '
+ git cat-file tree refs/mytrees/first >expected &&
+ echo >>expected &&
+ git for-each-ref --format="%(raw)" refs/mytrees/first >actual &&
+ test_cmp expected actual &&
+ git cat-file -s refs/mytrees/first >expected &&
+ git for-each-ref --format="%(raw:size)" refs/mytrees/first >actual &&
+ test_cmp expected actual
+'
+
test_atom refs/myblobs/first subject ""
test_atom refs/myblobs/first contents:subject ""
test_atom refs/myblobs/first body ""
@@ -727,6 +782,189 @@ test_atom refs/myblobs/first contents:body ""
test_atom refs/myblobs/first contents:signature ""
test_atom refs/myblobs/first contents ""
+test_expect_success 'basic atom: refs/myblobs/first raw' '
+ git cat-file blob refs/myblobs/first >expected &&
+ echo >>expected &&
+ git for-each-ref --format="%(raw)" refs/myblobs/first >actual &&
+ test_cmp expected actual &&
+ git cat-file -s refs/myblobs/first >expected &&
+ git for-each-ref --format="%(raw:size)" refs/myblobs/first >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'set up refs pointing to binary blob' '
+ printf "a\0b\0c" >blob1 &&
+ printf "a\0c\0b" >blob2 &&
+ printf "\0a\0b\0c" >blob3 &&
+ printf "abc" >blob4 &&
+ printf "\0 \0 \0 " >blob5 &&
+ printf "\0 \0a\0 " >blob6 &&
+ printf " " >blob7 &&
+ >blob8 &&
+ obj=$(git hash-object -w blob1) &&
+ git update-ref refs/myblobs/blob1 "$obj" &&
+ obj=$(git hash-object -w blob2) &&
+ git update-ref refs/myblobs/blob2 "$obj" &&
+ obj=$(git hash-object -w blob3) &&
+ git update-ref refs/myblobs/blob3 "$obj" &&
+ obj=$(git hash-object -w blob4) &&
+ git update-ref refs/myblobs/blob4 "$obj" &&
+ obj=$(git hash-object -w blob5) &&
+ git update-ref refs/myblobs/blob5 "$obj" &&
+ obj=$(git hash-object -w blob6) &&
+ git update-ref refs/myblobs/blob6 "$obj" &&
+ obj=$(git hash-object -w blob7) &&
+ git update-ref refs/myblobs/blob7 "$obj" &&
+ obj=$(git hash-object -w blob8) &&
+ git update-ref refs/myblobs/blob8 "$obj"
+'
+
+test_expect_success 'Verify sorts with raw' '
+ cat >expected <<-EOF &&
+ refs/myblobs/blob8
+ refs/myblobs/blob5
+ refs/myblobs/blob6
+ refs/myblobs/blob3
+ refs/myblobs/blob7
+ refs/mytrees/first
+ refs/myblobs/first
+ refs/myblobs/blob1
+ refs/myblobs/blob2
+ refs/myblobs/blob4
+ refs/heads/main
+ EOF
+ git for-each-ref --format="%(refname)" --sort=raw \
+ refs/heads/main refs/myblobs/ refs/mytrees/first >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Verify sorts with raw:size' '
+ cat >expected <<-EOF &&
+ refs/myblobs/blob8
+ refs/myblobs/first
+ refs/myblobs/blob7
+ refs/heads/main
+ refs/myblobs/blob4
+ refs/myblobs/blob1
+ refs/myblobs/blob2
+ refs/myblobs/blob3
+ refs/myblobs/blob5
+ refs/myblobs/blob6
+ refs/mytrees/first
+ EOF
+ git for-each-ref --format="%(refname)" --sort=raw:size \
+ refs/heads/main refs/myblobs/ refs/mytrees/first >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'validate raw atom with %(if:equals)' '
+ cat >expected <<-EOF &&
+ not equals
+ not equals
+ not equals
+ not equals
+ not equals
+ not equals
+ refs/myblobs/blob4
+ not equals
+ not equals
+ not equals
+ not equals
+ not equals
+ EOF
+ git for-each-ref --format="%(if:equals=abc)%(raw)%(then)%(refname)%(else)not equals%(end)" \
+ refs/myblobs/ refs/heads/ >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'validate raw atom with %(if:notequals)' '
+ cat >expected <<-EOF &&
+ refs/heads/ambiguous
+ refs/heads/main
+ refs/heads/newtag
+ refs/myblobs/blob1
+ refs/myblobs/blob2
+ refs/myblobs/blob3
+ equals
+ refs/myblobs/blob5
+ refs/myblobs/blob6
+ refs/myblobs/blob7
+ refs/myblobs/blob8
+ refs/myblobs/first
+ EOF
+ git for-each-ref --format="%(if:notequals=abc)%(raw)%(then)%(refname)%(else)equals%(end)" \
+ refs/myblobs/ refs/heads/ >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'empty raw refs with %(if)' '
+ cat >expected <<-EOF &&
+ refs/myblobs/blob1 not empty
+ refs/myblobs/blob2 not empty
+ refs/myblobs/blob3 not empty
+ refs/myblobs/blob4 not empty
+ refs/myblobs/blob5 not empty
+ refs/myblobs/blob6 not empty
+ refs/myblobs/blob7 empty
+ refs/myblobs/blob8 empty
+ refs/myblobs/first not empty
+ EOF
+ git for-each-ref --format="%(refname) %(if)%(raw)%(then)not empty%(else)empty%(end)" \
+ refs/myblobs/ >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success '%(raw) with --python must fail' '
+ test_must_fail git for-each-ref --format="%(raw)" --python
+'
+
+test_expect_success '%(raw) with --tcl must fail' '
+ test_must_fail git for-each-ref --format="%(raw)" --tcl
+'
+
+test_expect_success '%(raw) with --perl' '
+ git for-each-ref --format="\$name= %(raw);
+print \"\$name\"" refs/myblobs/blob1 --perl | perl >actual &&
+ cmp blob1 actual &&
+ git for-each-ref --format="\$name= %(raw);
+print \"\$name\"" refs/myblobs/blob3 --perl | perl >actual &&
+ cmp blob3 actual &&
+ git for-each-ref --format="\$name= %(raw);
+print \"\$name\"" refs/myblobs/blob8 --perl | perl >actual &&
+ cmp blob8 actual &&
+ git for-each-ref --format="\$name= %(raw);
+print \"\$name\"" refs/myblobs/first --perl | perl >actual &&
+ cmp one actual &&
+ git cat-file tree refs/mytrees/first > expected &&
+ git for-each-ref --format="\$name= %(raw);
+print \"\$name\"" refs/mytrees/first --perl | perl >actual &&
+ cmp expected actual
+'
+
+test_expect_success '%(raw) with --shell must fail' '
+ test_must_fail git for-each-ref --format="%(raw)" --shell
+'
+
+test_expect_success '%(raw) with --shell and --sort=raw must fail' '
+ test_must_fail git for-each-ref --format="%(raw)" --sort=raw --shell
+'
+
+test_expect_success '%(raw:size) with --shell' '
+ git for-each-ref --format="%(raw:size)" | while read line
+ do
+ echo "'\''$line'\''" >>expect
+ done &&
+ git for-each-ref --format="%(raw:size)" --shell >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'for-each-ref --format compare with cat-file --batch' '
+ git rev-parse refs/mytrees/first | git cat-file --batch >expected &&
+ git for-each-ref --format="%(objectname) %(objecttype) %(objectsize)
+%(raw)" refs/mytrees/first >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'set up multiple-sort tags' '
for when in 100000 200000
do
@@ -980,6 +1218,10 @@ test_expect_success 'basic atom: head contents:trailers' '
test_cmp expect actual.clean
'
+test_expect_success 'basic atom: rest must fail' '
+ test_must_fail git for-each-ref --format="%(rest)" refs/heads/main
+'
+
test_expect_success 'trailer parsing not fooled by --- line' '
git commit --allow-empty -F - <<-\EOF &&
this is the subject
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index 9866b1b573..1537aa2179 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -117,6 +117,25 @@ test_expect_success '%(color) must fail' '
test_must_fail git for-each-ref --format="%(color)%(refname)"
'
+test_expect_success '%(color:#aa22ac) must succeed' '
+ test_when_finished rm -rf test &&
+ git init test &&
+ (
+ cd test &&
+ test_commit initial &&
+ git branch -M main &&
+ cat >expect <<-\EOF &&
+ refs/heads/main
+ refs/tags/initial
+ EOF
+ git remote add origin nowhere &&
+ git config branch.main.remote origin &&
+ git config branch.main.merge refs/heads/main &&
+ git for-each-ref --format="%(color:#aa22ac)%(refname)" >actual &&
+ test_cmp expect actual
+ )
+'
+
test_expect_success 'left alignment is default' '
cat >expect <<-\EOF &&
refname is refs/heads/main |refs/heads/main
diff --git a/t/t6400-merge-df.sh b/t/t6400-merge-df.sh
index 38700d29b5..57a67cf362 100755
--- a/t/t6400-merge-df.sh
+++ b/t/t6400-merge-df.sh
@@ -82,13 +82,13 @@ test_expect_success 'modify/delete + directory/file conflict' '
git checkout delete^0 &&
test_must_fail git merge modify &&
- test 5 -eq $(git ls-files -s | wc -l) &&
- test 4 -eq $(git ls-files -u | wc -l) &&
+ test_stdout_line_count = 5 git ls-files -s &&
+ test_stdout_line_count = 4 git ls-files -u &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
- test 0 -eq $(git ls-files -o | wc -l)
+ test_stdout_line_count = 0 git ls-files -o
else
- test 1 -eq $(git ls-files -o | wc -l)
+ test_stdout_line_count = 1 git ls-files -o
fi &&
test_path_is_file letters/file &&
@@ -103,13 +103,13 @@ test_expect_success 'modify/delete + directory/file conflict; other way' '
test_must_fail git merge delete &&
- test 5 -eq $(git ls-files -s | wc -l) &&
- test 4 -eq $(git ls-files -u | wc -l) &&
+ test_stdout_line_count = 5 git ls-files -s &&
+ test_stdout_line_count = 4 git ls-files -u &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
- test 0 -eq $(git ls-files -o | wc -l)
+ test_stdout_line_count = 0 git ls-files -o
else
- test 1 -eq $(git ls-files -o | wc -l)
+ test_stdout_line_count = 1 git ls-files -o
fi &&
test_path_is_file letters/file &&
diff --git a/t/t6402-merge-rename.sh b/t/t6402-merge-rename.sh
index 425dad97d5..3a32b1a45c 100755
--- a/t/t6402-merge-rename.sh
+++ b/t/t6402-merge-rename.sh
@@ -103,12 +103,10 @@ test_expect_success 'setup' '
test_expect_success 'pull renaming branch into unrenaming one' \
'
git show-branch &&
- test_expect_code 1 git pull . white &&
+ test_expect_code 1 git pull --no-rebase . white &&
git ls-files -s &&
- git ls-files -u B >b.stages &&
- test_line_count = 3 b.stages &&
- git ls-files -s N >n.stages &&
- test_line_count = 1 n.stages &&
+ test_stdout_line_count = 3 git ls-files -u B &&
+ test_stdout_line_count = 1 git ls-files -s N &&
sed -ne "/^g/{
p
q
@@ -121,11 +119,9 @@ test_expect_success 'pull renaming branch into another renaming one' \
rm -f B &&
git reset --hard &&
git checkout red &&
- test_expect_code 1 git pull . white &&
- git ls-files -u B >b.stages &&
- test_line_count = 3 b.stages &&
- git ls-files -s N >n.stages &&
- test_line_count = 1 n.stages &&
+ test_expect_code 1 git pull --no-rebase . white &&
+ test_stdout_line_count = 3 git ls-files -u B &&
+ test_stdout_line_count = 1 git ls-files -s N &&
sed -ne "/^g/{
p
q
@@ -137,11 +133,9 @@ test_expect_success 'pull unrenaming branch into renaming one' \
'
git reset --hard &&
git show-branch &&
- test_expect_code 1 git pull . main &&
- git ls-files -u B >b.stages &&
- test_line_count = 3 b.stages &&
- git ls-files -s N >n.stages &&
- test_line_count = 1 n.stages &&
+ test_expect_code 1 git pull --no-rebase . main &&
+ test_stdout_line_count = 3 git ls-files -u B &&
+ test_stdout_line_count = 1 git ls-files -s N &&
sed -ne "/^g/{
p
q
@@ -153,15 +147,11 @@ test_expect_success 'pull conflicting renames' \
'
git reset --hard &&
git show-branch &&
- test_expect_code 1 git pull . blue &&
- git ls-files -u A >a.stages &&
- test_line_count = 1 a.stages &&
- git ls-files -u B >b.stages &&
- test_line_count = 1 b.stages &&
- git ls-files -u C >c.stages &&
- test_line_count = 1 c.stages &&
- git ls-files -s N >n.stages &&
- test_line_count = 1 n.stages &&
+ test_expect_code 1 git pull --no-rebase . blue &&
+ test_stdout_line_count = 1 git ls-files -u A &&
+ test_stdout_line_count = 1 git ls-files -u B &&
+ test_stdout_line_count = 1 git ls-files -u C &&
+ test_stdout_line_count = 1 git ls-files -s N &&
sed -ne "/^g/{
p
q
@@ -173,7 +163,7 @@ test_expect_success 'interference with untracked working tree file' '
git reset --hard &&
git show-branch &&
echo >A this file should not matter &&
- test_expect_code 1 git pull . white &&
+ test_expect_code 1 git pull --no-rebase . white &&
test_path_is_file A
'
@@ -183,7 +173,7 @@ test_expect_success 'interference with untracked working tree file' '
git show-branch &&
rm -f A &&
echo >A this file should not matter &&
- test_expect_code 1 git pull . red &&
+ test_expect_code 1 git pull --no-rebase . red &&
test_path_is_file A
'
@@ -193,7 +183,7 @@ test_expect_success 'interference with untracked working tree file' '
git checkout -f main &&
git tag -f anchor &&
git show-branch &&
- git pull . yellow &&
+ git pull --no-rebase . yellow &&
test_path_is_missing M &&
git reset --hard anchor
'
@@ -220,7 +210,7 @@ test_expect_success 'updated working tree file should prevent the merge' '
echo >>M one line addition &&
cat M >M.saved &&
git update-index M &&
- test_expect_code 128 git pull . yellow &&
+ test_expect_code 128 git pull --no-rebase . yellow &&
test_cmp M M.saved &&
rm -f M.saved
'
@@ -232,7 +222,7 @@ test_expect_success 'interference with untracked working tree file' '
git tag -f anchor &&
git show-branch &&
echo >M this file should not matter &&
- git pull . main &&
+ git pull --no-rebase . main &&
test_path_is_file M &&
! {
git ls-files -s |
@@ -330,8 +320,8 @@ test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '
test_i18ngrep "Adding as dir~HEAD instead" output
fi &&
- test 3 -eq "$(git ls-files -u | wc -l)" &&
- test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
+ test_stdout_line_count = 3 git ls-files -u &&
+ test_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&
test_must_fail git diff --quiet &&
test_must_fail git diff --cached --quiet &&
@@ -357,8 +347,8 @@ test_expect_success 'Same as previous, but merged other way' '
test_i18ngrep "Adding as dir~renamed-file-has-no-conflicts instead" output
fi &&
- test 3 -eq "$(git ls-files -u | wc -l)" &&
- test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
+ test_stdout_line_count = 3 git ls-files -u &&
+ test_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&
test_must_fail git diff --quiet &&
test_must_fail git diff --cached --quiet &&
@@ -374,8 +364,8 @@ test_expect_success 'Rename+D/F conflict; renamed file cannot merge, dir not in
git checkout -q renamed-file-has-conflicts^0 &&
test_must_fail git merge --strategy=recursive dir-not-in-way &&
- test 3 -eq "$(git ls-files -u | wc -l)" &&
- test 3 -eq "$(git ls-files -u dir | wc -l)" &&
+ test_stdout_line_count = 3 git ls-files -u &&
+ test_stdout_line_count = 3 git ls-files -u dir &&
test_must_fail git diff --quiet &&
test_must_fail git diff --cached --quiet &&
@@ -409,14 +399,16 @@ test_expect_success 'Rename+D/F conflict; renamed file cannot merge and dir in t
git checkout -q renamed-file-has-conflicts^0 &&
test_must_fail git merge --strategy=recursive dir-in-way &&
- test 5 -eq "$(git ls-files -u | wc -l)" &&
+ test_stdout_line_count = 5 git ls-files -u &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
- test 3 -eq "$(git ls-files -u dir~HEAD | wc -l)"
+ test_stdout_line_count = 3 git ls-files -u dir~HEAD
else
- test 3 -eq "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)"
+ git ls-files -u dir >out &&
+ test 3 -eq $(grep -v file-in-the-way out | wc -l) &&
+ rm -f out
fi &&
- test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
+ test_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&
test_must_fail git diff --quiet &&
test_must_fail git diff --cached --quiet &&
@@ -432,14 +424,16 @@ test_expect_success 'Same as previous, but merged other way' '
git checkout -q dir-in-way^0 &&
test_must_fail git merge --strategy=recursive renamed-file-has-conflicts &&
- test 5 -eq "$(git ls-files -u | wc -l)" &&
+ test_stdout_line_count = 5 git ls-files -u &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
- test 3 -eq "$(git ls-files -u dir~renamed-file-has-conflicts | wc -l)"
+ test_stdout_line_count = 3 git ls-files -u dir~renamed-file-has-conflicts
else
- test 3 -eq "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)"
+ git ls-files -u dir >out &&
+ test 3 -eq $(grep -v file-in-the-way out | wc -l) &&
+ rm -f out
fi &&
- test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
+ test_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&
test_must_fail git diff --quiet &&
test_must_fail git diff --cached --quiet &&
@@ -496,9 +490,9 @@ test_expect_success 'both rename source and destination involved in D/F conflict
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
- test 2 -eq "$(git ls-files -u | wc -l)"
+ test_stdout_line_count = 2 git ls-files -u
else
- test 1 -eq "$(git ls-files -u | wc -l)"
+ test_stdout_line_count = 1 git ls-files -u
fi &&
test_must_fail git diff --quiet &&
@@ -540,9 +534,9 @@ then
mkdir one &&
test_must_fail git merge --strategy=recursive rename-two &&
- test 4 -eq "$(git ls-files -u | wc -l)" &&
- test 2 -eq "$(git ls-files -u one | wc -l)" &&
- test 2 -eq "$(git ls-files -u two | wc -l)" &&
+ test_stdout_line_count = 4 git ls-files -u &&
+ test_stdout_line_count = 2 git ls-files -u one &&
+ test_stdout_line_count = 2 git ls-files -u two &&
test_must_fail git diff --quiet &&
@@ -559,9 +553,9 @@ else
mkdir one &&
test_must_fail git merge --strategy=recursive rename-two &&
- test 2 -eq "$(git ls-files -u | wc -l)" &&
- test 1 -eq "$(git ls-files -u one | wc -l)" &&
- test 1 -eq "$(git ls-files -u two | wc -l)" &&
+ test_stdout_line_count = 2 git ls-files -u &&
+ test_stdout_line_count = 1 git ls-files -u one &&
+ test_stdout_line_count = 1 git ls-files -u two &&
test_must_fail git diff --quiet &&
@@ -582,13 +576,13 @@ test_expect_success 'pair rename to parent of other (D/F conflicts) w/ clean sta
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
- test 4 -eq "$(git ls-files -u | wc -l)" &&
- test 2 -eq "$(git ls-files -u one | wc -l)" &&
- test 2 -eq "$(git ls-files -u two | wc -l)"
+ test_stdout_line_count = 4 git ls-files -u &&
+ test_stdout_line_count = 2 git ls-files -u one &&
+ test_stdout_line_count = 2 git ls-files -u two
else
- test 2 -eq "$(git ls-files -u | wc -l)" &&
- test 1 -eq "$(git ls-files -u one | wc -l)" &&
- test 1 -eq "$(git ls-files -u two | wc -l)"
+ test_stdout_line_count = 2 git ls-files -u &&
+ test_stdout_line_count = 1 git ls-files -u one &&
+ test_stdout_line_count = 1 git ls-files -u two
fi &&
test_must_fail git diff --quiet &&
@@ -631,19 +625,19 @@ test_expect_success 'check handling of differently renamed file with D/F conflic
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
- test 5 -eq "$(git ls-files -s | wc -l)" &&
- test 3 -eq "$(git ls-files -u | wc -l)" &&
- test 1 -eq "$(git ls-files -u one~HEAD | wc -l)" &&
- test 1 -eq "$(git ls-files -u two~second-rename | wc -l)" &&
- test 1 -eq "$(git ls-files -u original | wc -l)" &&
- test 0 -eq "$(git ls-files -o | wc -l)"
+ test_stdout_line_count = 5 git ls-files -s &&
+ test_stdout_line_count = 3 git ls-files -u &&
+ test_stdout_line_count = 1 git ls-files -u one~HEAD &&
+ test_stdout_line_count = 1 git ls-files -u two~second-rename &&
+ test_stdout_line_count = 1 git ls-files -u original &&
+ test_stdout_line_count = 0 git ls-files -o
else
- test 5 -eq "$(git ls-files -s | wc -l)" &&
- test 3 -eq "$(git ls-files -u | wc -l)" &&
- test 1 -eq "$(git ls-files -u one | wc -l)" &&
- test 1 -eq "$(git ls-files -u two | wc -l)" &&
- test 1 -eq "$(git ls-files -u original | wc -l)" &&
- test 2 -eq "$(git ls-files -o | wc -l)"
+ test_stdout_line_count = 5 git ls-files -s &&
+ test_stdout_line_count = 3 git ls-files -u &&
+ test_stdout_line_count = 1 git ls-files -u one &&
+ test_stdout_line_count = 1 git ls-files -u two &&
+ test_stdout_line_count = 1 git ls-files -u original &&
+ test_stdout_line_count = 2 git ls-files -o
fi &&
test_path_is_file one/file &&
@@ -679,11 +673,11 @@ test_expect_success 'check handling of differently renamed file with D/F conflic
git checkout -q first-rename-redo^0 &&
test_must_fail git merge --strategy=recursive second-rename-redo &&
- test 3 -eq "$(git ls-files -u | wc -l)" &&
- test 1 -eq "$(git ls-files -u one | wc -l)" &&
- test 1 -eq "$(git ls-files -u two | wc -l)" &&
- test 1 -eq "$(git ls-files -u original | wc -l)" &&
- test 0 -eq "$(git ls-files -o | wc -l)" &&
+ test_stdout_line_count = 3 git ls-files -u &&
+ test_stdout_line_count = 1 git ls-files -u one &&
+ test_stdout_line_count = 1 git ls-files -u two &&
+ test_stdout_line_count = 1 git ls-files -u original &&
+ test_stdout_line_count = 0 git ls-files -o &&
test_path_is_file one &&
test_path_is_file two &&
@@ -861,9 +855,11 @@ test_expect_success 'setup merge of rename + small change' '
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_stdout_line_count = 1 git ls-files -s &&
+ test_stdout_line_count = 0 git ls-files -o &&
+ newhash=$(git rev-parse HEAD:renamed_file) &&
+ oldhash=$(git rev-parse HEAD~1:file) &&
+ test $newhash = $oldhash
'
test_expect_success 'setup for use of extended merge markers' '
diff --git a/t/t6406-merge-attr.sh b/t/t6406-merge-attr.sh
index d5a4ac2d81..8494645837 100755
--- a/t/t6406-merge-attr.sh
+++ b/t/t6406-merge-attr.sh
@@ -207,4 +207,22 @@ test_expect_success 'custom merge does not lock index' '
git merge main
'
+test_expect_success 'binary files with union attribute' '
+ git checkout -b bin-main &&
+ printf "base\0" >bin.txt &&
+ echo "bin.txt merge=union" >.gitattributes &&
+ git add bin.txt .gitattributes &&
+ git commit -m base &&
+
+ printf "one\0" >bin.txt &&
+ git commit -am one &&
+
+ git checkout -b bin-side HEAD^ &&
+ printf "two\0" >bin.txt &&
+ git commit -am two &&
+
+ test_must_fail git merge bin-main 2>stderr &&
+ grep -i "warning.*cannot merge.*HEAD vs. bin-main" stderr
+'
+
test_done
diff --git a/t/t6409-merge-subtree.sh b/t/t6409-merge-subtree.sh
index d406b2343c..ba7890ec52 100755
--- a/t/t6409-merge-subtree.sh
+++ b/t/t6409-merge-subtree.sh
@@ -100,7 +100,7 @@ test_expect_success 'merge update' '
git checkout -b topic_2 &&
git commit -m "update git-gui" &&
cd ../git &&
- git pull -s subtree gui topic_2 &&
+ git pull --no-rebase -s subtree gui topic_2 &&
git ls-files -s >actual &&
(
echo "100644 $o3 0 git-gui/git-gui.sh" &&
@@ -129,7 +129,7 @@ test_expect_success 'initial ambiguous subtree' '
test_expect_success 'merge using explicit' '
cd ../git &&
git reset --hard topic_2 &&
- git pull -Xsubtree=git-gui gui topic_2 &&
+ git pull --no-rebase -Xsubtree=git-gui gui topic_2 &&
git ls-files -s >actual &&
(
echo "100644 $o3 0 git-gui/git-gui.sh" &&
@@ -142,7 +142,7 @@ test_expect_success 'merge using explicit' '
test_expect_success 'merge2 using explicit' '
cd ../git &&
git reset --hard topic_2 &&
- git pull -Xsubtree=git-gui2 gui topic_2 &&
+ git pull --no-rebase -Xsubtree=git-gui2 gui topic_2 &&
git ls-files -s >actual &&
(
echo "100644 $o1 0 git-gui/git-gui.sh" &&
diff --git a/t/t6415-merge-dir-to-symlink.sh b/t/t6415-merge-dir-to-symlink.sh
index 2ce104aca7..2655e295f5 100755
--- a/t/t6415-merge-dir-to-symlink.sh
+++ b/t/t6415-merge-dir-to-symlink.sh
@@ -25,7 +25,8 @@ test_expect_success 'checkout does not clobber untracked symlink' '
git reset --hard main &&
git rm --cached a/b &&
git commit -m "untracked symlink remains" &&
- test_must_fail git checkout start^0
+ test_must_fail git checkout start^0 &&
+ git clean -fd # Do not leave the untracked symlink in the way
'
test_expect_success 'a/b-2/c/d is kept when clobbering symlink b' '
@@ -34,7 +35,8 @@ test_expect_success 'a/b-2/c/d is kept when clobbering symlink b' '
git rm --cached a/b &&
git commit -m "untracked symlink remains" &&
git checkout -f start^0 &&
- test_path_is_file a/b-2/c/d
+ test_path_is_file a/b-2/c/d &&
+ git clean -fd # Do not leave the untracked symlink in the way
'
test_expect_success 'checkout should not have deleted a/b-2/c/d' '
diff --git a/t/t6417-merge-ours-theirs.sh b/t/t6417-merge-ours-theirs.sh
index ac9aee9a66..ec065d6a65 100755
--- a/t/t6417-merge-ours-theirs.sh
+++ b/t/t6417-merge-ours-theirs.sh
@@ -69,11 +69,11 @@ test_expect_success 'binary file with -Xours/-Xtheirs' '
'
test_expect_success 'pull passes -X to underlying merge' '
- git reset --hard main && git pull -s recursive -Xours . side &&
- git reset --hard main && git pull -s recursive -X ours . side &&
- git reset --hard main && git pull -s recursive -Xtheirs . side &&
- git reset --hard main && git pull -s recursive -X theirs . side &&
- git reset --hard main && test_must_fail git pull -s recursive -X bork . side
+ git reset --hard main && git pull --no-rebase -s recursive -Xours . side &&
+ git reset --hard main && git pull --no-rebase -s recursive -X ours . side &&
+ git reset --hard main && git pull --no-rebase -s recursive -Xtheirs . side &&
+ git reset --hard main && git pull --no-rebase -s recursive -X theirs . side &&
+ git reset --hard main && test_must_fail git pull --no-rebase -s recursive -X bork . side
'
test_expect_success SYMLINKS 'symlink with -Xours/-Xtheirs' '
diff --git a/t/t6421-merge-partial-clone.sh b/t/t6421-merge-partial-clone.sh
new file mode 100755
index 0000000000..36bcd7c328
--- /dev/null
+++ b/t/t6421-merge-partial-clone.sh
@@ -0,0 +1,440 @@
+#!/bin/sh
+
+test_description="limiting blob downloads when merging with partial clones"
+# Uses a methodology similar to
+# t6042: corner cases with renames but not criss-cross merges
+# t6036: corner cases with both renames and criss-cross merges
+# t6423: directory rename detection
+#
+# The setup for all of them, pictorially, is:
+#
+# A
+# o
+# / \
+# O o ?
+# \ /
+# o
+# B
+#
+# To help make it easier to follow the flow of tests, they have been
+# divided into sections and each test will start with a quick explanation
+# of what commits O, A, and B contain.
+#
+# Notation:
+# z/{b,c} means files z/b and z/c both exist
+# x/d_1 means file x/d exists with content d1. (Purpose of the
+# underscore notation is to differentiate different
+# files that might be renamed into each other's paths.)
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-merge.sh
+
+test_setup_repo () {
+ test -d server && return
+ test_create_repo server &&
+ (
+ cd server &&
+
+ git config uploadpack.allowfilter 1 &&
+ git config uploadpack.allowanysha1inwant 1 &&
+
+ mkdir -p general &&
+ test_seq 2 9 >general/leap1 &&
+ cp general/leap1 general/leap2 &&
+ echo leap2 >>general/leap2 &&
+
+ mkdir -p basename &&
+ cp general/leap1 basename/numbers &&
+ cp general/leap1 basename/sequence &&
+ cp general/leap1 basename/values &&
+ echo numbers >>basename/numbers &&
+ echo sequence >>basename/sequence &&
+ echo values >>basename/values &&
+
+ mkdir -p dir/unchanged &&
+ mkdir -p dir/subdir/tweaked &&
+ echo a >dir/subdir/a &&
+ echo b >dir/subdir/b &&
+ echo c >dir/subdir/c &&
+ echo d >dir/subdir/d &&
+ echo e >dir/subdir/e &&
+ cp general/leap1 dir/subdir/Makefile &&
+ echo toplevel makefile >>dir/subdir/Makefile &&
+ echo f >dir/subdir/tweaked/f &&
+ echo g >dir/subdir/tweaked/g &&
+ echo h >dir/subdir/tweaked/h &&
+ echo subdirectory makefile >dir/subdir/tweaked/Makefile &&
+ for i in $(test_seq 1 88)
+ do
+ echo content $i >dir/unchanged/file_$i
+ done &&
+ git add . &&
+ git commit -m "O" &&
+
+ git branch O &&
+ git branch A &&
+ git branch B-single &&
+ git branch B-dir &&
+ git branch B-many &&
+
+ git switch A &&
+
+ git rm general/leap* &&
+ mkdir general/ &&
+ test_seq 1 9 >general/jump1 &&
+ cp general/jump1 general/jump2 &&
+ echo leap2 >>general/jump2 &&
+
+ rm basename/numbers basename/sequence basename/values &&
+ mkdir -p basename/subdir/
+ cp general/jump1 basename/subdir/numbers &&
+ cp general/jump1 basename/subdir/sequence &&
+ cp general/jump1 basename/subdir/values &&
+ echo numbers >>basename/subdir/numbers &&
+ echo sequence >>basename/subdir/sequence &&
+ echo values >>basename/subdir/values &&
+
+ git rm dir/subdir/tweaked/f &&
+ echo more >>dir/subdir/e &&
+ echo more >>dir/subdir/Makefile &&
+ echo more >>dir/subdir/tweaked/Makefile &&
+ mkdir dir/subdir/newsubdir &&
+ echo rust code >dir/subdir/newsubdir/newfile.rs &&
+ git mv dir/subdir/e dir/subdir/newsubdir/ &&
+ git mv dir folder &&
+ git add . &&
+ git commit -m "A" &&
+
+ git switch B-single &&
+ echo new first line >dir/subdir/Makefile &&
+ cat general/leap1 >>dir/subdir/Makefile &&
+ echo toplevel makefile >>dir/subdir/Makefile &&
+ echo perl code >general/newfile.pl &&
+ git add . &&
+ git commit -m "B-single" &&
+
+ git switch B-dir &&
+ echo java code >dir/subdir/newfile.java &&
+ echo scala code >dir/subdir/newfile.scala &&
+ echo groovy code >dir/subdir/newfile.groovy &&
+ git add . &&
+ git commit -m "B-dir" &&
+
+ git switch B-many &&
+ test_seq 2 10 >general/leap1 &&
+ rm general/leap2 &&
+ cp general/leap1 general/leap2 &&
+ echo leap2 >>general/leap2 &&
+
+ rm basename/numbers basename/sequence basename/values &&
+ mkdir -p basename/subdir/
+ cp general/leap1 basename/subdir/numbers &&
+ cp general/leap1 basename/subdir/sequence &&
+ cp general/leap1 basename/subdir/values &&
+ echo numbers >>basename/subdir/numbers &&
+ echo sequence >>basename/subdir/sequence &&
+ echo values >>basename/subdir/values &&
+
+ mkdir dir/subdir/newsubdir/ &&
+ echo c code >dir/subdir/newfile.c &&
+ echo python code >dir/subdir/newsubdir/newfile.py &&
+ git add . &&
+ git commit -m "B-many" &&
+
+ git switch A
+ )
+}
+
+# Testcase: Objects downloaded for single relevant rename
+# Commit O:
+# general/{leap1_O, leap2_O}
+# basename/{numbers_O, sequence_O, values_O}
+# dir/subdir/{a,b,c,d,e_O,Makefile_TOP_O}
+# dir/subdir/tweaked/{f,g,h,Makefile_SUB_O}
+# dir/unchanged/<LOTS OF FILES>
+# Commit A:
+# (Rename leap->jump, rename basename/ -> basename/subdir/, rename dir/
+# -> folder/, move e into newsubdir, add newfile.rs, remove f, modify
+# both both Makefiles and jumps)
+# general/{jump1_A, jump2_A}
+# basename/subdir/{numbers_A, sequence_A, values_A}
+# folder/subdir/{a,b,c,d,Makefile_TOP_A}
+# folder/subdir/newsubdir/{e_A,newfile.rs}
+# folder/subdir/tweaked/{g,h,Makefile_SUB_A}
+# folder/unchanged/<LOTS OF FILES>
+# Commit B(-single):
+# (add newfile.pl, tweak Makefile_TOP)
+# general/{leap1_O, leap2_O,newfile.pl}
+# basename/{numbers_O, sequence_O, values_O}
+# dir/{a,b,c,d,e_O,Makefile_TOP_B}
+# dir/tweaked/{f,g,h,Makefile_SUB_O}
+# dir/unchanged/<LOTS OF FILES>
+# Expected:
+# general/{jump1_A, jump2_A,newfile.pl}
+# basename/subdir/{numbers_A, sequence_A, values_A}
+# folder/subdir/{a,b,c,d,Makefile_TOP_Merged}
+# folder/subdir/newsubdir/{e_A,newfile.rs}
+# folder/subdir/tweaked/{g,h,Makefile_SUB_A}
+# folder/unchanged/<LOTS OF FILES>
+#
+# Objects that need to be fetched:
+# Rename detection:
+# Side1 (O->A):
+# Basename-matches rename detection only needs to fetch these objects:
+# Makefile_TOP_O, Makefile_TOP_A
+# (Despite many renames, all others are content irrelevant. They
+# are also location irrelevant because newfile.rs was added on
+# the side doing the directory rename, and newfile.pl was added to
+# a directory that was not renamed on either side.)
+# General rename detection only needs to fetch these objects:
+# <None>
+# (Even though newfile.rs, jump[12], basename/subdir/*, and e
+# could all be used as destinations in rename detection, the
+# basename detection for Makefile matches up all relevant
+# sources, so these other files never end up needing to be
+# used)
+# Side2 (O->B):
+# Basename-matches rename detection only needs to fetch these objects:
+# <None>
+# (there are no deleted files, so no possible sources)
+# General rename detection only needs to fetch these objects:
+# <None>
+# (there are no deleted files, so no possible sources)
+# Merge:
+# 3-way content merge needs to grab these objects:
+# Makefile_TOP_B
+# Nothing else needs to fetch objects
+#
+# Summary: 2 fetches (1 for 2 objects, 1 for 1 object)
+#
+test_expect_merge_algorithm failure success 'Objects downloaded for single relevant rename' '
+ test_setup_repo &&
+ git clone --sparse --filter=blob:none "file://$(pwd)/server" objects-single &&
+ (
+ cd objects-single &&
+
+ git rev-list --objects --all --missing=print |
+ grep "^?" | sort >missing-objects-before &&
+
+ git checkout -q origin/A &&
+
+ GIT_TRACE2_PERF="$(pwd)/trace.output" git \
+ -c merge.directoryRenames=true merge --no-stat \
+ --no-progress origin/B-single &&
+
+ # Check the number of objects we reported we would fetch
+ cat >expect <<-EOF &&
+ fetch_count:2
+ fetch_count:1
+ EOF
+ grep fetch_count trace.output | cut -d "|" -f 9 | tr -d " ." >actual &&
+ test_cmp expect actual &&
+
+ # Check the number of fetch commands exec-ed
+ grep d0.*fetch.negotiationAlgorithm trace.output >fetches &&
+ test_line_count = 2 fetches &&
+
+ git rev-list --objects --all --missing=print |
+ grep "^?" | sort >missing-objects-after &&
+ comm -2 -3 missing-objects-before missing-objects-after >old &&
+ comm -1 -3 missing-objects-before missing-objects-after >new &&
+ # No new missing objects
+ test_must_be_empty new &&
+ # Fetched 2 + 1 = 3 objects
+ test_line_count = 3 old
+ )
+'
+
+# Testcase: Objects downloaded for directory rename
+# Commit O:
+# general/{leap1_O, leap2_O}
+# basename/{numbers_O, sequence_O, values_O}
+# dir/subdir/{a,b,c,d,e_O,Makefile_TOP_O}
+# dir/subdir/tweaked/{f,g,h,Makefile_SUB_O}
+# dir/unchanged/<LOTS OF FILES>
+# Commit A:
+# (Rename leap->jump, rename basename/ -> basename/subdir/, rename dir/ ->
+# folder/, move e into newsubdir, add newfile.rs, remove f, modify
+# both Makefiles and jumps)
+# general/{jump1_A, jump2_A}
+# basename/subdir/{numbers_A, sequence_A, values_A}
+# folder/subdir/{a,b,c,d,Makefile_TOP_A}
+# folder/subdir/newsubdir/{e_A,newfile.rs}
+# folder/subdir/tweaked/{g,h,Makefile_SUB_A}
+# folder/unchanged/<LOTS OF FILES>
+# Commit B(-dir):
+# (add dir/subdir/newfile.{java,scala,groovy}
+# general/{leap1_O, leap2_O}
+# basename/{numbers_O, sequence_O, values_O}
+# dir/subdir/{a,b,c,d,e_O,Makefile_TOP_O,
+# newfile.java,newfile.scala,newfile.groovy}
+# dir/subdir/tweaked/{f,g,h,Makefile_SUB_O}
+# dir/unchanged/<LOTS OF FILES>
+# Expected:
+# general/{jump1_A, jump2_A}
+# basename/subdir/{numbers_A, sequence_A, values_A}
+# folder/subdir/{a,b,c,d,Makefile_TOP_A,
+# newfile.java,newfile.scala,newfile.groovy}
+# folder/subdir/newsubdir/{e_A,newfile.rs}
+# folder/subdir/tweaked/{g,h,Makefile_SUB_A}
+# folder/unchanged/<LOTS OF FILES>
+#
+# Objects that need to be fetched:
+# Makefile_TOP_O, Makefile_TOP_A
+# Makefile_SUB_O, Makefile_SUB_A
+# e_O, e_A
+# * Despite A's rename of jump->leap, those renames are irrelevant.
+# * Despite A's rename of basename/ -> basename/subdir/, those renames are
+# irrelevant.
+# * Because of A's rename of dir/ -> folder/ and B-dir's addition of
+# newfile.* into dir/subdir/, we need to determine directory renames.
+# (Technically, there are enough exact renames to determine directory
+# rename detection, but the current implementation always does
+# basename searching before directory rename detection. Running it
+# also before basename searching would mean doing directory rename
+# detection twice, but it's a bit expensive to do that and cases like
+# this are not all that common.)
+# Summary: 1 fetches for 6 objects
+#
+test_expect_merge_algorithm failure success 'Objects downloaded when a directory rename triggered' '
+ test_setup_repo &&
+ git clone --sparse --filter=blob:none "file://$(pwd)/server" objects-dir &&
+ (
+ cd objects-dir &&
+
+ git rev-list --objects --all --missing=print |
+ grep "^?" | sort >missing-objects-before &&
+
+ git checkout -q origin/A &&
+
+ GIT_TRACE2_PERF="$(pwd)/trace.output" git \
+ -c merge.directoryRenames=true merge --no-stat \
+ --no-progress origin/B-dir &&
+
+ # Check the number of objects we reported we would fetch
+ cat >expect <<-EOF &&
+ fetch_count:6
+ EOF
+ grep fetch_count trace.output | cut -d "|" -f 9 | tr -d " ." >actual &&
+ test_cmp expect actual &&
+
+ # Check the number of fetch commands exec-ed
+ grep d0.*fetch.negotiationAlgorithm trace.output >fetches &&
+ test_line_count = 1 fetches &&
+
+ git rev-list --objects --all --missing=print |
+ grep "^?" | sort >missing-objects-after &&
+ comm -2 -3 missing-objects-before missing-objects-after >old &&
+ comm -1 -3 missing-objects-before missing-objects-after >new &&
+ # No new missing objects
+ test_must_be_empty new &&
+ # Fetched 6 objects
+ test_line_count = 6 old
+ )
+'
+
+# Testcase: Objects downloaded with lots of renames and modifications
+# Commit O:
+# general/{leap1_O, leap2_O}
+# basename/{numbers_O, sequence_O, values_O}
+# dir/subdir/{a,b,c,d,e_O,Makefile_TOP_O}
+# dir/subdir/tweaked/{f,g,h,Makefile_SUB_O}
+# dir/unchanged/<LOTS OF FILES>
+# Commit A:
+# (Rename leap->jump, rename basename/ -> basename/subdir/, rename dir/
+# -> folder/, move e into newsubdir, add newfile.rs, remove f, modify
+# both both Makefiles and jumps)
+# general/{jump1_A, jump2_A}
+# basename/subdir/{numbers_A, sequence_A, values_A}
+# folder/subdir/{a,b,c,d,Makefile_TOP_A}
+# folder/subdir/newsubdir/{e_A,newfile.rs}
+# folder/subdir/tweaked/{g,h,Makefile_SUB_A}
+# folder/unchanged/<LOTS OF FILES>
+# Commit B(-minimal):
+# (modify both leaps, rename basename/ -> basename/subdir/, add
+# newfile.{c,py})
+# general/{leap1_B, leap2_B}
+# basename/subdir/{numbers_B, sequence_B, values_B}
+# dir/{a,b,c,d,e_O,Makefile_TOP_O,newfile.c}
+# dir/tweaked/{f,g,h,Makefile_SUB_O,newfile.py}
+# dir/unchanged/<LOTS OF FILES>
+# Expected:
+# general/{jump1_Merged, jump2_Merged}
+# basename/subdir/{numbers_Merged, sequence_Merged, values_Merged}
+# folder/subdir/{a,b,c,d,Makefile_TOP_A,newfile.c}
+# folder/subdir/newsubdir/e_A
+# folder/subdir/tweaked/{g,h,Makefile_SUB_A,newfile.py}
+# folder/unchanged/<LOTS OF FILES>
+#
+# Objects that need to be fetched:
+# Rename detection:
+# Side1 (O->A):
+# Basename-matches rename detection only needs to fetch these objects:
+# numbers_O, numbers_A
+# sequence_O, sequence_A
+# values_O, values_A
+# Makefile_TOP_O, Makefile_TOP_A
+# Makefile_SUB_O, Makefile_SUB_A
+# e_O, e_A
+# General rename detection only needs to fetch these objects:
+# leap1_O, leap2_O
+# jump1_A, jump2_A, newfile.rs
+# (only need remaining relevant sources, but any relevant sources need
+# to be matched against all possible unpaired destinations)
+# Side2 (O->B):
+# Basename-matches rename detection only needs to fetch these objects:
+# numbers_B
+# sequence_B
+# values_B
+# (because numbers_O, sequence_O, and values_O already fetched above)
+# General rename detection only needs to fetch these objects:
+# <None>
+# Merge:
+# 3-way content merge needs to grab these objects:
+# leap1_B
+# leap2_B
+# Nothing else needs to fetch objects
+#
+# Summary: 4 fetches (1 for 6 objects, 1 for 8, 1 for 3, 1 for 2)
+#
+test_expect_merge_algorithm failure success 'Objects downloaded with lots of renames and modifications' '
+ test_setup_repo &&
+ git clone --sparse --filter=blob:none "file://$(pwd)/server" objects-many &&
+ (
+ cd objects-many &&
+
+ git rev-list --objects --all --missing=print |
+ grep "^?" | sort >missing-objects-before &&
+
+ git checkout -q origin/A &&
+
+ GIT_TRACE2_PERF="$(pwd)/trace.output" git \
+ -c merge.directoryRenames=true merge --no-stat \
+ --no-progress origin/B-many &&
+
+ # Check the number of objects we reported we would fetch
+ cat >expect <<-EOF &&
+ fetch_count:12
+ fetch_count:5
+ fetch_count:3
+ fetch_count:2
+ EOF
+ grep fetch_count trace.output | cut -d "|" -f 9 | tr -d " ." >actual &&
+ test_cmp expect actual &&
+
+ # Check the number of fetch commands exec-ed
+ grep d0.*fetch.negotiationAlgorithm trace.output >fetches &&
+ test_line_count = 4 fetches &&
+
+ git rev-list --objects --all --missing=print |
+ grep "^?" | sort >missing-objects-after &&
+ comm -2 -3 missing-objects-before missing-objects-after >old &&
+ comm -1 -3 missing-objects-before missing-objects-after >new &&
+ # No new missing objects
+ test_must_be_empty new &&
+ # Fetched 12 + 5 + 3 + 2 = 22 objects
+ test_line_count = 22 old
+ )
+'
+
+test_done
diff --git a/t/t6423-merge-rename-directories.sh b/t/t6423-merge-rename-directories.sh
index 7134769149..5b81a130e9 100755
--- a/t/t6423-merge-rename-directories.sh
+++ b/t/t6423-merge-rename-directories.sh
@@ -454,7 +454,7 @@ test_expect_success '1f: Split a directory into two other directories' '
# the directory renamed, but the files within it. (see 1b)
#
# If renames split a directory into two or more others, the directory
-# with the most renames, "wins" (see 1c). However, see the testcases
+# with the most renames, "wins" (see 1f). However, see the testcases
# in section 2, plus testcases 3a and 4a.
###########################################################################
@@ -4797,7 +4797,7 @@ test_setup_12f () {
)
}
-test_expect_merge_algorithm failure failure '12f: Trivial directory resolve, caching, all kinds of fun' '
+test_expect_merge_algorithm failure success '12f: Trivial directory resolve, caching, all kinds of fun' '
test_setup_12f &&
(
cd 12f &&
@@ -4966,6 +4966,239 @@ test_expect_success '12g: Testcase with two kinds of "relevant" renames' '
)
'
+# Testcase 12h, Testcase with two kinds of "relevant" renames
+# Commit O: olddir/{a_1, b}
+# Commit A: newdir/{a_2, b}
+# Commit B: olddir/{alpha_1, b}
+# Expected: newdir/{alpha_2, b}
+
+test_setup_12h () {
+ test_create_repo 12h &&
+ (
+ cd 12h &&
+
+ mkdir olddir &&
+ test_seq 3 8 >olddir/a &&
+ >olddir/b &&
+ git add olddir &&
+ git commit -m orig &&
+
+ git branch O &&
+ git branch A &&
+ git branch B &&
+
+ git switch A &&
+ test_seq 3 10 >olddir/a &&
+ git add olddir/a &&
+ git mv olddir newdir &&
+ git commit -m A &&
+
+ git switch B &&
+
+ git mv olddir/a olddir/alpha &&
+ git commit -m B
+ )
+}
+
+test_expect_failure '12h: renaming a file within a renamed directory' '
+ test_setup_12h &&
+ (
+ cd 12h &&
+
+ git checkout A^0 &&
+
+ test_might_fail git -c merge.directoryRenames=true merge -s recursive B^0 &&
+
+ git ls-files >tracked &&
+ test_line_count = 2 tracked &&
+
+ test_path_is_missing olddir/a &&
+ test_path_is_file newdir/alpha &&
+ test_path_is_file newdir/b &&
+
+ git rev-parse >actual \
+ HEAD:newdir/alpha HEAD:newdir/b &&
+ git rev-parse >expect \
+ A:newdir/a O:oldir/b &&
+ test_cmp expect actual
+ )
+'
+
+# Testcase 12i, Directory rename causes rename-to-self
+# Commit O: source/{subdir/foo, bar, baz_1}
+# Commit A: source/{foo, bar, baz_1}
+# Commit B: source/{subdir/{foo, bar}, baz_2}
+# Expected: source/{foo, bar, baz_2}, with conflicts on
+# source/bar vs. source/subdir/bar
+
+test_setup_12i () {
+ test_create_repo 12i &&
+ (
+ cd 12i &&
+
+ mkdir -p source/subdir &&
+ echo foo >source/subdir/foo &&
+ echo bar >source/bar &&
+ echo baz >source/baz &&
+ git add source &&
+ git commit -m orig &&
+
+ git branch O &&
+ git branch A &&
+ git branch B &&
+
+ git switch A &&
+ git mv source/subdir/foo source/foo &&
+ git commit -m A &&
+
+ git switch B &&
+ git mv source/bar source/subdir/bar &&
+ echo more baz >>source/baz &&
+ git commit -m B
+ )
+}
+
+test_expect_success '12i: Directory rename causes rename-to-self' '
+ test_setup_12i &&
+ (
+ cd 12i &&
+
+ git checkout A^0 &&
+
+ test_must_fail git -c merge.directoryRenames=conflict merge -s recursive B^0 &&
+
+ test_path_is_missing source/subdir &&
+ test_path_is_file source/bar &&
+ test_path_is_file source/baz &&
+
+ git ls-files | uniq >tracked &&
+ test_line_count = 3 tracked &&
+
+ git status --porcelain -uno >actual &&
+ cat >expect <<-\EOF &&
+ UU source/bar
+ M source/baz
+ EOF
+ test_cmp expect actual
+ )
+'
+
+# Testcase 12j, Directory rename to root causes rename-to-self
+# Commit O: {subdir/foo, bar, baz_1}
+# Commit A: {foo, bar, baz_1}
+# Commit B: {subdir/{foo, bar}, baz_2}
+# Expected: {foo, bar, baz_2}, with conflicts on bar vs. subdir/bar
+
+test_setup_12j () {
+ test_create_repo 12j &&
+ (
+ cd 12j &&
+
+ mkdir -p subdir &&
+ echo foo >subdir/foo &&
+ echo bar >bar &&
+ echo baz >baz &&
+ git add . &&
+ git commit -m orig &&
+
+ git branch O &&
+ git branch A &&
+ git branch B &&
+
+ git switch A &&
+ git mv subdir/foo foo &&
+ git commit -m A &&
+
+ git switch B &&
+ git mv bar subdir/bar &&
+ echo more baz >>baz &&
+ git commit -m B
+ )
+}
+
+test_expect_success '12j: Directory rename to root causes rename-to-self' '
+ test_setup_12j &&
+ (
+ cd 12j &&
+
+ git checkout A^0 &&
+
+ test_must_fail git -c merge.directoryRenames=conflict merge -s recursive B^0 &&
+
+ test_path_is_missing subdir &&
+ test_path_is_file bar &&
+ test_path_is_file baz &&
+
+ git ls-files | uniq >tracked &&
+ test_line_count = 3 tracked &&
+
+ git status --porcelain -uno >actual &&
+ cat >expect <<-\EOF &&
+ UU bar
+ M baz
+ EOF
+ test_cmp expect actual
+ )
+'
+
+# Testcase 12k, Directory rename with sibling causes rename-to-self
+# Commit O: dirB/foo, dirA/{bar, baz_1}
+# Commit A: dirA/{foo, bar, baz_1}
+# Commit B: dirB/{foo, bar}, dirA/baz_2
+# Expected: dirA/{foo, bar, baz_2}, with conflicts on dirA/bar vs. dirB/bar
+
+test_setup_12k () {
+ test_create_repo 12k &&
+ (
+ cd 12k &&
+
+ mkdir dirA dirB &&
+ echo foo >dirB/foo &&
+ echo bar >dirA/bar &&
+ echo baz >dirA/baz &&
+ git add . &&
+ git commit -m orig &&
+
+ git branch O &&
+ git branch A &&
+ git branch B &&
+
+ git switch A &&
+ git mv dirB/* dirA/ &&
+ git commit -m A &&
+
+ git switch B &&
+ git mv dirA/bar dirB/bar &&
+ echo more baz >>dirA/baz &&
+ git commit -m B
+ )
+}
+
+test_expect_success '12k: Directory rename with sibling causes rename-to-self' '
+ test_setup_12k &&
+ (
+ cd 12k &&
+
+ git checkout A^0 &&
+
+ test_must_fail git -c merge.directoryRenames=conflict merge -s recursive B^0 &&
+
+ test_path_is_missing dirB &&
+ test_path_is_file dirA/bar &&
+ test_path_is_file dirA/baz &&
+
+ git ls-files | uniq >tracked &&
+ test_line_count = 3 tracked &&
+
+ git status --porcelain -uno >actual &&
+ cat >expect <<-\EOF &&
+ UU dirA/bar
+ M dirA/baz
+ EOF
+ test_cmp expect actual
+ )
+'
+
###########################################################################
# SECTION 13: Checking informational and conflict messages
#
diff --git a/t/t6424-merge-unrelated-index-changes.sh b/t/t6424-merge-unrelated-index-changes.sh
index 5e3779ebc9..89dd544f38 100755
--- a/t/t6424-merge-unrelated-index-changes.sh
+++ b/t/t6424-merge-unrelated-index-changes.sh
@@ -132,6 +132,7 @@ test_expect_success 'merge-recursive, when index==head but head!=HEAD' '
# Make index match B
git diff C B -- | git apply --cached &&
+ test_when_finished "git clean -fd" && # Do not leave untracked around
# Merge B & F, with B as "head"
git merge-recursive A -- B F > out &&
test_i18ngrep "Already up to date" out
diff --git a/t/t6429-merge-sequence-rename-caching.sh b/t/t6429-merge-sequence-rename-caching.sh
new file mode 100755
index 0000000000..035edc40b1
--- /dev/null
+++ b/t/t6429-merge-sequence-rename-caching.sh
@@ -0,0 +1,700 @@
+#!/bin/sh
+
+test_description="remember regular & dir renames in sequence of merges"
+
+. ./test-lib.sh
+
+#
+# NOTE 1: this testfile tends to not only rename files, but modify on both
+# sides; without modifying on both sides, optimizations can kick in
+# which make rename detection irrelevant or trivial. We want to make
+# sure that we are triggering rename caching rather than rename
+# bypassing.
+#
+# NOTE 2: this testfile uses 'test-tool fast-rebase' instead of either
+# cherry-pick or rebase. sequencer.c is only superficially
+# integrated with merge-ort; it calls merge_switch_to_result()
+# after EACH merge, which updates the index and working copy AND
+# throws away the cached results (because merge_switch_to_result()
+# is only supposed to be called at the end of the sequence).
+# Integrating them more deeply is a big task, so for now the tests
+# use 'test-tool fast-rebase'.
+#
+
+
+#
+# In the following simple testcase:
+# Base: numbers_1, values_1
+# Upstream: numbers_2, values_2
+# Topic_1: sequence_3
+# Topic_2: scruples_3
+# or, in english, rename numbers -> sequence in the first commit, and rename
+# values -> scruples in the second commit.
+#
+# This shouldn't be a challenge, it's just verifying that cached renames isn't
+# preventing us from finding new renames.
+#
+test_expect_success 'caching renames does not preclude finding new ones' '
+ test_create_repo caching-renames-and-new-renames &&
+ (
+ cd caching-renames-and-new-renames &&
+
+ test_seq 2 10 >numbers &&
+ test_seq 2 10 >values &&
+ git add numbers values &&
+ git commit -m orig &&
+
+ git branch upstream &&
+ git branch topic &&
+
+ git switch upstream &&
+ test_seq 1 10 >numbers &&
+ test_seq 1 10 >values &&
+ git add numbers values &&
+ git commit -m "Tweaked both files" &&
+
+ git switch topic &&
+
+ test_seq 2 12 >numbers &&
+ git add numbers &&
+ git mv numbers sequence &&
+ git commit -m A &&
+
+ test_seq 2 12 >values &&
+ git add values &&
+ git mv values scruples &&
+ git commit -m B &&
+
+ #
+ # Actual testing
+ #
+
+ git switch upstream &&
+
+ test-tool fast-rebase --onto HEAD upstream~1 topic &&
+ #git cherry-pick upstream~1..topic
+
+ git ls-files >tracked-files &&
+ test_line_count = 2 tracked-files &&
+ test_seq 1 12 >expect &&
+ test_cmp expect sequence &&
+ test_cmp expect scruples
+ )
+'
+
+#
+# In the following testcase:
+# Base: numbers_1
+# Upstream: rename numbers_1 -> sequence_2
+# Topic_1: numbers_3
+# Topic_2: numbers_1
+# or, in english, the first commit on the topic branch modifies numbers by
+# shrinking it (dramatically) and the second commit on topic reverts its
+# parent.
+#
+# Can git apply both patches?
+#
+# Traditional cherry-pick/rebase will fail to apply the second commit, the
+# one that reverted its parent, because despite detecting the rename from
+# 'numbers' to 'sequence' for the first commit, it fails to detect that
+# rename when picking the second commit. That's "reasonable" given the
+# dramatic change in size of the file, but remembering the rename and
+# reusing it is reasonable too.
+#
+# We do test here that we expect rename detection to only be run once total
+# (the topic side of history doesn't need renames, and with caching we
+# should be able to only run rename detection on the upstream side one
+# time.)
+test_expect_success 'cherry-pick both a commit and its immediate revert' '
+ test_create_repo pick-commit-and-its-immediate-revert &&
+ (
+ cd pick-commit-and-its-immediate-revert &&
+
+ test_seq 11 30 >numbers &&
+ git add numbers &&
+ git commit -m orig &&
+
+ git branch upstream &&
+ git branch topic &&
+
+ git switch upstream &&
+ test_seq 1 30 >numbers &&
+ git add numbers &&
+ git mv numbers sequence &&
+ git commit -m "Renamed (and modified) numbers -> sequence" &&
+
+ git switch topic &&
+
+ test_seq 11 13 >numbers &&
+ git add numbers &&
+ git commit -m A &&
+
+ git revert HEAD &&
+
+ #
+ # Actual testing
+ #
+
+ git switch upstream &&
+
+ GIT_TRACE2_PERF="$(pwd)/trace.output" &&
+ export GIT_TRACE2_PERF &&
+
+ test-tool fast-rebase --onto HEAD upstream~1 topic &&
+ #git cherry-pick upstream~1..topic &&
+
+ grep region_enter.*diffcore_rename trace.output >calls &&
+ test_line_count = 1 calls
+ )
+'
+
+#
+# In the following testcase:
+# Base: sequence_1
+# Upstream: rename sequence_1 -> values_2
+# Topic_1: rename sequence_1 -> values_3
+# Topic_2: add unrelated sequence_4
+# or, in english, both sides rename sequence -> values, and then the second
+# commit on the topic branch adds an unrelated file called sequence.
+#
+# This testcase presents no problems for git traditionally, but having both
+# sides do the same rename in effect "uses it up" and if it remains cached,
+# could cause a spurious rename/add conflict.
+#
+test_expect_success 'rename same file identically, then reintroduce it' '
+ test_create_repo rename-rename-1to1-then-add-old-filename &&
+ (
+ cd rename-rename-1to1-then-add-old-filename &&
+
+ test_seq 3 8 >sequence &&
+ git add sequence &&
+ git commit -m orig &&
+
+ git branch upstream &&
+ git branch topic &&
+
+ git switch upstream &&
+ test_seq 1 8 >sequence &&
+ git add sequence &&
+ git mv sequence values &&
+ git commit -m "Renamed (and modified) sequence -> values" &&
+
+ git switch topic &&
+
+ test_seq 3 10 >sequence &&
+ git add sequence &&
+ git mv sequence values &&
+ git commit -m A &&
+
+ test_write_lines A B C D E F G H I J >sequence &&
+ git add sequence &&
+ git commit -m B &&
+
+ #
+ # Actual testing
+ #
+
+ git switch upstream &&
+
+ GIT_TRACE2_PERF="$(pwd)/trace.output" &&
+ export GIT_TRACE2_PERF &&
+
+ test-tool fast-rebase --onto HEAD upstream~1 topic &&
+ #git cherry-pick upstream~1..topic &&
+
+ git ls-files >tracked &&
+ test_line_count = 2 tracked &&
+ test_path_is_file values &&
+ test_path_is_file sequence &&
+
+ grep region_enter.*diffcore_rename trace.output >calls &&
+ test_line_count = 2 calls
+ )
+'
+
+#
+# In the following testcase:
+# Base: olddir/{valuesZ_1, valuesY_1, valuesX_1}
+# Upstream: rename olddir/valuesZ_1 -> dirA/valuesZ_2
+# rename olddir/valuesY_1 -> dirA/valuesY_2
+# rename olddir/valuesX_1 -> dirB/valuesX_2
+# Topic_1: rename olddir/valuesZ_1 -> dirA/valuesZ_3
+# rename olddir/valuesY_1 -> dirA/valuesY_3
+# Topic_2: add olddir/newfile
+# Expected Pick1: dirA/{valuesZ, valuesY}, dirB/valuesX
+# Expected Pick2: dirA/{valuesZ, valuesY}, dirB/{valuesX, newfile}
+#
+# This testcase presents no problems for git traditionally, but having both
+# sides do the same renames in effect "use it up" but if the renames remain
+# cached, the directory rename could put newfile in the wrong directory.
+#
+test_expect_success 'rename same file identically, then add file to old dir' '
+ test_create_repo rename-rename-1to1-then-add-file-to-old-dir &&
+ (
+ cd rename-rename-1to1-then-add-file-to-old-dir &&
+
+ mkdir olddir/ &&
+ test_seq 3 8 >olddir/valuesZ &&
+ test_seq 3 8 >olddir/valuesY &&
+ test_seq 3 8 >olddir/valuesX &&
+ git add olddir &&
+ git commit -m orig &&
+
+ git branch upstream &&
+ git branch topic &&
+
+ git switch upstream &&
+ test_seq 1 8 >olddir/valuesZ &&
+ test_seq 1 8 >olddir/valuesY &&
+ test_seq 1 8 >olddir/valuesX &&
+ git add olddir &&
+ mkdir dirA &&
+ git mv olddir/valuesZ olddir/valuesY dirA &&
+ git mv olddir/ dirB/ &&
+ git commit -m "Renamed (and modified) values*" &&
+
+ git switch topic &&
+
+ test_seq 3 10 >olddir/valuesZ &&
+ test_seq 3 10 >olddir/valuesY &&
+ git add olddir &&
+ mkdir dirA &&
+ git mv olddir/valuesZ olddir/valuesY dirA &&
+ git commit -m A &&
+
+ >olddir/newfile &&
+ git add olddir/newfile &&
+ git commit -m B &&
+
+ #
+ # Actual testing
+ #
+
+ git switch upstream &&
+ git config merge.directoryRenames true &&
+
+ GIT_TRACE2_PERF="$(pwd)/trace.output" &&
+ export GIT_TRACE2_PERF &&
+
+ test-tool fast-rebase --onto HEAD upstream~1 topic &&
+ #git cherry-pick upstream~1..topic &&
+
+ git ls-files >tracked &&
+ test_line_count = 4 tracked &&
+ test_path_is_file dirA/valuesZ &&
+ test_path_is_file dirA/valuesY &&
+ test_path_is_file dirB/valuesX &&
+ test_path_is_file dirB/newfile &&
+
+ grep region_enter.*diffcore_rename trace.output >calls &&
+ test_line_count = 3 calls
+ )
+'
+
+#
+# In the following testcase, upstream renames a directory, and the topic branch
+# first adds a file to the directory, then later renames the directory
+# differently:
+# Base: olddir/a
+# olddir/b
+# Upstream: rename olddir/ -> newdir/
+# Topic_1: add olddir/newfile
+# Topic_2: rename olddir/ -> otherdir/
+#
+# Here we are just concerned that cached renames might prevent us from seeing
+# the rename conflict, and we want to ensure that we do get a conflict.
+#
+# While at it, though, we do test that we only try to detect renames 2
+# times and not three. (The first merge needs to detect renames on the
+# upstream side. Traditionally, the second merge would need to detect
+# renames on both sides of history, but our caching of upstream renames
+# should avoid the need to re-detect upstream renames.)
+#
+test_expect_success 'cached dir rename does not prevent noticing later conflict' '
+ test_create_repo dir-rename-cache-not-occluding-later-conflict &&
+ (
+ cd dir-rename-cache-not-occluding-later-conflict &&
+
+ mkdir olddir &&
+ test_seq 3 10 >olddir/a &&
+ test_seq 3 10 >olddir/b &&
+ git add olddir &&
+ git commit -m orig &&
+
+ git branch upstream &&
+ git branch topic &&
+
+ git switch upstream &&
+ test_seq 3 10 >olddir/a &&
+ test_seq 3 10 >olddir/b &&
+ git add olddir &&
+ git mv olddir newdir &&
+ git commit -m "Dir renamed" &&
+
+ git switch topic &&
+
+ >olddir/newfile &&
+ git add olddir/newfile &&
+ git commit -m A &&
+
+ test_seq 1 8 >olddir/a &&
+ test_seq 1 8 >olddir/b &&
+ git add olddir &&
+ git mv olddir otherdir &&
+ git commit -m B &&
+
+ #
+ # Actual testing
+ #
+
+ git switch upstream &&
+ git config merge.directoryRenames true &&
+
+ GIT_TRACE2_PERF="$(pwd)/trace.output" &&
+ export GIT_TRACE2_PERF &&
+
+ test_must_fail test-tool fast-rebase --onto HEAD upstream~1 topic >output &&
+ #git cherry-pick upstream..topic &&
+
+ grep CONFLICT..rename/rename output &&
+
+ grep region_enter.*diffcore_rename trace.output >calls &&
+ test_line_count = 2 calls
+ )
+'
+
+# Helper for the next two tests
+test_setup_upstream_rename () {
+ test_create_repo $1 &&
+ (
+ cd $1 &&
+
+ test_seq 3 8 >somefile &&
+ test_seq 3 8 >relevant-rename &&
+ git add somefile relevant-rename &&
+ mkdir olddir &&
+ test_write_lines a b c d e f g >olddir/a &&
+ test_write_lines z y x w v u t >olddir/b &&
+ git add olddir &&
+ git commit -m orig &&
+
+ git branch upstream &&
+ git branch topic &&
+
+ git switch upstream &&
+ test_seq 1 8 >somefile &&
+ test_seq 1 8 >relevant-rename &&
+ git add somefile relevant-rename &&
+ git mv relevant-rename renamed &&
+ echo h >>olddir/a &&
+ echo s >>olddir/b &&
+ git add olddir &&
+ git mv olddir newdir &&
+ git commit -m "Dir renamed"
+ )
+}
+
+#
+# In the following testcase, upstream renames a file in the toplevel directory
+# as well as its only directory:
+# Base: relevant-rename_1
+# somefile
+# olddir/a
+# olddir/b
+# Upstream: rename relevant-rename_1 -> renamed_2
+# rename olddir/ -> newdir/
+# Topic_1: relevant-rename_3
+# Topic_2: olddir/newfile_1
+# Topic_3: olddir/newfile_2
+#
+# In this testcase, since the first commit being picked only modifies a
+# file in the toplevel directory, the directory rename is irrelevant for
+# that first merge. However, we need to notice the directory rename for
+# the merge that picks the second commit, and we don't want the third
+# commit to mess up its location either. We want to make sure that
+# olddir/newfile doesn't exist in the result and that newdir/newfile does.
+#
+# We also test that we only do rename detection twice. We never need
+# rename detection on the topic side of history, but we do need it twice on
+# the upstream side of history. For the first topic commit, we only need
+# the
+# relevant-rename -> renamed
+# rename, because olddir is unmodified by Topic_1. For Topic_2, however,
+# the new file being added to olddir means files that were previously
+# irrelevant for rename detection are now relevant, forcing us to repeat
+# rename detection for the paths we don't already have cached. Topic_3 also
+# tweaks olddir/newfile, but the renames in olddir/ will have been cached
+# from the second rename detection run.
+#
+test_expect_success 'dir rename unneeded, then add new file to old dir' '
+ test_setup_upstream_rename dir-rename-unneeded-until-new-file &&
+ (
+ cd dir-rename-unneeded-until-new-file &&
+
+ git switch topic &&
+
+ test_seq 3 10 >relevant-rename &&
+ git add relevant-rename &&
+ git commit -m A &&
+
+ echo foo >olddir/newfile &&
+ git add olddir/newfile &&
+ git commit -m B &&
+
+ echo bar >>olddir/newfile &&
+ git add olddir/newfile &&
+ git commit -m C &&
+
+ #
+ # Actual testing
+ #
+
+ git switch upstream &&
+ git config merge.directoryRenames true &&
+
+ GIT_TRACE2_PERF="$(pwd)/trace.output" &&
+ export GIT_TRACE2_PERF &&
+
+ test-tool fast-rebase --onto HEAD upstream~1 topic &&
+ #git cherry-pick upstream..topic &&
+
+ grep region_enter.*diffcore_rename trace.output >calls &&
+ test_line_count = 2 calls &&
+
+ git ls-files >tracked &&
+ test_line_count = 5 tracked &&
+ test_path_is_missing olddir/newfile &&
+ test_path_is_file newdir/newfile
+ )
+'
+
+#
+# The following testcase is *very* similar to the last one, but instead of
+# adding a new olddir/newfile, it renames somefile -> olddir/newfile:
+# Base: relevant-rename_1
+# somefile_1
+# olddir/a
+# olddir/b
+# Upstream: rename relevant-rename_1 -> renamed_2
+# rename olddir/ -> newdir/
+# Topic_1: relevant-rename_3
+# Topic_2: rename somefile -> olddir/newfile_2
+# Topic_3: modify olddir/newfile_3
+#
+# In this testcase, since the first commit being picked only modifies a
+# file in the toplevel directory, the directory rename is irrelevant for
+# that first merge. However, we need to notice the directory rename for
+# the merge that picks the second commit, and we don't want the third
+# commit to mess up its location either. We want to make sure that
+# neither somefile or olddir/newfile exists in the result and that
+# newdir/newfile does.
+#
+# This testcase needs one more call to rename detection than the last
+# testcase, because of the somefile -> olddir/newfile rename in Topic_2.
+test_expect_success 'dir rename unneeded, then rename existing file into old dir' '
+ test_setup_upstream_rename dir-rename-unneeded-until-file-moved-inside &&
+ (
+ cd dir-rename-unneeded-until-file-moved-inside &&
+
+ git switch topic &&
+
+ test_seq 3 10 >relevant-rename &&
+ git add relevant-rename &&
+ git commit -m A &&
+
+ test_seq 1 10 >somefile &&
+ git add somefile &&
+ git mv somefile olddir/newfile &&
+ git commit -m B &&
+
+ test_seq 1 12 >olddir/newfile &&
+ git add olddir/newfile &&
+ git commit -m C &&
+
+ #
+ # Actual testing
+ #
+
+ git switch upstream &&
+ git config merge.directoryRenames true &&
+
+ GIT_TRACE2_PERF="$(pwd)/trace.output" &&
+ export GIT_TRACE2_PERF &&
+
+ test-tool fast-rebase --onto HEAD upstream~1 topic &&
+ #git cherry-pick upstream..topic &&
+
+ grep region_enter.*diffcore_rename trace.output >calls &&
+ test_line_count = 3 calls &&
+
+ test_path_is_missing somefile &&
+ test_path_is_missing olddir/newfile &&
+ test_path_is_file newdir/newfile &&
+ git ls-files >tracked &&
+ test_line_count = 4 tracked
+ )
+'
+
+# Helper for the next two tests
+test_setup_topic_rename () {
+ test_create_repo $1 &&
+ (
+ cd $1 &&
+
+ test_seq 3 8 >somefile &&
+ mkdir olddir &&
+ test_seq 3 8 >olddir/a &&
+ echo b >olddir/b &&
+ git add olddir somefile &&
+ git commit -m orig &&
+
+ git branch upstream &&
+ git branch topic &&
+
+ git switch topic &&
+ test_seq 1 8 >somefile &&
+ test_seq 1 8 >olddir/a &&
+ git add somefile olddir/a &&
+ git mv olddir newdir &&
+ git commit -m "Dir renamed" &&
+
+ test_seq 1 10 >somefile &&
+ git add somefile &&
+ mkdir olddir &&
+ >olddir/unrelated-file &&
+ git add olddir &&
+ git commit -m "Unrelated file in recreated old dir"
+ )
+}
+
+#
+# In the following testcase, the first commit on the topic branch renames
+# a directory, while the second recreates the old directory and places a
+# file into it:
+# Base: somefile
+# olddir/a
+# olddir/b
+# Upstream: olddir/newfile
+# Topic_1: somefile_2
+# rename olddir/ -> newdir/
+# Topic_2: olddir/unrelated-file
+#
+# Note that the first pick should merge:
+# Base: somefile
+# olddir/{a,b}
+# Upstream: olddir/newfile
+# Topic_1: rename olddir/ -> newdir/
+# For which the expected result (assuming merge.directoryRenames=true) is
+# clearly:
+# Result: somefile
+# newdir/{a, b, newfile}
+#
+# While the second pick does the following three-way merge:
+# Base (Topic_1): somefile
+# newdir/{a,b}
+# Upstream (Result from 1): same files as base, but adds newdir/newfile
+# Topic_2: same files as base, but adds olddir/unrelated-file
+#
+# The second merge is pretty trivial; upstream adds newdir/newfile, and
+# topic_2 adds olddir/unrelated-file. We're just testing that we don't
+# accidentally cache directory renames somehow and rename
+# olddir/unrelated-file to newdir/unrelated-file.
+#
+# This testcase should only need one call to diffcore_rename_extended().
+test_expect_success 'caching renames only on upstream side, part 1' '
+ test_setup_topic_rename cache-renames-only-upstream-add-file &&
+ (
+ cd cache-renames-only-upstream-add-file &&
+
+ git switch upstream &&
+
+ >olddir/newfile &&
+ git add olddir/newfile &&
+ git commit -m "Add newfile" &&
+
+ #
+ # Actual testing
+ #
+
+ git switch upstream &&
+
+ git config merge.directoryRenames true &&
+
+ GIT_TRACE2_PERF="$(pwd)/trace.output" &&
+ export GIT_TRACE2_PERF &&
+
+ test-tool fast-rebase --onto HEAD upstream~1 topic &&
+ #git cherry-pick upstream..topic &&
+
+ grep region_enter.*diffcore_rename trace.output >calls &&
+ test_line_count = 1 calls &&
+
+ git ls-files >tracked &&
+ test_line_count = 5 tracked &&
+ test_path_is_missing newdir/unrelated-file &&
+ test_path_is_file olddir/unrelated-file &&
+ test_path_is_file newdir/newfile &&
+ test_path_is_file newdir/b &&
+ test_path_is_file newdir/a &&
+ test_path_is_file somefile
+ )
+'
+
+#
+# The following testcase is *very* similar to the last one, but instead of
+# adding a new olddir/newfile, it renames somefile -> olddir/newfile:
+# Base: somefile
+# olddir/a
+# olddir/b
+# Upstream: somefile_1 -> olddir/newfile
+# Topic_1: rename olddir/ -> newdir/
+# somefile_2
+# Topic_2: olddir/unrelated-file
+# somefile_3
+#
+# Much like the previous test, this case is actually trivial and we are just
+# making sure there isn't some spurious directory rename caching going on
+# for the wrong side of history.
+#
+#
+# This testcase should only need two calls to diffcore_rename_extended(),
+# both for the first merge, one for each side of history.
+#
+test_expect_success 'caching renames only on upstream side, part 2' '
+ test_setup_topic_rename cache-renames-only-upstream-rename-file &&
+ (
+ cd cache-renames-only-upstream-rename-file &&
+
+ git switch upstream &&
+
+ git mv somefile olddir/newfile &&
+ git commit -m "Add newfile" &&
+
+ #
+ # Actual testing
+ #
+
+ git switch upstream &&
+
+ git config merge.directoryRenames true &&
+
+ GIT_TRACE2_PERF="$(pwd)/trace.output" &&
+ export GIT_TRACE2_PERF &&
+
+ test-tool fast-rebase --onto HEAD upstream~1 topic &&
+ #git cherry-pick upstream..topic &&
+
+ grep region_enter.*diffcore_rename trace.output >calls &&
+ test_line_count = 2 calls &&
+
+ git ls-files >tracked &&
+ test_line_count = 4 tracked &&
+ test_path_is_missing newdir/unrelated-file &&
+ test_path_is_file olddir/unrelated-file &&
+ test_path_is_file newdir/newfile &&
+ test_path_is_file newdir/b &&
+ test_path_is_file newdir/a
+ )
+'
+
+test_done
diff --git a/t/t6430-merge-recursive.sh b/t/t6430-merge-recursive.sh
index ffcc01fe65..a0efe7cb6d 100755
--- a/t/t6430-merge-recursive.sh
+++ b/t/t6430-merge-recursive.sh
@@ -718,7 +718,9 @@ test_expect_success 'merge-recursive remembers the names of all base trees' '
# merge-recursive prints in reverse order, but we do not care
sort <trees >expect &&
sed -n "s/^virtual //p" out | sort >actual &&
- test_cmp expect actual
+ test_cmp expect actual &&
+
+ git clean -fd
'
test_expect_success 'merge-recursive internal merge resolves to the sameness' '
diff --git a/t/t6436-merge-overwrite.sh b/t/t6436-merge-overwrite.sh
index 84b4aacf49..c0b7bd7c3f 100755
--- a/t/t6436-merge-overwrite.sh
+++ b/t/t6436-merge-overwrite.sh
@@ -68,7 +68,8 @@ test_expect_success 'will not overwrite removed file' '
git commit -m "rm c1.c" &&
cp important c1.c &&
test_must_fail git merge c1a &&
- test_cmp important c1.c
+ test_cmp important c1.c &&
+ rm c1.c # Do not leave untracked file in way of future tests
'
test_expect_success 'will not overwrite re-added file' '
diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh
index 60d961b526..c2021267f2 100755
--- a/t/t6500-gc.sh
+++ b/t/t6500-gc.sh
@@ -95,6 +95,52 @@ test_expect_success 'gc --keep-largest-pack' '
)
'
+test_expect_success 'pre-auto-gc hook can stop auto gc' '
+ cat >err.expect <<-\EOF &&
+ no gc for you
+ EOF
+
+ git init pre-auto-gc-hook &&
+ (
+ cd pre-auto-gc-hook &&
+ write_script ".git/hooks/pre-auto-gc" <<-\EOF &&
+ echo >&2 no gc for you &&
+ exit 1
+ EOF
+
+ git config gc.auto 3 &&
+ git config gc.autoDetach false &&
+
+ # We need to create two object whose sha1s start with 17
+ # since this is what git gc counts. As it happens, these
+ # two blobs will do so.
+ test_commit "$(test_oid obj1)" &&
+ test_commit "$(test_oid obj2)" &&
+
+ git gc --auto >../out.actual 2>../err.actual
+ ) &&
+ test_must_be_empty out.actual &&
+ test_cmp err.expect err.actual &&
+
+ cat >err.expect <<-\EOF &&
+ will gc for you
+ Auto packing the repository for optimum performance.
+ See "git help gc" for manual housekeeping.
+ EOF
+
+ (
+ cd pre-auto-gc-hook &&
+ write_script ".git/hooks/pre-auto-gc" <<-\EOF &&
+ echo >&2 will gc for you &&
+ exit 0
+ EOF
+ git gc --auto >../out.actual 2>../err.actual
+ ) &&
+
+ test_must_be_empty out.actual &&
+ test_cmp err.expect err.actual
+'
+
test_expect_success 'auto gc with too many loose objects does not attempt to create bitmaps' '
test_config gc.auto 3 &&
test_config gc.autodetach false &&
@@ -195,7 +241,7 @@ test_expect_success 'background auto gc respects lock for all operations' '
# create a ref whose loose presence we can use to detect a pack-refs run
git update-ref refs/heads/should-be-loose HEAD &&
- test_path_is_file .git/refs/heads/should-be-loose &&
+ (ls -1 .git/refs/heads .git/reftable >expect || true) &&
# now fake a concurrent gc that holds the lock; we can use our
# shell pid so that it looks valid.
@@ -212,7 +258,8 @@ test_expect_success 'background auto gc respects lock for all operations' '
# our gc should exit zero without doing anything
run_and_wait_for_auto_gc &&
- test_path_is_file .git/refs/heads/should-be-loose
+ (ls -1 .git/refs/heads .git/reftable >actual || true) &&
+ test_cmp expect actual
'
# DO NOT leave a detached auto gc process running near the end of the
diff --git a/t/t6501-freshen-objects.sh b/t/t6501-freshen-objects.sh
index 75210f012b..10662456ae 100755
--- a/t/t6501-freshen-objects.sh
+++ b/t/t6501-freshen-objects.sh
@@ -43,15 +43,25 @@ commit () {
}
maybe_repack () {
- if test -n "$repack"; then
+ case "$title" in
+ loose)
+ : skip repack
+ ;;
+ repack)
git repack -ad
- fi
+ ;;
+ bitmap)
+ git repack -adb
+ ;;
+ *)
+ echo >&2 "unknown test type in maybe_repack"
+ return 1
+ ;;
+ esac
}
-for repack in '' true; do
- title=${repack:+repack}
- title=${title:-loose}
-
+for title in loose repack bitmap
+do
test_expect_success "make repo completely empty ($title)" '
rm -rf .git &&
git init
diff --git a/t/t7002-mv-sparse-checkout.sh b/t/t7002-mv-sparse-checkout.sh
new file mode 100755
index 0000000000..545748949a
--- /dev/null
+++ b/t/t7002-mv-sparse-checkout.sh
@@ -0,0 +1,189 @@
+#!/bin/sh
+
+test_description='git mv in sparse working trees'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' "
+ mkdir -p sub/dir sub/dir2 &&
+ touch a b c sub/d sub/dir/e sub/dir2/e &&
+ git add -A &&
+ git commit -m files &&
+
+ cat >sparse_error_header <<-EOF &&
+ The following paths and/or pathspecs matched paths that exist
+ outside of your sparse-checkout definition, so will not be
+ updated in the index:
+ EOF
+
+ cat >sparse_hint <<-EOF
+ hint: If you intend to update such entries, try one of the following:
+ hint: * Use the --sparse option.
+ hint: * Disable or modify the sparsity rules.
+ hint: Disable this message with \"git config advice.updateSparsePath false\"
+ EOF
+"
+
+test_expect_success 'mv refuses to move sparse-to-sparse' '
+ test_when_finished rm -f e &&
+ git reset --hard &&
+ git sparse-checkout set a &&
+ touch b &&
+ test_must_fail git mv b e 2>stderr &&
+ cat sparse_error_header >expect &&
+ echo b >>expect &&
+ echo e >>expect &&
+ cat sparse_hint >>expect &&
+ test_cmp expect stderr &&
+ git mv --sparse b e 2>stderr &&
+ test_must_be_empty stderr
+'
+
+test_expect_success 'mv refuses to move sparse-to-sparse, ignores failure' '
+ test_when_finished rm -f b c e &&
+ git reset --hard &&
+ git sparse-checkout set a &&
+
+ # tracked-to-untracked
+ touch b &&
+ git mv -k b e 2>stderr &&
+ test_path_exists b &&
+ test_path_is_missing e &&
+ cat sparse_error_header >expect &&
+ echo b >>expect &&
+ echo e >>expect &&
+ cat sparse_hint >>expect &&
+ test_cmp expect stderr &&
+
+ git mv --sparse b e 2>stderr &&
+ test_must_be_empty stderr &&
+ test_path_is_missing b &&
+ test_path_exists e &&
+
+ # tracked-to-tracked
+ git reset --hard &&
+ touch b &&
+ git mv -k b c 2>stderr &&
+ test_path_exists b &&
+ test_path_is_missing c &&
+ cat sparse_error_header >expect &&
+ echo b >>expect &&
+ echo c >>expect &&
+ cat sparse_hint >>expect &&
+ test_cmp expect stderr &&
+
+ git mv --sparse b c 2>stderr &&
+ test_must_be_empty stderr &&
+ test_path_is_missing b &&
+ test_path_exists c
+'
+
+test_expect_success 'mv refuses to move non-sparse-to-sparse' '
+ test_when_finished rm -f b c e &&
+ git reset --hard &&
+ git sparse-checkout set a &&
+
+ # tracked-to-untracked
+ test_must_fail git mv a e 2>stderr &&
+ test_path_exists a &&
+ test_path_is_missing e &&
+ cat sparse_error_header >expect &&
+ echo e >>expect &&
+ cat sparse_hint >>expect &&
+ test_cmp expect stderr &&
+ git mv --sparse a e 2>stderr &&
+ test_must_be_empty stderr &&
+ test_path_is_missing a &&
+ test_path_exists e &&
+
+ # tracked-to-tracked
+ rm e &&
+ git reset --hard &&
+ test_must_fail git mv a c 2>stderr &&
+ test_path_exists a &&
+ test_path_is_missing c &&
+ cat sparse_error_header >expect &&
+ echo c >>expect &&
+ cat sparse_hint >>expect &&
+ test_cmp expect stderr &&
+ git mv --sparse a c 2>stderr &&
+ test_must_be_empty stderr &&
+ test_path_is_missing a &&
+ test_path_exists c
+'
+
+test_expect_success 'mv refuses to move sparse-to-non-sparse' '
+ test_when_finished rm -f b c e &&
+ git reset --hard &&
+ git sparse-checkout set a e &&
+
+ # tracked-to-untracked
+ touch b &&
+ test_must_fail git mv b e 2>stderr &&
+ cat sparse_error_header >expect &&
+ echo b >>expect &&
+ cat sparse_hint >>expect &&
+ test_cmp expect stderr &&
+ git mv --sparse b e 2>stderr &&
+ test_must_be_empty stderr
+'
+
+test_expect_success 'recursive mv refuses to move (possible) sparse' '
+ test_when_finished rm -rf b c e sub2 &&
+ git reset --hard &&
+ # Without cone mode, "sub" and "sub2" do not match
+ git sparse-checkout set sub/dir sub2/dir &&
+
+ # Add contained contents to ensure we avoid non-existence errors
+ mkdir sub/dir2 &&
+ touch sub/d sub/dir2/e &&
+
+ test_must_fail git mv sub sub2 2>stderr &&
+ cat sparse_error_header >expect &&
+ cat >>expect <<-\EOF &&
+ sub/d
+ sub2/d
+ sub/dir/e
+ sub2/dir/e
+ sub/dir2/e
+ sub2/dir2/e
+ EOF
+ cat sparse_hint >>expect &&
+ test_cmp expect stderr &&
+ git mv --sparse sub sub2 2>stderr &&
+ test_must_be_empty stderr &&
+ git commit -m "moved sub to sub2" &&
+ git rev-parse HEAD~1:sub >expect &&
+ git rev-parse HEAD:sub2 >actual &&
+ test_cmp expect actual &&
+ git reset --hard HEAD~1
+'
+
+test_expect_success 'recursive mv refuses to move sparse' '
+ git reset --hard &&
+ # Use cone mode so "sub/" matches the sparse-checkout patterns
+ git sparse-checkout init --cone &&
+ git sparse-checkout set sub/dir sub2/dir &&
+
+ # Add contained contents to ensure we avoid non-existence errors
+ mkdir sub/dir2 &&
+ touch sub/dir2/e &&
+
+ test_must_fail git mv sub sub2 2>stderr &&
+ cat sparse_error_header >expect &&
+ cat >>expect <<-\EOF &&
+ sub/dir2/e
+ sub2/dir2/e
+ EOF
+ cat sparse_hint >>expect &&
+ test_cmp expect stderr &&
+ git mv --sparse sub sub2 2>stderr &&
+ test_must_be_empty stderr &&
+ git commit -m "moved sub to sub2" &&
+ git rev-parse HEAD~1:sub >expect &&
+ git rev-parse HEAD:sub2 >actual &&
+ test_cmp expect actual &&
+ git reset --hard HEAD~1
+'
+
+test_done
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index 1349e5b232..e18a218952 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -395,8 +395,11 @@ test_expect_success '--prune-empty is able to prune root commit' '
test_expect_success '--prune-empty is able to prune entire branch' '
git branch prune-entire B &&
git filter-branch -f --prune-empty --index-filter "git update-index --remove A.t B.t" prune-entire &&
- test_path_is_missing .git/refs/heads/prune-entire &&
- test_must_fail git reflog exists refs/heads/prune-entire
+ test_must_fail git rev-parse refs/heads/prune-entire &&
+ if test_have_prereq REFFILES
+ then
+ test_must_fail git reflog exists refs/heads/prune-entire
+ fi
'
test_expect_success '--remap-to-ancestor with filename filters' '
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 2f72c5c688..082be85dff 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -1998,6 +1998,10 @@ test_expect_success '--format should list tags as per format given' '
test_cmp expect actual
'
+test_expect_success 'git tag -l with --format="%(rest)" must fail' '
+ test_must_fail git tag -l --format="%(rest)" "v1*"
+'
+
test_expect_success "set up color tests" '
echo "<RED>v1.0<RESET>" >expect.color &&
echo "v1.0" >expect.bare &&
diff --git a/t/t7011-skip-worktree-reading.sh b/t/t7011-skip-worktree-reading.sh
index 26852586ac..1761a2b1b9 100755
--- a/t/t7011-skip-worktree-reading.sh
+++ b/t/t7011-skip-worktree-reading.sh
@@ -132,11 +132,6 @@ test_expect_success 'diff-files does not examine skip-worktree dirty entries' '
test -z "$(git diff-files -- one)"
'
-test_expect_success 'git-rm succeeds on skip-worktree absent entries' '
- setup_absent &&
- git rm 1
-'
-
test_expect_success 'commit on skip-worktree absent entries' '
git reset &&
setup_absent &&
diff --git a/t/t7012-skip-worktree-writing.sh b/t/t7012-skip-worktree-writing.sh
index f2a8e76511..a1080b94e3 100755
--- a/t/t7012-skip-worktree-writing.sh
+++ b/t/t7012-skip-worktree-writing.sh
@@ -60,13 +60,6 @@ setup_absent() {
git update-index --skip-worktree 1
}
-test_absent() {
- echo "100644 $EMPTY_BLOB 0 1" > expected &&
- git ls-files --stage 1 > result &&
- test_cmp expected result &&
- test ! -f 1
-}
-
setup_dirty() {
git update-index --force-remove 1 &&
echo dirty > 1 &&
@@ -100,18 +93,6 @@ test_expect_success 'index setup' '
test_cmp expected result
'
-test_expect_success 'git-add ignores worktree content' '
- setup_absent &&
- git add 1 &&
- test_absent
-'
-
-test_expect_success 'git-add ignores worktree content' '
- setup_dirty &&
- git add 1 &&
- test_dirty
-'
-
test_expect_success 'git-rm fails if worktree is dirty' '
setup_dirty &&
test_must_fail git rm 1 &&
diff --git a/t/t7030-verify-tag.sh b/t/t7030-verify-tag.sh
index 3cefde9602..10faa64515 100755
--- a/t/t7030-verify-tag.sh
+++ b/t/t7030-verify-tag.sh
@@ -194,6 +194,10 @@ test_expect_success GPG 'verifying tag with --format' '
test_cmp expect actual
'
+test_expect_success GPG 'verifying tag with --format="%(rest)" must fail' '
+ test_must_fail git verify-tag --format="%(rest)" "fourth-signed"
+'
+
test_expect_success GPG 'verifying a forged tag with --format should fail silently' '
test_must_fail git verify-tag --format="tagname : %(tag)" $(cat forged1.tag) >actual-forged &&
test_must_be_empty actual-forged
diff --git a/t/t7063-status-untracked-cache.sh b/t/t7063-status-untracked-cache.sh
index accefde72f..a0c123b0a7 100755
--- a/t/t7063-status-untracked-cache.sh
+++ b/t/t7063-status-untracked-cache.sh
@@ -57,6 +57,20 @@ iuc () {
return $ret
}
+get_relevant_traces () {
+ # From the GIT_TRACE2_PERF data of the form
+ # $TIME $FILE:$LINE | d0 | main | data | r1 | ? | ? | read_directo | $RELEVANT_STAT
+ # extract the $RELEVANT_STAT fields. We don't care about region_enter
+ # or region_leave, or stats for things outside read_directory.
+ INPUT_FILE=$1
+ OUTPUT_FILE=$2
+ grep data.*read_directo $INPUT_FILE |
+ cut -d "|" -f 9 |
+ grep -v visited \
+ >"$OUTPUT_FILE"
+}
+
+
test_lazy_prereq UNTRACKED_CACHE '
{ git update-index --test-untracked-cache; ret=$?; } &&
test $ret -ne 1
@@ -129,19 +143,21 @@ EOF
test_expect_success 'status first time (empty cache)' '
avoid_racy &&
- : >../trace &&
- GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+ : >../trace.output &&
+ GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../actual &&
iuc status --porcelain >../status.iuc &&
test_cmp ../status.expect ../status.iuc &&
test_cmp ../status.expect ../actual &&
+ get_relevant_traces ../trace.output ../trace.relevant &&
cat >../trace.expect <<EOF &&
-node creation: 3
-gitignore invalidation: 1
-directory invalidation: 0
-opendir: 4
+ ....path:
+ ....node-creation:3
+ ....gitignore-invalidation:1
+ ....directory-invalidation:0
+ ....opendir:4
EOF
- test_cmp ../trace.expect ../trace
+ test_cmp ../trace.expect ../trace.relevant
'
test_expect_success 'untracked cache after first status' '
@@ -151,19 +167,21 @@ test_expect_success 'untracked cache after first status' '
test_expect_success 'status second time (fully populated cache)' '
avoid_racy &&
- : >../trace &&
- GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+ : >../trace.output &&
+ GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../actual &&
iuc status --porcelain >../status.iuc &&
test_cmp ../status.expect ../status.iuc &&
test_cmp ../status.expect ../actual &&
+ get_relevant_traces ../trace.output ../trace.relevant &&
cat >../trace.expect <<EOF &&
-node creation: 0
-gitignore invalidation: 0
-directory invalidation: 0
-opendir: 0
+ ....path:
+ ....node-creation:0
+ ....gitignore-invalidation:0
+ ....directory-invalidation:0
+ ....opendir:0
EOF
- test_cmp ../trace.expect ../trace
+ test_cmp ../trace.expect ../trace.relevant
'
test_expect_success 'untracked cache after second status' '
@@ -174,8 +192,8 @@ test_expect_success 'untracked cache after second status' '
test_expect_success 'modify in root directory, one dir invalidation' '
avoid_racy &&
: >four &&
- : >../trace &&
- GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+ : >../trace.output &&
+ GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../actual &&
iuc status --porcelain >../status.iuc &&
cat >../status.expect <<EOF &&
@@ -189,13 +207,15 @@ A two
EOF
test_cmp ../status.expect ../status.iuc &&
test_cmp ../status.expect ../actual &&
+ get_relevant_traces ../trace.output ../trace.relevant &&
cat >../trace.expect <<EOF &&
-node creation: 0
-gitignore invalidation: 0
-directory invalidation: 1
-opendir: 1
+ ....path:
+ ....node-creation:0
+ ....gitignore-invalidation:0
+ ....directory-invalidation:1
+ ....opendir:1
EOF
- test_cmp ../trace.expect ../trace
+ test_cmp ../trace.expect ../trace.relevant
'
@@ -223,8 +243,8 @@ EOF
test_expect_success 'new .gitignore invalidates recursively' '
avoid_racy &&
echo four >.gitignore &&
- : >../trace &&
- GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+ : >../trace.output &&
+ GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../actual &&
iuc status --porcelain >../status.iuc &&
cat >../status.expect <<EOF &&
@@ -238,13 +258,15 @@ A two
EOF
test_cmp ../status.expect ../status.iuc &&
test_cmp ../status.expect ../actual &&
+ get_relevant_traces ../trace.output ../trace.relevant &&
cat >../trace.expect <<EOF &&
-node creation: 0
-gitignore invalidation: 1
-directory invalidation: 1
-opendir: 4
+ ....path:
+ ....node-creation:0
+ ....gitignore-invalidation:1
+ ....directory-invalidation:1
+ ....opendir:4
EOF
- test_cmp ../trace.expect ../trace
+ test_cmp ../trace.expect ../trace.relevant
'
@@ -272,8 +294,8 @@ EOF
test_expect_success 'new info/exclude invalidates everything' '
avoid_racy &&
echo three >>.git/info/exclude &&
- : >../trace &&
- GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+ : >../trace.output &&
+ GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../actual &&
iuc status --porcelain >../status.iuc &&
cat >../status.expect <<EOF &&
@@ -285,13 +307,15 @@ A two
EOF
test_cmp ../status.expect ../status.iuc &&
test_cmp ../status.expect ../actual &&
+ get_relevant_traces ../trace.output ../trace.relevant &&
cat >../trace.expect <<EOF &&
-node creation: 0
-gitignore invalidation: 1
-directory invalidation: 0
-opendir: 4
+ ....path:
+ ....node-creation:0
+ ....gitignore-invalidation:1
+ ....directory-invalidation:0
+ ....opendir:4
EOF
- test_cmp ../trace.expect ../trace
+ test_cmp ../trace.expect ../trace.relevant
'
test_expect_success 'verify untracked cache dump' '
@@ -330,8 +354,8 @@ EOF
'
test_expect_success 'status after the move' '
- : >../trace &&
- GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+ : >../trace.output &&
+ GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../actual &&
iuc status --porcelain >../status.iuc &&
cat >../status.expect <<EOF &&
@@ -343,13 +367,15 @@ A one
EOF
test_cmp ../status.expect ../status.iuc &&
test_cmp ../status.expect ../actual &&
+ get_relevant_traces ../trace.output ../trace.relevant &&
cat >../trace.expect <<EOF &&
-node creation: 0
-gitignore invalidation: 0
-directory invalidation: 0
-opendir: 1
+ ....path:
+ ....node-creation:0
+ ....gitignore-invalidation:0
+ ....directory-invalidation:0
+ ....opendir:1
EOF
- test_cmp ../trace.expect ../trace
+ test_cmp ../trace.expect ../trace.relevant
'
test_expect_success 'verify untracked cache dump' '
@@ -389,8 +415,8 @@ EOF
'
test_expect_success 'status after the move' '
- : >../trace &&
- GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+ : >../trace.output &&
+ GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../actual &&
iuc status --porcelain >../status.iuc &&
cat >../status.expect <<EOF &&
@@ -402,13 +428,15 @@ A two
EOF
test_cmp ../status.expect ../status.iuc &&
test_cmp ../status.expect ../actual &&
+ get_relevant_traces ../trace.output ../trace.relevant &&
cat >../trace.expect <<EOF &&
-node creation: 0
-gitignore invalidation: 0
-directory invalidation: 0
-opendir: 1
+ ....path:
+ ....node-creation:0
+ ....gitignore-invalidation:0
+ ....directory-invalidation:0
+ ....opendir:1
EOF
- test_cmp ../trace.expect ../trace
+ test_cmp ../trace.expect ../trace.relevant
'
test_expect_success 'verify untracked cache dump' '
@@ -438,8 +466,8 @@ test_expect_success 'set up for sparse checkout testing' '
'
test_expect_success 'status after commit' '
- : >../trace &&
- GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+ : >../trace.output &&
+ GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../actual &&
iuc status --porcelain >../status.iuc &&
cat >../status.expect <<EOF &&
@@ -448,13 +476,15 @@ test_expect_success 'status after commit' '
EOF
test_cmp ../status.expect ../status.iuc &&
test_cmp ../status.expect ../actual &&
+ get_relevant_traces ../trace.output ../trace.relevant &&
cat >../trace.expect <<EOF &&
-node creation: 0
-gitignore invalidation: 0
-directory invalidation: 0
-opendir: 2
+ ....path:
+ ....node-creation:0
+ ....gitignore-invalidation:0
+ ....directory-invalidation:0
+ ....opendir:2
EOF
- test_cmp ../trace.expect ../trace
+ test_cmp ../trace.expect ../trace.relevant
'
test_expect_success 'untracked cache correct after commit' '
@@ -496,9 +526,9 @@ test_expect_success 'create/modify files, some of which are gitignored' '
'
test_expect_success 'test sparse status with untracked cache' '
- : >../trace &&
+ : >../trace.output &&
avoid_racy &&
- GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+ GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../status.actual &&
iuc status --porcelain >../status.iuc &&
cat >../status.expect <<EOF &&
@@ -509,13 +539,15 @@ test_expect_success 'test sparse status with untracked cache' '
EOF
test_cmp ../status.expect ../status.iuc &&
test_cmp ../status.expect ../status.actual &&
+ get_relevant_traces ../trace.output ../trace.relevant &&
cat >../trace.expect <<EOF &&
-node creation: 0
-gitignore invalidation: 1
-directory invalidation: 2
-opendir: 2
+ ....path:
+ ....node-creation:0
+ ....gitignore-invalidation:1
+ ....directory-invalidation:2
+ ....opendir:2
EOF
- test_cmp ../trace.expect ../trace
+ test_cmp ../trace.expect ../trace.relevant
'
test_expect_success 'untracked cache correct after status' '
@@ -539,8 +571,8 @@ EOF
test_expect_success 'test sparse status again with untracked cache' '
avoid_racy &&
- : >../trace &&
- GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+ : >../trace.output &&
+ GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../status.actual &&
iuc status --porcelain >../status.iuc &&
cat >../status.expect <<EOF &&
@@ -551,13 +583,15 @@ test_expect_success 'test sparse status again with untracked cache' '
EOF
test_cmp ../status.expect ../status.iuc &&
test_cmp ../status.expect ../status.actual &&
+ get_relevant_traces ../trace.output ../trace.relevant &&
cat >../trace.expect <<EOF &&
-node creation: 0
-gitignore invalidation: 0
-directory invalidation: 0
-opendir: 0
+ ....path:
+ ....node-creation:0
+ ....gitignore-invalidation:0
+ ....directory-invalidation:0
+ ....opendir:0
EOF
- test_cmp ../trace.expect ../trace
+ test_cmp ../trace.expect ../trace.relevant
'
test_expect_success 'set up for test of subdir and sparse checkouts' '
@@ -568,8 +602,8 @@ test_expect_success 'set up for test of subdir and sparse checkouts' '
test_expect_success 'test sparse status with untracked cache and subdir' '
avoid_racy &&
- : >../trace &&
- GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+ : >../trace.output &&
+ GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../status.actual &&
iuc status --porcelain >../status.iuc &&
cat >../status.expect <<EOF &&
@@ -581,13 +615,15 @@ test_expect_success 'test sparse status with untracked cache and subdir' '
EOF
test_cmp ../status.expect ../status.iuc &&
test_cmp ../status.expect ../status.actual &&
+ get_relevant_traces ../trace.output ../trace.relevant &&
cat >../trace.expect <<EOF &&
-node creation: 2
-gitignore invalidation: 0
-directory invalidation: 1
-opendir: 3
+ ....path:
+ ....node-creation:2
+ ....gitignore-invalidation:0
+ ....directory-invalidation:1
+ ....opendir:3
EOF
- test_cmp ../trace.expect ../trace
+ test_cmp ../trace.expect ../trace.relevant
'
test_expect_success 'verify untracked cache dump (sparse/subdirs)' '
@@ -616,19 +652,21 @@ EOF
test_expect_success 'test sparse status again with untracked cache and subdir' '
avoid_racy &&
- : >../trace &&
- GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+ : >../trace.output &&
+ GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../status.actual &&
iuc status --porcelain >../status.iuc &&
test_cmp ../status.expect ../status.iuc &&
test_cmp ../status.expect ../status.actual &&
+ get_relevant_traces ../trace.output ../trace.relevant &&
cat >../trace.expect <<EOF &&
-node creation: 0
-gitignore invalidation: 0
-directory invalidation: 0
-opendir: 0
+ ....path:
+ ....node-creation:0
+ ....gitignore-invalidation:0
+ ....directory-invalidation:0
+ ....opendir:0
EOF
- test_cmp ../trace.expect ../trace
+ test_cmp ../trace.expect ../trace.relevant
'
test_expect_success 'move entry in subdir from untracked to cached' '
diff --git a/t/t7064-wtstatus-pv2.sh b/t/t7064-wtstatus-pv2.sh
index 4613882caf..eeb0534163 100755
--- a/t/t7064-wtstatus-pv2.sh
+++ b/t/t7064-wtstatus-pv2.sh
@@ -373,10 +373,7 @@ test_expect_success 'verify upstream fields in branch header' '
## Test upstream-gone case. Fake this by pointing
## origin/initial-branch at a non-existing commit.
- OLD=$(git rev-parse origin/initial-branch) &&
- NEW=$ZERO_OID &&
- mv .git/packed-refs .git/old-packed-refs &&
- sed "s/$OLD/$NEW/g" <.git/old-packed-refs >.git/packed-refs &&
+ git update-ref -d refs/remotes/origin/initial-branch &&
HUF=$(git rev-parse HEAD) &&
diff --git a/t/t7112-reset-submodule.sh b/t/t7112-reset-submodule.sh
index 19830d9036..a3e2413bc3 100755
--- a/t/t7112-reset-submodule.sh
+++ b/t/t7112-reset-submodule.sh
@@ -6,7 +6,6 @@ test_description='reset can handle submodules'
. "$TEST_DIRECTORY"/lib-submodule-update.sh
KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1
-KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED=1
test_submodule_switch_recursing_with_args "reset --keep"
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index 7f6e23a4bb..b7ba1c3268 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -585,6 +585,7 @@ test_expect_success 'checkout --conflict=diff3' '
'
test_expect_success 'failing checkout -b should not break working tree' '
+ git clean -fd && # Remove untracked files in the way
git reset --hard main &&
git symbolic-ref HEAD refs/heads/main &&
test_must_fail git checkout -b renamer side^ &&
diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index a74816ca8b..0399701e62 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -746,4 +746,46 @@ test_expect_success 'clean untracked paths by pathspec' '
test_must_be_empty actual
'
+test_expect_success 'avoid traversing into ignored directories' '
+ test_when_finished rm -f output error trace.* &&
+ test_create_repo avoid-traversing-deep-hierarchy &&
+ (
+ cd avoid-traversing-deep-hierarchy &&
+
+ mkdir -p untracked/subdir/with/a &&
+ >untracked/subdir/with/a/random-file.txt &&
+
+ GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
+ git clean -ffdxn -e untracked
+ ) &&
+
+ # Make sure we only visited into the top-level directory, and did
+ # not traverse into the "untracked" subdirectory since it was excluded
+ grep data.*read_directo.*directories-visited trace.output |
+ cut -d "|" -f 9 >trace.relevant &&
+ cat >trace.expect <<-EOF &&
+ ..directories-visited:1
+ EOF
+ test_cmp trace.expect trace.relevant
+'
+
+test_expect_success 'traverse into directories that may have ignored entries' '
+ test_when_finished rm -f output &&
+ test_create_repo need-to-traverse-into-hierarchy &&
+ (
+ cd need-to-traverse-into-hierarchy &&
+ mkdir -p modules/foobar/src/generated &&
+ > modules/foobar/src/generated/code.c &&
+ > modules/foobar/Makefile &&
+ echo "/modules/**/src/generated/" >.gitignore &&
+
+ git clean -fX modules/foobar >../output &&
+
+ grep Removing ../output &&
+
+ test_path_is_missing modules/foobar/src/generated/code.c &&
+ test_path_is_file modules/foobar/Makefile
+ )
+'
+
test_done
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index a924fdb7a6..cb1b8e35db 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -51,7 +51,7 @@ test_expect_success 'submodule update aborts on missing gitmodules url' '
test_expect_success 'add aborts on repository with no commits' '
cat >expect <<-\EOF &&
- '"'repo-no-commits'"' does not have a commit checked out
+ fatal: '"'repo-no-commits'"' does not have a commit checked out
EOF
git init repo-no-commits &&
test_must_fail git submodule add ../a ./repo-no-commits 2>actual &&
@@ -196,6 +196,17 @@ test_expect_success 'submodule add to .gitignored path with --force' '
)
'
+test_expect_success 'submodule add to path with tracked content fails' '
+ (
+ cd addtest &&
+ echo "fatal: '\''dir-tracked'\'' already exists in the index" >expect &&
+ mkdir dir-tracked &&
+ test_commit foo dir-tracked/bar &&
+ test_must_fail git submodule add "$submodurl" dir-tracked >actual 2>&1 &&
+ test_cmp expect actual
+ )
+'
+
test_expect_success 'submodule add to reconfigure existing submodule with --force' '
(
cd addtest-ignore &&
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index ff3ba5422e..11cccbb333 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -448,7 +448,7 @@ test_expect_success 'fsck detects command in .gitmodules' '
'
cat << EOF >expect
-Execution of 'false $submodulesha1' failed in submodule path 'submodule'
+fatal: Execution of 'false $submodulesha1' failed in submodule path 'submodule'
EOF
test_expect_success 'submodule update - command in .git/config catches failure' '
@@ -465,7 +465,7 @@ test_expect_success 'submodule update - command in .git/config catches failure'
'
cat << EOF >expect
-Execution of 'false $submodulesha1' failed in submodule path '../submodule'
+fatal: Execution of 'false $submodulesha1' failed in submodule path '../submodule'
EOF
test_expect_success 'submodule update - command in .git/config catches failure -- subdirectory' '
@@ -484,7 +484,7 @@ test_expect_success 'submodule update - command in .git/config catches failure -
test_expect_success 'submodule update - command run for initial population of submodule' '
cat >expect <<-EOF &&
- Execution of '\''false $submodulesha1'\'' failed in submodule path '\''submodule'\''
+ fatal: Execution of '\''false $submodulesha1'\'' failed in submodule path '\''submodule'\''
EOF
rm -rf super/submodule &&
test_must_fail git -C super submodule update 2>actual &&
@@ -493,8 +493,8 @@ test_expect_success 'submodule update - command run for initial population of su
'
cat << EOF >expect
-Execution of 'false $submodulesha1' failed in submodule path '../super/submodule'
-Failed to recurse into submodule path '../super'
+fatal: Execution of 'false $submodulesha1' failed in submodule path '../super/submodule'
+fatal: Failed to recurse into submodule path '../super'
EOF
test_expect_success 'recursive submodule update - command in .git/config catches failure -- subdirectory' '
@@ -1037,4 +1037,28 @@ test_expect_success 'submodule update --quiet passes quietness to merge/rebase'
)
'
+test_expect_success 'submodule update --quiet passes quietness to fetch with a shallow clone' '
+ test_when_finished "rm -rf super4 super5 super6" &&
+ git clone . super4 &&
+ (cd super4 &&
+ git submodule add --quiet file://"$TRASH_DIRECTORY"/submodule submodule3 &&
+ git commit -am "setup submodule3"
+ ) &&
+ (cd submodule &&
+ test_commit line6 file
+ ) &&
+ git clone super4 super5 &&
+ (cd super5 &&
+ git submodule update --quiet --init --depth=1 submodule3 >out 2>err &&
+ test_must_be_empty out &&
+ test_must_be_empty err
+ ) &&
+ git clone super4 super6 &&
+ (cd super6 &&
+ git submodule update --init --depth=1 submodule3 >out 2>err &&
+ test_file_not_empty out &&
+ test_file_not_empty err
+ )
+'
+
test_done
diff --git a/t/t7415-submodule-names.sh b/t/t7450-bad-git-dotfiles.sh
index f70368bc2e..41706c1c9f 100755
--- a/t/t7415-submodule-names.sh
+++ b/t/t7450-bad-git-dotfiles.sh
@@ -1,9 +1,16 @@
#!/bin/sh
-test_description='check handling of .. in submodule names
+test_description='check broken or malicious patterns in .git* files
-Exercise the name-checking function on a variety of names, and then give a
-real-world setup that confirms we catch this in practice.
+Such as:
+
+ - presence of .. in submodule names;
+ Exercise the name-checking function on a variety of names, and then give a
+ real-world setup that confirms we catch this in practice.
+
+ - nested submodule names
+
+ - symlinked .gitmodules, etc
'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-pack.sh
@@ -132,31 +139,84 @@ test_expect_success 'index-pack --strict works for non-repo pack' '
grep gitmodulesName output
'
-test_expect_success 'fsck detects symlinked .gitmodules file' '
- git init symlink &&
- (
- cd symlink &&
-
- # Make the tree directly to avoid index restrictions.
- #
- # Because symlinks store the target as a blob, choose
- # a pathname that could be parsed as a .gitmodules file
- # to trick naive non-symlink-aware checking.
- tricky="[foo]bar=true" &&
- content=$(git hash-object -w ../.gitmodules) &&
- target=$(printf "$tricky" | git hash-object -w --stdin) &&
- {
- printf "100644 blob $content\t$tricky\n" &&
- printf "120000 blob $target\t.gitmodules\n"
- } | git mktree &&
-
- # Check not only that we fail, but that it is due to the
- # symlink detector; this grep string comes from the config
- # variable name and will not be translated.
- test_must_fail git fsck 2>output &&
- test_i18ngrep gitmodulesSymlink output
- )
-'
+check_dotx_symlink () {
+ fsck_must_fail=test_must_fail
+ fsck_prefix=error
+ refuse_index=t
+ case "$1" in
+ --warning)
+ fsck_must_fail=
+ fsck_prefix=warning
+ refuse_index=
+ shift
+ ;;
+ esac
+
+ name=$1
+ type=$2
+ path=$3
+ dir=symlink-$name-$type
+
+ test_expect_success "set up repo with symlinked $name ($type)" '
+ git init $dir &&
+ (
+ cd $dir &&
+
+ # Make the tree directly to avoid index restrictions.
+ #
+ # Because symlinks store the target as a blob, choose
+ # a pathname that could be parsed as a .gitmodules file
+ # to trick naive non-symlink-aware checking.
+ tricky="[foo]bar=true" &&
+ content=$(git hash-object -w ../.gitmodules) &&
+ target=$(printf "$tricky" | git hash-object -w --stdin) &&
+ {
+ printf "100644 blob $content\t$tricky\n" &&
+ printf "120000 blob $target\t$path\n"
+ } >bad-tree
+ ) &&
+ tree=$(git -C $dir mktree <$dir/bad-tree)
+ '
+
+ test_expect_success "fsck detects symlinked $name ($type)" '
+ (
+ cd $dir &&
+
+ # Check not only that we fail, but that it is due to the
+ # symlink detector
+ $fsck_must_fail git fsck 2>output &&
+ grep "$fsck_prefix.*tree $tree: ${name}Symlink" output
+ )
+ '
+
+ test -n "$refuse_index" &&
+ test_expect_success "refuse to load symlinked $name into index ($type)" '
+ test_must_fail \
+ git -C $dir \
+ -c core.protectntfs \
+ -c core.protecthfs \
+ read-tree $tree 2>err &&
+ grep "invalid path.*$name" err &&
+ git -C $dir ls-files -s >out &&
+ test_must_be_empty out
+ '
+}
+
+check_dotx_symlink gitmodules vanilla .gitmodules
+check_dotx_symlink gitmodules ntfs ".gitmodules ."
+check_dotx_symlink gitmodules hfs ".${u200c}gitmodules"
+
+check_dotx_symlink --warning gitattributes vanilla .gitattributes
+check_dotx_symlink --warning gitattributes ntfs ".gitattributes ."
+check_dotx_symlink --warning gitattributes hfs ".${u200c}gitattributes"
+
+check_dotx_symlink --warning gitignore vanilla .gitignore
+check_dotx_symlink --warning gitignore ntfs ".gitignore ."
+check_dotx_symlink --warning gitignore hfs ".${u200c}gitignore"
+
+check_dotx_symlink --warning mailmap vanilla .mailmap
+check_dotx_symlink --warning mailmap ntfs ".mailmap ."
+check_dotx_symlink --warning mailmap hfs ".${u200c}mailmap"
test_expect_success 'fsck detects non-blob .gitmodules' '
git init non-blob &&
@@ -191,7 +251,7 @@ test_expect_success 'fsck detects corrupt .gitmodules' '
)
'
-test_expect_success MINGW 'prevent git~1 squatting on Windows' '
+test_expect_success WINDOWS 'prevent git~1 squatting on Windows' '
git init squatting &&
(
cd squatting &&
@@ -219,10 +279,13 @@ test_expect_success MINGW 'prevent git~1 squatting on Windows' '
test_tick &&
git -c core.protectNTFS=false commit -m "module"
) &&
- test_must_fail git -c core.protectNTFS=false \
- clone --recurse-submodules squatting squatting-clone 2>err &&
- test_i18ngrep -e "directory not empty" -e "not an empty directory" err &&
- ! grep gitdir squatting-clone/d/a/git~2
+ if test_have_prereq MINGW
+ then
+ test_must_fail git -c core.protectNTFS=false \
+ clone --recurse-submodules squatting squatting-clone 2>err &&
+ test_i18ngrep -e "directory not empty" -e "not an empty directory" err &&
+ ! grep gitdir squatting-clone/d/a/git~2
+ fi
'
test_expect_success 'git dirs of sibling submodules must not be nested' '
diff --git a/t/t7500-commit-template-squash-signoff.sh b/t/t7500-commit-template-squash-signoff.sh
index 9092db5fdc..8dd0f98812 100755
--- a/t/t7500-commit-template-squash-signoff.sh
+++ b/t/t7500-commit-template-squash-signoff.sh
@@ -270,7 +270,7 @@ EOF
test_expect_success 'commit --fixup provides correct one-line commit message' '
commit_for_rebase_autosquash_setup &&
- git commit --fixup HEAD~1 &&
+ EDITOR="echo ignored >>" git commit --fixup HEAD~1 &&
commit_msg_is "fixup! target message subject line"
'
@@ -281,6 +281,13 @@ test_expect_success 'commit --fixup -m"something" -m"extra"' '
extra"
'
+test_expect_success 'commit --fixup --edit' '
+ commit_for_rebase_autosquash_setup &&
+ EDITOR="printf \"something\nextra\" >>" git commit --fixup HEAD~1 --edit &&
+ commit_msg_is "fixup! target message subject linesomething
+extra"
+'
+
get_commit_msg () {
rev="$1" &&
git log -1 --pretty=format:"%B" "$rev"
@@ -413,7 +420,7 @@ test_expect_success 'amend! commit allows empty commit msg body with --allow-emp
'
test_fixup_reword_opt () {
- test_expect_success C_LOCALE_OUTPUT "--fixup=reword: incompatible with $1" "
+ test_expect_success "--fixup=reword: incompatible with $1" "
echo 'fatal: reword option of --fixup is mutually exclusive with'\
'--patch/--interactive/--all/--include/--only' >expect &&
test_must_fail git commit --fixup=reword:HEAD~ $1 2>actual &&
@@ -498,7 +505,7 @@ test_expect_success 'invalid message options when using --fixup' '
cat >expected-template <<EOF
# Please enter the commit message for your changes. Lines starting
-# with '#' will be ignored, and an empty message aborts the commit.
+# with '#' will be ignored.
#
# Author: A U Thor <author@example.com>
#
diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh
index 7a8194ce72..2a07c70867 100755
--- a/t/t7505-prepare-commit-msg-hook.sh
+++ b/t/t7505-prepare-commit-msg-hook.sh
@@ -250,7 +250,6 @@ test_rebase () {
}
test_rebase success
-test_have_prereq !REBASE_P || test_rebase success -p
test_expect_success 'with hook (cherry-pick)' '
test_when_finished "git checkout -f main" &&
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index 2b72451ba3..05c6c02435 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -882,7 +882,7 @@ test_expect_success 'status shows detached HEAD properly after checking out non-
git clone upstream downstream &&
git -C downstream checkout @{u} &&
git -C downstream status >actual &&
- test_i18ngrep "HEAD detached at [0-9a-f]\\+" actual
+ grep -E "HEAD detached at [0-9a-f]+" actual
'
test_expect_success 'setup status submodule summary' '
diff --git a/t/t7509-commit-authorship.sh b/t/t7509-commit-authorship.sh
index ee6c47416e..d568593382 100755
--- a/t/t7509-commit-authorship.sh
+++ b/t/t7509-commit-authorship.sh
@@ -147,7 +147,7 @@ test_expect_success 'commit respects CHERRY_PICK_HEAD and MERGE_MSG' '
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 &&
+ git update-ref CHERRY_PICK_HEAD $(git rev-parse cherry-pick-head) &&
echo "This is a MERGE_MSG" >.git/MERGE_MSG &&
echo "cherry-pick 1b" >>foo &&
test_tick &&
@@ -162,7 +162,7 @@ test_expect_success 'commit respects CHERRY_PICK_HEAD and MERGE_MSG' '
'
test_expect_success '--reset-author with CHERRY_PICK_HEAD' '
- git rev-parse cherry-pick-head >.git/CHERRY_PICK_HEAD &&
+ git update-ref CHERRY_PICK_HEAD $(git rev-parse cherry-pick-head) &&
echo "cherry-pick 2" >>foo &&
test_tick &&
git commit -am "cherry-pick 2" --reset-author &&
diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh
index 6602790b5f..04885d0a5e 100755
--- a/t/t7513-interpret-trailers.sh
+++ b/t/t7513-interpret-trailers.sh
@@ -51,6 +51,69 @@ test_expect_success 'setup' '
EOF
'
+test_expect_success 'with cmd' '
+ test_when_finished "git config --remove-section trailer.bug" &&
+ git config trailer.bug.key "Bug-maker: " &&
+ git config trailer.bug.ifExists "add" &&
+ git config trailer.bug.cmd "echo \"maybe is\"" &&
+ cat >expected2 <<-EOF &&
+
+ Bug-maker: maybe is him
+ Bug-maker: maybe is me
+ EOF
+ git interpret-trailers --trailer "bug: him" --trailer "bug:me" \
+ >actual2 &&
+ test_cmp expected2 actual2
+'
+
+test_expect_success 'with cmd and $1' '
+ test_when_finished "git config --remove-section trailer.bug" &&
+ git config trailer.bug.key "Bug-maker: " &&
+ git config trailer.bug.ifExists "add" &&
+ git config trailer.bug.cmd "echo \"\$1\" is" &&
+ cat >expected2 <<-EOF &&
+
+ Bug-maker: him is him
+ Bug-maker: me is me
+ EOF
+ git interpret-trailers --trailer "bug: him" --trailer "bug:me" \
+ >actual2 &&
+ test_cmp expected2 actual2
+'
+
+test_expect_success 'with cmd and $1 with sh -c' '
+ test_when_finished "git config --remove-section trailer.bug" &&
+ git config trailer.bug.key "Bug-maker: " &&
+ git config trailer.bug.ifExists "replace" &&
+ git config trailer.bug.cmd "sh -c \"echo who is \"\$1\"\"" &&
+ cat >expected2 <<-EOF &&
+
+ Bug-maker: who is me
+ EOF
+ git interpret-trailers --trailer "bug: him" --trailer "bug:me" \
+ >actual2 &&
+ test_cmp expected2 actual2
+'
+
+test_expect_success 'with cmd and $1 with shell script' '
+ test_when_finished "git config --remove-section trailer.bug" &&
+ git config trailer.bug.key "Bug-maker: " &&
+ git config trailer.bug.ifExists "replace" &&
+ git config trailer.bug.cmd "./echoscript" &&
+ cat >expected2 <<-EOF &&
+
+ Bug-maker: who is me
+ EOF
+ cat >echoscript <<-EOF &&
+ #!/bin/sh
+ echo who is "\$1"
+ EOF
+ chmod +x echoscript &&
+ git interpret-trailers --trailer "bug: him" --trailer "bug:me" \
+ >actual2 &&
+ test_cmp expected2 actual2
+'
+
test_expect_success 'without config' '
sed -e "s/ Z\$/ /" >expected <<-\EOF &&
@@ -1274,6 +1337,27 @@ test_expect_success 'setup a commit' '
git commit -m "Add file a.txt"
'
+test_expect_success 'cmd takes precedence over command' '
+ test_when_finished "git config --unset trailer.fix.cmd" &&
+ git config trailer.fix.ifExists "replace" &&
+ git config trailer.fix.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%aN)\" \
+ --abbrev-commit --abbrev=14 \"\$1\" || true" &&
+ git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" \
+ --abbrev-commit --abbrev=14 \$ARG" &&
+ FIXED=$(git log -1 --oneline --format="%h (%aN)" --abbrev-commit --abbrev=14 HEAD) &&
+ cat complex_message_body >expected2 &&
+ sed -e "s/ Z\$/ /" >>expected2 <<-EOF &&
+ Fixes: $FIXED
+ Acked-by= Z
+ Reviewed-by:
+ Signed-off-by: Z
+ Signed-off-by: A U Thor <author@example.com>
+ EOF
+ git interpret-trailers --trailer "review:" --trailer "fix=HEAD" \
+ <complex_message >actual2 &&
+ test_cmp expected2 actual2
+'
+
test_expect_success 'with command using $ARG' '
git config trailer.fix.ifExists "replace" &&
git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" &&
diff --git a/t/t7517-per-repo-email.sh b/t/t7517-per-repo-email.sh
index 405420ae4d..163ae80468 100755
--- a/t/t7517-per-repo-email.sh
+++ b/t/t7517-per-repo-email.sh
@@ -75,19 +75,6 @@ test_expect_success 'noop interactive rebase does not care about ident' '
git rebase -i HEAD^
'
-test_expect_success REBASE_P \
- 'fast-forward rebase does not care about ident (preserve)' '
- git checkout -B tmp side-without-commit &&
- git rebase -p main
-'
-
-test_expect_success REBASE_P \
- 'non-fast-forward rebase refuses to write commits (preserve)' '
- test_when_finished "git rebase --abort || true" &&
- git checkout -B tmp side-with-commit &&
- test_must_fail git rebase -p main
-'
-
test_expect_success 'author.name overrides user.name' '
test_config user.name user &&
test_config user.email user@example.com &&
diff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh
index 45d025f960..f488d930df 100755
--- a/t/t7519-status-fsmonitor.sh
+++ b/t/t7519-status-fsmonitor.sh
@@ -73,6 +73,7 @@ test_expect_success 'setup' '
expect*
actual*
marker*
+ trace2*
EOF
'
@@ -334,7 +335,7 @@ test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR'
git config core.fsmonitor .git/hooks/fsmonitor-test &&
git update-index --untracked-cache &&
git update-index --fsmonitor &&
- GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace-before" \
+ GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace-before" \
git status &&
test-tool dump-untracked-cache >../before
) &&
@@ -346,12 +347,12 @@ test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR'
EOF
(
cd dot-git &&
- GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace-after" \
+ GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace-after" \
git status &&
test-tool dump-untracked-cache >../after
) &&
- grep "directory invalidation" trace-before >>before &&
- grep "directory invalidation" trace-after >>after &&
+ grep "directory-invalidation" trace-before | cut -d"|" -f 9 >>before &&
+ grep "directory-invalidation" trace-after | cut -d"|" -f 9 >>after &&
# UNTR extension unchanged, dir invalidation count unchanged
test_cmp before after
'
@@ -383,4 +384,60 @@ test_expect_success 'status succeeds after staging/unstaging' '
)
'
+# Usage:
+# check_sparse_index_behavior [!]
+# If "!" is supplied, then we verify that we do not call ensure_full_index
+# during a call to 'git status'. Otherwise, we verify that we _do_ call it.
+check_sparse_index_behavior () {
+ git -C full status --porcelain=v2 >expect &&
+ GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
+ git -C sparse status --porcelain=v2 >actual &&
+ test_region $1 index ensure_full_index trace2.txt &&
+ test_region fsm_hook query trace2.txt &&
+ test_cmp expect actual &&
+ rm trace2.txt
+}
+
+test_expect_success 'status succeeds with sparse index' '
+ (
+ sane_unset GIT_TEST_SPLIT_INDEX &&
+
+ git clone . full &&
+ git clone --sparse . sparse &&
+ git -C sparse sparse-checkout init --cone --sparse-index &&
+ git -C sparse sparse-checkout set dir1 dir2 &&
+
+ write_script .git/hooks/fsmonitor-test <<-\EOF &&
+ printf "last_update_token\0"
+ EOF
+ git -C full config core.fsmonitor ../.git/hooks/fsmonitor-test &&
+ git -C sparse config core.fsmonitor ../.git/hooks/fsmonitor-test &&
+ check_sparse_index_behavior ! &&
+
+ write_script .git/hooks/fsmonitor-test <<-\EOF &&
+ printf "last_update_token\0"
+ printf "dir1/modified\0"
+ EOF
+ check_sparse_index_behavior ! &&
+
+ git -C sparse sparse-checkout add dir1a &&
+
+ for repo in full sparse
+ do
+ cp -r $repo/dir1 $repo/dir1a &&
+ git -C $repo add dir1a &&
+ git -C $repo commit -m "add dir1a" || return 1
+ done &&
+ git -C sparse sparse-checkout set dir1 dir2 &&
+
+ # This one modifies outside the sparse-checkout definition
+ # and hence we expect to expand the sparse-index.
+ write_script .git/hooks/fsmonitor-test <<-\EOF &&
+ printf "last_update_token\0"
+ printf "dir1a/modified\0"
+ EOF
+ check_sparse_index_behavior
+ )
+'
+
test_done
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 1cbc9715a8..c773e30b3f 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -122,6 +122,8 @@ test_expect_success 'setup' '
c0=$(git rev-parse HEAD) &&
cp file.1 file &&
git add file &&
+ cp file.1 other &&
+ git add other &&
test_tick &&
git commit -m "commit 1" &&
git tag c1 &&
@@ -711,6 +713,16 @@ test_expect_success 'fast-forward merge with --autostash' '
test_cmp result.1-5 file
'
+test_expect_success 'failed fast-forward merge with --autostash' '
+ git reset --hard c0 &&
+ git merge-file file file.orig file.5 &&
+ cp file.5 other &&
+ test_when_finished "rm other" &&
+ test_must_fail git merge --autostash c1 2>err &&
+ test_i18ngrep "Applied autostash." err &&
+ test_cmp file.5 file
+'
+
test_expect_success 'octopus merge with --autostash' '
git reset --hard c1 &&
git merge-file file file.orig file.3 &&
@@ -721,6 +733,14 @@ test_expect_success 'octopus merge with --autostash' '
test_cmp result.1-3-5-9 file
'
+test_expect_success 'failed merge (exit 2) with --autostash' '
+ git reset --hard c1 &&
+ git merge-file file file.orig file.5 &&
+ test_must_fail git merge -s recursive --autostash c2 c3 2>err &&
+ test_i18ngrep "Applied autostash." err &&
+ test_cmp result.1-5 file
+'
+
test_expect_success 'conflicted merge with --autostash, --abort restores stash' '
git reset --hard c3 &&
cp file.1 file &&
diff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh
index 52e8ccc933..1f652f433e 100755
--- a/t/t7601-merge-pull-config.sh
+++ b/t/t7601-merge-pull-config.sh
@@ -27,120 +27,324 @@ test_expect_success 'setup' '
git tag c3
'
-test_expect_success 'pull.rebase not set' '
+test_expect_success 'pull.rebase not set, ff possible' '
git reset --hard c0 &&
git pull . c1 2>err &&
- test_i18ngrep ! "Pulling without specifying how to reconcile" err
+ test_i18ngrep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and pull.ff=true' '
git reset --hard c0 &&
test_config pull.ff true &&
git pull . c1 2>err &&
- test_i18ngrep ! "Pulling without specifying how to reconcile" err
+ test_i18ngrep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and pull.ff=false' '
git reset --hard c0 &&
test_config pull.ff false &&
git pull . c1 2>err &&
- test_i18ngrep ! "Pulling without specifying how to reconcile" err
+ test_i18ngrep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and pull.ff=only' '
git reset --hard c0 &&
test_config pull.ff only &&
git pull . c1 2>err &&
- test_i18ngrep ! "Pulling without specifying how to reconcile" err
+ test_i18ngrep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --rebase given' '
git reset --hard c0 &&
git pull --rebase . c1 2>err &&
- test_i18ngrep ! "Pulling without specifying how to reconcile" err
+ test_i18ngrep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --no-rebase given' '
git reset --hard c0 &&
git pull --no-rebase . c1 2>err &&
- test_i18ngrep ! "Pulling without specifying how to reconcile" err
+ test_i18ngrep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --ff given' '
git reset --hard c0 &&
git pull --ff . c1 2>err &&
- test_i18ngrep ! "Pulling without specifying how to reconcile" err
+ test_i18ngrep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --no-ff given' '
git reset --hard c0 &&
git pull --no-ff . c1 2>err &&
- test_i18ngrep ! "Pulling without specifying how to reconcile" err
+ test_i18ngrep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --ff-only given' '
git reset --hard c0 &&
git pull --ff-only . c1 2>err &&
- test_i18ngrep ! "Pulling without specifying how to reconcile" err
+ test_i18ngrep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set (not-fast-forward)' '
git reset --hard c2 &&
- git -c color.advice=always pull . c1 2>err &&
+ test_must_fail git -c color.advice=always pull . c1 2>err &&
test_decode_color <err >decoded &&
test_i18ngrep "<YELLOW>hint: " decoded &&
- test_i18ngrep "Pulling without specifying how to reconcile" decoded
+ test_i18ngrep "You have divergent branches" decoded
'
test_expect_success 'pull.rebase not set and pull.ff=true (not-fast-forward)' '
git reset --hard c2 &&
test_config pull.ff true &&
git pull . c1 2>err &&
- test_i18ngrep ! "Pulling without specifying how to reconcile" err
+ test_i18ngrep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and pull.ff=false (not-fast-forward)' '
git reset --hard c2 &&
test_config pull.ff false &&
git pull . c1 2>err &&
- test_i18ngrep ! "Pulling without specifying how to reconcile" err
+ test_i18ngrep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and pull.ff=only (not-fast-forward)' '
git reset --hard c2 &&
test_config pull.ff only &&
test_must_fail git pull . c1 2>err &&
- test_i18ngrep ! "Pulling without specifying how to reconcile" err
+ test_i18ngrep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --rebase given (not-fast-forward)' '
git reset --hard c2 &&
git pull --rebase . c1 2>err &&
- test_i18ngrep ! "Pulling without specifying how to reconcile" err
+ test_i18ngrep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --no-rebase given (not-fast-forward)' '
git reset --hard c2 &&
git pull --no-rebase . c1 2>err &&
- test_i18ngrep ! "Pulling without specifying how to reconcile" err
+ test_i18ngrep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --ff given (not-fast-forward)' '
git reset --hard c2 &&
git pull --ff . c1 2>err &&
- test_i18ngrep ! "Pulling without specifying how to reconcile" err
+ test_i18ngrep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --no-ff given (not-fast-forward)' '
git reset --hard c2 &&
git pull --no-ff . c1 2>err &&
- test_i18ngrep ! "Pulling without specifying how to reconcile" err
+ test_i18ngrep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --ff-only given (not-fast-forward)' '
git reset --hard c2 &&
test_must_fail git pull --ff-only . c1 2>err &&
- test_i18ngrep ! "Pulling without specifying how to reconcile" err
+ test_i18ngrep ! "You have divergent branches" err
+'
+
+test_does_rebase () {
+ git reset --hard c2 &&
+ git "$@" . c1 &&
+ # Check that we actually did a rebase
+ git rev-list --count HEAD >actual &&
+ git rev-list --merges --count HEAD >>actual &&
+ test_write_lines 3 0 >expect &&
+ test_cmp expect actual &&
+ rm actual expect
+}
+
+# Prefers merge over fast-forward
+test_does_merge_when_ff_possible () {
+ git reset --hard c0 &&
+ git "$@" . c1 &&
+ # Check that we actually did a merge
+ git rev-list --count HEAD >actual &&
+ git rev-list --merges --count HEAD >>actual &&
+ test_write_lines 3 1 >expect &&
+ test_cmp expect actual &&
+ rm actual expect
+}
+
+# Prefers fast-forward over merge or rebase
+test_does_fast_forward () {
+ git reset --hard c0 &&
+ git "$@" . c1 &&
+
+ # Check that we did not get any merges
+ git rev-list --count HEAD >actual &&
+ git rev-list --merges --count HEAD >>actual &&
+ test_write_lines 2 0 >expect &&
+ test_cmp expect actual &&
+
+ # Check that we ended up at c1
+ git rev-parse HEAD >actual &&
+ git rev-parse c1^{commit} >expect &&
+ test_cmp actual expect &&
+
+ # Remove temporary files
+ rm actual expect
+}
+
+# Doesn't fail when fast-forward not possible; does a merge
+test_falls_back_to_full_merge () {
+ git reset --hard c2 &&
+ git "$@" . c1 &&
+ # Check that we actually did a merge
+ git rev-list --count HEAD >actual &&
+ git rev-list --merges --count HEAD >>actual &&
+ test_write_lines 4 1 >expect &&
+ test_cmp expect actual &&
+ rm actual expect
+}
+
+# Attempts fast forward, which is impossible, and bails
+test_attempts_fast_forward () {
+ git reset --hard c2 &&
+ test_must_fail git "$@" . c1 2>err &&
+ test_i18ngrep "Not possible to fast-forward, aborting" err
+}
+
+#
+# Group 1: Interaction of --ff-only with --[no-]rebase
+# (And related interaction of pull.ff=only with pull.rebase)
+#
+test_expect_success '--ff-only overrides --rebase' '
+ test_attempts_fast_forward pull --rebase --ff-only
+'
+
+test_expect_success '--ff-only overrides --rebase even if first' '
+ test_attempts_fast_forward pull --ff-only --rebase
+'
+
+test_expect_success '--ff-only overrides --no-rebase' '
+ test_attempts_fast_forward pull --ff-only --no-rebase
+'
+
+test_expect_success 'pull.ff=only overrides pull.rebase=true' '
+ test_attempts_fast_forward -c pull.ff=only -c pull.rebase=true pull
+'
+
+test_expect_success 'pull.ff=only overrides pull.rebase=false' '
+ test_attempts_fast_forward -c pull.ff=only -c pull.rebase=false pull
+'
+
+# Group 2: --rebase=[!false] overrides --no-ff and --ff
+# (And related interaction of pull.rebase=!false and pull.ff=!only)
+test_expect_success '--rebase overrides --no-ff' '
+ test_does_rebase pull --rebase --no-ff
+'
+
+test_expect_success '--rebase overrides --ff' '
+ test_does_rebase pull --rebase --ff
+'
+
+test_expect_success '--rebase fast-forwards when possible' '
+ test_does_fast_forward pull --rebase --ff
+'
+
+test_expect_success 'pull.rebase=true overrides pull.ff=false' '
+ test_does_rebase -c pull.rebase=true -c pull.ff=false pull
+'
+
+test_expect_success 'pull.rebase=true overrides pull.ff=true' '
+ test_does_rebase -c pull.rebase=true -c pull.ff=true pull
+'
+
+# Group 3: command line flags take precedence over config
+test_expect_success '--ff-only takes precedence over pull.rebase=true' '
+ test_attempts_fast_forward -c pull.rebase=true pull --ff-only
+'
+
+test_expect_success '--ff-only takes precedence over pull.rebase=false' '
+ test_attempts_fast_forward -c pull.rebase=false pull --ff-only
+'
+
+test_expect_success '--no-rebase takes precedence over pull.ff=only' '
+ test_falls_back_to_full_merge -c pull.ff=only pull --no-rebase
+'
+
+test_expect_success '--rebase takes precedence over pull.ff=only' '
+ test_does_rebase -c pull.ff=only pull --rebase
+'
+
+test_expect_success '--rebase overrides pull.ff=true' '
+ test_does_rebase -c pull.ff=true pull --rebase
+'
+
+test_expect_success '--rebase overrides pull.ff=false' '
+ test_does_rebase -c pull.ff=false pull --rebase
+'
+
+test_expect_success '--rebase overrides pull.ff unset' '
+ test_does_rebase pull --rebase
+'
+
+# Group 4: --no-rebase heeds pull.ff=!only or explict --ff or --no-ff
+
+test_expect_success '--no-rebase works with --no-ff' '
+ test_does_merge_when_ff_possible pull --no-rebase --no-ff
+'
+
+test_expect_success '--no-rebase works with --ff' '
+ test_does_fast_forward pull --no-rebase --ff
+'
+
+test_expect_success '--no-rebase does ff if pull.ff unset' '
+ test_does_fast_forward pull --no-rebase
+'
+
+test_expect_success '--no-rebase heeds pull.ff=true' '
+ test_does_fast_forward -c pull.ff=true pull --no-rebase
+'
+
+test_expect_success '--no-rebase heeds pull.ff=false' '
+ test_does_merge_when_ff_possible -c pull.ff=false pull --no-rebase
+'
+
+# Group 5: pull.rebase=!false in combination with --no-ff or --ff
+test_expect_success 'pull.rebase=true and --no-ff' '
+ test_does_rebase -c pull.rebase=true pull --no-ff
+'
+
+test_expect_success 'pull.rebase=true and --ff' '
+ test_does_rebase -c pull.rebase=true pull --ff
+'
+
+test_expect_success 'pull.rebase=false and --no-ff' '
+ test_does_merge_when_ff_possible -c pull.rebase=false pull --no-ff
+'
+
+test_expect_success 'pull.rebase=false and --ff, ff possible' '
+ test_does_fast_forward -c pull.rebase=false pull --ff
+'
+
+test_expect_success 'pull.rebase=false and --ff, ff not possible' '
+ test_falls_back_to_full_merge -c pull.rebase=false pull --ff
+'
+
+# End of groupings for conflicting merge vs. rebase flags/options
+
+test_expect_success 'Multiple heads warns about inability to fast forward' '
+ git reset --hard c1 &&
+ test_must_fail git pull . c2 c3 2>err &&
+ test_i18ngrep "You have divergent branches" err
+'
+
+test_expect_success 'Multiple can never be fast forwarded' '
+ git reset --hard c0 &&
+ test_must_fail git -c pull.ff=only pull . c1 c2 c3 2>err &&
+ test_i18ngrep ! "You have divergent branches" err &&
+ # In addition to calling out "cannot fast-forward", we very much
+ # want the "multiple branches" piece to be called out to users.
+ test_i18ngrep "Cannot fast-forward to multiple branches" err
+'
+
+test_expect_success 'Cannot rebase with multiple heads' '
+ git reset --hard c0 &&
+ test_must_fail git -c pull.rebase=true pull . c1 c2 c3 2>err &&
+ test_i18ngrep ! "You have divergent branches" err &&
+ test_i18ngrep "Cannot rebase onto multiple branches." err
'
test_expect_success 'merge c1 with c2' '
diff --git a/t/t7603-merge-reduce-heads.sh b/t/t7603-merge-reduce-heads.sh
index 98948955ae..27cd94ad6f 100755
--- a/t/t7603-merge-reduce-heads.sh
+++ b/t/t7603-merge-reduce-heads.sh
@@ -68,7 +68,7 @@ test_expect_success 'merge c1 with c2, c3, c4, c5' '
test_expect_success 'pull c2, c3, c4, c5 into c1' '
git reset --hard c1 &&
- git pull . c2 c3 c4 c5 &&
+ git pull --no-rebase . c2 c3 c4 c5 &&
test "$(git rev-parse c1)" != "$(git rev-parse HEAD)" &&
test "$(git rev-parse c1)" = "$(git rev-parse HEAD^1)" &&
test "$(git rev-parse c2)" = "$(git rev-parse HEAD^2)" &&
diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh
index 25b235c063..0260ad6f0e 100755
--- a/t/t7700-repack.sh
+++ b/t/t7700-repack.sh
@@ -3,6 +3,8 @@
test_description='git repack works correctly'
. ./test-lib.sh
+. "${TEST_DIRECTORY}/lib-bitmap.sh"
+. "${TEST_DIRECTORY}/lib-midx.sh"
commit_and_pack () {
test_commit "$@" 1>&2 &&
@@ -63,13 +65,14 @@ test_expect_success 'objects in packs marked .keep are not repacked' '
test_expect_success 'writing bitmaps via command-line can duplicate .keep objects' '
# build on $oid, $packid, and .keep state from previous
- git repack -Adbl &&
+ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 git repack -Adbl &&
test_has_duplicate_object true
'
test_expect_success 'writing bitmaps via config can duplicate .keep objects' '
# build on $oid, $packid, and .keep state from previous
- git -c repack.writebitmaps=true repack -Adl &&
+ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
+ git -c repack.writebitmaps=true repack -Adl &&
test_has_duplicate_object true
'
@@ -189,7 +192,9 @@ test_expect_success 'repack --keep-pack' '
test_expect_success 'bitmaps are created by default in bare repos' '
git clone --bare .git bare.git &&
- git -C bare.git repack -ad &&
+ rm -f bare.git/objects/pack/*.bitmap &&
+ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
+ git -C bare.git repack -ad &&
bitmap=$(ls bare.git/objects/pack/*.bitmap) &&
test_path_is_file "$bitmap"
'
@@ -200,7 +205,8 @@ test_expect_success 'incremental repack does not complain' '
'
test_expect_success 'bitmaps can be disabled on bare repos' '
- git -c repack.writeBitmaps=false -C bare.git repack -ad &&
+ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
+ git -c repack.writeBitmaps=false -C bare.git repack -ad &&
bitmap=$(ls bare.git/objects/pack/*.bitmap || :) &&
test -z "$bitmap"
'
@@ -211,7 +217,8 @@ test_expect_success 'no bitmaps created if .keep files present' '
keep=${pack%.pack}.keep &&
test_when_finished "rm -f \"\$keep\"" &&
>"$keep" &&
- git -C bare.git repack -ad 2>stderr &&
+ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
+ git -C bare.git repack -ad 2>stderr &&
test_must_be_empty stderr &&
find bare.git/objects/pack/ -type f -name "*.bitmap" >actual &&
test_must_be_empty actual
@@ -222,10 +229,147 @@ test_expect_success 'auto-bitmaps do not complain if unavailable' '
blob=$(test-tool genrandom big $((1024*1024)) |
git -C bare.git hash-object -w --stdin) &&
git -C bare.git update-ref refs/tags/big $blob &&
- git -C bare.git repack -ad 2>stderr &&
+ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
+ git -C bare.git repack -ad 2>stderr &&
test_must_be_empty stderr &&
find bare.git/objects/pack -type f -name "*.bitmap" >actual &&
test_must_be_empty actual
'
+objdir=.git/objects
+midx=$objdir/pack/multi-pack-index
+
+test_expect_success 'setup for --write-midx tests' '
+ git init midx &&
+ (
+ cd midx &&
+ git config core.multiPackIndex true &&
+
+ test_commit base
+ )
+'
+
+test_expect_success '--write-midx unchanged' '
+ (
+ cd midx &&
+ GIT_TEST_MULTI_PACK_INDEX=0 git repack &&
+ test_path_is_missing $midx &&
+ test_path_is_missing $midx-*.bitmap &&
+
+ GIT_TEST_MULTI_PACK_INDEX=0 git repack --write-midx &&
+
+ test_path_is_file $midx &&
+ test_path_is_missing $midx-*.bitmap &&
+ test_midx_consistent $objdir
+ )
+'
+
+test_expect_success '--write-midx with a new pack' '
+ (
+ cd midx &&
+ test_commit loose &&
+
+ GIT_TEST_MULTI_PACK_INDEX=0 git repack --write-midx &&
+
+ test_path_is_file $midx &&
+ test_path_is_missing $midx-*.bitmap &&
+ test_midx_consistent $objdir
+ )
+'
+
+test_expect_success '--write-midx with -b' '
+ (
+ cd midx &&
+ GIT_TEST_MULTI_PACK_INDEX=0 git repack -mb &&
+
+ test_path_is_file $midx &&
+ test_path_is_file $midx-*.bitmap &&
+ test_midx_consistent $objdir
+ )
+'
+
+test_expect_success '--write-midx with -d' '
+ (
+ cd midx &&
+ test_commit repack &&
+
+ GIT_TEST_MULTI_PACK_INDEX=0 git repack -Ad --write-midx &&
+
+ test_path_is_file $midx &&
+ test_path_is_missing $midx-*.bitmap &&
+ test_midx_consistent $objdir
+ )
+'
+
+test_expect_success 'cleans up MIDX when appropriate' '
+ (
+ cd midx &&
+
+ test_commit repack-2 &&
+ GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adb --write-midx &&
+
+ checksum=$(midx_checksum $objdir) &&
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$checksum.bitmap &&
+ test_path_is_file $midx-$checksum.rev &&
+
+ test_commit repack-3 &&
+ GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adb --write-midx &&
+
+ test_path_is_file $midx &&
+ test_path_is_missing $midx-$checksum.bitmap &&
+ test_path_is_missing $midx-$checksum.rev &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+ test_path_is_file $midx-$(midx_checksum $objdir).rev &&
+
+ test_commit repack-4 &&
+ GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adb &&
+
+ find $objdir/pack -type f -name "multi-pack-index*" >files &&
+ test_must_be_empty files
+ )
+'
+
+test_expect_success '--write-midx with preferred bitmap tips' '
+ git init midx-preferred-tips &&
+ test_when_finished "rm -fr midx-preferred-tips" &&
+ (
+ cd midx-preferred-tips &&
+
+ test_commit_bulk --message="%s" 103 &&
+
+ git log --format="%H" >commits.raw &&
+ sort <commits.raw >commits &&
+
+ git log --format="create refs/tags/%s/%s %H" HEAD >refs &&
+ git update-ref --stdin <refs &&
+
+ git repack --write-midx --write-bitmap-index &&
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+
+ test-tool bitmap list-commits | sort >bitmaps &&
+ comm -13 bitmaps commits >before &&
+ test_line_count = 1 before &&
+
+ rm -fr $midx-$(midx_checksum $objdir).bitmap &&
+ rm -fr $midx-$(midx_checksum $objdir).rev &&
+ rm -fr $midx &&
+
+ # instead of constructing the snapshot ourselves (c.f., the test
+ # "write a bitmap with --refs-snapshot (preferred tips)" in
+ # t5326), mark the missing commit as preferred by adding it to
+ # the pack.preferBitmapTips configuration.
+ git for-each-ref --format="%(refname:rstrip=1)" \
+ --points-at="$(cat before)" >missing &&
+ git config pack.preferBitmapTips "$(cat missing)" &&
+ git repack --write-midx --write-bitmap-index &&
+
+ test-tool bitmap list-commits | sort >bitmaps &&
+ comm -13 bitmaps commits >after &&
+
+ ! test_cmp before after
+ )
+'
+
test_done
diff --git a/t/t7703-repack-geometric.sh b/t/t7703-repack-geometric.sh
index 5ccaa440e0..bdbbcbf1ec 100755
--- a/t/t7703-repack-geometric.sh
+++ b/t/t7703-repack-geometric.sh
@@ -15,7 +15,7 @@ test_expect_success '--geometric with no packs' '
(
cd geometric &&
- git repack --geometric 2 >out &&
+ git repack --write-midx --geometric 2 >out &&
test_i18ngrep "Nothing new to pack" out
)
'
@@ -180,4 +180,26 @@ test_expect_success '--geometric ignores kept packs' '
)
'
+test_expect_success '--geometric chooses largest MIDX preferred pack' '
+ git init geometric &&
+ test_when_finished "rm -fr geometric" &&
+ (
+ cd geometric &&
+
+ # These packs already form a geometric progression.
+ test_commit_bulk --start=1 1 && # 3 objects
+ test_commit_bulk --start=2 2 && # 6 objects
+ ls $objdir/pack/pack-*.idx >before &&
+ test_commit_bulk --start=4 4 && # 12 objects
+ ls $objdir/pack/pack-*.idx >after &&
+
+ git repack --geometric 2 -dbm &&
+
+ comm -3 before after | xargs -n 1 basename >expect &&
+ test-tool read-midx --preferred-pack $objdir >actual &&
+
+ test_cmp expect actual
+ )
+'
+
test_done
diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
index 3e041e83ae..096456292c 100755
--- a/t/t7800-difftool.sh
+++ b/t/t7800-difftool.sh
@@ -453,6 +453,13 @@ run_dir_diff_test 'difftool --dir-diff' '
grep "^file$" output
'
+run_dir_diff_test 'difftool --dir-diff avoids repeated slashes in TMPDIR' '
+ TMPDIR="${TMPDIR:-/tmp}////" \
+ git difftool --dir-diff $symlinks --extcmd echo branch >output &&
+ grep -v // output >actual &&
+ test_line_count = 1 actual
+'
+
run_dir_diff_test 'difftool --dir-diff ignores --prompt' '
git difftool --dir-diff $symlinks --prompt --extcmd ls branch >output &&
grep "^sub$" output &&
@@ -674,7 +681,6 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' '
rm c &&
ln -s d c &&
cat >expect <<-EOF &&
- b
c
c
@@ -710,7 +716,6 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' '
# Deleted symlinks
rm -f c &&
cat >expect <<-EOF &&
- b
c
EOF
@@ -723,6 +728,71 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' '
test_cmp expect actual
'
+test_expect_success SYMLINKS 'difftool --dir-diff writes symlinks as raw text' '
+ # Start out on a branch called "branch-init".
+ git init -b branch-init symlink-files &&
+ (
+ cd symlink-files &&
+ # This test ensures that symlinks are written as raw text.
+ # The "cat" tools output link and file contents.
+ git config difftool.cat-left-link.cmd "cat \"\$LOCAL/link\"" &&
+ git config difftool.cat-left-a.cmd "cat \"\$LOCAL/file-a\"" &&
+ git config difftool.cat-right-link.cmd "cat \"\$REMOTE/link\"" &&
+ git config difftool.cat-right-b.cmd "cat \"\$REMOTE/file-b\"" &&
+
+ # Record the empty initial state so that we can come back here
+ # later and not have to consider the any cases where difftool
+ # will create symlinks back into the worktree.
+ test_tick &&
+ git commit --allow-empty -m init &&
+
+ # Create a file called "file-a" with a symlink pointing to it.
+ git switch -c branch-a &&
+ echo a >file-a &&
+ ln -s file-a link &&
+ git add file-a link &&
+ test_tick &&
+ git commit -m link-to-file-a &&
+
+ # Create a file called "file-b" and point the symlink to it.
+ git switch -c branch-b &&
+ echo b >file-b &&
+ rm link &&
+ ln -s file-b link &&
+ git add file-b link &&
+ git rm file-a &&
+ test_tick &&
+ git commit -m link-to-file-b &&
+
+ # Checkout the initial branch so that the --symlinks behavior is
+ # not activated. The two directories should be completely
+ # independent with no symlinks pointing back here.
+ git switch branch-init &&
+
+ # The left link must be "file-a" and "file-a" must contain "a".
+ echo file-a >expect &&
+ git difftool --symlinks --dir-diff --tool cat-left-link \
+ branch-a branch-b >actual &&
+ test_cmp expect actual &&
+
+ echo a >expect &&
+ git difftool --symlinks --dir-diff --tool cat-left-a \
+ branch-a branch-b >actual &&
+ test_cmp expect actual &&
+
+ # The right link must be "file-b" and "file-b" must contain "b".
+ echo file-b >expect &&
+ git difftool --symlinks --dir-diff --tool cat-right-link \
+ branch-a branch-b >actual &&
+ test_cmp expect actual &&
+
+ echo b >expect &&
+ git difftool --symlinks --dir-diff --tool cat-right-b \
+ branch-a branch-b >actual &&
+ test_cmp expect actual
+ )
+'
+
test_expect_success 'add -N and difftool -d' '
test_when_finished git reset --hard &&
@@ -770,7 +840,7 @@ test_expect_success 'difftool --rotate-to' '
echo 4 >4 &&
git add 1 2 4 &&
git commit -a -m "124" &&
- git difftool --no-prompt --extcmd=cat --rotate-to="2" HEAD^ >output&&
+ git difftool --no-prompt --extcmd=cat --rotate-to="2" HEAD^ >output &&
cat >expect <<-\EOF &&
2
4
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index 5830733f3d..6b6423a07c 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -11,6 +11,13 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
+test_invalid_grep_expression() {
+ params="$@" &&
+ test_expect_success "invalid expression: grep $params" '
+ test_must_fail git grep $params -- nonexisting
+ '
+}
+
cat >hello.c <<EOF
#include <assert.h>
#include <stdio.h>
@@ -89,6 +96,8 @@ test_expect_success 'grep should not segfault with a bad input' '
test_must_fail git grep "("
'
+test_invalid_grep_expression --and -e A
+
for H in HEAD ''
do
case "$H" in
diff --git a/t/t7814-grep-recurse-submodules.sh b/t/t7814-grep-recurse-submodules.sh
index 828cb3ba58..058e5d0c96 100755
--- a/t/t7814-grep-recurse-submodules.sh
+++ b/t/t7814-grep-recurse-submodules.sh
@@ -8,6 +8,9 @@ submodules.
. ./test-lib.sh
+GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1
+export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB
+
test_expect_success 'setup directory structure and submodule' '
echo "(1|2)d(3|4)" >a &&
mkdir b &&
@@ -438,4 +441,107 @@ test_expect_success 'grep --recurse-submodules with --cached ignores worktree mo
test_must_fail git grep --recurse-submodules --cached "A modified line in submodule" >actual 2>&1 &&
test_must_be_empty actual
'
+
+test_expect_failure 'grep --textconv: superproject .gitattributes does not affect submodules' '
+ reset_and_clean &&
+ test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
+ echo "a diff=d2x" >.gitattributes &&
+
+ cat >expect <<-\EOF &&
+ a:(1|2)x(3|4)
+ EOF
+ git grep --textconv --recurse-submodules x >actual &&
+ test_cmp expect actual
+'
+
+test_expect_failure 'grep --textconv: superproject .gitattributes (from index) does not affect submodules' '
+ reset_and_clean &&
+ test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
+ echo "a diff=d2x" >.gitattributes &&
+ git add .gitattributes &&
+ rm .gitattributes &&
+
+ cat >expect <<-\EOF &&
+ a:(1|2)x(3|4)
+ EOF
+ git grep --textconv --recurse-submodules x >actual &&
+ test_cmp expect actual
+'
+
+test_expect_failure 'grep --textconv: superproject .git/info/attributes does not affect submodules' '
+ reset_and_clean &&
+ test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
+ super_attr="$(git rev-parse --git-path info/attributes)" &&
+ test_when_finished "rm -f \"$super_attr\"" &&
+ echo "a diff=d2x" >"$super_attr" &&
+
+ cat >expect <<-\EOF &&
+ a:(1|2)x(3|4)
+ EOF
+ git grep --textconv --recurse-submodules x >actual &&
+ test_cmp expect actual
+'
+
+# Note: what currently prevents this test from passing is not that the
+# .gitattributes file from "./submodule" is being ignored, but that it is being
+# propagated to the nested "./submodule/sub" files.
+#
+test_expect_failure 'grep --textconv correctly reads submodule .gitattributes' '
+ reset_and_clean &&
+ test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
+ echo "a diff=d2x" >submodule/.gitattributes &&
+
+ cat >expect <<-\EOF &&
+ submodule/a:(1|2)x(3|4)
+ EOF
+ git grep --textconv --recurse-submodules x >actual &&
+ test_cmp expect actual
+'
+
+test_expect_failure 'grep --textconv correctly reads submodule .gitattributes (from index)' '
+ reset_and_clean &&
+ test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
+ echo "a diff=d2x" >submodule/.gitattributes &&
+ git -C submodule add .gitattributes &&
+ rm submodule/.gitattributes &&
+
+ cat >expect <<-\EOF &&
+ submodule/a:(1|2)x(3|4)
+ EOF
+ git grep --textconv --recurse-submodules x >actual &&
+ test_cmp expect actual
+'
+
+test_expect_failure 'grep --textconv correctly reads submodule .git/info/attributes' '
+ reset_and_clean &&
+ test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
+
+ submodule_attr="$(git -C submodule rev-parse --path-format=absolute --git-path info/attributes)" &&
+ test_when_finished "rm -f \"$submodule_attr\"" &&
+ echo "a diff=d2x" >"$submodule_attr" &&
+
+ cat >expect <<-\EOF &&
+ submodule/a:(1|2)x(3|4)
+ EOF
+ git grep --textconv --recurse-submodules x >actual &&
+ test_cmp expect actual
+'
+
+test_expect_failure 'grep saves textconv cache in the appropriate repository' '
+ reset_and_clean &&
+ test_config_global diff.d2x_cached.textconv "sed -e \"s/d/x/\"" &&
+ test_config_global diff.d2x_cached.cachetextconv true &&
+ echo "a diff=d2x_cached" >submodule/.gitattributes &&
+
+ # We only read/write to the textconv cache when grepping from an OID,
+ # as the working tree file might have modifications.
+ git grep --textconv --cached --recurse-submodules x &&
+
+ super_textconv_cache="$(git rev-parse --git-path refs/notes/textconv/d2x_cached)" &&
+ sub_textconv_cache="$(git -C submodule rev-parse \
+ --path-format=absolute --git-path refs/notes/textconv/d2x_cached)" &&
+ test_path_is_missing "$super_textconv_cache" &&
+ test_path_is_file "$sub_textconv_cache"
+'
+
test_done
diff --git a/t/t7816-grep-binary-pattern.sh b/t/t7816-grep-binary-pattern.sh
index 60bab291e4..9d67a5fc4c 100755
--- a/t/t7816-grep-binary-pattern.sh
+++ b/t/t7816-grep-binary-pattern.sh
@@ -59,7 +59,7 @@ test_expect_success 'setup' "
git commit -m.
"
-# Simple fixed-string matching that can use kwset (no -i && non-ASCII)
+# Simple fixed-string matching
nul_match P P P '-F' 'yQf'
nul_match P P P '-F' 'yQx'
nul_match P P P '-Fi' 'YQf'
@@ -78,7 +78,7 @@ nul_match P P P '-Fi' '[Y]QF'
nul_match P P P '-F' 'æQ[ð]'
nul_match P P P '-F' '[æ]Qð'
-# The -F kwset codepath can't handle -i && non-ASCII...
+# Matching pattern and subject case with -i
nul_match P 1 1 '-i' '[æ]Qð'
# ...PCRE v2 only matches non-ASCII with -i casefolding under UTF-8
diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh
index b93ae014ee..9b9f11a8e7 100755
--- a/t/t7900-maintenance.sh
+++ b/t/t7900-maintenance.sh
@@ -20,6 +20,17 @@ test_xmllint () {
fi
}
+test_lazy_prereq SYSTEMD_ANALYZE '
+ systemd-analyze verify /lib/systemd/system/basic.target
+'
+
+test_systemd_analyze_verify () {
+ if test_have_prereq SYSTEMD_ANALYZE
+ then
+ systemd-analyze verify "$@"
+ fi
+}
+
test_expect_success 'help text' '
test_expect_code 129 git maintenance -h 2>err &&
test_i18ngrep "usage: git maintenance <subcommand>" err &&
@@ -265,7 +276,7 @@ test_expect_success 'incremental-repack task' '
# Delete refs that have not been repacked in these packs.
git for-each-ref --format="delete %(refname)" \
- refs/prefetch refs/tags >refs &&
+ refs/prefetch refs/tags refs/remotes >refs &&
git update-ref --stdin <refs &&
# Replace the object directory with this pack layout.
@@ -274,6 +285,10 @@ test_expect_success 'incremental-repack task' '
ls $packDir/*.pack >packs-before &&
test_line_count = 3 packs-before &&
+ # make sure we do not have any broken refs that were
+ # missed in the deletion above
+ git for-each-ref &&
+
# the job repacks the two into a new pack, but does not
# delete the old ones.
git maintenance run --task=incremental-repack &&
@@ -356,8 +371,6 @@ test_expect_success 'pack-refs task' '
done &&
GIT_TRACE2_EVENT="$(pwd)/pack-refs.txt" \
git maintenance run --task=pack-refs &&
- ls .git/refs/heads/ >after &&
- test_must_be_empty after &&
test_subcommand git pack-refs --all --prune <pack-refs.txt
'
@@ -494,8 +507,21 @@ test_expect_success !MINGW 'register and unregister with regex metacharacters' '
maintenance.repo "$(pwd)/$META"
'
+test_expect_success 'start --scheduler=<scheduler>' '
+ test_expect_code 129 git maintenance start --scheduler=foo 2>err &&
+ test_i18ngrep "unrecognized --scheduler argument" err &&
+
+ test_expect_code 129 git maintenance start --no-scheduler 2>err &&
+ test_i18ngrep "unknown option" err &&
+
+ test_expect_code 128 \
+ env GIT_TEST_MAINT_SCHEDULER="launchctl:true,schtasks:true" \
+ git maintenance start --scheduler=crontab 2>err &&
+ test_i18ngrep "fatal: crontab scheduler is not available" err
+'
+
test_expect_success 'start from empty cron table' '
- GIT_TEST_MAINT_SCHEDULER="crontab:test-tool crontab cron.txt" git maintenance start &&
+ GIT_TEST_MAINT_SCHEDULER="crontab:test-tool crontab cron.txt" git maintenance start --scheduler=crontab &&
# start registers the repo
git config --get --global --fixed-value maintenance.repo "$(pwd)" &&
@@ -518,7 +544,7 @@ test_expect_success 'stop from existing schedule' '
test_expect_success 'start preserves existing schedule' '
echo "Important information!" >cron.txt &&
- GIT_TEST_MAINT_SCHEDULER="crontab:test-tool crontab cron.txt" git maintenance start &&
+ GIT_TEST_MAINT_SCHEDULER="crontab:test-tool crontab cron.txt" git maintenance start --scheduler=crontab &&
grep "Important information!" cron.txt
'
@@ -547,7 +573,7 @@ test_expect_success 'start and stop macOS maintenance' '
EOF
rm -f args &&
- GIT_TEST_MAINT_SCHEDULER=launchctl:./print-args git maintenance start &&
+ GIT_TEST_MAINT_SCHEDULER=launchctl:./print-args git maintenance start --scheduler=launchctl &&
# start registers the repo
git config --get --global --fixed-value maintenance.repo "$(pwd)" &&
@@ -584,6 +610,23 @@ test_expect_success 'start and stop macOS maintenance' '
test_line_count = 0 actual
'
+test_expect_success 'use launchctl list to prevent extra work' '
+ # ensure we are registered
+ GIT_TEST_MAINT_SCHEDULER=launchctl:./print-args git maintenance start --scheduler=launchctl &&
+
+ # do it again on a fresh args file
+ rm -f args &&
+ GIT_TEST_MAINT_SCHEDULER=launchctl:./print-args git maintenance start --scheduler=launchctl &&
+
+ ls "$HOME/Library/LaunchAgents" >actual &&
+ cat >expect <<-\EOF &&
+ list org.git-scm.git.hourly
+ list org.git-scm.git.daily
+ list org.git-scm.git.weekly
+ EOF
+ test_cmp expect args
+'
+
test_expect_success 'start and stop Windows maintenance' '
write_script print-args <<-\EOF &&
echo $* >>args
@@ -598,7 +641,7 @@ test_expect_success 'start and stop Windows maintenance' '
EOF
rm -f args &&
- GIT_TEST_MAINT_SCHEDULER="schtasks:./print-args" git maintenance start &&
+ GIT_TEST_MAINT_SCHEDULER="schtasks:./print-args" git maintenance start --scheduler=schtasks &&
# start registers the repo
git config --get --global --fixed-value maintenance.repo "$(pwd)" &&
@@ -621,6 +664,83 @@ test_expect_success 'start and stop Windows maintenance' '
test_cmp expect args
'
+test_expect_success 'start and stop Linux/systemd maintenance' '
+ write_script print-args <<-\EOF &&
+ printf "%s\n" "$*" >>args
+ EOF
+
+ XDG_CONFIG_HOME="$PWD" &&
+ export XDG_CONFIG_HOME &&
+ rm -f args &&
+ GIT_TEST_MAINT_SCHEDULER="systemctl:./print-args" git maintenance start --scheduler=systemd-timer &&
+
+ # start registers the repo
+ git config --get --global --fixed-value maintenance.repo "$(pwd)" &&
+
+ test_systemd_analyze_verify "systemd/user/git-maintenance@.service" &&
+
+ printf -- "--user enable --now git-maintenance@%s.timer\n" hourly daily weekly >expect &&
+ test_cmp expect args &&
+
+ rm -f args &&
+ GIT_TEST_MAINT_SCHEDULER="systemctl:./print-args" git maintenance stop &&
+
+ # stop does not unregister the repo
+ git config --get --global --fixed-value maintenance.repo "$(pwd)" &&
+
+ test_path_is_missing "systemd/user/git-maintenance@.timer" &&
+ test_path_is_missing "systemd/user/git-maintenance@.service" &&
+
+ printf -- "--user disable --now git-maintenance@%s.timer\n" hourly daily weekly >expect &&
+ test_cmp expect args
+'
+
+test_expect_success 'start and stop when several schedulers are available' '
+ write_script print-args <<-\EOF &&
+ printf "%s\n" "$*" | sed "s:gui/[0-9][0-9]*:gui/[UID]:; s:\(schtasks /create .* /xml\).*:\1:;" >>args
+ EOF
+
+ rm -f args &&
+ GIT_TEST_MAINT_SCHEDULER="systemctl:./print-args systemctl,launchctl:./print-args launchctl,schtasks:./print-args schtasks" git maintenance start --scheduler=systemd-timer &&
+ printf "launchctl bootout gui/[UID] $pfx/Library/LaunchAgents/org.git-scm.git.%s.plist\n" \
+ hourly daily weekly >expect &&
+ printf "schtasks /delete /tn Git Maintenance (%s) /f\n" \
+ hourly daily weekly >>expect &&
+ printf -- "systemctl --user enable --now git-maintenance@%s.timer\n" hourly daily weekly >>expect &&
+ test_cmp expect args &&
+
+ rm -f args &&
+ GIT_TEST_MAINT_SCHEDULER="systemctl:./print-args systemctl,launchctl:./print-args launchctl,schtasks:./print-args schtasks" git maintenance start --scheduler=launchctl &&
+ printf -- "systemctl --user disable --now git-maintenance@%s.timer\n" hourly daily weekly >expect &&
+ printf "schtasks /delete /tn Git Maintenance (%s) /f\n" \
+ hourly daily weekly >>expect &&
+ for frequency in hourly daily weekly
+ do
+ PLIST="$pfx/Library/LaunchAgents/org.git-scm.git.$frequency.plist" &&
+ echo "launchctl bootout gui/[UID] $PLIST" >>expect &&
+ echo "launchctl bootstrap gui/[UID] $PLIST" >>expect || return 1
+ done &&
+ test_cmp expect args &&
+
+ rm -f args &&
+ GIT_TEST_MAINT_SCHEDULER="systemctl:./print-args systemctl,launchctl:./print-args launchctl,schtasks:./print-args schtasks" git maintenance start --scheduler=schtasks &&
+ printf -- "systemctl --user disable --now git-maintenance@%s.timer\n" hourly daily weekly >expect &&
+ printf "launchctl bootout gui/[UID] $pfx/Library/LaunchAgents/org.git-scm.git.%s.plist\n" \
+ hourly daily weekly >>expect &&
+ printf "schtasks /create /tn Git Maintenance (%s) /f /xml\n" \
+ hourly daily weekly >>expect &&
+ test_cmp expect args &&
+
+ rm -f args &&
+ GIT_TEST_MAINT_SCHEDULER="systemctl:./print-args systemctl,launchctl:./print-args launchctl,schtasks:./print-args schtasks" git maintenance stop &&
+ printf -- "systemctl --user disable --now git-maintenance@%s.timer\n" hourly daily weekly >expect &&
+ printf "launchctl bootout gui/[UID] $pfx/Library/LaunchAgents/org.git-scm.git.%s.plist\n" \
+ hourly daily weekly >>expect &&
+ printf "schtasks /delete /tn Git Maintenance (%s) /f\n" \
+ hourly daily weekly >>expect &&
+ test_cmp expect args
+'
+
test_expect_success 'register preserves existing strategy' '
git config maintenance.strategy none &&
git maintenance register &&
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 65b3035371..aa0c20499b 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -539,7 +539,7 @@ test_expect_success $PREREQ "--validate respects relative core.hooksPath path" '
test_path_is_file my-hooks.ran &&
cat >expect <<-EOF &&
fatal: longline.patch: rejected by sendemail-validate hook
- fatal: command '"'"'$(pwd)/my-hooks/sendemail-validate'"'"' died with exit code 1
+ fatal: command '"'"'my-hooks/sendemail-validate'"'"' died with exit code 1
warning: no patches were sent
EOF
test_cmp expect actual
@@ -644,14 +644,33 @@ test_expect_success $PREREQ 'In-Reply-To with --chain-reply-to' '
test_cmp expect actual
'
+test_set_editor "$(pwd)/fake-editor"
+
+test_expect_success $PREREQ 'setup erroring fake editor' '
+ write_script fake-editor <<-\EOF
+ echo >&2 "I am about to error"
+ exit 1
+ EOF
+'
+
+test_expect_success $PREREQ 'fake editor dies with error' '
+ clean_fake_sendmail &&
+ test_must_fail git send-email \
+ --compose --subject foo \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $patches 2>err &&
+ grep "I am about to error" err &&
+ grep "the editor exited uncleanly, aborting everything" err
+'
+
test_expect_success $PREREQ 'setup fake editor' '
write_script fake-editor <<-\EOF
echo fake edit >>"$1"
EOF
'
-test_set_editor "$(pwd)/fake-editor"
-
test_expect_success $PREREQ '--compose works' '
clean_fake_sendmail &&
git send-email \
@@ -1349,6 +1368,16 @@ test_expect_success $PREREQ 'sendemail.identity: bool variable fallback' '
! grep "X-Mailer" stdout
'
+test_expect_success $PREREQ 'sendemail.identity: bool variable without a value' '
+ git -c sendemail.xmailer \
+ send-email \
+ --dry-run \
+ --from="nobody@example.com" \
+ $patches >stdout &&
+ grep "To: default@example.com" stdout &&
+ grep "X-Mailer" stdout
+'
+
test_expect_success $PREREQ '--no-to overrides sendemail.to' '
git send-email \
--dry-run \
@@ -1504,6 +1533,21 @@ test_expect_success $PREREQ 'sendemail.8bitEncoding works' '
test_cmp content-type-decl actual
'
+test_expect_success $PREREQ 'sendemail.8bitEncoding in .git/config overrides --global .gitconfig' '
+ clean_fake_sendmail &&
+ git config sendemail.assume8bitEncoding UTF-8 &&
+ test_when_finished "rm -rf home" &&
+ mkdir home &&
+ git config -f home/.gitconfig sendemail.assume8bitEncoding "bogus too" &&
+ echo bogus |
+ env HOME="$(pwd)/home" DEBUG=1 \
+ git send-email --from=author@example.com --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ email-using-8bit >stdout &&
+ egrep "Content|MIME" msgtxt1 >actual &&
+ test_cmp content-type-decl actual
+'
+
test_expect_success $PREREQ '--8bit-encoding overrides sendemail.8bitEncoding' '
clean_fake_sendmail &&
git config sendemail.assume8bitEncoding "bogus too" &&
@@ -1810,7 +1854,7 @@ test_expect_success $PREREQ 'sendemail.aliasfiletype=mailrc' '
grep "^!somebody@example\.org!$" commandline1
'
-test_expect_success $PREREQ 'sendemail.aliasfile=~/.mailrc' '
+test_expect_success $PREREQ 'sendemail.aliasesfile=~/.mailrc' '
clean_fake_sendmail &&
echo "alias sbd someone@example.org" >"$HOME/.mailrc" &&
git config --replace-all sendemail.aliasesfile "~/.mailrc" &&
@@ -2073,6 +2117,18 @@ test_expect_success $PREREQ '--[no-]xmailer with sendemail.xmailer=true' '
do_xmailer_test 1 "--xmailer"
'
+test_expect_success $PREREQ '--[no-]xmailer with sendemail.xmailer' '
+ test_when_finished "test_unconfig sendemail.xmailer" &&
+ cat >>.git/config <<-\EOF &&
+ [sendemail]
+ xmailer
+ EOF
+ test_config sendemail.xmailer true &&
+ do_xmailer_test 1 "" &&
+ do_xmailer_test 0 "--no-xmailer" &&
+ do_xmailer_test 1 "--xmailer"
+'
+
test_expect_success $PREREQ '--[no-]xmailer with sendemail.xmailer=false' '
test_config sendemail.xmailer false &&
do_xmailer_test 0 "" &&
@@ -2080,6 +2136,13 @@ test_expect_success $PREREQ '--[no-]xmailer with sendemail.xmailer=false' '
do_xmailer_test 1 "--xmailer"
'
+test_expect_success $PREREQ '--[no-]xmailer with sendemail.xmailer=' '
+ test_config sendemail.xmailer "" &&
+ do_xmailer_test 0 "" &&
+ do_xmailer_test 0 "--no-xmailer" &&
+ do_xmailer_test 1 "--xmailer"
+'
+
test_expect_success $PREREQ 'setup expected-list' '
git send-email \
--dry-run \
@@ -2148,6 +2211,82 @@ test_expect_success $PREREQ 'leading and trailing whitespaces are removed' '
test_cmp expected-list actual-list
'
+test_expect_success $PREREQ 'test using command name with --sendmail-cmd' '
+ clean_fake_sendmail &&
+ PATH="$PWD:$PATH" \
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --sendmail-cmd="fake.sendmail" \
+ HEAD^ &&
+ test_path_is_file commandline1
+'
+
+test_expect_success $PREREQ 'test using arguments with --sendmail-cmd' '
+ clean_fake_sendmail &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --sendmail-cmd='\''"$(pwd)/fake.sendmail" -f nobody@example.com'\'' \
+ HEAD^ &&
+ test_path_is_file commandline1
+'
+
+test_expect_success $PREREQ 'test shell expression with --sendmail-cmd' '
+ clean_fake_sendmail &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --sendmail-cmd='\''f() { "$(pwd)/fake.sendmail" "$@"; };f'\'' \
+ HEAD^ &&
+ test_path_is_file commandline1
+'
+
+test_expect_success $PREREQ 'set up in-reply-to/references patches' '
+ cat >has-reply.patch <<-\EOF &&
+ From: A U Thor <author@example.com>
+ Subject: patch with in-reply-to
+ Message-ID: <patch.with.in.reply.to@example.com>
+ In-Reply-To: <replied.to@example.com>
+ References: <replied.to@example.com>
+
+ This is the body.
+ EOF
+ cat >no-reply.patch <<-\EOF
+ From: A U Thor <author@example.com>
+ Subject: patch without in-reply-to
+ Message-ID: <patch.without.in.reply.to@example.com>
+
+ This is the body.
+ EOF
+'
+
+test_expect_success $PREREQ 'patch reply headers correct with --no-thread' '
+ clean_fake_sendmail &&
+ git send-email \
+ --no-thread \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ has-reply.patch no-reply.patch &&
+ grep "In-Reply-To: <replied.to@example.com>" msgtxt1 &&
+ grep "References: <replied.to@example.com>" msgtxt1 &&
+ ! grep replied.to@example.com msgtxt2
+'
+
+test_expect_success $PREREQ 'cmdline in-reply-to used with --no-thread' '
+ clean_fake_sendmail &&
+ git send-email \
+ --no-thread \
+ --in-reply-to="<cmdline.reply@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ has-reply.patch no-reply.patch &&
+ grep "In-Reply-To: <cmdline.reply@example.com>" msgtxt1 &&
+ grep "References: <cmdline.reply@example.com>" msgtxt1 &&
+ grep "In-Reply-To: <cmdline.reply@example.com>" msgtxt2 &&
+ grep "References: <cmdline.reply@example.com>" msgtxt2
+'
+
test_expect_success $PREREQ 'invoke hook' '
mkdir -p .git/hooks &&
diff --git a/t/t9002-column.sh b/t/t9002-column.sh
index 89983527b6..6d3dbde3fe 100755
--- a/t/t9002-column.sh
+++ b/t/t9002-column.sh
@@ -42,6 +42,24 @@ EOF
test_cmp expected actual
'
+test_expect_success '--nl' '
+ cat >expected <<\EOF &&
+oneZ
+twoZ
+threeZ
+fourZ
+fiveZ
+sixZ
+sevenZ
+eightZ
+nineZ
+tenZ
+elevenZ
+EOF
+ git column --nl="Z$LF" --mode=plain <lista >actual &&
+ test_cmp expected actual
+'
+
test_expect_success '80 columns' '
cat >expected <<\EOF &&
one two three four five six seven eight nine ten eleven
diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh
index 1d3fdcc997..fea41b3c36 100755
--- a/t/t9100-git-svn-basic.sh
+++ b/t/t9100-git-svn-basic.sh
@@ -4,21 +4,13 @@
#
test_description='git svn basic tests'
-GIT_SVN_LC_ALL=${LC_ALL:-$LANG}
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./lib-git-svn.sh
-case "$GIT_SVN_LC_ALL" in
-*.UTF-8)
- test_set_prereq UTF8
- ;;
-*)
- say "# UTF-8 locale not set, some tests skipped ($GIT_SVN_LC_ALL)"
- ;;
-esac
+prepare_utf8_locale
test_expect_success 'git svn --version works anywhere' '
nongit git svn --version
@@ -187,8 +179,8 @@ test_expect_success POSIXPERM,SYMLINKS "$name" '
test ! -h "$SVN_TREE"/exec-2.sh &&
test_cmp help "$SVN_TREE"/exec-2.sh'
-name="commit with UTF-8 message: locale: $GIT_SVN_LC_ALL"
-LC_ALL="$GIT_SVN_LC_ALL"
+name="commit with UTF-8 message: locale: $GIT_TEST_UTF8_LOCALE"
+LC_ALL="$GIT_TEST_UTF8_LOCALE"
export LC_ALL
# This test relies on the previous test, hence requires POSIXPERM,SYMLINKS
test_expect_success UTF8,POSIXPERM,SYMLINKS "$name" "
@@ -330,7 +322,7 @@ test_expect_success 'git-svn works in a bare repository' '
git svn fetch ) &&
rm -rf bare-repo
'
-test_expect_success 'git-svn works in in a repository with a gitdir: link' '
+test_expect_success 'git-svn works in a repository with a gitdir: link' '
mkdir worktree gitdir &&
( cd worktree &&
git svn init "$svnrepo" &&
diff --git a/t/t9115-git-svn-dcommit-funky-renames.sh b/t/t9115-git-svn-dcommit-funky-renames.sh
index 9b44a44bc1..743fbe1fe4 100755
--- a/t/t9115-git-svn-dcommit-funky-renames.sh
+++ b/t/t9115-git-svn-dcommit-funky-renames.sh
@@ -93,9 +93,9 @@ test_expect_success 'git svn rebase works inside a fresh-cloned repository' '
# > ... All of the above characters, except for the backslash, are converted
# > to special UNICODE characters in the range 0xf000 to 0xf0ff (the
# > "Private use area") when creating or accessing files.
-prepare_a_utf8_locale
+prepare_utf8_locale
test_expect_success UTF8,!MINGW,!UTF8_NFD_TO_NFC 'svn.pathnameencoding=cp932 new file on dcommit' '
- LC_ALL=$a_utf8_locale &&
+ LC_ALL=$GIT_TEST_UTF8_LOCALE &&
export LC_ALL &&
neq=$(printf "\201\202") &&
git config svn.pathnameencoding cp932 &&
@@ -107,7 +107,7 @@ test_expect_success UTF8,!MINGW,!UTF8_NFD_TO_NFC 'svn.pathnameencoding=cp932 new
# See the comment on the above test for setting of LC_ALL.
test_expect_success !MINGW,!UTF8_NFD_TO_NFC 'svn.pathnameencoding=cp932 rename on dcommit' '
- LC_ALL=$a_utf8_locale &&
+ LC_ALL=$GIT_TEST_UTF8_LOCALE &&
export LC_ALL &&
inf=$(printf "\201\207") &&
git config svn.pathnameencoding cp932 &&
diff --git a/t/t9117-git-svn-init-clone.sh b/t/t9117-git-svn-init-clone.sh
index 044f65e916..62de819a44 100755
--- a/t/t9117-git-svn-init-clone.sh
+++ b/t/t9117-git-svn-init-clone.sh
@@ -7,12 +7,6 @@ test_description='git svn init/clone tests'
. ./lib-git-svn.sh
-# setup, run inside tmp so we don't have any conflicts with $svnrepo
-set -e
-rm -r .git
-mkdir tmp
-cd tmp
-
test_expect_success 'setup svnrepo' '
mkdir project project/trunk project/branches project/tags &&
echo foo > project/trunk/foo &&
diff --git a/t/t9129-git-svn-i18n-commitencoding.sh b/t/t9129-git-svn-i18n-commitencoding.sh
index 2c213ae654..01e1e8a8f7 100755
--- a/t/t9129-git-svn-i18n-commitencoding.sh
+++ b/t/t9129-git-svn-i18n-commitencoding.sh
@@ -14,12 +14,12 @@ compare_git_head_with () {
test_cmp current "$1"
}
-prepare_a_utf8_locale
+prepare_utf8_locale
compare_svn_head_with () {
# extract just the log message and strip out committer info.
# don't use --limit here since svn 1.1.x doesn't have it,
- LC_ALL="$a_utf8_locale" svn log $(git svn info --url) | perl -w -e '
+ LC_ALL="$GIT_TEST_UTF8_LOCALE" svn log $(git svn info --url) | perl -w -e '
use bytes;
$/ = ("-"x72) . "\n";
my @x = <STDIN>;
diff --git a/t/t9148-git-svn-propset.sh b/t/t9148-git-svn-propset.sh
index 102639090c..aebb28995e 100755
--- a/t/t9148-git-svn-propset.sh
+++ b/t/t9148-git-svn-propset.sh
@@ -7,19 +7,22 @@ test_description='git svn propset tests'
. ./lib-git-svn.sh
-foo_subdir2="subdir/subdir2/foo_subdir2"
+test_expect_success 'setup propset via import' '
+ test_when_finished "rm -rf import" &&
-set -e
-mkdir import &&
-(set -e ; cd import
- mkdir subdir
- mkdir subdir/subdir2
- touch foo # for 'add props top level'
- touch subdir/foo_subdir # for 'add props relative'
- touch "$foo_subdir2" # for 'add props subdir'
- svn_cmd import -m 'import for git svn' . "$svnrepo" >/dev/null
-)
-rm -rf import
+ foo_subdir2="subdir/subdir2/foo_subdir2" &&
+ mkdir -p import/subdir/subdir2 &&
+ (
+ cd import &&
+ # for "add props top level"
+ >foo &&
+ # for "add props relative"
+ >subdir/foo_subdir &&
+ # for "add props subdir"
+ >"$foo_subdir2" &&
+ svn_cmd import -m "import for git svn" . "$svnrepo"
+ )
+'
test_expect_success 'initialize git svn' '
git svn init "$svnrepo"
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index 5c47ac4465..aa55b41b9a 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -392,7 +392,7 @@ test_expect_success 'B: accept branch name "TEMP_TAG"' '
git gc
git prune" &&
git fast-import <input &&
- test -f .git/TEMP_TAG &&
+ test $(test-tool ref-store main resolve-ref TEMP_TAG 0 | cut -f1 -d " " ) != "$ZERO_OID" &&
test $(git rev-parse main) = $(git rev-parse TEMP_TAG^)
'
@@ -1538,7 +1538,6 @@ test_expect_success 'O: comments are all skipped' '
commit refs/heads/O1
# -- ignore all of this text
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
- # $GIT_COMMITTER_NAME has inserted here for his benefit.
data <<COMMIT
dirty directory copy
COMMIT
diff --git a/t/t9351-fast-export-anonymize.sh b/t/t9351-fast-export-anonymize.sh
index 1c6e6fcdaf..77047e250d 100755
--- a/t/t9351-fast-export-anonymize.sh
+++ b/t/t9351-fast-export-anonymize.sh
@@ -18,7 +18,8 @@ test_expect_success 'setup simple repo' '
git update-index --add --cacheinfo 160000,$fake_commit,link1 &&
git update-index --add --cacheinfo 160000,$fake_commit,link2 &&
git commit -m "add gitlink" &&
- git tag -m "annotated tag" mytag
+ git tag -m "annotated tag" mytag &&
+ git tag -m "annotated tag with long message" longtag
'
test_expect_success 'export anonymized stream' '
@@ -55,7 +56,8 @@ test_expect_success 'stream retains other as refname' '
test_expect_success 'stream omits other refnames' '
! grep main stream &&
- ! grep mytag stream
+ ! grep mytag stream &&
+ ! grep longtag stream
'
test_expect_success 'stream omits identities' '
@@ -118,9 +120,9 @@ test_expect_success 'identical gitlinks got identical oid' '
test_line_count = 1 commits
'
-test_expect_success 'tag points to branch tip' '
+test_expect_success 'all tags point to branch tip' '
git rev-parse $other_branch >expect &&
- git for-each-ref --format="%(*objectname)" | grep . >actual &&
+ git for-each-ref --format="%(*objectname)" | grep . | uniq >actual &&
test_cmp expect actual
'
diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh
index 2d29d486ee..17f988edd2 100755
--- a/t/t9400-git-cvsserver-server.sh
+++ b/t/t9400-git-cvsserver-server.sh
@@ -36,6 +36,13 @@ CVSWORK="$PWD/cvswork"
CVS_SERVER=git-cvsserver
export CVSROOT CVS_SERVER
+if perl -e 'exit(1) if not defined crypt("", "cv")'
+then
+ PWDHASH='lac2ItudM3.KM'
+else
+ PWDHASH='$2b$10$t8fGvE/a9eLmfOLzsZme2uOa2QtoMYwIxq9wZA6aBKtF1Yb7FJIzi'
+fi
+
rm -rf "$CVSWORK" "$SERVERDIR"
test_expect_success 'setup' '
git config push.default matching &&
@@ -54,7 +61,7 @@ test_expect_success 'setup' '
GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true &&
GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" &&
GIT_DIR="$SERVERDIR" git config gitcvs.authdb "$SERVERDIR/auth.db" &&
- echo cvsuser:cvGVEarMLnhlA > "$SERVERDIR/auth.db"
+ echo "cvsuser:$PWDHASH" >"$SERVERDIR/auth.db"
'
# note that cvs doesn't accept absolute pathnames
diff --git a/t/t9801-git-p4-branch.sh b/t/t9801-git-p4-branch.sh
index ff94c3f17d..50a6f8bad5 100755
--- a/t/t9801-git-p4-branch.sh
+++ b/t/t9801-git-p4-branch.sh
@@ -294,11 +294,13 @@ test_expect_success 'git p4 clone complex branches' '
test_path_is_file file3 &&
grep update file2 &&
git reset --hard p4/depot/branch4 &&
+ git diff-tree --quiet HEAD &&
test_path_is_file file1 &&
test_path_is_file file2 &&
test_path_is_missing file3 &&
! grep update file2 &&
git reset --hard p4/depot/branch5 &&
+ git diff-tree --quiet HEAD &&
test_path_is_file file1 &&
test_path_is_file file2 &&
test_path_is_file file3 &&
diff --git a/t/t9802-git-p4-filetype.sh b/t/t9802-git-p4-filetype.sh
index 94edebe272..19073c6e9f 100755
--- a/t/t9802-git-p4-filetype.sh
+++ b/t/t9802-git-p4-filetype.sh
@@ -263,7 +263,7 @@ test_expect_success SYMLINKS 'ensure p4 symlink parsed correctly' '
(
cd "$git" &&
test -L symlink &&
- test $(readlink symlink) = symlink-target
+ test $(test_readlink symlink) = symlink-target
)
'
@@ -329,7 +329,7 @@ test_expect_success SYMLINKS 'empty symlink target' '
git p4 clone --dest="$git" //depot@all &&
(
cd "$git" &&
- test $(readlink empty-symlink) = target2
+ test $(test_readlink empty-symlink) = target2
)
'
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 04ce884ef5..5decc3b269 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -540,6 +540,15 @@ test_expect_success '__gitcomp - expand/narrow all negative options' '
EOF
'
+test_expect_success '__gitcomp - equal skip' '
+ test_gitcomp "--option=" "--option=" <<-\EOF &&
+
+ EOF
+ test_gitcomp "option=" "option=" <<-\EOF
+
+ EOF
+'
+
test_expect_success '__gitcomp - doesnt fail because of invalid variable name' '
__gitcomp "$invalid_variable_name"
'
@@ -1879,6 +1888,7 @@ test_expect_success '__git_find_on_cmdline - single match' '
(
words=(git command --opt list) &&
cword=${#words[@]} &&
+ __git_cmd_idx=1 &&
__git_find_on_cmdline "add list remove" >actual
) &&
test_cmp expect actual
@@ -1889,6 +1899,7 @@ test_expect_success '__git_find_on_cmdline - multiple matches' '
(
words=(git command -o --opt remove list add) &&
cword=${#words[@]} &&
+ __git_cmd_idx=1 &&
__git_find_on_cmdline "add list remove" >actual
) &&
test_cmp expect actual
@@ -1898,6 +1909,7 @@ test_expect_success '__git_find_on_cmdline - no match' '
(
words=(git command --opt branch) &&
cword=${#words[@]} &&
+ __git_cmd_idx=1 &&
__git_find_on_cmdline "add list remove" >actual
) &&
test_must_be_empty actual
@@ -1908,6 +1920,7 @@ test_expect_success '__git_find_on_cmdline - single match with index' '
(
words=(git command --opt list) &&
cword=${#words[@]} &&
+ __git_cmd_idx=1 &&
__git_find_on_cmdline --show-idx "add list remove" >actual
) &&
test_cmp expect actual
@@ -1918,6 +1931,7 @@ test_expect_success '__git_find_on_cmdline - multiple matches with index' '
(
words=(git command -o --opt remove list add) &&
cword=${#words[@]} &&
+ __git_cmd_idx=1 &&
__git_find_on_cmdline --show-idx "add list remove" >actual
) &&
test_cmp expect actual
@@ -1927,11 +1941,23 @@ test_expect_success '__git_find_on_cmdline - no match with index' '
(
words=(git command --opt branch) &&
cword=${#words[@]} &&
+ __git_cmd_idx=1 &&
__git_find_on_cmdline --show-idx "add list remove" >actual
) &&
test_must_be_empty actual
'
+test_expect_success '__git_find_on_cmdline - ignores matches before command with index' '
+ echo "6 remove" >expect &&
+ (
+ words=(git -C remove command -o --opt remove list add) &&
+ cword=${#words[@]} &&
+ __git_cmd_idx=3 &&
+ __git_find_on_cmdline --show-idx "add list remove" >actual
+ ) &&
+ test_cmp expect actual
+'
+
test_expect_success '__git_get_config_variables' '
cat >expect <<-EOF &&
name-1
@@ -2275,6 +2301,7 @@ do
(
words=(git push '$flag' other ma) &&
cword=${#words[@]} cur=${words[cword-1]} &&
+ __git_cmd_idx=1 &&
__git_complete_remote_or_refspec &&
print_comp
) &&
@@ -2288,6 +2315,7 @@ do
(
words=(git push other '$flag' ma) &&
cword=${#words[@]} cur=${words[cword-1]} &&
+ __git_cmd_idx=1 &&
__git_complete_remote_or_refspec &&
print_comp
) &&
@@ -2306,6 +2334,7 @@ test_expect_success 'git config - variable name' '
test_completion "git config log.d" <<-\EOF
log.date Z
log.decorate Z
+ log.diffMerges Z
EOF
'
@@ -2327,6 +2356,7 @@ test_expect_success 'git -c - variable name' '
test_completion "git -c log.d" <<-\EOF
log.date=Z
log.decorate=Z
+ log.diffMerges=Z
EOF
'
@@ -2348,6 +2378,7 @@ test_expect_success 'git clone --config= - variable name' '
test_completion "git clone --config=log.d" <<-\EOF
log.date=Z
log.decorate=Z
+ log.diffMerges=Z
EOF
'
@@ -2358,6 +2389,12 @@ test_expect_success 'git clone --config= - value' '
EOF
'
+test_expect_success 'options with value' '
+ test_completion "git merge -X diff-algorithm=" <<-\EOF
+
+ EOF
+'
+
test_expect_success 'sourcing the completion script clears cached commands' '
__git_compute_all_commands &&
verbose test -n "$__git_all_commands" &&
@@ -2382,6 +2419,19 @@ test_expect_success 'sourcing the completion script clears cached --options' '
verbose test -z "$__gitcomp_builtin_notes_edit"
'
+test_expect_success 'option aliases are not shown by default' '
+ test_completion "git clone --recurs" "--recurse-submodules "
+'
+
+test_expect_success 'option aliases are shown with GIT_COMPLETION_SHOW_ALL' '
+ . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
+ GIT_COMPLETION_SHOW_ALL=1 && export GIT_COMPLETION_SHOW_ALL &&
+ test_completion "git clone --recurs" <<-\EOF
+ --recurse-submodules Z
+ --recursive Z
+ EOF
+'
+
test_expect_success '__git_complete' '
unset -f __git_wrap__git_main &&
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index b823c14027..eef2262a36 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -137,33 +137,110 @@ test_tick () {
# Stop execution and start a shell. This is useful for debugging tests.
#
# Be sure to remove all invocations of this command before submitting.
+# WARNING: the shell invoked by this helper does not have the same environment
+# as the one running the tests (shell variables and functions are not
+# available, and the options below further modify the environment). As such,
+# commands copied from a test script might behave differently than when
+# running the test.
+#
+# Usage: test_pause [options]
+# -t
+# Use your original TERM instead of test-lib.sh's "dumb".
+# This usually restores color output in the invoked shell.
+# -s
+# Invoke $SHELL instead of $TEST_SHELL_PATH.
+# -h
+# Use your original HOME instead of test-lib.sh's "$TRASH_DIRECTORY".
+# This allows you to use your regular shell environment and Git aliases.
+# CAUTION: running commands copied from a test script into the paused shell
+# might result in files in your HOME being overwritten.
+# -a
+# Shortcut for -t -s -h
test_pause () {
- "$SHELL_PATH" <&6 >&5 2>&7
+ PAUSE_TERM=$TERM &&
+ PAUSE_SHELL=$TEST_SHELL_PATH &&
+ PAUSE_HOME=$HOME &&
+ while test $# != 0
+ do
+ case "$1" in
+ -t)
+ PAUSE_TERM="$USER_TERM"
+ ;;
+ -s)
+ PAUSE_SHELL="$SHELL"
+ ;;
+ -h)
+ PAUSE_HOME="$USER_HOME"
+ ;;
+ -a)
+ PAUSE_TERM="$USER_TERM"
+ PAUSE_SHELL="$SHELL"
+ PAUSE_HOME="$USER_HOME"
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+ done &&
+ TERM="$PAUSE_TERM" HOME="$PAUSE_HOME" "$PAUSE_SHELL" <&6 >&5 2>&7
}
# Wrap git with a debugger. Adding this to a command can make it easier
# to understand what is going on in a failing test.
#
+# Usage: debug [options] <git command>
+# -d <debugger>
+# --debugger=<debugger>
+# Use <debugger> instead of GDB
+# -t
+# Use your original TERM instead of test-lib.sh's "dumb".
+# This usually restores color output in the debugger.
+# WARNING: the command being debugged might behave differently than when
+# running the test.
+#
# Examples:
# debug git checkout master
# debug --debugger=nemiver git $ARGS
# debug -d "valgrind --tool=memcheck --track-origins=yes" git $ARGS
debug () {
- case "$1" in
- -d)
- GIT_DEBUGGER="$2" &&
- shift 2
- ;;
- --debugger=*)
- GIT_DEBUGGER="${1#*=}" &&
- shift 1
- ;;
- *)
- GIT_DEBUGGER=1
- ;;
- esac &&
- GIT_DEBUGGER="${GIT_DEBUGGER}" "$@" <&6 >&5 2>&7
+ GIT_DEBUGGER=1 &&
+ DEBUG_TERM=$TERM &&
+ while test $# != 0
+ do
+ case "$1" in
+ -t)
+ DEBUG_TERM="$USER_TERM"
+ ;;
+ -d)
+ GIT_DEBUGGER="$2" &&
+ shift
+ ;;
+ --debugger=*)
+ GIT_DEBUGGER="${1#*=}"
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+ done &&
+
+ dotfiles=".gdbinit .lldbinit"
+
+ for dotfile in $dotfiles
+ do
+ dotfile="$USER_HOME/$dotfile" &&
+ test -f "$dotfile" && cp "$dotfile" "$HOME" || :
+ done &&
+
+ TERM="$DEBUG_TERM" GIT_DEBUGGER="${GIT_DEBUGGER}" "$@" <&6 >&5 2>&7 &&
+
+ for dotfile in $dotfiles
+ do
+ rm -f "$HOME/$dotfile"
+ done
}
# Usage: test_commit [options] <message> [<file> [<contents> [<tag>]]]
@@ -172,12 +249,23 @@ debug () {
# --notick
# Do not call test_tick before making a commit
# --append
-# Use "echo >>" instead of "echo >" when writing "<contents>" to
-# "<file>"
+# Use ">>" instead of ">" when writing "<contents>" to "<file>"
+# --printf
+# Use "printf" instead of "echo" when writing "<contents>" to
+# "<file>", use this to write escape sequences such as "\0", a
+# trailing "\n" won't be added automatically. This option
+# supports nothing but the FORMAT of printf(1), i.e. no custom
+# ARGUMENT(s).
# --signoff
# Invoke "git commit" with --signoff
# --author <author>
# Invoke "git commit" with --author <author>
+# --no-tag
+# Do not tag the resulting commit
+# --annotate
+# Create an annotated tag with "--annotate -m <message>". Calls
+# test_tick between making the commit and tag, unless --notick
+# is given.
#
# This will commit a file with the given contents and the given commit
# message, and tag the resulting commit with the given tag name.
@@ -186,17 +274,21 @@ debug () {
test_commit () {
notick= &&
+ echo=echo &&
append= &&
author= &&
signoff= &&
indir= &&
- no_tag= &&
+ tag=light &&
while test $# != 0
do
case "$1" in
--notick)
notick=yes
;;
+ --printf)
+ echo=printf
+ ;;
--append)
append=yes
;;
@@ -218,7 +310,10 @@ test_commit () {
shift
;;
--no-tag)
- no_tag=yes
+ tag=none
+ ;;
+ --annotate)
+ tag=annotate
;;
*)
break
@@ -230,9 +325,9 @@ test_commit () {
file=${2:-"$1.t"} &&
if test -n "$append"
then
- echo "${3-$1}" >>"$indir$file"
+ $echo "${3-$1}" >>"$indir$file"
else
- echo "${3-$1}" >"$indir$file"
+ $echo "${3-$1}" >"$indir$file"
fi &&
git ${indir:+ -C "$indir"} add "$file" &&
if test -z "$notick"
@@ -242,10 +337,20 @@ test_commit () {
git ${indir:+ -C "$indir"} commit \
${author:+ --author "$author"} \
$signoff -m "$1" &&
- if test -z "$no_tag"
- then
+ case "$tag" in
+ none)
+ ;;
+ light)
git ${indir:+ -C "$indir"} tag "${4:-$1}"
- fi
+ ;;
+ annotate)
+ if test -z "$notick"
+ then
+ test_tick
+ fi &&
+ git ${indir:+ -C "$indir"} tag -a -m "$1" "${4:-$1}"
+ ;;
+ esac
}
# Call test_merge with the arguments "<message> <commit>", where <commit>
@@ -817,6 +922,32 @@ test_line_count () {
fi
}
+# SYNOPSIS:
+# test_stdout_line_count <bin-ops> <value> <cmd> [<args>...]
+#
+# test_stdout_line_count checks that the output of a command has the number
+# of lines it ought to. For example:
+#
+# test_stdout_line_count = 3 git ls-files -u
+# test_stdout_line_count -gt 10 ls
+test_stdout_line_count () {
+ local ops val trashdir &&
+ if test "$#" -le 3
+ then
+ BUG "expect 3 or more arguments"
+ fi &&
+ ops="$1" &&
+ val="$2" &&
+ shift 2 &&
+ if ! trashdir="$(git rev-parse --git-dir)/trash"; then
+ BUG "expect to be run inside a worktree"
+ fi &&
+ mkdir -p "$trashdir" &&
+ "$@" >"$trashdir/output" &&
+ test_line_count "$ops" "$val" "$trashdir/output"
+}
+
+
test_file_size () {
test "$#" -ne 1 && BUG "1 param"
test-tool path-utils file-size "$1"
@@ -1215,22 +1346,10 @@ test_atexit () {
} && (exit \"\$eval_ret\"); eval_ret=\$?; $test_atexit_cleanup"
}
-# Most tests can use the created repository, but some may need to create more.
+# Deprecated wrapper for "git init", use "git init" directly instead
# Usage: test_create_repo <directory>
test_create_repo () {
- test "$#" = 1 ||
- BUG "not 1 parameter to test-create-repo"
- repo="$1"
- mkdir -p "$repo"
- (
- cd "$repo" || error "Cannot setup test environment"
- "${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" -c \
- init.defaultBranch="${GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME-master}" \
- init \
- "--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 ||
- error "cannot run git init -- have you built things yet?"
- mv .git/hooks .git/hooks-disabled
- ) || exit
+ git init "$@"
}
# This function helps on symlink challenged file systems when it is not
@@ -1437,46 +1556,24 @@ nongit () {
)
} 7>&2 2>&4
-# convert function arguments or stdin (if not arguments given) to pktline
-# representation. If multiple arguments are given, they are separated by
-# whitespace and put in a single packet. Note that data containing NULs must be
-# given on stdin, and that empty input becomes an empty packet, not a flush
-# packet (for that you can just print 0000 yourself).
+# These functions are historical wrappers around "test-tool pkt-line"
+# for older tests. Use "test-tool pkt-line" itself in new tests.
packetize () {
if test $# -gt 0
then
packet="$*"
printf '%04x%s' "$((4 + ${#packet}))" "$packet"
else
- perl -e '
- my $packet = do { local $/; <STDIN> };
- printf "%04x%s", 4 + length($packet), $packet;
- '
+ test-tool pkt-line pack
fi
}
-# Parse the input as a series of pktlines, writing the result to stdout.
-# Sideband markers are removed automatically, and the output is routed to
-# stderr if appropriate.
-#
-# NUL bytes are converted to "\\0" for ease of parsing with text tools.
+packetize_raw () {
+ test-tool pkt-line pack-raw-stdin
+}
+
depacketize () {
- perl -e '
- while (read(STDIN, $len, 4) == 4) {
- if ($len eq "0000") {
- print "FLUSH\n";
- } else {
- read(STDIN, $buf, hex($len) - 4);
- $buf =~ s/\0/\\0/g;
- if ($buf =~ s/^[\x2\x3]//) {
- print STDERR $buf;
- } else {
- $buf =~ s/^\x1//;
- print $buf;
- }
- }
- }
- '
+ test-tool pkt-line unpack
}
# Converts base-16 data into base-8. The output is given as a sequence of
@@ -1692,3 +1789,9 @@ test_region () {
return 0
}
+
+# Print the destination of symlink(s) provided as arguments. Basically
+# the same as the readlink command, but it's not available everywhere.
+test_readlink () {
+ perl -le 'print readlink($_) for @ARGV' "$@"
+}
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 3dec266221..151da80c56 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -57,6 +57,15 @@ fi
. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS
export PERL_PATH SHELL_PATH
+# In t0000, we need to override test directories of nested testcases. In case
+# the developer has TEST_OUTPUT_DIRECTORY part of his build options, then we'd
+# reset this value to instead contain what the developer has specified. We thus
+# have this knob to allow overriding the directory.
+if test -n "${TEST_OUTPUT_DIRECTORY_OVERRIDE}"
+then
+ TEST_OUTPUT_DIRECTORY="${TEST_OUTPUT_DIRECTORY_OVERRIDE}"
+fi
+
# Disallow the use of abbreviated options in the test suite by default
if test -z "${GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS}"
then
@@ -64,6 +73,11 @@ then
export GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS
fi
+# Explicitly set the default branch name for testing, to avoid the
+# transitory "git init" warning under --verbose.
+: ${GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME:=master}
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
################################################################
# It appears that people try to run tests without building...
"${GIT_TEST_INSTALLED:-$GIT_BUILD_DIR}/git$X" >/dev/null
@@ -395,20 +409,27 @@ then
verbose=t
fi
+# Since bash 5.0, checkwinsize is enabled by default which does
+# update the COLUMNS variable every time a non-builtin command
+# completes, even for non-interactive shells.
+# Disable that since we are aiming for repeatability.
+test -n "$BASH_VERSION" && shopt -u checkwinsize 2>/dev/null
+
# For repeatability, reset the environment to known value.
# TERM is sanitized below, after saving color control sequences.
LANG=C
LC_ALL=C
PAGER=cat
TZ=UTC
-export LANG LC_ALL PAGER TZ
+COLUMNS=80
+export LANG LC_ALL PAGER TZ COLUMNS
EDITOR=:
# A call to "unset" with no arguments causes at least Solaris 10
# /usr/xpg4/bin/sh and /bin/ksh to bail out. So keep the unsets
# deriving from the command substitution clustered with the other
# ones.
-unset VISUAL EMAIL LANGUAGE COLUMNS $("$PERL_PATH" -e '
+unset VISUAL EMAIL LANGUAGE $("$PERL_PATH" -e '
my @env = keys %ENV;
my $ok = join("|", qw(
TRACE
@@ -513,7 +534,7 @@ SQ=\'
# when case-folding filenames
u200c=$(printf '\342\200\214')
-export _x05 _x35 _x40 _z40 LF u200c EMPTY_TREE EMPTY_BLOB ZERO_OID OID_REGEX
+export _x05 _x35 LF u200c EMPTY_TREE EMPTY_BLOB ZERO_OID OID_REGEX
# Each test should start with something like this, after copyright notices:
#
@@ -564,8 +585,9 @@ else
}
fi
+USER_TERM="$TERM"
TERM=dumb
-export TERM
+export TERM USER_TERM
error () {
say_color error "error: $*"
@@ -727,14 +749,24 @@ match_pattern_list () {
arg="$1"
shift
test -z "$*" && return 1
- for pattern_
- do
- case "$arg" in
- $pattern_)
- return 0
- esac
- done
- return 1
+ # We need to use "$*" to get field-splitting, but we want to
+ # disable globbing, since we are matching against an arbitrary
+ # $arg, not what's in the filesystem. Using "set -f" accomplishes
+ # that, but we must do it in a subshell to avoid impacting the
+ # rest of the script. The exit value of the subshell becomes
+ # the function's return value.
+ (
+ set -f
+ for pattern_ in $*
+ do
+ case "$arg" in
+ $pattern_)
+ exit 0
+ ;;
+ esac
+ done
+ exit 1
+ )
}
match_test_selector_list () {
@@ -843,7 +875,7 @@ maybe_teardown_verbose () {
last_verbose=t
maybe_setup_verbose () {
test -z "$verbose_only" && return
- if match_pattern_list $test_count $verbose_only
+ if match_pattern_list $test_count "$verbose_only"
then
exec 4>&2 3>&1
# Emit a delimiting blank line when going from
@@ -873,7 +905,7 @@ maybe_setup_valgrind () {
return
fi
GIT_VALGRIND_ENABLED=
- if match_pattern_list $test_count $valgrind_only
+ if match_pattern_list $test_count "$valgrind_only"
then
GIT_VALGRIND_ENABLED=t
fi
@@ -947,8 +979,11 @@ test_run_ () {
trace=
# 117 is magic because it is unlikely to match the exit
# code of other programs
- if $(printf '%s\n' "$1" | sed -f "$GIT_BUILD_DIR/t/chainlint.sed" | grep -q '?![A-Z][A-Z]*?!') ||
- test "OK-117" != "$(test_eval_ "(exit 117) && $1${LF}${LF}echo OK-\$?" 3>&1)"
+ if test "OK-117" != "$(test_eval_ "(exit 117) && $1${LF}${LF}echo OK-\$?" 3>&1)" ||
+ {
+ test "${GIT_TEST_CHAIN_LINT_HARDER:-${GIT_TEST_CHAIN_LINT_HARDER_DEFAULT:-1}}" != 0 &&
+ $(printf '%s\n' "$1" | sed -f "$GIT_BUILD_DIR/t/chainlint.sed" | grep -q '?![A-Z][A-Z]*?!')
+ }
then
BUG "broken &&-chain or run-away HERE-DOC: $1"
fi
@@ -998,7 +1033,7 @@ test_finish_ () {
test_skip () {
to_skip=
skipped_reason=
- if match_pattern_list $this_test.$test_count $GIT_SKIP_TESTS
+ if match_pattern_list $this_test.$test_count "$GIT_SKIP_TESTS"
then
to_skip=t
skipped_reason="GIT_SKIP_TESTS"
@@ -1169,7 +1204,7 @@ test_done () {
esac
fi
- if test -z "$debug"
+ if test -z "$debug" && test -n "$remove_trash"
then
test -d "$TRASH_DIRECTORY" ||
error "Tests passed but trash directory already removed before test cleanup; aborting"
@@ -1309,7 +1344,8 @@ fi
GIT_TEMPLATE_DIR="$GIT_BUILD_DIR"/templates/blt
GIT_CONFIG_NOSYSTEM=1
GIT_ATTR_NOSYSTEM=1
-export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM
+GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY/.."
+export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM GIT_CEILING_DIRECTORIES
if test -z "$GIT_TEST_CMP"
then
@@ -1334,6 +1370,43 @@ then
exit 1
fi
+# Are we running this test at all?
+remove_trash=
+this_test=${0##*/}
+this_test=${this_test%%-*}
+if match_pattern_list "$this_test" "$GIT_SKIP_TESTS"
+then
+ say_color info >&3 "skipping test $this_test altogether"
+ skip_all="skip all tests in $this_test"
+ test_done
+fi
+
+# skip non-whitelisted tests when compiled with SANITIZE=leak
+if test -n "$SANITIZE_LEAK"
+then
+ if test_bool_env GIT_TEST_PASSING_SANITIZE_LEAK false
+ then
+ # We need to see it in "git env--helper" (via
+ # test_bool_env)
+ export TEST_PASSES_SANITIZE_LEAK
+
+ if ! test_bool_env TEST_PASSES_SANITIZE_LEAK false
+ then
+ skip_all="skipping $this_test under GIT_TEST_PASSING_SANITIZE_LEAK=true"
+ test_done
+ fi
+ fi
+elif test_bool_env GIT_TEST_PASSING_SANITIZE_LEAK false
+then
+ error "GIT_TEST_PASSING_SANITIZE_LEAK=true has no effect except when compiled with SANITIZE=leak"
+fi
+
+# Last-minute variable setup
+USER_HOME="$HOME"
+HOME="$TRASH_DIRECTORY"
+GNUPGHOME="$HOME/gnupg-home-not-used"
+export HOME GNUPGHOME USER_HOME
+
# Test repository
rm -fr "$TRASH_DIRECTORY" || {
GIT_EXIT_OK=t
@@ -1341,13 +1414,11 @@ rm -fr "$TRASH_DIRECTORY" || {
exit 1
}
-HOME="$TRASH_DIRECTORY"
-GNUPGHOME="$HOME/gnupg-home-not-used"
-export HOME GNUPGHOME
-
+remove_trash=t
if test -z "$TEST_NO_CREATE_REPO"
then
- test_create_repo "$TRASH_DIRECTORY"
+ git init "$TRASH_DIRECTORY" >&3 2>&4 ||
+ error "cannot run git init"
else
mkdir -p "$TRASH_DIRECTORY"
fi
@@ -1356,15 +1427,6 @@ fi
# in subprocesses like git equals our $PWD (for pathname comparisons).
cd -P "$TRASH_DIRECTORY" || exit 1
-this_test=${0##*/}
-this_test=${this_test%%-*}
-if match_pattern_list "$this_test" $GIT_SKIP_TESTS
-then
- say_color info >&3 "skipping test $this_test altogether"
- skip_all="skip all tests in $this_test"
- test_done
-fi
-
if test -n "$write_junit_xml"
then
junit_xml_dir="$TEST_OUTPUT_DIRECTORY/out"
@@ -1383,10 +1445,9 @@ then
fi
# Convenience
-# A regexp to match 5, 35 and 40 hexdigits
+# A regexp to match 5 and 35 hexdigits
_x05='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
_x35="$_x05$_x05$_x05$_x05$_x05$_x05$_x05"
-_x40="$_x35$_x05"
test_oid_init
@@ -1395,7 +1456,6 @@ OID_REGEX=$(echo $ZERO_OID | sed -e 's/0/[0-9a-f]/g')
OIDPATH_REGEX=$(test_oid_to_path $ZERO_OID | sed -e 's/0/[0-9a-f]/g')
EMPTY_TREE=$(test_oid empty_tree)
EMPTY_BLOB=$(test_oid empty_blob)
-_z40=$ZERO_OID
# Provide an implementation of the 'yes' utility; the upper bound
# limit is there to help Windows that cannot stop this loop from
@@ -1459,6 +1519,7 @@ case $uname_s in
test_set_prereq NATIVE_CRLF
test_set_prereq SED_STRIPS_CR
test_set_prereq GREP_STRIPS_CR
+ test_set_prereq WINDOWS
GIT_TEST_CMP=mingw_test_cmp
;;
*CYGWIN*)
@@ -1467,6 +1528,7 @@ case $uname_s in
test_set_prereq CYGWIN
test_set_prereq SED_STRIPS_CR
test_set_prereq GREP_STRIPS_CR
+ test_set_prereq WINDOWS
;;
*)
test_set_prereq POSIXPERM
@@ -1483,6 +1545,8 @@ parisc* | hppa*)
;;
esac
+test_set_prereq REFFILES
+
( COLUMNS=1 && test $COLUMNS = 1 ) && test_set_prereq COLUMNS_CAN_BE_1
test -z "$NO_PERL" && test_set_prereq PERL
test -z "$NO_PTHREADS" && test_set_prereq PTHREADS
@@ -1490,6 +1554,7 @@ test -z "$NO_PYTHON" && test_set_prereq PYTHON
test -n "$USE_LIBPCRE2" && test_set_prereq PCRE
test -n "$USE_LIBPCRE2" && test_set_prereq LIBPCRE2
test -z "$NO_GETTEXT" && test_set_prereq GETTEXT
+test -n "$SANITIZE_LEAK" && test_set_prereq SANITIZE_LEAK
if test -z "$GIT_TEST_CHECK_CACHE_TREE"
then
@@ -1508,6 +1573,12 @@ test_lazy_prereq SYMLINKS '
ln -s x y && test -h y
'
+test_lazy_prereq SYMLINKS_WINDOWS '
+ # test whether symbolic links are enabled on Windows
+ test_have_prereq MINGW &&
+ cmd //c "mklink y x" &> /dev/null && test -h y
+'
+
test_lazy_prereq FILEMODE '
test "$(git config --bool core.filemode)" = true
'
@@ -1659,10 +1730,6 @@ test_lazy_prereq SHA1 '
esac
'
-test_lazy_prereq REBASE_P '
- test -z "$GIT_TEST_SKIP_REBASE_P"
-'
-
# Ensure that no test accidentally triggers a Git command
# that runs the actual maintenance scheduler, affecting a user's
# system permanently.