summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/RelNotes/2.31.0.txt49
-rw-r--r--Documentation/blame-options.txt2
-rw-r--r--Documentation/config/rebase.txt3
-rw-r--r--Documentation/date-formats.txt11
-rw-r--r--Documentation/diff-options.txt8
-rw-r--r--Documentation/git-am.txt2
-rw-r--r--Documentation/git-branch.txt2
-rw-r--r--Documentation/git-difftool.txt8
-rw-r--r--Documentation/git-gc.txt14
-rw-r--r--Documentation/git-http-fetch.txt10
-rw-r--r--Documentation/git-index-pack.txt7
-rw-r--r--Documentation/git-mailinfo.txt4
-rw-r--r--Documentation/git-pack-objects.txt11
-rw-r--r--Documentation/git-repack.txt9
-rw-r--r--Documentation/git-rev-list.txt93
-rw-r--r--Documentation/git-status.txt2
-rw-r--r--Documentation/git-tag.txt2
-rw-r--r--Documentation/git.txt2
-rw-r--r--Documentation/gitdiffcore.txt41
-rw-r--r--Documentation/gitmailmap.txt8
-rw-r--r--Documentation/i18n.txt2
-rw-r--r--Documentation/rev-list-options.txt15
-rw-r--r--Documentation/technical/chunk-format.txt116
-rw-r--r--Documentation/technical/commit-graph-format.txt3
-rw-r--r--Documentation/technical/index-format.txt4
-rw-r--r--Documentation/technical/pack-format.txt3
-rw-r--r--Documentation/technical/protocol-v2.txt4
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile2
-rw-r--r--bisect.c2
-rw-r--r--builtin/add.c18
-rw-r--r--builtin/blame.c8
-rw-r--r--builtin/checkout-index.c35
-rw-r--r--builtin/diff-files.c1
-rw-r--r--builtin/diff-index.c2
-rw-r--r--builtin/diff-tree.c3
-rw-r--r--builtin/diff.c1
-rw-r--r--builtin/gc.c50
-rw-r--r--builtin/grep.c7
-rw-r--r--builtin/index-pack.c25
-rw-r--r--builtin/notes.c20
-rw-r--r--builtin/push.c2
-rw-r--r--builtin/rebase.c20
-rw-r--r--builtin/receive-pack.c2
-rw-r--r--builtin/rev-list.c46
-rw-r--r--builtin/stash.c2
-rw-r--r--builtin/tag.c2
-rw-r--r--chunk-format.c179
-rw-r--r--chunk-format.h68
-rw-r--r--commit-graph.c327
-rw-r--r--commit-reach.c190
-rw-r--r--diff.c21
-rw-r--r--diff.h21
-rw-r--r--diffcore-rename.c255
-rw-r--r--diffcore-rotate.c46
-rw-r--r--diffcore.h1
-rw-r--r--entry.c8
-rw-r--r--fetch-pack.c103
-rw-r--r--fsck.c5
-rw-r--r--fsck.h2
-rw-r--r--fsmonitor.c107
-rw-r--r--fsmonitor.h5
-rwxr-xr-xgit-gui/git-gui.sh5
-rw-r--r--git-gui/lib/commit.tcl18
-rw-r--r--git-gui/po/ru.po2
-rw-r--r--http-fetch.c20
-rw-r--r--http.c15
-rw-r--r--http.h10
-rw-r--r--merge-ort.c66
-rw-r--r--mergetools/vimdiff13
-rw-r--r--midx.c433
-rw-r--r--pack-bitmap.c81
-rw-r--r--pack-bitmap.h2
-rw-r--r--pack-write.c8
-rw-r--r--pack.h2
-rw-r--r--preload-index.c10
-rw-r--r--read-cache.c24
-rw-r--r--t/lib-credential.sh2
-rw-r--r--t/lib-log-graph.sh4
-rw-r--r--t/perf/.gitignore1
-rw-r--r--t/perf/Makefile4
-rwxr-xr-xt/perf/p7519-fsmonitor.sh71
-rwxr-xr-xt/t0000-basic.sh2
-rwxr-xr-xt/t0006-date.sh4
-rwxr-xr-xt/t0008-ignores.sh2
-rwxr-xr-xt/t0012-help.sh2
-rwxr-xr-xt/t0018-advice.sh4
-rwxr-xr-xt/t0020-crlf.sh6
-rwxr-xr-xt/t0027-auto-crlf.sh2
-rwxr-xr-xt/t0040-parse-options.sh8
-rwxr-xr-xt/t0201-gettext-fallbacks.sh16
-rwxr-xr-xt/t0300-credentials.sh8
-rwxr-xr-xt/t0500-progress-display.sh22
-rwxr-xr-xt/t1011-read-tree-sparse-checkout.sh2
-rwxr-xr-xt/t1308-config-set.sh4
-rwxr-xr-xt/t1400-update-ref.sh6
-rwxr-xr-xt/t1404-update-ref-errors.sh2
-rwxr-xr-xt/t1430-bad-ref-name.sh2
-rwxr-xr-xt/t1450-fsck.sh6
-rwxr-xr-xt/t1502-rev-parse-parseopt.sh10
-rwxr-xr-xt/t1506-rev-parse-diagnosis.sh2
-rwxr-xr-xt/t1507-rev-parse-upstream.sh10
-rwxr-xr-xt/t1509-root-work-tree.sh4
-rwxr-xr-xt/t1512-rev-parse-disambiguation.sh14
-rwxr-xr-xt/t1600-index.sh6
-rwxr-xr-xt/t2006-checkout-index-basic.sh23
-rwxr-xr-xt/t2018-checkout-branch.sh2
-rwxr-xr-xt/t2020-checkout-detach.sh20
-rwxr-xr-xt/t2200-add-update.sh2
-rwxr-xr-xt/t2401-worktree-prune.sh4
-rwxr-xr-xt/t2402-worktree-list.sh2
-rwxr-xr-xt/t3005-ls-files-relative.sh4
-rwxr-xr-xt/t3200-branch.sh26
-rwxr-xr-xt/t3201-branch-contains.sh2
-rwxr-xr-xt/t3203-branch-output.sh28
-rwxr-xr-xt/t3300-funny-names.sh2
-rwxr-xr-xt/t3301-notes.sh6
-rwxr-xr-xt/t3400-rebase.sh2
-rwxr-xr-xt/t3404-rebase-interactive.sh38
-rwxr-xr-xt/t3415-rebase-autosquash.sh10
-rwxr-xr-xt/t3420-rebase-autostash.sh4
-rwxr-xr-xt/t3431-rebase-fork-point.sh55
-rwxr-xr-xt/t3504-cherry-pick-rerere.sh4
-rwxr-xr-xt/t3507-cherry-pick-conflict.sh12
-rwxr-xr-xt/t3508-cherry-pick-many-commits.sh4
-rwxr-xr-xt/t3510-cherry-pick-sequence.sh8
-rwxr-xr-xt/t3600-rm.sh16
-rwxr-xr-xt/t3700-add.sh54
-rwxr-xr-xt/t3701-add-interactive.sh4
-rwxr-xr-xt/t3800-mktag.sh12
-rwxr-xr-xt/t3903-stash.sh8
-rwxr-xr-xt/t3905-stash-include-untracked.sh2
-rwxr-xr-xt/t4001-diff-rename.sh24
-rwxr-xr-xt/t4006-diff-mode.sh8
-rwxr-xr-xt/t4012-diff-binary.sh10
-rwxr-xr-xt/t4013-diff-various.sh2
-rwxr-xr-xt/t4014-format-patch.sh6
-rwxr-xr-xt/t4016-diff-quote.sh2
-rwxr-xr-xt/t4030-diff-textconv.sh2
-rwxr-xr-xt/t4045-diff-relative.sh2
-rwxr-xr-xt/t4049-diff-stat-count.sh6
-rwxr-xr-xt/t4056-diff-order.sh72
-rwxr-xr-xt/t4100-apply-stat.sh4
-rwxr-xr-xt/t4150-am.sh2
-rwxr-xr-xt/t4153-am-resume-override-opts.sh2
-rwxr-xr-xt/t4205-log-pretty-formats.sh4
-rwxr-xr-xt/t4208-log-magic-pathspec.sh9
-rwxr-xr-xt/t4254-am-corrupt.sh2
-rwxr-xr-xt/t5150-request-pull.sh4
-rwxr-xr-xt/t5300-pack-object.sh4
-rwxr-xr-xt/t5316-pack-delta-depth.sh4
-rwxr-xr-xt/t5318-commit-graph.sh2
-rwxr-xr-xt/t5319-multi-pack-index.sh6
-rwxr-xr-xt/t5500-fetch-pack.sh6
-rwxr-xr-xt/t5505-remote.sh30
-rwxr-xr-xt/t5510-fetch.sh6
-rwxr-xr-xt/t5512-ls-remote.sh2
-rwxr-xr-xt/t5516-fetch-push.sh5
-rwxr-xr-xt/t5526-fetch-submodules.sh38
-rwxr-xr-xt/t5541-http-push-smart.sh2
-rwxr-xr-xt/t5550-http-fetch-dumb.sh5
-rwxr-xr-xt/t5601-clone.sh2
-rwxr-xr-xt/t5702-protocol-v2.sh66
-rwxr-xr-xt/t6020-bundle-misc.sh28
-rwxr-xr-xt/t6030-bisect-porcelain.sh8
-rwxr-xr-xt/t6040-tracking-info.sh22
-rwxr-xr-xt/t6115-rev-list-du.sh51
-rwxr-xr-xt/t6120-describe.sh2
-rwxr-xr-xt/t6134-pathspec-in-submodule.sh2
-rwxr-xr-xt/t6301-for-each-ref-errors.sh10
-rwxr-xr-xt/t6423-merge-rename-directories.sh2
-rwxr-xr-xt/t6436-merge-overwrite.sh4
-rwxr-xr-xt/t6439-merge-co-error-msgs.sh12
-rwxr-xr-xt/t7001-mv.sh422
-rwxr-xr-xt/t7004-tag.sh8
-rwxr-xr-xt/t7011-skip-worktree-reading.sh9
-rwxr-xr-xt/t7012-skip-worktree-writing.sh4
-rwxr-xr-xt/t7060-wtstatus.sh14
-rwxr-xr-xt/t7063-status-untracked-cache.sh2
-rwxr-xr-xt/t7102-reset.sh6
-rwxr-xr-xt/t7300-clean.sh6
-rwxr-xr-xt/t7400-submodule-basic.sh4
-rwxr-xr-xt/t7401-submodule-summary.sh12
-rwxr-xr-xt/t7406-submodule-update.sh16
-rwxr-xr-xt/t7407-submodule-foreach.sh10
-rwxr-xr-xt/t7500-commit-template-squash-signoff.sh4
-rwxr-xr-xt/t7502-commit-porcelain.sh6
-rwxr-xr-xt/t7505-prepare-commit-msg-hook.sh4
-rwxr-xr-xt/t7508-status.sh110
-rwxr-xr-xt/t7512-status-help.sh74
-rwxr-xr-xt/t7519-status-fsmonitor.sh4
-rwxr-xr-xt/t7521-ignored-mode.sh22
-rwxr-xr-xt/t7600-merge.sh4
-rwxr-xr-xt/t7602-merge-octopus-many.sh6
-rwxr-xr-xt/t7800-difftool.sh32
-rwxr-xr-xt/t7810-grep.sh2
-rwxr-xr-xt/t7817-grep-sparse-checkout.sh174
-rwxr-xr-xt/t7900-maintenance.sh13
-rwxr-xr-xt/t9003-help-autocorrect.sh7
-rw-r--r--t/test-lib-functions.sh9
-rw-r--r--t/test-lib.sh5
201 files changed, 3344 insertions, 1437 deletions
diff --git a/Documentation/RelNotes/2.31.0.txt b/Documentation/RelNotes/2.31.0.txt
index 1d2dba2c80..ef8b0d158e 100644
--- a/Documentation/RelNotes/2.31.0.txt
+++ b/Documentation/RelNotes/2.31.0.txt
@@ -89,6 +89,22 @@ UI, Workflows & Features
two object names (one in SHA-1, the other in SHA-256) are both
signed.
+ * "git rev-list" command learned "--disk-usage" option.
+
+ * "git {diff,log} --{skip,rotate}-to=<path>" allows the user to
+ discard diff output for early paths or move them to the end of the
+ output.
+
+ * "git difftool" learned "--skip-to=<path>" option to restart an
+ interrupted session from an arbitrary path.
+
+ * "git grep" has been tweaked to be limited to the sparse checkout
+ paths.
+
+ * "git rebase --[no-]fork-point" gained a configuration variable
+ rebase.forkPoint so that users do not have to keep specifying a
+ non-default setting.
+
Performance, Internal Implementation, Development Support etc.
@@ -176,6 +192,11 @@ Performance, Internal Implementation, Development Support etc.
* When a pager spawned by us exited, the trace log did not record its
exit status correctly, which has been corrected.
+ * Removal of GIT_TEST_GETTEXT_POISON continues.
+
+ * The code to implement "git merge-base --independent" was poorly
+ done and was kept from the very beginning of the feature.
+
Fixes since v2.30
-----------------
@@ -274,5 +295,33 @@ Fixes since v2.30
turned commit-graph off; we now tell the user what we are doing.
(merge c85eec7fc3 js/commit-graph-warning later to maint).
+ * Objects that lost references can be pruned away, even when they
+ have notes attached to it (and these notes will become dangling,
+ which in turn can be pruned with "git notes prune"). This has been
+ clarified in the documentation.
+ (merge fa9ab027ba mz/doc-notes-are-not-anchors later to maint).
+
+ * The error codepath around the "--temp/--prefix" feature of "git
+ checkout-index" has been improved.
+ (merge 3f7ba60350 mt/checkout-index-corner-cases later to maint).
+
+ * The "git maintenance register" command had trouble registering bare
+ repositories, which had been corrected.
+
+ * A handful of multi-word configuration variable names in
+ documentation that are spelled in all lowercase have been corrected
+ to use the more canonical camelCase.
+ (merge 7dd0eaa39c dl/doc-config-camelcase later to maint).
+
+ * "git push $there --delete ''" should have been diagnosed as an
+ error, but instead turned into a matching push, which has been
+ corrected.
+ (merge 20e416409f jc/push-delete-nothing later to maint).
+
* Other code cleanup, docfix, build fix, etc.
(merge e3f5da7e60 sg/t7800-difftool-robustify later to maint).
+ (merge 9d336655ba js/doc-proto-v2-response-end later to maint).
+ (merge 1b5b8cf072 jc/maint-column-doc-typofix later to maint).
+ (merge 3a837b58e3 cw/pack-config-doc later to maint).
+ (merge 01168a9d89 ug/doc-commit-approxidate later to maint).
+ (merge b865734760 js/params-vs-args later to maint).
diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt
index dc3bceb6d1..117f4cf806 100644
--- a/Documentation/blame-options.txt
+++ b/Documentation/blame-options.txt
@@ -1,6 +1,6 @@
-b::
Show blank SHA-1 for boundary commits. This can also
- be controlled via the `blame.blankboundary` config option.
+ be controlled via the `blame.blankBoundary` config option.
--root::
Do not treat root commits as boundaries. This can also be
diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt
index 7f7a07d22f..214f31b451 100644
--- a/Documentation/config/rebase.txt
+++ b/Documentation/config/rebase.txt
@@ -68,3 +68,6 @@ rebase.rescheduleFailedExec::
Automatically reschedule `exec` commands that failed. This only makes
sense in interactive mode (or when an `--exec` option was provided).
This is the same as specifying the `--reschedule-failed-exec` option.
+
+rebase.forkPoint::
+ If set to false set `--no-fork-point` option by default.
diff --git a/Documentation/date-formats.txt b/Documentation/date-formats.txt
index f1097fac69..99c455f51c 100644
--- a/Documentation/date-formats.txt
+++ b/Documentation/date-formats.txt
@@ -1,10 +1,7 @@
DATE FORMATS
------------
-The `GIT_AUTHOR_DATE`, `GIT_COMMITTER_DATE` environment variables
-ifdef::git-commit[]
-and the `--date` option
-endif::git-commit[]
+The `GIT_AUTHOR_DATE` and `GIT_COMMITTER_DATE` environment variables
support the following date formats:
Git internal format::
@@ -26,3 +23,9 @@ ISO 8601::
+
NOTE: In addition, the date part is accepted in the following formats:
`YYYY.MM.DD`, `MM/DD/YYYY` and `DD.MM.YYYY`.
+
+ifdef::git-commit[]
+In addition to recognizing all date formats above, the `--date` option
+will also try to make sense of other, more human-centric date formats,
+such as relative dates like "yesterday" or "last Friday at noon".
+endif::git-commit[]
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index e5733ccb2d..aa2b5c11f2 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -700,6 +700,14 @@ matches a pattern if removing any number of the final pathname
components matches the pattern. For example, the pattern "`foo*bar`"
matches "`fooasdfbar`" and "`foo/bar/baz/asdf`" but not "`foobarx`".
+--skip-to=<file>::
+--rotate-to=<file>::
+ Discard the files before the named <file> from the output
+ (i.e. 'skip to'), or move them to the end of the output
+ (i.e. 'rotate to'). These were invented primarily for use
+ of the `git difftool` command, and may not be very useful
+ otherwise.
+
ifndef::git-format-patch[]
-R::
Swap two inputs; that is, show differences from index or
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 06bc063542..decd8ae122 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -79,7 +79,7 @@ OPTIONS
Pass `-u` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]).
The proposed commit log message taken from the e-mail
is re-coded into UTF-8 encoding (configuration variable
- `i18n.commitencoding` can be used to specify project's
+ `i18n.commitEncoding` can be used to specify project's
preferred encoding if it is not UTF-8).
+
This was optional in prior versions of git, but now it is the
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index eb815c2248..94dc9a54f2 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -153,7 +153,7 @@ OPTIONS
--column[=<options>]::
--no-column::
Display branch listing in columns. See configuration variable
- column.branch for option syntax.`--column` and `--no-column`
+ `column.branch` for option syntax. `--column` and `--no-column`
without options are equivalent to 'always' and 'never' respectively.
+
This option is only applicable in non-verbose mode.
diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
index 484c485fd0..143b0c49d7 100644
--- a/Documentation/git-difftool.txt
+++ b/Documentation/git-difftool.txt
@@ -34,6 +34,14 @@ OPTIONS
This is the default behaviour; the option is provided to
override any configuration settings.
+--rotate-to=<file>::
+ Start showing the diff for the given path,
+ the paths before it will move to end and output.
+
+--skip-to=<file>::
+ Start showing the diff for the given path, skipping all
+ the paths before it.
+
-t <tool>::
--tool=<tool>::
Use the diff tool specified by <tool>. Valid values include
diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt
index 0c114ad1ca..853967dea0 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.txt
@@ -117,12 +117,14 @@ NOTES
'git gc' tries very hard not to delete objects that are referenced
anywhere in your repository. In particular, it will keep not only
objects referenced by your current set of branches and tags, but also
-objects referenced by the index, remote-tracking branches, notes saved
-by 'git notes' under refs/notes/, reflogs (which may reference commits
-in branches that were later amended or rewound), and anything else in
-the refs/* namespace. If you are expecting some objects to be deleted
-and they aren't, check all of those locations and decide whether it
-makes sense in your case to remove those references.
+objects referenced by the index, remote-tracking branches, reflogs
+(which may reference commits in branches that were later amended or
+rewound), and anything else in the refs/* namespace. Note that a note
+(of the kind created by 'git notes') attached to an object does not
+contribute in keeping the object alive. If you are expecting some
+objects to be deleted and they aren't, check all of those locations
+and decide whether it makes sense in your case to remove those
+references.
On the other hand, when 'git gc' runs concurrently with another process,
there is a risk of it deleting an object that the other process is using
diff --git a/Documentation/git-http-fetch.txt b/Documentation/git-http-fetch.txt
index 4deb4893f5..9fa17b60e4 100644
--- a/Documentation/git-http-fetch.txt
+++ b/Documentation/git-http-fetch.txt
@@ -41,11 +41,17 @@ commit-id::
<commit-id>['\t'<filename-as-in--w>]
--packfile=<hash>::
- Instead of a commit id on the command line (which is not expected in
+ For internal use only. Instead of a commit id on the command
+ line (which is not expected in
this case), 'git http-fetch' fetches the packfile directly at the given
URL and uses index-pack to generate corresponding .idx and .keep files.
The hash is used to determine the name of the temporary file and is
- arbitrary. The output of index-pack is printed to stdout.
+ arbitrary. The output of index-pack is printed to stdout. Requires
+ --index-pack-args.
+
+--index-pack-args=<args>::
+ For internal use only. The command to run on the contents of the
+ downloaded pack. Arguments are URL-encoded separated by spaces.
--recover::
Verify that everything reachable from target is fetched. Used after
diff --git a/Documentation/git-index-pack.txt b/Documentation/git-index-pack.txt
index 69ba904d44..7fa74b9e79 100644
--- a/Documentation/git-index-pack.txt
+++ b/Documentation/git-index-pack.txt
@@ -86,7 +86,12 @@ OPTIONS
Die if the pack contains broken links. For internal use only.
--fsck-objects::
- Die if the pack contains broken objects. For internal use only.
+ For internal use only.
++
+Die if the pack contains broken objects. If the pack contains a tree
+pointing to a .gitmodules blob that does not exist, prints the hash of
+that blob (for the caller to check) after the hash that goes into the
+name of the pack/idx file (see "Notes").
--threads=<n>::
Specifies the number of threads to spawn when resolving
diff --git a/Documentation/git-mailinfo.txt b/Documentation/git-mailinfo.txt
index 7a6aed0e30..d343f040f5 100644
--- a/Documentation/git-mailinfo.txt
+++ b/Documentation/git-mailinfo.txt
@@ -53,7 +53,7 @@ character.
The commit log message, author name and author email are
taken from the e-mail, and after minimally decoding MIME
transfer encoding, re-coded in the charset specified by
- i18n.commitencoding (defaulting to UTF-8) by transliterating
+ `i18n.commitEncoding` (defaulting to UTF-8) by transliterating
them. This used to be optional but now it is the default.
+
Note that the patch is always used as-is without charset
@@ -61,7 +61,7 @@ conversion, even with this flag.
--encoding=<encoding>::
Similar to -u. But when re-coding, the charset specified here is
- used instead of the one specified by i18n.commitencoding or UTF-8.
+ used instead of the one specified by `i18n.commitEncoding` or UTF-8.
-n::
Disable all charset re-coding of the metadata.
diff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.txt
index 54d715ead1..f85cb7ea93 100644
--- a/Documentation/git-pack-objects.txt
+++ b/Documentation/git-pack-objects.txt
@@ -400,6 +400,17 @@ Note that we pick a single island for each regex to go into, using "last
one wins" ordering (which allows repo-specific config to take precedence
over user-wide config, and so forth).
+
+CONFIGURATION
+-------------
+
+Various configuration variables affect packing, see
+linkgit:git-config[1] (search for "pack" and "delta").
+
+Notably, delta compression is not used on objects larger than the
+`core.bigFileThreshold` configuration variable and on files with the
+attribute `delta` set to false.
+
SEE ALSO
--------
linkgit:git-rev-list[1]
diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt
index 92f146d27d..fbd4b4ae06 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.txt
@@ -165,9 +165,12 @@ depth is 4095.
Pass the `--delta-islands` option to `git-pack-objects`, see
linkgit:git-pack-objects[1].
-Configuration
+CONFIGURATION
-------------
+Various configuration variables affect packing, see
+linkgit:git-config[1] (search for "pack" and "delta").
+
By default, the command passes `--delta-base-offset` option to
'git pack-objects'; this typically results in slightly smaller packs,
but the generated packs are incompatible with versions of Git older than
@@ -178,6 +181,10 @@ need to set the configuration variable `repack.UseDeltaBaseOffset` to
is unaffected by this option as the conversion is performed on the fly
as needed in that case.
+Delta compression is not used on objects larger than the
+`core.bigFileThreshold` configuration variable and on files with the
+attribute `delta` set to false.
+
SEE ALSO
--------
linkgit:git-pack-objects[1]
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index 5da66232dc..20bb8e8217 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -31,6 +31,99 @@ include::rev-list-options.txt[]
include::pretty-formats.txt[]
+EXAMPLES
+--------
+
+* Print the list of commits reachable from the current branch.
++
+----------
+git rev-list HEAD
+----------
+
+* Print the list of commits on this branch, but not present in the
+ upstream branch.
++
+----------
+git rev-list @{upstream}..HEAD
+----------
+
+* Format commits with their author and commit message (see also the
+ porcelain linkgit:git-log[1]).
++
+----------
+git rev-list --format=medium HEAD
+----------
+
+* Format commits along with their diffs (see also the porcelain
+ linkgit:git-log[1], which can do this in a single process).
++
+----------
+git rev-list HEAD |
+git diff-tree --stdin --format=medium -p
+----------
+
+* Print the list of commits on the current branch that touched any
+ file in the `Documentation` directory.
++
+----------
+git rev-list HEAD -- Documentation/
+----------
+
+* Print the list of commits authored by you in the past year, on
+ any branch, tag, or other ref.
++
+----------
+git rev-list --author=you@example.com --since=1.year.ago --all
+----------
+
+* Print the list of objects reachable from the current branch (i.e., all
+ commits and the blobs and trees they contain).
++
+----------
+git rev-list --objects HEAD
+----------
+
+* Compare the disk size of all reachable objects, versus those
+ reachable from reflogs, versus the total packed size. This can tell
+ you whether running `git repack -ad` might reduce the repository size
+ (by dropping unreachable objects), and whether expiring reflogs might
+ help.
++
+----------
+# reachable objects
+git rev-list --disk-usage --objects --all
+# plus reflogs
+git rev-list --disk-usage --objects --all --reflog
+# total disk size used
+du -c .git/objects/pack/*.pack .git/objects/??/*
+# alternative to du: add up "size" and "size-pack" fields
+git count-objects -v
+----------
+
+* Report the disk size of each branch, not including objects used by the
+ current branch. This can find outliers that are contributing to a
+ bloated repository size (e.g., because somebody accidentally committed
+ large build artifacts).
++
+----------
+git for-each-ref --format='%(refname)' |
+while read branch
+do
+ size=$(git rev-list --disk-usage --objects HEAD..$branch)
+ echo "$size $branch"
+done |
+sort -n
+----------
+
+* Compare the on-disk size of branches in one group of refs, excluding
+ another. If you co-mingle objects from multiple remotes in a single
+ repository, this can show which remotes are contributing to the
+ repository size (taking the size of `origin` as a baseline).
++
+----------
+git rev-list --disk-usage --objects --remotes=$suspect --not --remotes=origin
+----------
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index c0764e850a..83f38e3198 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -130,7 +130,7 @@ ignored, then the directory is not shown, but all contents are shown.
--column[=<options>]::
--no-column::
Display untracked files in columns. See configuration variable
- column.status for option syntax.`--column` and `--no-column`
+ `column.status` for option syntax. `--column` and `--no-column`
without options are equivalent to 'always' and 'never'
respectively.
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 56656d1be6..31a97a1b6c 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -134,7 +134,7 @@ options for details.
--column[=<options>]::
--no-column::
Display tag listing in columns. See configuration variable
- column.tag for option syntax.`--column` and `--no-column`
+ `column.tag` for option syntax. `--column` and `--no-column`
without options are equivalent to 'always' and 'never' respectively.
+
This option is only applicable when listing tags without annotation lines.
diff --git a/Documentation/git.txt b/Documentation/git.txt
index d36e6fd482..3a9c44987f 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -88,7 +88,7 @@ foo.bar= ...`) sets `foo.bar` to the empty string which `git config
empty string, instead the environment variable itself must be
set to the empty string. It is an error if the `<envvar>` does not exist
in the environment. `<envvar>` may not contain an equals sign
- to avoid ambiguity with `<name>`s which contain one.
+ to avoid ambiguity with `<name>` containing one.
+
This is useful for cases where you want to pass transitory
configuration options to git, but are doing so on OS's where
diff --git a/Documentation/gitdiffcore.txt b/Documentation/gitdiffcore.txt
index c970d9fe43..1c7269655f 100644
--- a/Documentation/gitdiffcore.txt
+++ b/Documentation/gitdiffcore.txt
@@ -74,6 +74,7 @@ into another list. There are currently 5 such transformations:
- diffcore-merge-broken
- diffcore-pickaxe
- diffcore-order
+- diffcore-rotate
These are applied in sequence. The set of filepairs 'git diff-{asterisk}'
commands find are used as the input to diffcore-break, and
@@ -168,6 +169,26 @@ a similarity score different from the default of 50% by giving a
number after the "-M" or "-C" option (e.g. "-M8" to tell it to use
8/10 = 80%).
+Note that when rename detection is on but both copy and break
+detection are off, rename detection adds a preliminary step that first
+checks if files are moved across directories while keeping their
+filename the same. If there is a file added to a directory whose
+contents is sufficiently similar to a file with the same name that got
+deleted from a different directory, it will mark them as renames and
+exclude them from the later quadratic step (the one that pairwise
+compares all unmatched files to find the "best" matches, determined by
+the highest content similarity). So, for example, if a deleted
+docs/ext.txt and an added docs/config/ext.txt are similar enough, they
+will be marked as a rename and prevent an added docs/ext.md that may
+be even more similar to the deleted docs/ext.txt from being considered
+as the rename destination in the later step. For this reason, the
+preliminary "match same filename" step uses a bit higher threshold to
+mark a file pair as a rename and stop considering other candidates for
+better matches. At most, one comparison is done per file in this
+preliminary pass; so if there are several remaining ext.txt files
+throughout the directory hierarchy after exact rename detection, this
+preliminary step will be skipped for those files.
+
Note. When the "-C" option is used with `--find-copies-harder`
option, 'git diff-{asterisk}' commands feed unmodified filepairs to
diffcore mechanism as well as modified ones. This lets the copy
@@ -276,6 +297,26 @@ Documentation
t
------------------------------------------------
+diffcore-rotate: For Changing At Which Path Output Starts
+---------------------------------------------------------
+
+This transformation takes one pathname, and rotates the set of
+filepairs so that the filepair for the given pathname comes first,
+optionally discarding the paths that come before it. This is used
+to implement the `--skip-to` and the `--rotate-to` options. It is
+an error when the specified pathname is not in the set of filepairs,
+but it is not useful to error out when used with "git log" family of
+commands, because it is unreasonable to expect that a given path
+would be modified by each and every commit shown by the "git log"
+command. For this reason, when used with "git log", the filepair
+that sorts the same as, or the first one that sorts after, the given
+pathname is where the output starts.
+
+Use of this transformation combined with diffcore-order will produce
+unexpected results, as the input to this transformation is likely
+not sorted when diffcore-order is in effect.
+
+
SEE ALSO
--------
linkgit:git-diff[1],
diff --git a/Documentation/gitmailmap.txt b/Documentation/gitmailmap.txt
index 052209b33b..3fb39f801f 100644
--- a/Documentation/gitmailmap.txt
+++ b/Documentation/gitmailmap.txt
@@ -50,9 +50,9 @@ which allows mailmap to replace both the name and the email of a
commit matching both the specified commit name and email address.
Both E-Mails and names are matched case-insensitively. For example
-this would also match the 'Commit Name <commit@email.xx>' above:
+this would also match the 'Commit Name <commit&#64;email.xx>' above:
--
-Proper Name <proper@email.xx> CoMmIt NaMe <CoMmIt@EmAiL.xX>
+ Proper Name <proper@email.xx> CoMmIt NaMe <CoMmIt@EmAiL.xX>
--
EXAMPLES
@@ -79,9 +79,9 @@ Jane Doe <jane@example.com>
Jane Doe <jane@desktop.(none)>
------------
-Note that there's no need to map the name for 'jane@laptop.(none)' to
+Note that there's no need to map the name for '<jane&#64;laptop.(none)>' to
only correct the names. However, leaving the obviously broken
-`<jane@laptop.(none)>' and '<jane@desktop.(none)>' E-Mails as-is is
+'<jane&#64;laptop.(none)>' and '<jane&#64;desktop.(none)>' E-Mails as-is is
usually not what you want. A `.mailmap` file which also corrects those
is:
diff --git a/Documentation/i18n.txt b/Documentation/i18n.txt
index 7e36e5b55b..6c6baeeeb7 100644
--- a/Documentation/i18n.txt
+++ b/Documentation/i18n.txt
@@ -38,7 +38,7 @@ mind.
a warning if the commit log message given to it does not look
like a valid UTF-8 string, unless you explicitly say your
project uses a legacy encoding. The way to say this is to
- have i18n.commitencoding in `.git/config` file, like this:
+ have `i18n.commitEncoding` in `.git/config` file, like this:
+
------------
[i18n]
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 96cc89d157..b1c8f86c6e 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -129,10 +129,10 @@ parents) and `--max-parents=-1` (negative numbers denote no upper limit).
adjusting to updated upstream from time to time, and
this option allows you to ignore the individual commits
brought in to your history by such a merge.
-
ifdef::git-log[]
- This option also changes default diff format for merge commits
- to `first-parent`, see `--diff-merges=first-parent` for details.
++
+This option also changes default diff format for merge commits
+to `first-parent`, see `--diff-merges=first-parent` for details.
endif::git-log[]
--not::
@@ -227,6 +227,15 @@ ifdef::git-rev-list[]
test the exit status to see if a range of objects is fully
connected (or not). It is faster than redirecting stdout
to `/dev/null` as the output does not have to be formatted.
+
+--disk-usage::
+ Suppress normal output; instead, print the sum of the bytes used
+ for on-disk storage by the selected commits or objects. This is
+ equivalent to piping the output into `git cat-file
+ --batch-check='%(objectsize:disk)'`, except that it runs much
+ faster (especially with `--use-bitmap-index`). See the `CAVEATS`
+ section in linkgit:git-cat-file[1] for the limitations of what
+ "on-disk storage" means.
endif::git-rev-list[]
--cherry-mark::
diff --git a/Documentation/technical/chunk-format.txt b/Documentation/technical/chunk-format.txt
new file mode 100644
index 0000000000..593614fced
--- /dev/null
+++ b/Documentation/technical/chunk-format.txt
@@ -0,0 +1,116 @@
+Chunk-based file formats
+========================
+
+Some file formats in Git use a common concept of "chunks" to describe
+sections of the file. This allows structured access to a large file by
+scanning a small "table of contents" for the remaining data. This common
+format is used by the `commit-graph` and `multi-pack-index` files. See
+link:technical/pack-format.html[the `multi-pack-index` format] and
+link:technical/commit-graph-format.html[the `commit-graph` format] for
+how they use the chunks to describe structured data.
+
+A chunk-based file format begins with some header information custom to
+that format. That header should include enough information to identify
+the file type, format version, and number of chunks in the file. From this
+information, that file can determine the start of the chunk-based region.
+
+The chunk-based region starts with a table of contents describing where
+each chunk starts and ends. This consists of (C+1) rows of 12 bytes each,
+where C is the number of chunks. Consider the following table:
+
+ | Chunk ID (4 bytes) | Chunk Offset (8 bytes) |
+ |--------------------|------------------------|
+ | ID[0] | OFFSET[0] |
+ | ... | ... |
+ | ID[C] | OFFSET[C] |
+ | 0x0000 | OFFSET[C+1] |
+
+Each row consists of a 4-byte chunk identifier (ID) and an 8-byte offset.
+Each integer is stored in network-byte order.
+
+The chunk identifier `ID[i]` is a label for the data stored within this
+fill from `OFFSET[i]` (inclusive) to `OFFSET[i+1]` (exclusive). Thus, the
+size of the `i`th chunk is equal to the difference between `OFFSET[i+1]`
+and `OFFSET[i]`. This requires that the chunk data appears contiguously
+in the same order as the table of contents.
+
+The final entry in the table of contents must be four zero bytes. This
+confirms that the table of contents is ending and provides the offset for
+the end of the chunk-based data.
+
+Note: The chunk-based format expects that the file contains _at least_ a
+trailing hash after `OFFSET[C+1]`.
+
+Functions for working with chunk-based file formats are declared in
+`chunk-format.h`. Using these methods provide extra checks that assist
+developers when creating new file formats.
+
+Writing chunk-based file formats
+--------------------------------
+
+To write a chunk-based file format, create a `struct chunkfile` by
+calling `init_chunkfile()` and pass a `struct hashfile` pointer. The
+caller is responsible for opening the `hashfile` and writing header
+information so the file format is identifiable before the chunk-based
+format begins.
+
+Then, call `add_chunk()` for each chunk that is intended for write. This
+populates the `chunkfile` with information about the order and size of
+each chunk to write. Provide a `chunk_write_fn` function pointer to
+perform the write of the chunk data upon request.
+
+Call `write_chunkfile()` to write the table of contents to the `hashfile`
+followed by each of the chunks. This will verify that each chunk wrote
+the expected amount of data so the table of contents is correct.
+
+Finally, call `free_chunkfile()` to clear the `struct chunkfile` data. The
+caller is responsible for finalizing the `hashfile` by writing the trailing
+hash and closing the file.
+
+Reading chunk-based file formats
+--------------------------------
+
+To read a chunk-based file format, the file must be opened as a
+memory-mapped region. The chunk-format API expects that the entire file
+is mapped as a contiguous memory region.
+
+Initialize a `struct chunkfile` pointer with `init_chunkfile(NULL)`.
+
+After reading the header information from the beginning of the file,
+including the chunk count, call `read_table_of_contents()` to populate
+the `struct chunkfile` with the list of chunks, their offsets, and their
+sizes.
+
+Extract the data information for each chunk using `pair_chunk()` or
+`read_chunk()`:
+
+* `pair_chunk()` assigns a given pointer with the location inside the
+ memory-mapped file corresponding to that chunk's offset. If the chunk
+ does not exist, then the pointer is not modified.
+
+* `read_chunk()` takes a `chunk_read_fn` function pointer and calls it
+ with the appropriate initial pointer and size information. The function
+ is not called if the chunk does not exist. Use this method to read chunks
+ if you need to perform immediate parsing or if you need to execute logic
+ based on the size of the chunk.
+
+After calling these methods, call `free_chunkfile()` to clear the
+`struct chunkfile` data. This will not close the memory-mapped region.
+Callers are expected to own that data for the timeframe the pointers into
+the region are needed.
+
+Examples
+--------
+
+These file formats use the chunk-format API, and can be used as examples
+for future formats:
+
+* *commit-graph:* see `write_commit_graph_file()` and `parse_commit_graph()`
+ in `commit-graph.c` for how the chunk-format API is used to write and
+ parse the commit-graph file format documented in
+ link:technical/commit-graph-format.html[the commit-graph file format].
+
+* *multi-pack-index:* see `write_midx_internal()` and `load_multi_pack_index()`
+ in `midx.c` for how the chunk-format API is used to write and
+ parse the multi-pack-index file format documented in
+ link:technical/pack-format.html[the multi-pack-index file format].
diff --git a/Documentation/technical/commit-graph-format.txt b/Documentation/technical/commit-graph-format.txt
index b6658eff18..87971c27dd 100644
--- a/Documentation/technical/commit-graph-format.txt
+++ b/Documentation/technical/commit-graph-format.txt
@@ -61,6 +61,9 @@ CHUNK LOOKUP:
the length using the next chunk position if necessary.) Each chunk
ID appears at most once.
+ The CHUNK LOOKUP matches the table of contents from
+ link:technical/chunk-format.html[the chunk-based file format].
+
The remaining data in the body is described one chunk at a time, and
these chunks may be given in any order. Chunks are required unless
otherwise specified.
diff --git a/Documentation/technical/index-format.txt b/Documentation/technical/index-format.txt
index b633482b1b..d363a71c37 100644
--- a/Documentation/technical/index-format.txt
+++ b/Documentation/technical/index-format.txt
@@ -273,14 +273,14 @@ Git index format
- Stat data of $GIT_DIR/info/exclude. See "Index entry" section from
ctime field until "file size".
- - Stat data of core.excludesfile
+ - Stat data of core.excludesFile
- 32-bit dir_flags (see struct dir_struct)
- Hash of $GIT_DIR/info/exclude. A null hash means the file
does not exist.
- - Hash of core.excludesfile. A null hash means the file does
+ - Hash of core.excludesFile. A null hash means the file does
not exist.
- NUL-terminated string of per-dir exclude file name. This usually
diff --git a/Documentation/technical/pack-format.txt b/Documentation/technical/pack-format.txt
index 8833b71c8b..1faa949bf6 100644
--- a/Documentation/technical/pack-format.txt
+++ b/Documentation/technical/pack-format.txt
@@ -336,6 +336,9 @@ CHUNK LOOKUP:
(Chunks are provided in file-order, so you can infer the length
using the next chunk position if necessary.)
+ The CHUNK LOOKUP matches the table of contents from
+ link:technical/chunk-format.html[the chunk-based file format].
+
The remaining data in the body is described one chunk at a time, and
these chunks may be given in any order. Chunks are required unless
otherwise specified.
diff --git a/Documentation/technical/protocol-v2.txt b/Documentation/technical/protocol-v2.txt
index f772d90eaf..a7c806a73e 100644
--- a/Documentation/technical/protocol-v2.txt
+++ b/Documentation/technical/protocol-v2.txt
@@ -33,8 +33,8 @@ In protocol v2 these special packets will have the following semantics:
* '0000' Flush Packet (flush-pkt) - indicates the end of a message
* '0001' Delimiter Packet (delim-pkt) - separates sections of a message
- * '0002' Message Packet (response-end-pkt) - indicates the end of a response
- for stateless connections
+ * '0002' Response End Packet (response-end-pkt) - indicates the end of a
+ response for stateless connections
Initial Client Request
----------------------
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 0327733794..6fb66d3e55 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.30.GIT
+DEF_VER=v2.31.0-rc0
LF='
'
diff --git a/Makefile b/Makefile
index 5a239cac20..dd08b4ced0 100644
--- a/Makefile
+++ b/Makefile
@@ -834,6 +834,7 @@ LIB_OBJS += bundle.o
LIB_OBJS += cache-tree.o
LIB_OBJS += chdir-notify.o
LIB_OBJS += checkout.o
+LIB_OBJS += chunk-format.o
LIB_OBJS += color.o
LIB_OBJS += column.o
LIB_OBJS += combine-diff.o
@@ -863,6 +864,7 @@ LIB_OBJS += diffcore-delta.o
LIB_OBJS += diffcore-order.o
LIB_OBJS += diffcore-pickaxe.o
LIB_OBJS += diffcore-rename.o
+LIB_OBJS += diffcore-rotate.o
LIB_OBJS += dir-iterator.o
LIB_OBJS += dir.o
LIB_OBJS += editor.o
diff --git a/bisect.c b/bisect.c
index 75ea0eb57f..ae48d19acf 100644
--- a/bisect.c
+++ b/bisect.c
@@ -1064,7 +1064,7 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
if (!all) {
fprintf(stderr, _("No testable commit found.\n"
- "Maybe you started with bad path parameters?\n"));
+ "Maybe you started with bad path arguments?\n"));
return BISECT_NO_TESTABLE_COMMIT;
}
diff --git a/builtin/add.c b/builtin/add.c
index a825887c50..ea762a41e3 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -38,19 +38,27 @@ struct update_callback_data {
int add_errors;
};
-static void chmod_pathspec(struct pathspec *pathspec, char flip)
+static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
{
- int i;
+ int i, ret = 0;
for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = active_cache[i];
+ int err;
if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))
continue;
- if (chmod_cache_entry(ce, flip) < 0)
- fprintf(stderr, "cannot chmod %cx '%s'\n", flip, ce->name);
+ if (!show_only)
+ err = chmod_cache_entry(ce, flip);
+ else
+ err = S_ISREG(ce->ce_mode) ? 0 : -1;
+
+ if (err < 0)
+ ret = error(_("cannot chmod %cx '%s'"), flip, ce->name);
}
+
+ return ret;
}
static int fix_unmerged_status(struct diff_filepair *p,
@@ -609,7 +617,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
exit_status |= add_files(&dir, flags);
if (chmod_arg && pathspec.nr)
- chmod_pathspec(&pathspec, chmod_arg[0]);
+ exit_status |= chmod_pathspec(&pathspec, chmod_arg[0], show_only);
unplug_bulk_checkin();
finish:
diff --git a/builtin/blame.c b/builtin/blame.c
index b66e938022..641523ff9a 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -425,13 +425,11 @@ static void setup_default_color_by_age(void)
parse_color_fields("blue,12 month ago,white,1 month ago,red");
}
-static void determine_line_heat(struct blame_entry *ent, const char **dest_color)
+static void determine_line_heat(struct commit_info *ci, const char **dest_color)
{
int i = 0;
- struct commit_info ci;
- get_commit_info(ent->suspect->commit, &ci, 1);
- while (i < colorfield_nr && ci.author_time > colorfield[i].hop)
+ while (i < colorfield_nr && ci->author_time > colorfield[i].hop)
i++;
*dest_color = colorfield[i].col;
@@ -453,7 +451,7 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
cp = blame_nth_line(sb, ent->lno);
if (opt & OUTPUT_SHOW_AGE_WITH_COLOR) {
- determine_line_heat(ent, &default_color);
+ determine_line_heat(&ci, &default_color);
color = default_color;
reset = GIT_COLOR_RESET;
}
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index 4bbfc92dce..023e49e271 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -23,22 +23,35 @@ static struct checkout state = CHECKOUT_INIT;
static void write_tempfile_record(const char *name, const char *prefix)
{
int i;
+ int have_tempname = 0;
if (CHECKOUT_ALL == checkout_stage) {
- for (i = 1; i < 4; i++) {
- if (i > 1)
- putchar(' ');
- if (topath[i][0])
- fputs(topath[i], stdout);
- else
- putchar('.');
+ for (i = 1; i < 4; i++)
+ if (topath[i][0]) {
+ have_tempname = 1;
+ break;
+ }
+
+ if (have_tempname) {
+ for (i = 1; i < 4; i++) {
+ if (i > 1)
+ putchar(' ');
+ if (topath[i][0])
+ fputs(topath[i], stdout);
+ else
+ putchar('.');
+ }
}
- } else
+ } else if (topath[checkout_stage][0]) {
+ have_tempname = 1;
fputs(topath[checkout_stage], stdout);
+ }
- putchar('\t');
- write_name_quoted_relative(name, prefix, stdout,
- nul_term_line ? '\0' : '\n');
+ if (have_tempname) {
+ putchar('\t');
+ write_name_quoted_relative(name, prefix, stdout,
+ nul_term_line ? '\0' : '\n');
+ }
for (i = 0; i < 4; i++) {
topath[i][0] = 0;
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index bb85266102..70103c4095 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -54,6 +54,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
}
if (!rev.diffopt.output_format)
rev.diffopt.output_format = DIFF_FORMAT_RAW;
+ rev.diffopt.rotate_to_strict = 1;
/*
* Make sure there are NO revision (i.e. pending object) parameter,
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index c33d7af478..176fe7ff2b 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -41,6 +41,8 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
if (!rev.diffopt.output_format)
rev.diffopt.output_format = DIFF_FORMAT_RAW;
+ rev.diffopt.rotate_to_strict = 1;
+
/*
* Make sure there is one revision (i.e. pending object),
* and there is no revision filtering parameters.
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 178d12f07f..f33d30d57b 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -156,6 +156,8 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
if (merge_base && opt->pending.nr != 2)
die(_("--merge-base only works with two commits"));
+ opt->diffopt.rotate_to_strict = 1;
+
/*
* NOTE! We expect "a..b" to expand to "^a b" but it is
* perfectly valid for revision range parser to yield "b ^a",
@@ -192,6 +194,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
int saved_nrl = 0;
int saved_dcctc = 0;
+ opt->diffopt.rotate_to_strict = 0;
if (opt->diffopt.detect_rename) {
if (!the_index.cache)
repo_read_index(the_repository);
diff --git a/builtin/diff.c b/builtin/diff.c
index 0f4859abf7..617b9a4101 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -491,6 +491,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
}
rev.diffopt.flags.recursive = 1;
+ rev.diffopt.rotate_to_strict = 1;
setup_diff_pager(&rev.diffopt);
diff --git a/builtin/gc.c b/builtin/gc.c
index 6db9cb39e6..ef7226d7bc 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -1461,11 +1461,23 @@ static int maintenance_run(int argc, const char **argv, const char *prefix)
return maintenance_run_tasks(&opts);
}
+static char *get_maintpath(void)
+{
+ struct strbuf sb = STRBUF_INIT;
+ const char *p = the_repository->worktree ?
+ the_repository->worktree : the_repository->gitdir;
+
+ strbuf_realpath(&sb, p, 1);
+ return strbuf_detach(&sb, NULL);
+}
+
static int maintenance_register(void)
{
+ int rc;
char *config_value;
struct child_process config_set = CHILD_PROCESS_INIT;
struct child_process config_get = CHILD_PROCESS_INIT;
+ char *maintpath = get_maintpath();
/* Disable foreground maintenance */
git_config_set("maintenance.auto", "false");
@@ -1478,40 +1490,44 @@ static int maintenance_register(void)
config_get.git_cmd = 1;
strvec_pushl(&config_get.args, "config", "--global", "--get",
- "--fixed-value", "maintenance.repo",
- the_repository->worktree ? the_repository->worktree
- : the_repository->gitdir,
- NULL);
+ "--fixed-value", "maintenance.repo", maintpath, NULL);
config_get.out = -1;
- if (start_command(&config_get))
- return error(_("failed to run 'git config'"));
+ if (start_command(&config_get)) {
+ rc = error(_("failed to run 'git config'"));
+ goto done;
+ }
/* We already have this value in our config! */
- if (!finish_command(&config_get))
- return 0;
+ if (!finish_command(&config_get)) {
+ rc = 0;
+ goto done;
+ }
config_set.git_cmd = 1;
strvec_pushl(&config_set.args, "config", "--add", "--global", "maintenance.repo",
- the_repository->worktree ? the_repository->worktree
- : the_repository->gitdir,
- NULL);
+ maintpath, NULL);
+
+ rc = run_command(&config_set);
- return run_command(&config_set);
+done:
+ free(maintpath);
+ return rc;
}
static int maintenance_unregister(void)
{
+ int rc;
struct child_process config_unset = CHILD_PROCESS_INIT;
+ char *maintpath = get_maintpath();
config_unset.git_cmd = 1;
strvec_pushl(&config_unset.args, "config", "--global", "--unset",
- "--fixed-value", "maintenance.repo",
- the_repository->worktree ? the_repository->worktree
- : the_repository->gitdir,
- NULL);
+ "--fixed-value", "maintenance.repo", maintpath, NULL);
- return run_command(&config_unset);
+ rc = run_command(&config_unset);
+ free(maintpath);
+ return rc;
}
static const char *get_frequency(enum schedule_priority schedule)
diff --git a/builtin/grep.c b/builtin/grep.c
index e348e6bb32..4e91a253ac 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -506,6 +506,10 @@ static int grep_cache(struct grep_opt *opt,
for (nr = 0; nr < repo->index->cache_nr; nr++) {
const struct cache_entry *ce = repo->index->cache[nr];
+
+ if (!cached && ce_skip_worktree(ce))
+ continue;
+
strbuf_setlen(&name, name_base_len);
strbuf_addstr(&name, ce->name);
@@ -518,8 +522,7 @@ static int grep_cache(struct grep_opt *opt,
* cache entry are identical, even if worktree file has
* been modified, so use cache version instead
*/
- if (cached || (ce->ce_flags & CE_VALID) ||
- ce_skip_worktree(ce)) {
+ if (cached || (ce->ce_flags & CE_VALID)) {
if (ce_stage(ce) || ce_intent_to_add(ce))
continue;
hit |= grep_oid(opt, &ce->oid, name.buf,
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 54f74c4874..bad5748807 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1712,6 +1712,22 @@ static void show_pack_info(int stat_only)
}
}
+static int print_dangling_gitmodules(struct fsck_options *o,
+ const struct object_id *oid,
+ enum object_type object_type,
+ int msg_type, const char *message)
+{
+ /*
+ * NEEDSWORK: Plumb the MSG_ID (from fsck.c) here and use it
+ * instead of relying on this string check.
+ */
+ if (starts_with(message, "gitmodulesMissing")) {
+ printf("%s\n", oid_to_hex(oid));
+ return 0;
+ }
+ return fsck_error_function(o, oid, object_type, msg_type, message);
+}
+
int cmd_index_pack(int argc, const char **argv, const char *prefix)
{
int i, fix_thin_pack = 0, verify = 0, stat_only = 0, rev_index;
@@ -1932,8 +1948,13 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
else
close(input_fd);
- if (do_fsck_object && fsck_finish(&fsck_options))
- die(_("fsck error in pack objects"));
+ if (do_fsck_object) {
+ struct fsck_options fo = fsck_options;
+
+ fo.error_func = print_dangling_gitmodules;
+ if (fsck_finish(&fo))
+ die(_("fsck error in pack objects"));
+ }
free(objects);
strbuf_release(&index_name_buf);
diff --git a/builtin/notes.c b/builtin/notes.c
index 2987c08a2e..08b8914d29 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -373,7 +373,7 @@ static int list(int argc, const char **argv, const char *prefix)
git_notes_list_usage, 0);
if (1 < argc) {
- error(_("too many parameters"));
+ error(_("too many arguments"));
usage_with_options(git_notes_list_usage, options);
}
@@ -428,7 +428,7 @@ static int add(int argc, const char **argv, const char *prefix)
PARSE_OPT_KEEP_ARGV0);
if (2 < argc) {
- error(_("too many parameters"));
+ error(_("too many arguments"));
usage_with_options(git_notes_add_usage, options);
}
@@ -506,7 +506,7 @@ static int copy(int argc, const char **argv, const char *prefix)
if (from_stdin || rewrite_cmd) {
if (argc) {
- error(_("too many parameters"));
+ error(_("too many arguments"));
usage_with_options(git_notes_copy_usage, options);
} else {
return notes_copy_from_stdin(force, rewrite_cmd);
@@ -514,11 +514,11 @@ static int copy(int argc, const char **argv, const char *prefix)
}
if (argc < 1) {
- error(_("too few parameters"));
+ error(_("too few arguments"));
usage_with_options(git_notes_copy_usage, options);
}
if (2 < argc) {
- error(_("too many parameters"));
+ error(_("too many arguments"));
usage_with_options(git_notes_copy_usage, options);
}
@@ -595,7 +595,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
PARSE_OPT_KEEP_ARGV0);
if (2 < argc) {
- error(_("too many parameters"));
+ error(_("too many arguments"));
usage_with_options(usage, options);
}
@@ -662,7 +662,7 @@ static int show(int argc, const char **argv, const char *prefix)
0);
if (1 < argc) {
- error(_("too many parameters"));
+ error(_("too many arguments"));
usage_with_options(git_notes_show_usage, options);
}
@@ -812,7 +812,7 @@ static int merge(int argc, const char **argv, const char *prefix)
error(_("must specify a notes ref to merge"));
usage_with_options(git_notes_merge_usage, options);
} else if (!do_merge && argc) {
- error(_("too many parameters"));
+ error(_("too many arguments"));
usage_with_options(git_notes_merge_usage, options);
}
@@ -960,7 +960,7 @@ static int prune(int argc, const char **argv, const char *prefix)
0);
if (argc) {
- error(_("too many parameters"));
+ error(_("too many arguments"));
usage_with_options(git_notes_prune_usage, options);
}
@@ -982,7 +982,7 @@ static int get_ref(int argc, const char **argv, const char *prefix)
git_notes_get_ref_usage, 0);
if (argc) {
- error(_("too many parameters"));
+ error(_("too many arguments"));
usage_with_options(git_notes_get_ref_usage, options);
}
diff --git a/builtin/push.c b/builtin/push.c
index 03adb58602..194967ed79 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -115,7 +115,7 @@ static void set_refspecs(const char **refs, int nr, const char *repo)
else
refspec_appendf(&rs, "refs/tags/%s", ref);
} else if (deleterefs) {
- if (strchr(ref, ':'))
+ if (strchr(ref, ':') || !*ref)
die(_("--delete only accepts plain target ref names"));
refspec_appendf(&rs, ":%s", ref);
} else if (!strchr(ref, ':')) {
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 840dbd7eb7..de400f9a19 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -102,6 +102,7 @@ struct rebase_options {
int reschedule_failed_exec;
int use_legacy_rebase;
int reapply_cherry_picks;
+ int fork_point;
};
#define REBASE_OPTIONS_INIT { \
@@ -111,7 +112,8 @@ struct rebase_options {
.default_backend = "merge", \
.flags = REBASE_NO_QUIET, \
.git_am_opts = STRVEC_INIT, \
- .git_format_patch_opt = STRBUF_INIT \
+ .git_format_patch_opt = STRBUF_INIT, \
+ .fork_point = -1, \
}
static struct replay_opts get_replay_opts(const struct rebase_options *opts)
@@ -1095,6 +1097,11 @@ static int rebase_config(const char *var, const char *value, void *data)
return 0;
}
+ if (!strcmp(var, "rebase.forkpoint")) {
+ opts->fork_point = git_config_bool(var, value) ? -1 : 0;
+ return 0;
+ }
+
if (!strcmp(var, "rebase.usebuiltin")) {
opts->use_legacy_rebase = !git_config_bool(var, value);
return 0;
@@ -1306,7 +1313,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
const char *gpg_sign = NULL;
struct string_list exec = STRING_LIST_INIT_NODUP;
const char *rebase_merges = NULL;
- int fork_point = -1;
struct string_list strategy_options = STRING_LIST_INIT_NODUP;
struct object_id squash_onto;
char *squash_onto_name = NULL;
@@ -1406,7 +1412,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
N_("mode"),
N_("try to rebase merges instead of skipping them"),
PARSE_OPT_OPTARG, NULL, (intptr_t)""},
- OPT_BOOL(0, "fork-point", &fork_point,
+ OPT_BOOL(0, "fork-point", &options.fork_point,
N_("use 'merge-base --fork-point' to refine upstream")),
OPT_STRING('s', "strategy", &options.strategy,
N_("strategy"), N_("use the given merge strategy")),
@@ -1494,7 +1500,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
die(_("cannot combine '--keep-base' with '--root'"));
}
- if (options.root && fork_point > 0)
+ if (options.root && options.fork_point > 0)
die(_("cannot combine '--root' with '--fork-point'"));
if (action != ACTION_NONE && !in_progress)
@@ -1840,8 +1846,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
NULL);
if (!options.upstream_name)
error_on_missing_default_upstream();
- if (fork_point < 0)
- fork_point = 1;
+ if (options.fork_point < 0)
+ options.fork_point = 1;
} else {
options.upstream_name = argv[0];
argc--;
@@ -1945,7 +1951,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
} else
BUG("unexpected number of arguments left to parse");
- if (fork_point > 0) {
+ if (options.fork_point > 0) {
struct commit *head =
lookup_commit_reference(the_repository,
&options.orig_head);
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index b89ce31bf2..d26040c477 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -2275,7 +2275,7 @@ static const char *unpack(int err_fd, struct shallow_info *si)
status = start_command(&child);
if (status)
return "index-pack fork failed";
- pack_lockfile = index_pack_lockfile(child.out);
+ pack_lockfile = index_pack_lockfile(child.out, NULL);
close(child.out);
status = finish_command(&child);
if (status)
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 25c6c3b38d..b4d8ea0a35 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -80,6 +80,19 @@ static int arg_show_object_names = 1;
#define DEFAULT_OIDSET_SIZE (16*1024)
+static int show_disk_usage;
+static off_t total_disk_usage;
+
+static off_t get_object_disk_usage(struct object *obj)
+{
+ off_t size;
+ struct object_info oi = OBJECT_INFO_INIT;
+ oi.disk_sizep = &size;
+ if (oid_object_info_extended(the_repository, &obj->oid, &oi, 0) < 0)
+ die(_("unable to get disk usage of %s"), oid_to_hex(&obj->oid));
+ return size;
+}
+
static void finish_commit(struct commit *commit);
static void show_commit(struct commit *commit, void *data)
{
@@ -88,6 +101,9 @@ static void show_commit(struct commit *commit, void *data)
display_progress(progress, ++progress_counter);
+ if (show_disk_usage)
+ total_disk_usage += get_object_disk_usage(&commit->object);
+
if (info->flags & REV_LIST_QUIET) {
finish_commit(commit);
return;
@@ -258,6 +274,8 @@ static void show_object(struct object *obj, const char *name, void *cb_data)
if (finish_object(obj, name, cb_data))
return;
display_progress(progress, ++progress_counter);
+ if (show_disk_usage)
+ total_disk_usage += get_object_disk_usage(obj);
if (info->flags & REV_LIST_QUIET)
return;
@@ -452,6 +470,23 @@ static int try_bitmap_traversal(struct rev_info *revs,
return 0;
}
+static int try_bitmap_disk_usage(struct rev_info *revs,
+ struct list_objects_filter_options *filter)
+{
+ struct bitmap_index *bitmap_git;
+
+ if (!show_disk_usage)
+ return -1;
+
+ bitmap_git = prepare_bitmap_walk(revs, filter);
+ if (!bitmap_git)
+ return -1;
+
+ printf("%"PRIuMAX"\n",
+ (uintmax_t)get_disk_usage_from_bitmap(bitmap_git, revs));
+ return 0;
+}
+
int cmd_rev_list(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
@@ -584,6 +619,12 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
continue;
}
+ if (!strcmp(arg, "--disk-usage")) {
+ show_disk_usage = 1;
+ info.flags |= REV_LIST_QUIET;
+ continue;
+ }
+
usage(rev_list_usage);
}
@@ -626,6 +667,8 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (use_bitmap_index) {
if (!try_bitmap_count(&revs, &filter_options))
return 0;
+ if (!try_bitmap_disk_usage(&revs, &filter_options))
+ return 0;
if (!try_bitmap_traversal(&revs, &filter_options))
return 0;
}
@@ -690,5 +733,8 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
printf("%d\n", revs.count_left + revs.count_right);
}
+ if (show_disk_usage)
+ printf("%"PRIuMAX"\n", (uintmax_t)total_disk_usage);
+
return 0;
}
diff --git a/builtin/stash.c b/builtin/stash.c
index 6f2b58f6ab..ba774cce67 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -222,7 +222,7 @@ static int clear_stash(int argc, const char **argv, const char *prefix)
PARSE_OPT_STOP_AT_NON_OPTION);
if (argc)
- return error(_("git stash clear with parameters is "
+ return error(_("git stash clear with arguments is "
"unimplemented"));
return do_clear_stash();
diff --git a/builtin/tag.c b/builtin/tag.c
index 4237dc724c..d403417b56 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -572,7 +572,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
object_ref = argc == 2 ? argv[1] : "HEAD";
if (argc > 2)
- die(_("too many params"));
+ die(_("too many arguments"));
if (get_oid(object_ref, &object))
die(_("Failed to resolve '%s' as a valid ref."), object_ref);
diff --git a/chunk-format.c b/chunk-format.c
new file mode 100644
index 0000000000..da191e59a2
--- /dev/null
+++ b/chunk-format.c
@@ -0,0 +1,179 @@
+#include "cache.h"
+#include "chunk-format.h"
+#include "csum-file.h"
+
+/*
+ * When writing a chunk-based file format, collect the chunks in
+ * an array of chunk_info structs. The size stores the _expected_
+ * amount of data that will be written by write_fn.
+ */
+struct chunk_info {
+ uint32_t id;
+ uint64_t size;
+ chunk_write_fn write_fn;
+
+ const void *start;
+};
+
+struct chunkfile {
+ struct hashfile *f;
+
+ struct chunk_info *chunks;
+ size_t chunks_nr;
+ size_t chunks_alloc;
+};
+
+struct chunkfile *init_chunkfile(struct hashfile *f)
+{
+ struct chunkfile *cf = xcalloc(1, sizeof(*cf));
+ cf->f = f;
+ return cf;
+}
+
+void free_chunkfile(struct chunkfile *cf)
+{
+ if (!cf)
+ return;
+ free(cf->chunks);
+ free(cf);
+}
+
+int get_num_chunks(struct chunkfile *cf)
+{
+ return cf->chunks_nr;
+}
+
+void add_chunk(struct chunkfile *cf,
+ uint32_t id,
+ size_t size,
+ chunk_write_fn fn)
+{
+ ALLOC_GROW(cf->chunks, cf->chunks_nr + 1, cf->chunks_alloc);
+
+ cf->chunks[cf->chunks_nr].id = id;
+ cf->chunks[cf->chunks_nr].write_fn = fn;
+ cf->chunks[cf->chunks_nr].size = size;
+ cf->chunks_nr++;
+}
+
+int write_chunkfile(struct chunkfile *cf, void *data)
+{
+ int i;
+ uint64_t cur_offset = hashfile_total(cf->f);
+
+ /* Add the table of contents to the current offset */
+ cur_offset += (cf->chunks_nr + 1) * CHUNK_TOC_ENTRY_SIZE;
+
+ for (i = 0; i < cf->chunks_nr; i++) {
+ hashwrite_be32(cf->f, cf->chunks[i].id);
+ hashwrite_be64(cf->f, cur_offset);
+
+ cur_offset += cf->chunks[i].size;
+ }
+
+ /* Trailing entry marks the end of the chunks */
+ hashwrite_be32(cf->f, 0);
+ hashwrite_be64(cf->f, cur_offset);
+
+ for (i = 0; i < cf->chunks_nr; i++) {
+ off_t start_offset = hashfile_total(cf->f);
+ int result = cf->chunks[i].write_fn(cf->f, data);
+
+ if (result)
+ return result;
+
+ if (hashfile_total(cf->f) - start_offset != cf->chunks[i].size)
+ BUG("expected to write %"PRId64" bytes to chunk %"PRIx32", but wrote %"PRId64" instead",
+ cf->chunks[i].size, cf->chunks[i].id,
+ hashfile_total(cf->f) - start_offset);
+ }
+
+ return 0;
+}
+
+int read_table_of_contents(struct chunkfile *cf,
+ const unsigned char *mfile,
+ size_t mfile_size,
+ uint64_t toc_offset,
+ int toc_length)
+{
+ int i;
+ uint32_t chunk_id;
+ const unsigned char *table_of_contents = mfile + toc_offset;
+
+ ALLOC_GROW(cf->chunks, toc_length, cf->chunks_alloc);
+
+ while (toc_length--) {
+ uint64_t chunk_offset, next_chunk_offset;
+
+ chunk_id = get_be32(table_of_contents);
+ chunk_offset = get_be64(table_of_contents + 4);
+
+ if (!chunk_id) {
+ error(_("terminating chunk id appears earlier than expected"));
+ return 1;
+ }
+
+ table_of_contents += CHUNK_TOC_ENTRY_SIZE;
+ next_chunk_offset = get_be64(table_of_contents + 4);
+
+ if (next_chunk_offset < chunk_offset ||
+ next_chunk_offset > mfile_size - the_hash_algo->rawsz) {
+ error(_("improper chunk offset(s) %"PRIx64" and %"PRIx64""),
+ chunk_offset, next_chunk_offset);
+ return -1;
+ }
+
+ for (i = 0; i < cf->chunks_nr; i++) {
+ if (cf->chunks[i].id == chunk_id) {
+ error(_("duplicate chunk ID %"PRIx32" found"),
+ chunk_id);
+ return -1;
+ }
+ }
+
+ cf->chunks[cf->chunks_nr].id = chunk_id;
+ cf->chunks[cf->chunks_nr].start = mfile + chunk_offset;
+ cf->chunks[cf->chunks_nr].size = next_chunk_offset - chunk_offset;
+ cf->chunks_nr++;
+ }
+
+ chunk_id = get_be32(table_of_contents);
+ if (chunk_id) {
+ error(_("final chunk has non-zero id %"PRIx32""), chunk_id);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int pair_chunk_fn(const unsigned char *chunk_start,
+ size_t chunk_size,
+ void *data)
+{
+ const unsigned char **p = data;
+ *p = chunk_start;
+ return 0;
+}
+
+int pair_chunk(struct chunkfile *cf,
+ uint32_t chunk_id,
+ const unsigned char **p)
+{
+ return read_chunk(cf, chunk_id, pair_chunk_fn, p);
+}
+
+int read_chunk(struct chunkfile *cf,
+ uint32_t chunk_id,
+ chunk_read_fn fn,
+ void *data)
+{
+ int i;
+
+ for (i = 0; i < cf->chunks_nr; i++) {
+ if (cf->chunks[i].id == chunk_id)
+ return fn(cf->chunks[i].start, cf->chunks[i].size, data);
+ }
+
+ return CHUNK_NOT_FOUND;
+}
diff --git a/chunk-format.h b/chunk-format.h
new file mode 100644
index 0000000000..9ccbe00377
--- /dev/null
+++ b/chunk-format.h
@@ -0,0 +1,68 @@
+#ifndef CHUNK_FORMAT_H
+#define CHUNK_FORMAT_H
+
+#include "git-compat-util.h"
+
+struct hashfile;
+struct chunkfile;
+
+#define CHUNK_TOC_ENTRY_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
+
+/*
+ * Initialize a 'struct chunkfile' for writing _or_ reading a file
+ * with the chunk format.
+ *
+ * If writing a file, supply a non-NULL 'struct hashfile *' that will
+ * be used to write.
+ *
+ * If reading a file, use a NULL 'struct hashfile *' and then call
+ * read_table_of_contents(). Supply the memory-mapped data to the
+ * pair_chunk() or read_chunk() methods, as appropriate.
+ *
+ * DO NOT MIX THESE MODES. Use different 'struct chunkfile' instances
+ * for reading and writing.
+ */
+struct chunkfile *init_chunkfile(struct hashfile *f);
+void free_chunkfile(struct chunkfile *cf);
+int get_num_chunks(struct chunkfile *cf);
+typedef int (*chunk_write_fn)(struct hashfile *f, void *data);
+void add_chunk(struct chunkfile *cf,
+ uint32_t id,
+ size_t size,
+ chunk_write_fn fn);
+int write_chunkfile(struct chunkfile *cf, void *data);
+
+int read_table_of_contents(struct chunkfile *cf,
+ const unsigned char *mfile,
+ size_t mfile_size,
+ uint64_t toc_offset,
+ int toc_length);
+
+#define CHUNK_NOT_FOUND (-2)
+
+/*
+ * Find 'chunk_id' in the given chunkfile and assign the
+ * given pointer to the position in the mmap'd file where
+ * that chunk begins.
+ *
+ * Returns CHUNK_NOT_FOUND if the chunk does not exist.
+ */
+int pair_chunk(struct chunkfile *cf,
+ uint32_t chunk_id,
+ const unsigned char **p);
+
+typedef int (*chunk_read_fn)(const unsigned char *chunk_start,
+ size_t chunk_size, void *data);
+/*
+ * Find 'chunk_id' in the given chunkfile and call the
+ * given chunk_read_fn method with the information for
+ * that chunk.
+ *
+ * Returns CHUNK_NOT_FOUND if the chunk does not exist.
+ */
+int read_chunk(struct chunkfile *cf,
+ uint32_t chunk_id,
+ chunk_read_fn fn,
+ void *data);
+
+#endif
diff --git a/commit-graph.c b/commit-graph.c
index ed31843fa5..ca025ce8eb 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -19,6 +19,7 @@
#include "shallow.h"
#include "json-writer.h"
#include "trace2.h"
+#include "chunk-format.h"
void git_test_write_commit_graph_or_die(void)
{
@@ -44,7 +45,6 @@ void git_test_write_commit_graph_or_die(void)
#define GRAPH_CHUNKID_BLOOMINDEXES 0x42494458 /* "BIDX" */
#define GRAPH_CHUNKID_BLOOMDATA 0x42444154 /* "BDAT" */
#define GRAPH_CHUNKID_BASE 0x42415345 /* "BASE" */
-#define MAX_NUM_CHUNKS 9
#define GRAPH_DATA_WIDTH (the_hash_algo->rawsz + 16)
@@ -59,8 +59,7 @@ void git_test_write_commit_graph_or_die(void)
#define GRAPH_HEADER_SIZE 8
#define GRAPH_FANOUT_SIZE (4 * 256)
-#define GRAPH_CHUNKLOOKUP_WIDTH 12
-#define GRAPH_MIN_SIZE (GRAPH_HEADER_SIZE + 4 * GRAPH_CHUNKLOOKUP_WIDTH \
+#define GRAPH_MIN_SIZE (GRAPH_HEADER_SIZE + 4 * CHUNK_TOC_ENTRY_SIZE \
+ GRAPH_FANOUT_SIZE + the_hash_algo->rawsz)
#define CORRECTED_COMMIT_DATE_OFFSET_OVERFLOW (1ULL << 31)
@@ -215,24 +214,16 @@ static int commit_graph_compatible(struct repository *r)
if (read_replace_refs) {
prepare_replace_object(r);
- if (hashmap_get_size(&r->objects->replace_map->map)) {
- warning(_("repository contains replace objects; "
- "skipping commit-graph"));
+ if (hashmap_get_size(&r->objects->replace_map->map))
return 0;
- }
}
prepare_commit_graft(r);
if (r->parsed_objects &&
- (r->parsed_objects->grafts_nr || r->parsed_objects->substituted_parent)) {
- warning(_("repository contains (deprecated) grafts; "
- "skipping commit-graph"));
+ (r->parsed_objects->grafts_nr || r->parsed_objects->substituted_parent))
return 0;
- }
- if (is_repository_shallow(r)) {
- warning(_("repository is shallow; skipping commit-graph"));
+ if (is_repository_shallow(r))
return 0;
- }
return 1;
}
@@ -306,15 +297,43 @@ static int verify_commit_graph_lite(struct commit_graph *g)
return 0;
}
+static int graph_read_oid_lookup(const unsigned char *chunk_start,
+ size_t chunk_size, void *data)
+{
+ struct commit_graph *g = data;
+ g->chunk_oid_lookup = chunk_start;
+ g->num_commits = chunk_size / g->hash_len;
+ return 0;
+}
+
+static int graph_read_bloom_data(const unsigned char *chunk_start,
+ size_t chunk_size, void *data)
+{
+ struct commit_graph *g = data;
+ uint32_t hash_version;
+ g->chunk_bloom_data = chunk_start;
+ hash_version = get_be32(chunk_start);
+
+ if (hash_version != 1)
+ return 0;
+
+ g->bloom_filter_settings = xmalloc(sizeof(struct bloom_filter_settings));
+ g->bloom_filter_settings->hash_version = hash_version;
+ g->bloom_filter_settings->num_hashes = get_be32(chunk_start + 4);
+ g->bloom_filter_settings->bits_per_entry = get_be32(chunk_start + 8);
+ g->bloom_filter_settings->max_changed_paths = DEFAULT_BLOOM_MAX_CHANGES;
+
+ return 0;
+}
+
struct commit_graph *parse_commit_graph(struct repository *r,
void *graph_map, size_t graph_size)
{
- const unsigned char *data, *chunk_lookup;
- uint32_t i;
+ const unsigned char *data;
struct commit_graph *graph;
- uint64_t next_chunk_offset;
uint32_t graph_signature;
unsigned char graph_version, hash_version;
+ struct chunkfile *cf = NULL;
if (!graph_map)
return NULL;
@@ -355,7 +374,7 @@ struct commit_graph *parse_commit_graph(struct repository *r,
graph->data_len = graph_size;
if (graph_size < GRAPH_HEADER_SIZE +
- (graph->num_chunks + 1) * GRAPH_CHUNKLOOKUP_WIDTH +
+ (graph->num_chunks + 1) * CHUNK_TOC_ENTRY_SIZE +
GRAPH_FANOUT_SIZE + the_hash_algo->rawsz) {
error(_("commit-graph file is too small to hold %u chunks"),
graph->num_chunks);
@@ -363,108 +382,28 @@ struct commit_graph *parse_commit_graph(struct repository *r,
return NULL;
}
- chunk_lookup = data + 8;
- next_chunk_offset = get_be64(chunk_lookup + 4);
- for (i = 0; i < graph->num_chunks; i++) {
- uint32_t chunk_id;
- uint64_t chunk_offset = next_chunk_offset;
- int chunk_repeated = 0;
-
- chunk_id = get_be32(chunk_lookup + 0);
-
- chunk_lookup += GRAPH_CHUNKLOOKUP_WIDTH;
- next_chunk_offset = get_be64(chunk_lookup + 4);
-
- if (chunk_offset > graph_size - the_hash_algo->rawsz) {
- error(_("commit-graph improper chunk offset %08x%08x"), (uint32_t)(chunk_offset >> 32),
- (uint32_t)chunk_offset);
- goto free_and_return;
- }
-
- switch (chunk_id) {
- case GRAPH_CHUNKID_OIDFANOUT:
- if (graph->chunk_oid_fanout)
- chunk_repeated = 1;
- else
- graph->chunk_oid_fanout = (uint32_t*)(data + chunk_offset);
- break;
-
- case GRAPH_CHUNKID_OIDLOOKUP:
- if (graph->chunk_oid_lookup)
- chunk_repeated = 1;
- else {
- graph->chunk_oid_lookup = data + chunk_offset;
- graph->num_commits = (next_chunk_offset - chunk_offset)
- / graph->hash_len;
- }
- break;
-
- case GRAPH_CHUNKID_DATA:
- if (graph->chunk_commit_data)
- chunk_repeated = 1;
- else
- graph->chunk_commit_data = data + chunk_offset;
- break;
-
- case GRAPH_CHUNKID_GENERATION_DATA:
- if (graph->chunk_generation_data)
- chunk_repeated = 1;
- else
- graph->chunk_generation_data = data + chunk_offset;
- break;
-
- case GRAPH_CHUNKID_GENERATION_DATA_OVERFLOW:
- if (graph->chunk_generation_data_overflow)
- chunk_repeated = 1;
- else
- graph->chunk_generation_data_overflow = data + chunk_offset;
- break;
-
- case GRAPH_CHUNKID_EXTRAEDGES:
- if (graph->chunk_extra_edges)
- chunk_repeated = 1;
- else
- graph->chunk_extra_edges = data + chunk_offset;
- break;
-
- case GRAPH_CHUNKID_BASE:
- if (graph->chunk_base_graphs)
- chunk_repeated = 1;
- else
- graph->chunk_base_graphs = data + chunk_offset;
- break;
-
- case GRAPH_CHUNKID_BLOOMINDEXES:
- if (graph->chunk_bloom_indexes)
- chunk_repeated = 1;
- else if (r->settings.commit_graph_read_changed_paths)
- graph->chunk_bloom_indexes = data + chunk_offset;
- break;
+ cf = init_chunkfile(NULL);
- case GRAPH_CHUNKID_BLOOMDATA:
- if (graph->chunk_bloom_data)
- chunk_repeated = 1;
- else if (r->settings.commit_graph_read_changed_paths) {
- uint32_t hash_version;
- graph->chunk_bloom_data = data + chunk_offset;
- hash_version = get_be32(data + chunk_offset);
+ if (read_table_of_contents(cf, graph->data, graph_size,
+ GRAPH_HEADER_SIZE, graph->num_chunks))
+ goto free_and_return;
- if (hash_version != 1)
- break;
+ pair_chunk(cf, GRAPH_CHUNKID_OIDFANOUT,
+ (const unsigned char **)&graph->chunk_oid_fanout);
+ read_chunk(cf, GRAPH_CHUNKID_OIDLOOKUP, graph_read_oid_lookup, graph);
+ pair_chunk(cf, GRAPH_CHUNKID_DATA, &graph->chunk_commit_data);
+ pair_chunk(cf, GRAPH_CHUNKID_EXTRAEDGES, &graph->chunk_extra_edges);
+ pair_chunk(cf, GRAPH_CHUNKID_BASE, &graph->chunk_base_graphs);
+ pair_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA,
+ &graph->chunk_generation_data);
+ pair_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA_OVERFLOW,
+ &graph->chunk_generation_data_overflow);
- graph->bloom_filter_settings = xmalloc(sizeof(struct bloom_filter_settings));
- graph->bloom_filter_settings->hash_version = hash_version;
- graph->bloom_filter_settings->num_hashes = get_be32(data + chunk_offset + 4);
- graph->bloom_filter_settings->bits_per_entry = get_be32(data + chunk_offset + 8);
- graph->bloom_filter_settings->max_changed_paths = DEFAULT_BLOOM_MAX_CHANGES;
- }
- break;
- }
-
- if (chunk_repeated) {
- error(_("commit-graph chunk id %08x appears multiple times"), chunk_id);
- goto free_and_return;
- }
+ if (r->settings.commit_graph_read_changed_paths) {
+ pair_chunk(cf, GRAPH_CHUNKID_BLOOMINDEXES,
+ &graph->chunk_bloom_indexes);
+ read_chunk(cf, GRAPH_CHUNKID_BLOOMDATA,
+ graph_read_bloom_data, graph);
}
if (graph->chunk_bloom_indexes && graph->chunk_bloom_data) {
@@ -481,9 +420,11 @@ struct commit_graph *parse_commit_graph(struct repository *r,
if (verify_commit_graph_lite(graph))
goto free_and_return;
+ free_chunkfile(cf);
return graph;
free_and_return:
+ free_chunkfile(cf);
free(graph->bloom_filter_settings);
free(graph);
return NULL;
@@ -1059,8 +1000,9 @@ struct write_commit_graph_context {
};
static int write_graph_chunk_fanout(struct hashfile *f,
- struct write_commit_graph_context *ctx)
+ void *data)
{
+ struct write_commit_graph_context *ctx = data;
int i, count = 0;
struct commit **list = ctx->commits.list;
@@ -1085,8 +1027,9 @@ static int write_graph_chunk_fanout(struct hashfile *f,
}
static int write_graph_chunk_oids(struct hashfile *f,
- struct write_commit_graph_context *ctx)
+ void *data)
{
+ struct write_commit_graph_context *ctx = data;
struct commit **list = ctx->commits.list;
int count;
for (count = 0; count < ctx->commits.nr; count++, list++) {
@@ -1104,8 +1047,9 @@ static const struct object_id *commit_to_oid(size_t index, const void *table)
}
static int write_graph_chunk_data(struct hashfile *f,
- struct write_commit_graph_context *ctx)
+ void *data)
{
+ struct write_commit_graph_context *ctx = data;
struct commit **list = ctx->commits.list;
struct commit **last = ctx->commits.list + ctx->commits.nr;
uint32_t num_extra_edges = 0;
@@ -1206,8 +1150,9 @@ static int write_graph_chunk_data(struct hashfile *f,
}
static int write_graph_chunk_generation_data(struct hashfile *f,
- struct write_commit_graph_context *ctx)
+ void *data)
{
+ struct write_commit_graph_context *ctx = data;
int i, num_generation_data_overflows = 0;
for (i = 0; i < ctx->commits.nr; i++) {
@@ -1229,8 +1174,9 @@ static int write_graph_chunk_generation_data(struct hashfile *f,
}
static int write_graph_chunk_generation_data_overflow(struct hashfile *f,
- struct write_commit_graph_context *ctx)
+ void *data)
{
+ struct write_commit_graph_context *ctx = data;
int i;
for (i = 0; i < ctx->commits.nr; i++) {
struct commit *c = ctx->commits.list[i];
@@ -1247,8 +1193,9 @@ static int write_graph_chunk_generation_data_overflow(struct hashfile *f,
}
static int write_graph_chunk_extra_edges(struct hashfile *f,
- struct write_commit_graph_context *ctx)
+ void *data)
{
+ struct write_commit_graph_context *ctx = data;
struct commit **list = ctx->commits.list;
struct commit **last = ctx->commits.list + ctx->commits.nr;
struct commit_list *parent;
@@ -1301,8 +1248,9 @@ static int write_graph_chunk_extra_edges(struct hashfile *f,
}
static int write_graph_chunk_bloom_indexes(struct hashfile *f,
- struct write_commit_graph_context *ctx)
+ void *data)
{
+ struct write_commit_graph_context *ctx = data;
struct commit **list = ctx->commits.list;
struct commit **last = ctx->commits.list + ctx->commits.nr;
uint32_t cur_pos = 0;
@@ -1336,8 +1284,9 @@ static void trace2_bloom_filter_settings(struct write_commit_graph_context *ctx)
}
static int write_graph_chunk_bloom_data(struct hashfile *f,
- struct write_commit_graph_context *ctx)
+ void *data)
{
+ struct write_commit_graph_context *ctx = data;
struct commit **list = ctx->commits.list;
struct commit **last = ctx->commits.list + ctx->commits.nr;
@@ -1813,8 +1762,9 @@ static int write_graph_chunk_base_1(struct hashfile *f,
}
static int write_graph_chunk_base(struct hashfile *f,
- struct write_commit_graph_context *ctx)
+ void *data)
{
+ struct write_commit_graph_context *ctx = data;
int num = write_graph_chunk_base_1(f, ctx->new_base_graph);
if (num != ctx->num_commit_graphs_after - 1) {
@@ -1825,27 +1775,16 @@ static int write_graph_chunk_base(struct hashfile *f,
return 0;
}
-typedef int (*chunk_write_fn)(struct hashfile *f,
- struct write_commit_graph_context *ctx);
-
-struct chunk_info {
- uint32_t id;
- uint64_t size;
- chunk_write_fn write_fn;
-};
-
static int write_commit_graph_file(struct write_commit_graph_context *ctx)
{
uint32_t i;
int fd;
struct hashfile *f;
struct lock_file lk = LOCK_INIT;
- struct chunk_info chunks[MAX_NUM_CHUNKS + 1];
const unsigned hashsz = the_hash_algo->rawsz;
struct strbuf progress_title = STRBUF_INIT;
- int num_chunks = 3;
- uint64_t chunk_offset;
struct object_id file_hash;
+ struct chunkfile *cf;
if (ctx->split) {
struct strbuf tmp_file = STRBUF_INIT;
@@ -1891,98 +1830,62 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
f = hashfd(fd, get_lock_file_path(&lk));
}
- chunks[0].id = GRAPH_CHUNKID_OIDFANOUT;
- chunks[0].size = GRAPH_FANOUT_SIZE;
- chunks[0].write_fn = write_graph_chunk_fanout;
- chunks[1].id = GRAPH_CHUNKID_OIDLOOKUP;
- chunks[1].size = hashsz * ctx->commits.nr;
- chunks[1].write_fn = write_graph_chunk_oids;
- chunks[2].id = GRAPH_CHUNKID_DATA;
- chunks[2].size = (hashsz + 16) * ctx->commits.nr;
- chunks[2].write_fn = write_graph_chunk_data;
+ cf = init_chunkfile(f);
+
+ add_chunk(cf, GRAPH_CHUNKID_OIDFANOUT, GRAPH_FANOUT_SIZE,
+ write_graph_chunk_fanout);
+ add_chunk(cf, GRAPH_CHUNKID_OIDLOOKUP, hashsz * ctx->commits.nr,
+ write_graph_chunk_oids);
+ add_chunk(cf, GRAPH_CHUNKID_DATA, (hashsz + 16) * ctx->commits.nr,
+ write_graph_chunk_data);
if (git_env_bool(GIT_TEST_COMMIT_GRAPH_NO_GDAT, 0))
ctx->write_generation_data = 0;
- if (ctx->write_generation_data) {
- chunks[num_chunks].id = GRAPH_CHUNKID_GENERATION_DATA;
- chunks[num_chunks].size = sizeof(uint32_t) * ctx->commits.nr;
- chunks[num_chunks].write_fn = write_graph_chunk_generation_data;
- num_chunks++;
- }
- if (ctx->num_generation_data_overflows) {
- chunks[num_chunks].id = GRAPH_CHUNKID_GENERATION_DATA_OVERFLOW;
- chunks[num_chunks].size = sizeof(timestamp_t) * ctx->num_generation_data_overflows;
- chunks[num_chunks].write_fn = write_graph_chunk_generation_data_overflow;
- num_chunks++;
- }
- if (ctx->num_extra_edges) {
- chunks[num_chunks].id = GRAPH_CHUNKID_EXTRAEDGES;
- chunks[num_chunks].size = 4 * ctx->num_extra_edges;
- chunks[num_chunks].write_fn = write_graph_chunk_extra_edges;
- num_chunks++;
- }
+ if (ctx->write_generation_data)
+ add_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA,
+ sizeof(uint32_t) * ctx->commits.nr,
+ write_graph_chunk_generation_data);
+ if (ctx->num_generation_data_overflows)
+ add_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA_OVERFLOW,
+ sizeof(timestamp_t) * ctx->num_generation_data_overflows,
+ write_graph_chunk_generation_data_overflow);
+ if (ctx->num_extra_edges)
+ add_chunk(cf, GRAPH_CHUNKID_EXTRAEDGES,
+ 4 * ctx->num_extra_edges,
+ write_graph_chunk_extra_edges);
if (ctx->changed_paths) {
- chunks[num_chunks].id = GRAPH_CHUNKID_BLOOMINDEXES;
- chunks[num_chunks].size = sizeof(uint32_t) * ctx->commits.nr;
- chunks[num_chunks].write_fn = write_graph_chunk_bloom_indexes;
- num_chunks++;
- chunks[num_chunks].id = GRAPH_CHUNKID_BLOOMDATA;
- chunks[num_chunks].size = sizeof(uint32_t) * 3
- + ctx->total_bloom_filter_data_size;
- chunks[num_chunks].write_fn = write_graph_chunk_bloom_data;
- num_chunks++;
- }
- if (ctx->num_commit_graphs_after > 1) {
- chunks[num_chunks].id = GRAPH_CHUNKID_BASE;
- chunks[num_chunks].size = hashsz * (ctx->num_commit_graphs_after - 1);
- chunks[num_chunks].write_fn = write_graph_chunk_base;
- num_chunks++;
- }
-
- chunks[num_chunks].id = 0;
- chunks[num_chunks].size = 0;
+ add_chunk(cf, GRAPH_CHUNKID_BLOOMINDEXES,
+ sizeof(uint32_t) * ctx->commits.nr,
+ write_graph_chunk_bloom_indexes);
+ add_chunk(cf, GRAPH_CHUNKID_BLOOMDATA,
+ sizeof(uint32_t) * 3
+ + ctx->total_bloom_filter_data_size,
+ write_graph_chunk_bloom_data);
+ }
+ if (ctx->num_commit_graphs_after > 1)
+ add_chunk(cf, GRAPH_CHUNKID_BASE,
+ hashsz * (ctx->num_commit_graphs_after - 1),
+ write_graph_chunk_base);
hashwrite_be32(f, GRAPH_SIGNATURE);
hashwrite_u8(f, GRAPH_VERSION);
hashwrite_u8(f, oid_version());
- hashwrite_u8(f, num_chunks);
+ hashwrite_u8(f, get_num_chunks(cf));
hashwrite_u8(f, ctx->num_commit_graphs_after - 1);
- chunk_offset = 8 + (num_chunks + 1) * GRAPH_CHUNKLOOKUP_WIDTH;
- for (i = 0; i <= num_chunks; i++) {
- uint32_t chunk_write[3];
-
- chunk_write[0] = htonl(chunks[i].id);
- chunk_write[1] = htonl(chunk_offset >> 32);
- chunk_write[2] = htonl(chunk_offset & 0xffffffff);
- hashwrite(f, chunk_write, 12);
-
- chunk_offset += chunks[i].size;
- }
-
if (ctx->report_progress) {
strbuf_addf(&progress_title,
Q_("Writing out commit graph in %d pass",
"Writing out commit graph in %d passes",
- num_chunks),
- num_chunks);
+ get_num_chunks(cf)),
+ get_num_chunks(cf));
ctx->progress = start_delayed_progress(
progress_title.buf,
- num_chunks * ctx->commits.nr);
+ get_num_chunks(cf) * ctx->commits.nr);
}
- for (i = 0; i < num_chunks; i++) {
- uint64_t start_offset = f->total + f->offset;
-
- if (chunks[i].write_fn(f, ctx))
- return -1;
-
- if (f->total + f->offset != start_offset + chunks[i].size)
- BUG("expected to write %"PRId64" bytes to chunk %"PRIx32", but wrote %"PRId64" instead",
- chunks[i].size, chunks[i].id,
- f->total + f->offset - start_offset);
- }
+ write_chunkfile(cf, ctx);
stop_progress(&ctx->progress);
strbuf_release(&progress_title);
@@ -1999,6 +1902,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
close_commit_graph(ctx->r->objects);
finalize_hashfile(f, file_hash.hash, CSUM_HASH_IN_STREAM | CSUM_FSYNC);
+ free_chunkfile(cf);
if (ctx->split) {
FILE *chainf = fdopen_lock_file(&lk, "w");
@@ -2471,6 +2375,7 @@ cleanup:
free(ctx->graph_name);
free(ctx->commits.list);
oid_array_clear(&ctx->oids);
+ clear_topo_level_slab(&topo_levels);
if (ctx->commit_graph_filenames_after) {
for (i = 0; i < ctx->num_commit_graphs_after; i++) {
diff --git a/commit-reach.c b/commit-reach.c
index e38771ca5a..2ea84d3dc0 100644
--- a/commit-reach.c
+++ b/commit-reach.c
@@ -17,6 +17,25 @@
static const unsigned all_flags = (PARENT1 | PARENT2 | STALE | RESULT);
+static int compare_commits_by_gen(const void *_a, const void *_b)
+{
+ const struct commit *a = *(const struct commit * const *)_a;
+ const struct commit *b = *(const struct commit * const *)_b;
+
+ timestamp_t generation_a = commit_graph_generation(a);
+ timestamp_t generation_b = commit_graph_generation(b);
+
+ if (generation_a < generation_b)
+ return -1;
+ if (generation_a > generation_b)
+ return 1;
+ if (a->date < b->date)
+ return -1;
+ if (a->date > b->date)
+ return 1;
+ return 0;
+}
+
static int queue_has_nonstale(struct prio_queue *queue)
{
int i;
@@ -156,14 +175,9 @@ struct commit_list *get_octopus_merge_bases(struct commit_list *in)
return ret;
}
-static int remove_redundant(struct repository *r, struct commit **array, int cnt)
+static int remove_redundant_no_gen(struct repository *r,
+ struct commit **array, int cnt)
{
- /*
- * Some commit in the array may be an ancestor of
- * another commit. Move such commit to the end of
- * the array, and return the number of commits that
- * are independent from each other.
- */
struct commit **work;
unsigned char *redundant;
int *filled_index;
@@ -209,15 +223,156 @@ static int remove_redundant(struct repository *r, struct commit **array, int cnt
for (i = filled = 0; i < cnt; i++)
if (!redundant[i])
array[filled++] = work[i];
- for (j = filled, i = 0; i < cnt; i++)
- if (redundant[i])
- array[j++] = work[i];
free(work);
free(redundant);
free(filled_index);
return filled;
}
+static int remove_redundant_with_gen(struct repository *r,
+ struct commit **array, int cnt)
+{
+ int i, count_non_stale = 0, count_still_independent = cnt;
+ timestamp_t min_generation = GENERATION_NUMBER_INFINITY;
+ struct commit **walk_start, **sorted;
+ size_t walk_start_nr = 0, walk_start_alloc = cnt;
+ int min_gen_pos = 0;
+
+ /*
+ * Sort the input by generation number, ascending. This allows
+ * us to increase the "min_generation" limit when we discover
+ * the commit with lowest generation is STALE. The index
+ * min_gen_pos points to the current position within 'array'
+ * that is not yet known to be STALE.
+ */
+ ALLOC_ARRAY(sorted, cnt);
+ COPY_ARRAY(sorted, array, cnt);
+ QSORT(sorted, cnt, compare_commits_by_gen);
+ min_generation = commit_graph_generation(sorted[0]);
+
+ ALLOC_ARRAY(walk_start, walk_start_alloc);
+
+ /* Mark all parents of the input as STALE */
+ for (i = 0; i < cnt; i++) {
+ struct commit_list *parents;
+
+ repo_parse_commit(r, array[i]);
+ array[i]->object.flags |= RESULT;
+ parents = array[i]->parents;
+
+ while (parents) {
+ repo_parse_commit(r, parents->item);
+ if (!(parents->item->object.flags & STALE)) {
+ parents->item->object.flags |= STALE;
+ ALLOC_GROW(walk_start, walk_start_nr + 1, walk_start_alloc);
+ walk_start[walk_start_nr++] = parents->item;
+ }
+ parents = parents->next;
+ }
+ }
+
+ QSORT(walk_start, walk_start_nr, compare_commits_by_gen);
+
+ /* remove STALE bit for now to allow walking through parents */
+ for (i = 0; i < walk_start_nr; i++)
+ walk_start[i]->object.flags &= ~STALE;
+
+ /*
+ * Start walking from the highest generation. Hopefully, it will
+ * find all other items during the first-parent walk, and we can
+ * terminate early. Otherwise, we will do the same amount of work
+ * as before.
+ */
+ for (i = walk_start_nr - 1; i >= 0 && count_still_independent > 1; i--) {
+ /* push the STALE bits up to min generation */
+ struct commit_list *stack = NULL;
+
+ commit_list_insert(walk_start[i], &stack);
+ walk_start[i]->object.flags |= STALE;
+
+ while (stack) {
+ struct commit_list *parents;
+ struct commit *c = stack->item;
+
+ repo_parse_commit(r, c);
+
+ if (c->object.flags & RESULT) {
+ c->object.flags &= ~RESULT;
+ if (--count_still_independent <= 1)
+ break;
+ if (oideq(&c->object.oid, &sorted[min_gen_pos]->object.oid)) {
+ while (min_gen_pos < cnt - 1 &&
+ (sorted[min_gen_pos]->object.flags & STALE))
+ min_gen_pos++;
+ min_generation = commit_graph_generation(sorted[min_gen_pos]);
+ }
+ }
+
+ if (commit_graph_generation(c) < min_generation) {
+ pop_commit(&stack);
+ continue;
+ }
+
+ parents = c->parents;
+ while (parents) {
+ if (!(parents->item->object.flags & STALE)) {
+ parents->item->object.flags |= STALE;
+ commit_list_insert(parents->item, &stack);
+ break;
+ }
+ parents = parents->next;
+ }
+
+ /* pop if all parents have been visited already */
+ if (!parents)
+ pop_commit(&stack);
+ }
+ free_commit_list(stack);
+ }
+ free(sorted);
+
+ /* clear result */
+ for (i = 0; i < cnt; i++)
+ array[i]->object.flags &= ~RESULT;
+
+ /* rearrange array */
+ for (i = count_non_stale = 0; i < cnt; i++) {
+ if (!(array[i]->object.flags & STALE))
+ array[count_non_stale++] = array[i];
+ }
+
+ /* clear marks */
+ clear_commit_marks_many(walk_start_nr, walk_start, STALE);
+ free(walk_start);
+
+ return count_non_stale;
+}
+
+static int remove_redundant(struct repository *r, struct commit **array, int cnt)
+{
+ /*
+ * Some commit in the array may be an ancestor of
+ * another commit. Move the independent commits to the
+ * beginning of 'array' and return their number. Callers
+ * should not rely upon the contents of 'array' after
+ * that number.
+ */
+ if (generation_numbers_enabled(r)) {
+ int i;
+
+ /*
+ * If we have a single commit with finite generation
+ * number, then the _with_gen algorithm is preferred.
+ */
+ for (i = 0; i < cnt; i++) {
+ if (commit_graph_generation(array[i]) < GENERATION_NUMBER_INFINITY)
+ return remove_redundant_with_gen(r, array, cnt);
+ }
+ }
+
+ return remove_redundant_no_gen(r, array, cnt);
+}
+
static struct commit_list *get_merge_bases_many_0(struct repository *r,
struct commit *one,
int n,
@@ -561,21 +716,6 @@ int commit_contains(struct ref_filter *filter, struct commit *commit,
return repo_is_descendant_of(the_repository, commit, list);
}
-static int compare_commits_by_gen(const void *_a, const void *_b)
-{
- const struct commit *a = *(const struct commit * const *)_a;
- const struct commit *b = *(const struct commit * const *)_b;
-
- timestamp_t generation_a = commit_graph_generation(a);
- timestamp_t generation_b = commit_graph_generation(b);
-
- if (generation_a < generation_b)
- return -1;
- if (generation_a > generation_b)
- return 1;
- return 0;
-}
-
int can_all_from_reach_with_flag(struct object_array *from,
unsigned int with_flag,
unsigned int assign_flag,
diff --git a/diff.c b/diff.c
index bf2cbf15e7..6956f5e335 100644
--- a/diff.c
+++ b/diff.c
@@ -5348,6 +5348,19 @@ static int diff_opt_word_diff_regex(const struct option *opt,
return 0;
}
+static int diff_opt_rotate_to(const struct option *opt, const char *arg, int unset)
+{
+ struct diff_options *options = opt->value;
+
+ BUG_ON_OPT_NEG(unset);
+ if (!strcmp(opt->long_name, "skip-to"))
+ options->skip_instead_of_rotate = 1;
+ else
+ options->skip_instead_of_rotate = 0;
+ options->rotate_to = arg;
+ return 0;
+}
+
static void prep_parse_options(struct diff_options *options)
{
struct option parseopts[] = {
@@ -5599,6 +5612,12 @@ static void prep_parse_options(struct diff_options *options)
DIFF_PICKAXE_REGEX, PARSE_OPT_NONEG),
OPT_FILENAME('O', NULL, &options->orderfile,
N_("control the order in which files appear in the output")),
+ OPT_CALLBACK_F(0, "rotate-to", options, N_("<path>"),
+ N_("show the change in the specified path first"),
+ PARSE_OPT_NONEG, diff_opt_rotate_to),
+ OPT_CALLBACK_F(0, "skip-to", options, N_("<path>"),
+ N_("skip the output to the specified path"),
+ PARSE_OPT_NONEG, diff_opt_rotate_to),
OPT_CALLBACK_F(0, "find-object", options, N_("<object-id>"),
N_("look for differences that change the number of occurrences of the specified object"),
PARSE_OPT_NONEG, diff_opt_find_object),
@@ -6693,6 +6712,8 @@ void diffcore_std(struct diff_options *options)
diffcore_pickaxe(options);
if (options->orderfile)
diffcore_order(options->orderfile);
+ if (options->rotate_to)
+ diffcore_rotate(options);
if (!options->found_follow)
/* See try_to_follow_renames() in tree-diff.c */
diff_resolve_rename_copy();
diff --git a/diff.h b/diff.h
index 527fb56d85..c8f3faea8a 100644
--- a/diff.h
+++ b/diff.h
@@ -237,6 +237,27 @@ enum diff_submodule_format {
struct diff_options {
const char *orderfile;
+ /*
+ * "--rotate-to=<file>" would start showing at <file> and when
+ * the output reaches the end, wrap around by default.
+ * Setting skip_instead_of_rotate to true stops the output at the
+ * end, effectively discarding the earlier part of the output
+ * before <file>'s diff (this is used to implement the
+ * "--skip-to=<file>" option).
+ *
+ * When rotate_to_strict is set, it is an error if there is no
+ * <file> in the diff. Otherwise, the output starts at the
+ * path that is the same as, or first path that sorts after,
+ * <file>. Because it is unreasonable to require the exact
+ * match for "git log -p --rotate-to=<file>" (i.e. not all
+ * commit would touch that single <file>), "git log" sets it
+ * to false. "git diff" sets it to true to detect an error
+ * in the command line option.
+ */
+ const char *rotate_to;
+ int skip_instead_of_rotate;
+ int rotate_to_strict;
+
/**
* A constant string (can and typically does contain newlines to look for
* a block of text, not just a single line) to filter out the filepairs
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 8fe6c9384b..41558185ae 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -367,6 +367,144 @@ static int find_exact_renames(struct diff_options *options)
return renames;
}
+static const char *get_basename(const char *filename)
+{
+ /*
+ * gitbasename() has to worry about special drives, multiple
+ * directory separator characters, trailing slashes, NULL or
+ * empty strings, etc. We only work on filenames as stored in
+ * git, and thus get to ignore all those complications.
+ */
+ const char *base = strrchr(filename, '/');
+ return base ? base + 1 : filename;
+}
+
+static int find_basename_matches(struct diff_options *options,
+ int minimum_score)
+{
+ /*
+ * When I checked in early 2020, over 76% of file renames in linux
+ * just moved files to a different directory but kept the same
+ * basename. gcc did that with over 64% of renames, gecko did it
+ * with over 79%, and WebKit did it with over 89%.
+ *
+ * Therefore we can bypass the normal exhaustive NxM matrix
+ * comparison of similarities between all potential rename sources
+ * and destinations by instead using file basename as a hint (i.e.
+ * the portion of the filename after the last '/'), checking for
+ * similarity between files with the same basename, and if we find
+ * a pair that are sufficiently similar, record the rename pair and
+ * exclude those two from the NxM matrix.
+ *
+ * This *might* cause us to find a less than optimal pairing (if
+ * there is another file that we are even more similar to but has a
+ * different basename). Given the huge performance advantage
+ * basename matching provides, and given the frequency with which
+ * people use the same basename in real world projects, that's a
+ * trade-off we are willing to accept when doing just rename
+ * detection.
+ *
+ * If someone wants copy detection that implies they are willing to
+ * spend more cycles to find similarities between files, so it may
+ * be less likely that this heuristic is wanted. If someone is
+ * doing break detection, that means they do not want filename
+ * similarity to imply any form of content similiarity, and thus
+ * this heuristic would definitely be incompatible.
+ */
+
+ int i, renames = 0;
+ struct strintmap sources;
+ struct strintmap dests;
+ struct hashmap_iter iter;
+ struct strmap_entry *entry;
+
+ /*
+ * The prefeteching stuff wants to know if it can skip prefetching
+ * blobs that are unmodified...and will then do a little extra work
+ * to verify that the oids are indeed different before prefetching.
+ * Unmodified blobs are only relevant when doing copy detection;
+ * when limiting to rename detection, diffcore_rename[_extended]()
+ * will never be called with unmodified source paths fed to us, so
+ * the extra work necessary to check if rename_src entries are
+ * unmodified would be a small waste.
+ */
+ int skip_unmodified = 0;
+
+ /*
+ * Create maps of basename -> fullname(s) for remaining sources and
+ * dests.
+ */
+ strintmap_init_with_options(&sources, -1, NULL, 0);
+ strintmap_init_with_options(&dests, -1, NULL, 0);
+ for (i = 0; i < rename_src_nr; ++i) {
+ char *filename = rename_src[i].p->one->path;
+ const char *base;
+
+ /* exact renames removed in remove_unneeded_paths_from_src() */
+ assert(!rename_src[i].p->one->rename_used);
+
+ /* Record index within rename_src (i) if basename is unique */
+ base = get_basename(filename);
+ if (strintmap_contains(&sources, base))
+ strintmap_set(&sources, base, -1);
+ else
+ strintmap_set(&sources, base, i);
+ }
+ for (i = 0; i < rename_dst_nr; ++i) {
+ char *filename = rename_dst[i].p->two->path;
+ const char *base;
+
+ if (rename_dst[i].is_rename)
+ continue; /* involved in exact match already. */
+
+ /* Record index within rename_dst (i) if basename is unique */
+ base = get_basename(filename);
+ if (strintmap_contains(&dests, base))
+ strintmap_set(&dests, base, -1);
+ else
+ strintmap_set(&dests, base, i);
+ }
+
+ /* Now look for basename matchups and do similarity estimation */
+ strintmap_for_each_entry(&sources, &iter, entry) {
+ const char *base = entry->key;
+ intptr_t src_index = (intptr_t)entry->value;
+ intptr_t dst_index;
+ if (src_index == -1)
+ continue;
+
+ if (0 <= (dst_index = strintmap_get(&dests, base))) {
+ struct diff_filespec *one, *two;
+ int score;
+
+ /* Estimate the similarity */
+ one = rename_src[src_index].p->one;
+ two = rename_dst[dst_index].p->two;
+ score = estimate_similarity(options->repo, one, two,
+ minimum_score, skip_unmodified);
+
+ /* If sufficiently similar, record as rename pair */
+ if (score < minimum_score)
+ continue;
+ record_rename_pair(dst_index, src_index, score);
+ renames++;
+
+ /*
+ * Found a rename so don't need text anymore; if we
+ * didn't find a rename, the filespec_blob would get
+ * re-used when doing the matrix of comparisons.
+ */
+ diff_free_filespec_blob(one);
+ diff_free_filespec_blob(two);
+ }
+ }
+
+ strintmap_clear(&sources);
+ strintmap_clear(&dests);
+
+ return renames;
+}
+
#define NUM_CANDIDATE_PER_DST 4
static void record_if_better(struct diff_score m[], struct diff_score *o)
{
@@ -454,6 +592,54 @@ static int find_renames(struct diff_score *mx, int dst_cnt, int minimum_score, i
return count;
}
+static void remove_unneeded_paths_from_src(int detecting_copies)
+{
+ int i, new_num_src;
+
+ if (detecting_copies)
+ return; /* nothing to remove */
+ if (break_idx)
+ return; /* culling incompatible with break detection */
+
+ /*
+ * Note on reasons why we cull unneeded sources but not destinations:
+ * 1) Pairings are stored in rename_dst (not rename_src), which we
+ * need to keep around. So, we just can't cull rename_dst even
+ * if we wanted to. But doing so wouldn't help because...
+ *
+ * 2) There is a matrix pairwise comparison that follows the
+ * "Performing inexact rename detection" progress message.
+ * Iterating over the destinations is done in the outer loop,
+ * hence we only iterate over each of those once and we can
+ * easily skip the outer loop early if the destination isn't
+ * relevant. That's only one check per destination path to
+ * skip.
+ *
+ * By contrast, the sources are iterated in the inner loop; if
+ * we check whether a source can be skipped, then we'll be
+ * checking it N separate times, once for each destination.
+ * We don't want to have to iterate over known-not-needed
+ * sources N times each, so avoid that by removing the sources
+ * from rename_src here.
+ */
+ for (i = 0, new_num_src = 0; i < rename_src_nr; i++) {
+ /*
+ * renames are stored in rename_dst, so if a rename has
+ * already been detected using this source, we can just
+ * remove the source knowing rename_dst has its info.
+ */
+ if (rename_src[i].p->one->rename_used)
+ continue;
+
+ if (new_num_src < i)
+ memcpy(&rename_src[new_num_src], &rename_src[i],
+ sizeof(struct diff_rename_src));
+ new_num_src++;
+ }
+
+ rename_src_nr = new_num_src;
+}
+
void diffcore_rename(struct diff_options *options)
{
int detect_rename = options->detect_rename;
@@ -463,9 +649,11 @@ void diffcore_rename(struct diff_options *options)
struct diff_score *mx;
int i, j, rename_count, skip_unmodified = 0;
int num_destinations, dst_cnt;
+ int num_sources, want_copies;
struct progress *progress = NULL;
trace2_region_enter("diff", "setup", options->repo);
+ want_copies = (detect_rename == DIFF_DETECT_COPY);
if (!minimum_score)
minimum_score = DEFAULT_RENAME_SCORE;
@@ -502,7 +690,7 @@ void diffcore_rename(struct diff_options *options)
p->one->rename_used++;
register_rename_src(p);
}
- else if (detect_rename == DIFF_DETECT_COPY) {
+ else if (want_copies) {
/*
* Increment the "rename_used" score by
* one, to indicate ourselves as a user.
@@ -527,17 +715,60 @@ void diffcore_rename(struct diff_options *options)
if (minimum_score == MAX_SCORE)
goto cleanup;
- /*
- * Calculate how many renames are left (but all the source
- * files still remain as options for rename/copies!)
- */
+ num_sources = rename_src_nr;
+
+ if (want_copies || break_idx) {
+ /*
+ * Cull sources:
+ * - remove ones corresponding to exact renames
+ */
+ trace2_region_enter("diff", "cull after exact", options->repo);
+ remove_unneeded_paths_from_src(want_copies);
+ trace2_region_leave("diff", "cull after exact", options->repo);
+ } else {
+ /* Determine minimum score to match basenames */
+ double factor = 0.5;
+ char *basename_factor = getenv("GIT_BASENAME_FACTOR");
+ int min_basename_score;
+
+ if (basename_factor)
+ factor = strtol(basename_factor, NULL, 10)/100.0;
+ assert(factor >= 0.0 && factor <= 1.0);
+ min_basename_score = minimum_score +
+ (int)(factor * (MAX_SCORE - minimum_score));
+
+ /*
+ * Cull sources:
+ * - remove ones involved in renames (found via exact match)
+ */
+ trace2_region_enter("diff", "cull after exact", options->repo);
+ remove_unneeded_paths_from_src(want_copies);
+ trace2_region_leave("diff", "cull after exact", options->repo);
+
+ /* Utilize file basenames to quickly find renames. */
+ trace2_region_enter("diff", "basename matches", options->repo);
+ rename_count += find_basename_matches(options,
+ min_basename_score);
+ trace2_region_leave("diff", "basename matches", options->repo);
+
+ /*
+ * Cull sources, again:
+ * - remove ones involved in renames (found via basenames)
+ */
+ trace2_region_enter("diff", "cull basename", options->repo);
+ remove_unneeded_paths_from_src(want_copies);
+ trace2_region_leave("diff", "cull basename", options->repo);
+ }
+
+ /* Calculate how many rename destinations are left */
num_destinations = (rename_dst_nr - rename_count);
+ num_sources = rename_src_nr; /* rename_src_nr reflects lower number */
/* All done? */
- if (!num_destinations)
+ if (!num_destinations || !num_sources)
goto cleanup;
- switch (too_many_rename_candidates(num_destinations, rename_src_nr,
+ switch (too_many_rename_candidates(num_destinations, num_sources,
options)) {
case 1:
goto cleanup;
@@ -553,7 +784,7 @@ void diffcore_rename(struct diff_options *options)
if (options->show_rename_progress) {
progress = start_delayed_progress(
_("Performing inexact rename detection"),
- (uint64_t)num_destinations * (uint64_t)rename_src_nr);
+ (uint64_t)num_destinations * (uint64_t)num_sources);
}
mx = xcalloc(st_mult(NUM_CANDIDATE_PER_DST, num_destinations),
@@ -563,7 +794,7 @@ void diffcore_rename(struct diff_options *options)
struct diff_score *m;
if (rename_dst[i].is_rename)
- continue; /* dealt with exact match already. */
+ continue; /* exact or basename match already handled */
m = &mx[dst_cnt * NUM_CANDIDATE_PER_DST];
for (j = 0; j < NUM_CANDIDATE_PER_DST; j++)
@@ -573,6 +804,8 @@ void diffcore_rename(struct diff_options *options)
struct diff_filespec *one = rename_src[j].p->one;
struct diff_score this_src;
+ assert(!one->rename_used || want_copies || break_idx);
+
if (skip_unmodified &&
diff_unmodified_pair(rename_src[j].p))
continue;
@@ -594,7 +827,7 @@ void diffcore_rename(struct diff_options *options)
}
dst_cnt++;
display_progress(progress,
- (uint64_t)dst_cnt * (uint64_t)rename_src_nr);
+ (uint64_t)dst_cnt * (uint64_t)num_sources);
}
stop_progress(&progress);
@@ -602,7 +835,7 @@ void diffcore_rename(struct diff_options *options)
STABLE_QSORT(mx, dst_cnt * NUM_CANDIDATE_PER_DST, score_compare);
rename_count += find_renames(mx, dst_cnt, minimum_score, 0);
- if (detect_rename == DIFF_DETECT_COPY)
+ if (want_copies)
rename_count += find_renames(mx, dst_cnt, minimum_score, 1);
free(mx);
trace2_region_leave("diff", "inexact renames", options->repo);
diff --git a/diffcore-rotate.c b/diffcore-rotate.c
new file mode 100644
index 0000000000..445f060ab0
--- /dev/null
+++ b/diffcore-rotate.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021, Google LLC.
+ * Based on diffcore-order.c, which is Copyright (C) 2005, Junio C Hamano
+ */
+#include "cache.h"
+#include "diff.h"
+#include "diffcore.h"
+
+void diffcore_rotate(struct diff_options *opt)
+{
+ struct diff_queue_struct *q = &diff_queued_diff;
+ struct diff_queue_struct outq;
+ int rotate_to, i;
+
+ if (!q->nr)
+ return;
+
+ for (i = 0; i < q->nr; i++) {
+ int cmp = strcmp(opt->rotate_to, q->queue[i]->two->path);
+ if (!cmp)
+ break; /* exact match */
+ if (!opt->rotate_to_strict && cmp < 0)
+ break; /* q->queue[i] is now past the target pathname */
+ }
+
+ if (q->nr <= i) {
+ /* we did not find the specified path */
+ if (opt->rotate_to_strict)
+ die(_("No such path '%s' in the diff"), opt->rotate_to);
+ return;
+ }
+
+ DIFF_QUEUE_CLEAR(&outq);
+ rotate_to = i;
+
+ for (i = rotate_to; i < q->nr; i++)
+ diff_q(&outq, q->queue[i]);
+ for (i = 0; i < rotate_to; i++) {
+ if (opt->skip_instead_of_rotate)
+ diff_free_filepair(q->queue[i]);
+ else
+ diff_q(&outq, q->queue[i]);
+ }
+ free(q->queue);
+ *q = outq;
+}
diff --git a/diffcore.h b/diffcore.h
index d2a63c5c71..c1592bcd01 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -164,6 +164,7 @@ void diffcore_rename(struct diff_options *);
void diffcore_merge_broken(void);
void diffcore_pickaxe(struct diff_options *);
void diffcore_order(const char *orderfile);
+void diffcore_rotate(struct diff_options *);
/* low-level interface to diffcore_order */
struct obj_order {
diff --git a/entry.c b/entry.c
index a0532f1f00..7b9f43716f 100644
--- a/entry.c
+++ b/entry.c
@@ -282,7 +282,7 @@ static int write_entry(struct cache_entry *ce,
new_blob = read_blob_entry(ce, &size);
if (!new_blob)
return error("unable to read sha1 file of %s (%s)",
- path, oid_to_hex(&ce->oid));
+ ce->name, oid_to_hex(&ce->oid));
/*
* We can't make a real symlink; write out a regular file entry
@@ -309,7 +309,7 @@ static int write_entry(struct cache_entry *ce,
new_blob = read_blob_entry(ce, &size);
if (!new_blob)
return error("unable to read sha1 file of %s (%s)",
- path, oid_to_hex(&ce->oid));
+ ce->name, oid_to_hex(&ce->oid));
}
/*
@@ -354,7 +354,7 @@ static int write_entry(struct cache_entry *ce,
case S_IFGITLINK:
if (to_tempfile)
- return error("cannot create temporary submodule %s", path);
+ return error("cannot create temporary submodule %s", ce->name);
if (mkdir(path, 0777) < 0)
return error("cannot create submodule directory %s", path);
sub = submodule_from_ce(ce);
@@ -365,7 +365,7 @@ static int write_entry(struct cache_entry *ce,
break;
default:
- return error("unknown file mode for %s in index", path);
+ return error("unknown file mode for %s in index", ce->name);
}
finish:
diff --git a/fetch-pack.c b/fetch-pack.c
index 1eaedcb5dc..0cb59acc48 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -790,14 +790,36 @@ static void create_promisor_file(const char *keep_name,
strbuf_release(&promisor_name);
}
+static void parse_gitmodules_oids(int fd, struct oidset *gitmodules_oids)
+{
+ int len = the_hash_algo->hexsz + 1; /* hash + NL */
+
+ do {
+ char hex_hash[GIT_MAX_HEXSZ + 1];
+ int read_len = read_in_full(fd, hex_hash, len);
+ struct object_id oid;
+ const char *end;
+
+ if (!read_len)
+ return;
+ if (read_len != len)
+ die("invalid length read %d", read_len);
+ if (parse_oid_hex(hex_hash, &oid, &end) || *end != '\n')
+ die("invalid hash");
+ oidset_insert(gitmodules_oids, &oid);
+ } while (1);
+}
+
/*
- * Pass 1 as "only_packfile" if the pack received is the only pack in this
- * fetch request (that is, if there were no packfile URIs provided).
+ * If packfile URIs were provided, pass a non-NULL pointer to index_pack_args.
+ * The strings to pass as the --index-pack-arg arguments to http-fetch will be
+ * stored there. (It must be freed by the caller.)
*/
static int get_pack(struct fetch_pack_args *args,
int xd[2], struct string_list *pack_lockfiles,
- int only_packfile,
- struct ref **sought, int nr_sought)
+ struct strvec *index_pack_args,
+ struct ref **sought, int nr_sought,
+ struct oidset *gitmodules_oids)
{
struct async demux;
int do_keep = args->keep_pack;
@@ -805,6 +827,7 @@ static int get_pack(struct fetch_pack_args *args,
struct pack_header header;
int pass_header = 0;
struct child_process cmd = CHILD_PROCESS_INIT;
+ int fsck_objects = 0;
int ret;
memset(&demux, 0, sizeof(demux));
@@ -839,8 +862,15 @@ static int get_pack(struct fetch_pack_args *args,
strvec_push(&cmd.args, alternate_shallow_file);
}
- if (do_keep || args->from_promisor) {
- if (pack_lockfiles)
+ if (fetch_fsck_objects >= 0
+ ? fetch_fsck_objects
+ : transfer_fsck_objects >= 0
+ ? transfer_fsck_objects
+ : 0)
+ fsck_objects = 1;
+
+ if (do_keep || args->from_promisor || index_pack_args || fsck_objects) {
+ if (pack_lockfiles || fsck_objects)
cmd.out = -1;
cmd_name = "index-pack";
strvec_push(&cmd.args, cmd_name);
@@ -857,7 +887,7 @@ static int get_pack(struct fetch_pack_args *args,
"--keep=fetch-pack %"PRIuMAX " on %s",
(uintmax_t)getpid(), hostname);
}
- if (only_packfile && args->check_self_contained_and_connected)
+ if (!index_pack_args && args->check_self_contained_and_connected)
strvec_push(&cmd.args, "--check-self-contained-and-connected");
else
/*
@@ -890,12 +920,8 @@ static int get_pack(struct fetch_pack_args *args,
strvec_pushf(&cmd.args, "--pack_header=%"PRIu32",%"PRIu32,
ntohl(header.hdr_version),
ntohl(header.hdr_entries));
- if (fetch_fsck_objects >= 0
- ? fetch_fsck_objects
- : transfer_fsck_objects >= 0
- ? transfer_fsck_objects
- : 0) {
- if (args->from_promisor || !only_packfile)
+ if (fsck_objects) {
+ if (args->from_promisor || index_pack_args)
/*
* We cannot use --strict in index-pack because it
* checks both broken objects and links, but we only
@@ -907,14 +933,26 @@ static int get_pack(struct fetch_pack_args *args,
fsck_msg_types.buf);
}
+ if (index_pack_args) {
+ int i;
+
+ for (i = 0; i < cmd.args.nr; i++)
+ strvec_push(index_pack_args, cmd.args.v[i]);
+ }
+
cmd.in = demux.out;
cmd.git_cmd = 1;
if (start_command(&cmd))
die(_("fetch-pack: unable to fork off %s"), cmd_name);
- if (do_keep && pack_lockfiles) {
- char *pack_lockfile = index_pack_lockfile(cmd.out);
+ if (do_keep && (pack_lockfiles || fsck_objects)) {
+ int is_well_formed;
+ char *pack_lockfile = index_pack_lockfile(cmd.out, &is_well_formed);
+
+ if (!is_well_formed)
+ die(_("fetch-pack: invalid index-pack output"));
if (pack_lockfile)
string_list_append_nodup(pack_lockfiles, pack_lockfile);
+ parse_gitmodules_oids(cmd.out, gitmodules_oids);
close(cmd.out);
}
@@ -949,6 +987,22 @@ static int cmp_ref_by_name(const void *a_, const void *b_)
return strcmp(a->name, b->name);
}
+static void fsck_gitmodules_oids(struct oidset *gitmodules_oids)
+{
+ struct oidset_iter iter;
+ const struct object_id *oid;
+ struct fsck_options fo = FSCK_OPTIONS_STRICT;
+
+ if (!oidset_size(gitmodules_oids))
+ return;
+
+ oidset_iter_init(gitmodules_oids, &iter);
+ while ((oid = oidset_iter_next(&iter)))
+ register_found_gitmodules(oid);
+ if (fsck_finish(&fo))
+ die("fsck failed");
+}
+
static struct ref *do_fetch_pack(struct fetch_pack_args *args,
int fd[2],
const struct ref *orig_ref,
@@ -963,6 +1017,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
int agent_len;
struct fetch_negotiator negotiator_alloc;
struct fetch_negotiator *negotiator;
+ struct oidset gitmodules_oids = OIDSET_INIT;
negotiator = &negotiator_alloc;
fetch_negotiator_init(r, negotiator);
@@ -1078,8 +1133,10 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
alternate_shallow_file = setup_temporary_shallow(si->shallow);
else
alternate_shallow_file = NULL;
- if (get_pack(args, fd, pack_lockfiles, 1, sought, nr_sought))
+ if (get_pack(args, fd, pack_lockfiles, NULL, sought, nr_sought,
+ &gitmodules_oids))
die(_("git fetch-pack: fetch failed."));
+ fsck_gitmodules_oids(&gitmodules_oids);
all_done:
if (negotiator)
@@ -1529,6 +1586,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
int seen_ack = 0;
struct string_list packfile_uris = STRING_LIST_INIT_DUP;
int i;
+ struct strvec index_pack_args = STRVEC_INIT;
+ struct oidset gitmodules_oids = OIDSET_INIT;
negotiator = &negotiator_alloc;
fetch_negotiator_init(r, negotiator);
@@ -1618,7 +1677,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
receive_packfile_uris(&reader, &packfile_uris);
process_section_header(&reader, "packfile", 0);
if (get_pack(args, fd, pack_lockfiles,
- !packfile_uris.nr, sought, nr_sought))
+ packfile_uris.nr ? &index_pack_args : NULL,
+ sought, nr_sought, &gitmodules_oids))
die(_("git fetch-pack: fetch failed."));
do_check_stateless_delimiter(args, &reader);
@@ -1630,6 +1690,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
}
for (i = 0; i < packfile_uris.nr; i++) {
+ int j;
struct child_process cmd = CHILD_PROCESS_INIT;
char packname[GIT_MAX_HEXSZ + 1];
const char *uri = packfile_uris.items[i].string +
@@ -1639,6 +1700,9 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
strvec_pushf(&cmd.args, "--packfile=%.*s",
(int) the_hash_algo->hexsz,
packfile_uris.items[i].string);
+ for (j = 0; j < index_pack_args.nr; j++)
+ strvec_pushf(&cmd.args, "--index-pack-arg=%s",
+ index_pack_args.v[j]);
strvec_push(&cmd.args, uri);
cmd.git_cmd = 1;
cmd.no_stdin = 1;
@@ -1657,6 +1721,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
packname[the_hash_algo->hexsz] = '\0';
+ parse_gitmodules_oids(cmd.out, &gitmodules_oids);
+
close(cmd.out);
if (finish_command(&cmd))
@@ -1674,6 +1740,9 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
packname));
}
string_list_clear(&packfile_uris, 0);
+ strvec_clear(&index_pack_args);
+
+ fsck_gitmodules_oids(&gitmodules_oids);
if (negotiator)
negotiator->release(negotiator);
diff --git a/fsck.c b/fsck.c
index 71134fdefa..e3030f3b35 100644
--- a/fsck.c
+++ b/fsck.c
@@ -1276,6 +1276,11 @@ int fsck_error_function(struct fsck_options *o,
return 1;
}
+void register_found_gitmodules(const struct object_id *oid)
+{
+ oidset_insert(&gitmodules_found, oid);
+}
+
int fsck_finish(struct fsck_options *options)
{
int ret = 0;
diff --git a/fsck.h b/fsck.h
index 423c467feb..733378f126 100644
--- a/fsck.h
+++ b/fsck.h
@@ -62,6 +62,8 @@ int fsck_walk(struct object *obj, void *data, struct fsck_options *options);
int fsck_object(struct object *obj, void *data, unsigned long size,
struct fsck_options *options);
+void register_found_gitmodules(const struct object_id *oid);
+
/*
* fsck a tag, and pass info about it back to the caller. This is
* exposed fsck_object() internals for git-mktag(1).
diff --git a/fsmonitor.c b/fsmonitor.c
index fe9e9d7baf..23f8a0c97e 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -90,7 +90,11 @@ int read_fsmonitor_extension(struct index_state *istate, const void *data,
if (!istate->split_index)
assert_index_minimum(istate, istate->fsmonitor_dirty->bit_size);
- trace_printf_key(&trace_fsmonitor, "read fsmonitor extension successful");
+ trace2_data_string("index", NULL, "extension/fsmn/read/token",
+ istate->fsmonitor_last_update);
+ trace_printf_key(&trace_fsmonitor,
+ "read fsmonitor extension successful '%s'",
+ istate->fsmonitor_last_update);
return 0;
}
@@ -134,7 +138,11 @@ void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)
put_be32(&ewah_size, sb->len - ewah_start);
memcpy(sb->buf + fixup, &ewah_size, sizeof(uint32_t));
- trace_printf_key(&trace_fsmonitor, "write fsmonitor extension successful");
+ trace2_data_string("index", NULL, "extension/fsmn/write/token",
+ istate->fsmonitor_last_update);
+ trace_printf_key(&trace_fsmonitor,
+ "write fsmonitor extension successful '%s'",
+ istate->fsmonitor_last_update);
}
/*
@@ -143,6 +151,7 @@ void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)
static int query_fsmonitor(int version, const char *last_update, struct strbuf *query_result)
{
struct child_process cp = CHILD_PROCESS_INIT;
+ int result;
if (!core_fsmonitor)
return -1;
@@ -153,16 +162,63 @@ static int query_fsmonitor(int version, const char *last_update, struct strbuf *
cp.use_shell = 1;
cp.dir = get_git_work_tree();
- return capture_command(&cp, query_result, 1024);
+ trace2_region_enter("fsm_hook", "query", NULL);
+
+ result = capture_command(&cp, query_result, 1024);
+
+ if (result)
+ trace2_data_intmax("fsm_hook", NULL, "query/failed", result);
+ else {
+ trace2_data_intmax("fsm_hook", NULL, "query/response-length",
+ query_result->len);
+
+ if (fsmonitor_is_trivial_response(query_result))
+ trace2_data_intmax("fsm_hook", NULL,
+ "query/trivial-response", 1);
+ }
+
+ trace2_region_leave("fsm_hook", "query", NULL);
+
+ return result;
}
-static void fsmonitor_refresh_callback(struct index_state *istate, const char *name)
+int fsmonitor_is_trivial_response(const struct strbuf *query_result)
{
- int pos = index_name_pos(istate, name, strlen(name));
+ static char trivial_response[3] = { '\0', '/', '\0' };
+ int is_trivial = !memcmp(trivial_response,
+ &query_result->buf[query_result->len - 3], 3);
+
+ return is_trivial;
+}
+
+static void fsmonitor_refresh_callback(struct index_state *istate, char *name)
+{
+ int i, len = strlen(name);
+ if (name[len - 1] == '/') {
+
+ /*
+ * TODO We should binary search to find the first path with
+ * TODO this directory prefix. Then linearly update entries
+ * TODO while the prefix matches. Taking care to search without
+ * TODO the trailing slash -- because '/' sorts after a few
+ * TODO interesting special chars, like '.' and ' '.
+ */
+
+ /* Mark all entries for the folder invalid */
+ for (i = 0; i < istate->cache_nr; i++) {
+ if (istate->cache[i]->ce_flags & CE_FSMONITOR_VALID &&
+ starts_with(istate->cache[i]->name, name))
+ istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
+ }
+ /* Need to remove the / from the path for the untracked cache */
+ name[len - 1] = '\0';
+ } else {
+ int pos = index_name_pos(istate, name, strlen(name));
- if (pos >= 0) {
- struct cache_entry *ce = istate->cache[pos];
- ce->ce_flags &= ~CE_FSMONITOR_VALID;
+ if (pos >= 0) {
+ struct cache_entry *ce = istate->cache[pos];
+ ce->ce_flags &= ~CE_FSMONITOR_VALID;
+ }
}
/*
@@ -288,16 +344,45 @@ void refresh_fsmonitor(struct index_state *istate)
istate->fsmonitor_last_update = strbuf_detach(&last_update_token, NULL);
}
+/*
+ * The caller wants to turn on FSMonitor. And when the caller writes
+ * the index to disk, a FSMonitor extension should be included. This
+ * requires that `istate->fsmonitor_last_update` not be NULL. But we
+ * have not actually talked to a FSMonitor process yet, so we don't
+ * have an initial value for this field.
+ *
+ * For a protocol V1 FSMonitor process, this field is a formatted
+ * "nanoseconds since epoch" field. However, for a protocol V2
+ * FSMonitor process, this field is an opaque token.
+ *
+ * Historically, `add_fsmonitor()` has initialized this field to the
+ * current time for protocol V1 processes. There are lots of race
+ * conditions here, but that code has shipped...
+ *
+ * The only true solution is to use a V2 FSMonitor and get a current
+ * or default token value (that it understands), but we cannot do that
+ * until we have actually talked to an instance of the FSMonitor process
+ * (but the protocol requires that we send a token first...).
+ *
+ * For simplicity, just initialize like we have a V1 process and require
+ * that V2 processes adapt.
+ */
+static void initialize_fsmonitor_last_update(struct index_state *istate)
+{
+ struct strbuf last_update = STRBUF_INIT;
+
+ strbuf_addf(&last_update, "%"PRIu64"", getnanotime());
+ istate->fsmonitor_last_update = strbuf_detach(&last_update, NULL);
+}
+
void add_fsmonitor(struct index_state *istate)
{
unsigned int i;
- struct strbuf last_update = STRBUF_INIT;
if (!istate->fsmonitor_last_update) {
trace_printf_key(&trace_fsmonitor, "add fsmonitor");
istate->cache_changed |= FSMONITOR_CHANGED;
- strbuf_addf(&last_update, "%"PRIu64"", getnanotime());
- istate->fsmonitor_last_update = strbuf_detach(&last_update, NULL);
+ initialize_fsmonitor_last_update(istate);
/* reset the fsmonitor state */
for (i = 0; i < istate->cache_nr; i++)
diff --git a/fsmonitor.h b/fsmonitor.h
index 739318ab6d..7f1794b90b 100644
--- a/fsmonitor.h
+++ b/fsmonitor.h
@@ -45,6 +45,11 @@ void tweak_fsmonitor(struct index_state *istate);
void refresh_fsmonitor(struct index_state *istate);
/*
+ * Does the received result contain the "trivial" response?
+ */
+int fsmonitor_is_trivial_response(const struct strbuf *query_result);
+
+/*
* Set the given cache entries CE_FSMONITOR_VALID bit. This should be
* called any time the cache entry has been updated to reflect the
* current state of the file on disk.
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 201524c34e..236bc4e61d 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -875,6 +875,7 @@ set default_config(merge.summary) false
set default_config(merge.verbosity) 2
set default_config(user.name) {}
set default_config(user.email) {}
+set default_config(core.commentchar) "#"
set default_config(gui.encoding) [encoding system]
set default_config(gui.matchtrackingbranch) false
@@ -3436,6 +3437,10 @@ proc trace_commit_type {varname args} {
merge {set txt [mc "Merge Commit Message:"]}
* {set txt [mc "Commit Message:"]}
}
+
+ set comment_char [get_config core.commentchar]
+ set txt [string cat $txt \
+ [mc " (Lines starting with '$comment_char' will be ignored)"]]
$ui_coml conf -text $txt
}
trace add variable commit_type write trace_commit_type
diff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl
index 11379f8ad3..23d67d4651 100644
--- a/git-gui/lib/commit.tcl
+++ b/git-gui/lib/commit.tcl
@@ -141,6 +141,20 @@ proc setup_commit_encoding {msg_wt {quiet 0}} {
}
}
+proc strip_msg {msg} {
+ set cmd [concat [list | ] [_git_cmd stripspace] --strip-comments]
+ _trace_exec $cmd
+ set fd [open $cmd r+]
+ fconfigure $fd -translation binary -encoding utf-8
+
+ puts -nonewline $fd $msg
+ close $fd w
+ set result [read $fd]
+ close $fd
+
+ return $result
+}
+
proc commit_tree {} {
global HEAD commit_type file_states ui_comm repo_config
global pch_error
@@ -207,8 +221,8 @@ You must stage at least 1 file before you can commit.
# -- A message is required.
#
- set msg [string trim [$ui_comm get 1.0 end]]
- regsub -all -line {[ \t\r]+$} $msg {} msg
+ set msg [strip_msg [$ui_comm get 1.0 end]]
+
if {$msg eq {}} {
error_popup [mc "Please supply a commit message.
diff --git a/git-gui/po/ru.po b/git-gui/po/ru.po
index 161ee1ac8c..7aebaf809d 100644
--- a/git-gui/po/ru.po
+++ b/git-gui/po/ru.po
@@ -331,7 +331,7 @@ msgstr "Добавить изменённые файлы в индекс"
#: git-gui.sh:2936
msgid "Unstage From Commit"
-msgstr "Убрать из издекса"
+msgstr "Убрать из индекса"
#: git-gui.sh:2942 lib/index.tcl:521
msgid "Revert Changes"
diff --git a/http-fetch.c b/http-fetch.c
index c4ccc5fea9..fa642462a9 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -3,6 +3,7 @@
#include "exec-cmd.h"
#include "http.h"
#include "walker.h"
+#include "strvec.h"
static const char http_fetch_usage[] = "git http-fetch "
"[-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin | --packfile=hash | commit-id] url";
@@ -44,7 +45,8 @@ static int fetch_using_walker(const char *raw_url, int get_verbosely,
}
static void fetch_single_packfile(struct object_id *packfile_hash,
- const char *url) {
+ const char *url,
+ const char **index_pack_args) {
struct http_pack_request *preq;
struct slot_results results;
int ret;
@@ -55,7 +57,8 @@ static void fetch_single_packfile(struct object_id *packfile_hash,
if (preq == NULL)
die("couldn't create http pack request");
preq->slot->results = &results;
- preq->generate_keep = 1;
+ preq->index_pack_args = index_pack_args;
+ preq->preserve_index_pack_stdout = 1;
if (start_active_slot(preq->slot)) {
run_active_slot(preq->slot);
@@ -86,6 +89,7 @@ int cmd_main(int argc, const char **argv)
int packfile = 0;
int nongit;
struct object_id packfile_hash;
+ struct strvec index_pack_args = STRVEC_INIT;
setup_git_directory_gently(&nongit);
@@ -112,6 +116,8 @@ int cmd_main(int argc, const char **argv)
packfile = 1;
if (parse_oid_hex(p, &packfile_hash, &end) || *end)
die(_("argument to --packfile must be a valid hash (got '%s')"), p);
+ } else if (skip_prefix(argv[arg], "--index-pack-arg=", &p)) {
+ strvec_push(&index_pack_args, p);
}
arg++;
}
@@ -124,10 +130,18 @@ int cmd_main(int argc, const char **argv)
git_config(git_default_config, NULL);
if (packfile) {
- fetch_single_packfile(&packfile_hash, argv[arg]);
+ if (!index_pack_args.nr)
+ die(_("--packfile requires --index-pack-args"));
+
+ fetch_single_packfile(&packfile_hash, argv[arg],
+ index_pack_args.v);
+
return 0;
}
+ if (index_pack_args.nr)
+ die(_("--index-pack-args can only be used with --packfile"));
+
if (commits_on_stdin) {
commits = walker_targets_stdin(&commit_id, &write_ref);
} else {
diff --git a/http.c b/http.c
index 8b23a546af..f8ea28bb2e 100644
--- a/http.c
+++ b/http.c
@@ -2259,6 +2259,9 @@ void release_http_pack_request(struct http_pack_request *preq)
free(preq);
}
+static const char *default_index_pack_args[] =
+ {"index-pack", "--stdin", NULL};
+
int finish_http_pack_request(struct http_pack_request *preq)
{
struct child_process ip = CHILD_PROCESS_INIT;
@@ -2270,17 +2273,15 @@ int finish_http_pack_request(struct http_pack_request *preq)
tmpfile_fd = xopen(preq->tmpfile.buf, O_RDONLY);
- strvec_push(&ip.args, "index-pack");
- strvec_push(&ip.args, "--stdin");
ip.git_cmd = 1;
ip.in = tmpfile_fd;
- if (preq->generate_keep) {
- strvec_pushf(&ip.args, "--keep=git %"PRIuMAX,
- (uintmax_t)getpid());
+ ip.argv = preq->index_pack_args ? preq->index_pack_args
+ : default_index_pack_args;
+
+ if (preq->preserve_index_pack_stdout)
ip.out = 0;
- } else {
+ else
ip.no_stdout = 1;
- }
if (run_command(&ip)) {
ret = -1;
diff --git a/http.h b/http.h
index 5de792ef3f..bf3d1270ad 100644
--- a/http.h
+++ b/http.h
@@ -218,12 +218,12 @@ struct http_pack_request {
char *url;
/*
- * If this is true, finish_http_pack_request() will pass "--keep" to
- * index-pack, resulting in the creation of a keep file, and will not
- * suppress its stdout (that is, the "keep\t<hash>\n" line will be
- * printed to stdout).
+ * index-pack command to run. Must be terminated by NULL.
+ *
+ * If NULL, defaults to {"index-pack", "--stdin", NULL}.
*/
- unsigned generate_keep : 1;
+ const char **index_pack_args;
+ unsigned preserve_index_pack_stdout : 1;
FILE *packfile;
struct strbuf tmpfile;
diff --git a/merge-ort.c b/merge-ort.c
index 931b91438c..603d30c521 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -535,6 +535,23 @@ static void setup_path_info(struct merge_options *opt,
result->util = mi;
}
+static void add_pair(struct merge_options *opt,
+ struct name_entry *names,
+ const char *pathname,
+ unsigned side,
+ unsigned is_add /* if false, is_delete */)
+{
+ struct diff_filespec *one, *two;
+ struct rename_info *renames = &opt->priv->renames;
+ int names_idx = is_add ? side : 0;
+
+ one = alloc_filespec(pathname);
+ two = alloc_filespec(pathname);
+ fill_filespec(is_add ? two : one,
+ &names[names_idx].oid, 1, names[names_idx].mode);
+ diff_queue(&renames->pairs[side], one, two);
+}
+
static void collect_rename_info(struct merge_options *opt,
struct name_entry *names,
const char *dirname,
@@ -544,6 +561,7 @@ static void collect_rename_info(struct merge_options *opt,
unsigned match_mask)
{
struct rename_info *renames = &opt->priv->renames;
+ unsigned side;
/* Update dirs_removed, as needed */
if (dirmask == 1 || dirmask == 3 || dirmask == 5) {
@@ -554,6 +572,21 @@ static void collect_rename_info(struct merge_options *opt,
if (sides & 2)
strset_add(&renames->dirs_removed[2], fullname);
}
+
+ if (filemask == 0 || filemask == 7)
+ return;
+
+ for (side = MERGE_SIDE1; side <= MERGE_SIDE2; ++side) {
+ unsigned side_mask = (1 << side);
+
+ /* Check for deletion on side */
+ if ((filemask & 1) && !(filemask & side_mask))
+ add_pair(opt, names, fullname, side, 0 /* delete */);
+
+ /* Check for addition on side */
+ if (!(filemask & 1) && (filemask & side_mask))
+ add_pair(opt, names, fullname, side, 1 /* add */);
+ }
}
static int collect_merge_info_callback(int n,
@@ -2079,6 +2112,27 @@ static int process_renames(struct merge_options *opt,
return clean_merge;
}
+static void resolve_diffpair_statuses(struct diff_queue_struct *q)
+{
+ /*
+ * A simplified version of diff_resolve_rename_copy(); would probably
+ * just use that function but it's static...
+ */
+ int i;
+ struct diff_filepair *p;
+
+ for (i = 0; i < q->nr; ++i) {
+ p = q->queue[i];
+ p->status = 0; /* undecided */
+ if (!DIFF_FILE_VALID(p->one))
+ p->status = DIFF_STATUS_ADDED;
+ else if (!DIFF_FILE_VALID(p->two))
+ p->status = DIFF_STATUS_DELETED;
+ else if (DIFF_PAIR_RENAME(p))
+ p->status = DIFF_STATUS_RENAMED;
+ }
+}
+
static int compare_pairs(const void *a_, const void *b_)
{
const struct diff_filepair *a = *((const struct diff_filepair **)a_);
@@ -2089,8 +2143,6 @@ static int compare_pairs(const void *a_, const void *b_)
/* Call diffcore_rename() to compute which files have changed on given side */
static void detect_regular_renames(struct merge_options *opt,
- struct tree *merge_base,
- struct tree *side,
unsigned side_index)
{
struct diff_options diff_opts;
@@ -2108,11 +2160,11 @@ static void detect_regular_renames(struct merge_options *opt,
diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
diff_setup_done(&diff_opts);
+ diff_queued_diff = renames->pairs[side_index];
trace2_region_enter("diff", "diffcore_rename", opt->repo);
- diff_tree_oid(&merge_base->object.oid, &side->object.oid, "",
- &diff_opts);
- diffcore_std(&diff_opts);
+ diffcore_rename(&diff_opts);
trace2_region_leave("diff", "diffcore_rename", opt->repo);
+ resolve_diffpair_statuses(&diff_queued_diff);
if (diff_opts.needed_rename_limit > renames->needed_limit)
renames->needed_limit = diff_opts.needed_rename_limit;
@@ -2212,8 +2264,8 @@ static int detect_and_process_renames(struct merge_options *opt,
memset(&combined, 0, sizeof(combined));
trace2_region_enter("merge", "regular renames", opt->repo);
- detect_regular_renames(opt, merge_base, side1, MERGE_SIDE1);
- detect_regular_renames(opt, merge_base, side2, MERGE_SIDE2);
+ detect_regular_renames(opt, MERGE_SIDE1);
+ detect_regular_renames(opt, MERGE_SIDE2);
trace2_region_leave("merge", "regular renames", opt->repo);
trace2_region_enter("merge", "directory renames", opt->repo);
diff --git a/mergetools/vimdiff b/mergetools/vimdiff
index abc8ce4ec4..96f6209a04 100644
--- a/mergetools/vimdiff
+++ b/mergetools/vimdiff
@@ -15,6 +15,17 @@ merge_cmd () {
"$LOCAL" "$MERGED" "$REMOTE"
fi
;;
+ *vimdiff1)
+ "$merge_tool_path" -f -d \
+ -c 'echon "Resolve conflicts leftward then save. Use :cq to abort."' \
+ "$LOCAL" "$REMOTE"
+ ret="$?"
+ if test "$ret" -eq 0
+ then
+ cp -- "$LOCAL" "$MERGED"
+ fi
+ return "$ret"
+ ;;
*vimdiff2)
"$merge_tool_path" -f -d -c 'wincmd l' \
"$LOCAL" "$MERGED" "$REMOTE"
@@ -52,7 +63,7 @@ exit_code_trustable () {
list_tool_variants () {
for prefix in '' g n; do
- for suffix in '' 2 3; do
+ for suffix in '' 1 2 3; do
echo "${prefix}vimdiff${suffix}"
done
done
diff --git a/midx.c b/midx.c
index 05c40a98e0..971faa8cfc 100644
--- a/midx.c
+++ b/midx.c
@@ -11,6 +11,7 @@
#include "trace2.h"
#include "run-command.h"
#include "repository.h"
+#include "chunk-format.h"
#define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */
#define MIDX_VERSION 1
@@ -21,14 +22,12 @@
#define MIDX_HEADER_SIZE 12
#define MIDX_MIN_SIZE (MIDX_HEADER_SIZE + the_hash_algo->rawsz)
-#define MIDX_MAX_CHUNKS 5
#define MIDX_CHUNK_ALIGNMENT 4
#define MIDX_CHUNKID_PACKNAMES 0x504e414d /* "PNAM" */
#define MIDX_CHUNKID_OIDFANOUT 0x4f494446 /* "OIDF" */
#define MIDX_CHUNKID_OIDLOOKUP 0x4f49444c /* "OIDL" */
#define MIDX_CHUNKID_OBJECTOFFSETS 0x4f4f4646 /* "OOFF" */
#define MIDX_CHUNKID_LARGEOFFSETS 0x4c4f4646 /* "LOFF" */
-#define MIDX_CHUNKLOOKUP_WIDTH (sizeof(uint32_t) + sizeof(uint64_t))
#define MIDX_CHUNK_FANOUT_SIZE (sizeof(uint32_t) * 256)
#define MIDX_CHUNK_OFFSET_WIDTH (2 * sizeof(uint32_t))
#define MIDX_CHUNK_LARGE_OFFSET_WIDTH (sizeof(uint64_t))
@@ -53,6 +52,19 @@ static char *get_midx_filename(const char *object_dir)
return xstrfmt("%s/pack/multi-pack-index", object_dir);
}
+static int midx_read_oid_fanout(const unsigned char *chunk_start,
+ size_t chunk_size, void *data)
+{
+ struct multi_pack_index *m = data;
+ m->chunk_oid_fanout = (uint32_t *)chunk_start;
+
+ if (chunk_size != 4 * 256) {
+ error(_("multi-pack-index OID fanout is of the wrong size"));
+ return 1;
+ }
+ return 0;
+}
+
struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local)
{
struct multi_pack_index *m = NULL;
@@ -64,6 +76,7 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
char *midx_name = get_midx_filename(object_dir);
uint32_t i;
const char *cur_pack_name;
+ struct chunkfile *cf = NULL;
fd = git_open(midx_name);
@@ -113,58 +126,23 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
m->num_packs = get_be32(m->data + MIDX_BYTE_NUM_PACKS);
- for (i = 0; i < m->num_chunks; i++) {
- uint32_t chunk_id = get_be32(m->data + MIDX_HEADER_SIZE +
- MIDX_CHUNKLOOKUP_WIDTH * i);
- uint64_t chunk_offset = get_be64(m->data + MIDX_HEADER_SIZE + 4 +
- MIDX_CHUNKLOOKUP_WIDTH * i);
-
- if (chunk_offset >= m->data_len)
- die(_("invalid chunk offset (too large)"));
-
- switch (chunk_id) {
- case MIDX_CHUNKID_PACKNAMES:
- m->chunk_pack_names = m->data + chunk_offset;
- break;
-
- case MIDX_CHUNKID_OIDFANOUT:
- m->chunk_oid_fanout = (uint32_t *)(m->data + chunk_offset);
- break;
-
- case MIDX_CHUNKID_OIDLOOKUP:
- m->chunk_oid_lookup = m->data + chunk_offset;
- break;
-
- case MIDX_CHUNKID_OBJECTOFFSETS:
- m->chunk_object_offsets = m->data + chunk_offset;
- break;
-
- case MIDX_CHUNKID_LARGEOFFSETS:
- m->chunk_large_offsets = m->data + chunk_offset;
- break;
-
- case 0:
- die(_("terminating multi-pack-index chunk id appears earlier than expected"));
- break;
-
- default:
- /*
- * Do nothing on unrecognized chunks, allowing future
- * extensions to add optional chunks.
- */
- break;
- }
- }
+ cf = init_chunkfile(NULL);
+
+ if (read_table_of_contents(cf, m->data, midx_size,
+ MIDX_HEADER_SIZE, m->num_chunks))
+ goto cleanup_fail;
- if (!m->chunk_pack_names)
+ if (pair_chunk(cf, MIDX_CHUNKID_PACKNAMES, &m->chunk_pack_names) == CHUNK_NOT_FOUND)
die(_("multi-pack-index missing required pack-name chunk"));
- if (!m->chunk_oid_fanout)
+ if (read_chunk(cf, MIDX_CHUNKID_OIDFANOUT, midx_read_oid_fanout, m) == CHUNK_NOT_FOUND)
die(_("multi-pack-index missing required OID fanout chunk"));
- if (!m->chunk_oid_lookup)
+ if (pair_chunk(cf, MIDX_CHUNKID_OIDLOOKUP, &m->chunk_oid_lookup) == CHUNK_NOT_FOUND)
die(_("multi-pack-index missing required OID lookup chunk"));
- if (!m->chunk_object_offsets)
+ if (pair_chunk(cf, MIDX_CHUNKID_OBJECTOFFSETS, &m->chunk_object_offsets) == CHUNK_NOT_FOUND)
die(_("multi-pack-index missing required object offsets chunk"));
+ pair_chunk(cf, MIDX_CHUNKID_LARGEOFFSETS, &m->chunk_large_offsets);
+
m->num_objects = ntohl(m->chunk_oid_fanout[255]);
m->pack_names = xcalloc(m->num_packs, sizeof(*m->pack_names));
@@ -190,6 +168,7 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
cleanup_fail:
free(m);
free(midx_name);
+ free(cf);
if (midx_map)
munmap(midx_map, midx_size);
if (0 <= fd)
@@ -265,7 +244,7 @@ static off_t nth_midxed_offset(struct multi_pack_index *m, uint32_t pos)
const unsigned char *offset_data;
uint32_t offset32;
- offset_data = m->chunk_object_offsets + pos * MIDX_CHUNK_OFFSET_WIDTH;
+ offset_data = m->chunk_object_offsets + (off_t)pos * MIDX_CHUNK_OFFSET_WIDTH;
offset32 = get_be32(offset_data + sizeof(uint32_t));
if (m->chunk_large_offsets && offset32 & MIDX_LARGE_OFFSET_NEEDED) {
@@ -281,7 +260,8 @@ static off_t nth_midxed_offset(struct multi_pack_index *m, uint32_t pos)
static uint32_t nth_midxed_pack_int_id(struct multi_pack_index *m, uint32_t pos)
{
- return get_be32(m->chunk_object_offsets + pos * MIDX_CHUNK_OFFSET_WIDTH);
+ return get_be32(m->chunk_object_offsets +
+ (off_t)pos * MIDX_CHUNK_OFFSET_WIDTH);
}
static int nth_midxed_pack_entry(struct repository *r,
@@ -451,49 +431,56 @@ static int pack_info_compare(const void *_a, const void *_b)
return strcmp(a->pack_name, b->pack_name);
}
-struct pack_list {
+struct write_midx_context {
struct pack_info *info;
uint32_t nr;
uint32_t alloc;
struct multi_pack_index *m;
struct progress *progress;
unsigned pack_paths_checked;
+
+ struct pack_midx_entry *entries;
+ uint32_t entries_nr;
+
+ uint32_t *pack_perm;
+ unsigned large_offsets_needed:1;
+ uint32_t num_large_offsets;
};
static void add_pack_to_midx(const char *full_path, size_t full_path_len,
const char *file_name, void *data)
{
- struct pack_list *packs = (struct pack_list *)data;
+ struct write_midx_context *ctx = data;
if (ends_with(file_name, ".idx")) {
- display_progress(packs->progress, ++packs->pack_paths_checked);
- if (packs->m && midx_contains_pack(packs->m, file_name))
+ display_progress(ctx->progress, ++ctx->pack_paths_checked);
+ if (ctx->m && midx_contains_pack(ctx->m, file_name))
return;
- ALLOC_GROW(packs->info, packs->nr + 1, packs->alloc);
+ ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc);
- packs->info[packs->nr].p = add_packed_git(full_path,
- full_path_len,
- 0);
+ ctx->info[ctx->nr].p = add_packed_git(full_path,
+ full_path_len,
+ 0);
- if (!packs->info[packs->nr].p) {
+ if (!ctx->info[ctx->nr].p) {
warning(_("failed to add packfile '%s'"),
full_path);
return;
}
- if (open_pack_index(packs->info[packs->nr].p)) {
+ if (open_pack_index(ctx->info[ctx->nr].p)) {
warning(_("failed to open pack-index '%s'"),
full_path);
- close_pack(packs->info[packs->nr].p);
- FREE_AND_NULL(packs->info[packs->nr].p);
+ close_pack(ctx->info[ctx->nr].p);
+ FREE_AND_NULL(ctx->info[ctx->nr].p);
return;
}
- packs->info[packs->nr].pack_name = xstrdup(file_name);
- packs->info[packs->nr].orig_pack_int_id = packs->nr;
- packs->info[packs->nr].expired = 0;
- packs->nr++;
+ ctx->info[ctx->nr].pack_name = xstrdup(file_name);
+ ctx->info[ctx->nr].orig_pack_int_id = ctx->nr;
+ ctx->info[ctx->nr].expired = 0;
+ ctx->nr++;
}
}
@@ -643,27 +630,26 @@ static struct pack_midx_entry *get_sorted_entries(struct multi_pack_index *m,
return deduplicated_entries;
}
-static size_t write_midx_pack_names(struct hashfile *f,
- struct pack_info *info,
- uint32_t num_packs)
+static int write_midx_pack_names(struct hashfile *f, void *data)
{
+ struct write_midx_context *ctx = data;
uint32_t i;
unsigned char padding[MIDX_CHUNK_ALIGNMENT];
size_t written = 0;
- for (i = 0; i < num_packs; i++) {
+ for (i = 0; i < ctx->nr; i++) {
size_t writelen;
- if (info[i].expired)
+ if (ctx->info[i].expired)
continue;
- if (i && strcmp(info[i].pack_name, info[i - 1].pack_name) <= 0)
+ if (i && strcmp(ctx->info[i].pack_name, ctx->info[i - 1].pack_name) <= 0)
BUG("incorrect pack-file order: %s before %s",
- info[i - 1].pack_name,
- info[i].pack_name);
+ ctx->info[i - 1].pack_name,
+ ctx->info[i].pack_name);
- writelen = strlen(info[i].pack_name) + 1;
- hashwrite(f, info[i].pack_name, writelen);
+ writelen = strlen(ctx->info[i].pack_name) + 1;
+ hashwrite(f, ctx->info[i].pack_name, writelen);
written += writelen;
}
@@ -672,18 +658,17 @@ static size_t write_midx_pack_names(struct hashfile *f,
if (i < MIDX_CHUNK_ALIGNMENT) {
memset(padding, 0, sizeof(padding));
hashwrite(f, padding, i);
- written += i;
}
- return written;
+ return 0;
}
-static size_t write_midx_oid_fanout(struct hashfile *f,
- struct pack_midx_entry *objects,
- uint32_t nr_objects)
+static int write_midx_oid_fanout(struct hashfile *f,
+ void *data)
{
- struct pack_midx_entry *list = objects;
- struct pack_midx_entry *last = objects + nr_objects;
+ struct write_midx_context *ctx = data;
+ struct pack_midx_entry *list = ctx->entries;
+ struct pack_midx_entry *last = ctx->entries + ctx->entries_nr;
uint32_t count = 0;
uint32_t i;
@@ -704,21 +689,21 @@ static size_t write_midx_oid_fanout(struct hashfile *f,
list = next;
}
- return MIDX_CHUNK_FANOUT_SIZE;
+ return 0;
}
-static size_t write_midx_oid_lookup(struct hashfile *f, unsigned char hash_len,
- struct pack_midx_entry *objects,
- uint32_t nr_objects)
+static int write_midx_oid_lookup(struct hashfile *f,
+ void *data)
{
- struct pack_midx_entry *list = objects;
+ struct write_midx_context *ctx = data;
+ unsigned char hash_len = the_hash_algo->rawsz;
+ struct pack_midx_entry *list = ctx->entries;
uint32_t i;
- size_t written = 0;
- for (i = 0; i < nr_objects; i++) {
+ for (i = 0; i < ctx->entries_nr; i++) {
struct pack_midx_entry *obj = list++;
- if (i < nr_objects - 1) {
+ if (i < ctx->entries_nr - 1) {
struct pack_midx_entry *next = list;
if (oidcmp(&obj->oid, &next->oid) >= 0)
BUG("OIDs not in order: %s >= %s",
@@ -727,50 +712,48 @@ static size_t write_midx_oid_lookup(struct hashfile *f, unsigned char hash_len,
}
hashwrite(f, obj->oid.hash, (int)hash_len);
- written += hash_len;
}
- return written;
+ return 0;
}
-static size_t write_midx_object_offsets(struct hashfile *f, int large_offset_needed,
- uint32_t *perm,
- struct pack_midx_entry *objects, uint32_t nr_objects)
+static int write_midx_object_offsets(struct hashfile *f,
+ void *data)
{
- struct pack_midx_entry *list = objects;
+ struct write_midx_context *ctx = data;
+ struct pack_midx_entry *list = ctx->entries;
uint32_t i, nr_large_offset = 0;
- size_t written = 0;
- for (i = 0; i < nr_objects; i++) {
+ for (i = 0; i < ctx->entries_nr; i++) {
struct pack_midx_entry *obj = list++;
- if (perm[obj->pack_int_id] == PACK_EXPIRED)
+ if (ctx->pack_perm[obj->pack_int_id] == PACK_EXPIRED)
BUG("object %s is in an expired pack with int-id %d",
oid_to_hex(&obj->oid),
obj->pack_int_id);
- hashwrite_be32(f, perm[obj->pack_int_id]);
+ hashwrite_be32(f, ctx->pack_perm[obj->pack_int_id]);
- if (large_offset_needed && obj->offset >> 31)
+ if (ctx->large_offsets_needed && obj->offset >> 31)
hashwrite_be32(f, MIDX_LARGE_OFFSET_NEEDED | nr_large_offset++);
- else if (!large_offset_needed && obj->offset >> 32)
+ else if (!ctx->large_offsets_needed && obj->offset >> 32)
BUG("object %s requires a large offset (%"PRIx64") but the MIDX is not writing large offsets!",
oid_to_hex(&obj->oid),
obj->offset);
else
hashwrite_be32(f, (uint32_t)obj->offset);
-
- written += MIDX_CHUNK_OFFSET_WIDTH;
}
- return written;
+ return 0;
}
-static size_t write_midx_large_offsets(struct hashfile *f, uint32_t nr_large_offset,
- struct pack_midx_entry *objects, uint32_t nr_objects)
+static int write_midx_large_offsets(struct hashfile *f,
+ void *data)
{
- struct pack_midx_entry *list = objects, *end = objects + nr_objects;
- size_t written = 0;
+ struct write_midx_context *ctx = data;
+ struct pack_midx_entry *list = ctx->entries;
+ struct pack_midx_entry *end = ctx->entries + ctx->entries_nr;
+ uint32_t nr_large_offset = ctx->num_large_offsets;
while (nr_large_offset) {
struct pack_midx_entry *obj;
@@ -785,34 +768,26 @@ static size_t write_midx_large_offsets(struct hashfile *f, uint32_t nr_large_off
if (!(offset >> 31))
continue;
- written += hashwrite_be64(f, offset);
+ hashwrite_be64(f, offset);
nr_large_offset--;
}
- return written;
+ return 0;
}
static int write_midx_internal(const char *object_dir, struct multi_pack_index *m,
struct string_list *packs_to_drop, unsigned flags)
{
- unsigned char cur_chunk, num_chunks = 0;
char *midx_name;
uint32_t i;
struct hashfile *f = NULL;
struct lock_file lk;
- struct pack_list packs;
- uint32_t *pack_perm = NULL;
- uint64_t written = 0;
- uint32_t chunk_ids[MIDX_MAX_CHUNKS + 1];
- uint64_t chunk_offsets[MIDX_MAX_CHUNKS + 1];
- uint32_t nr_entries, num_large_offsets = 0;
- struct pack_midx_entry *entries = NULL;
- struct progress *progress = NULL;
- int large_offsets_needed = 0;
+ struct write_midx_context ctx = { 0 };
int pack_name_concat_len = 0;
int dropped_packs = 0;
int result = 0;
+ struct chunkfile *cf;
midx_name = get_midx_filename(object_dir);
if (safe_create_leading_directories(midx_name))
@@ -820,61 +795,62 @@ static int write_midx_internal(const char *object_dir, struct multi_pack_index *
midx_name);
if (m)
- packs.m = m;
+ ctx.m = m;
else
- packs.m = load_multi_pack_index(object_dir, 1);
-
- packs.nr = 0;
- packs.alloc = packs.m ? packs.m->num_packs : 16;
- packs.info = NULL;
- ALLOC_ARRAY(packs.info, packs.alloc);
-
- if (packs.m) {
- for (i = 0; i < packs.m->num_packs; i++) {
- ALLOC_GROW(packs.info, packs.nr + 1, packs.alloc);
-
- packs.info[packs.nr].orig_pack_int_id = i;
- packs.info[packs.nr].pack_name = xstrdup(packs.m->pack_names[i]);
- packs.info[packs.nr].p = NULL;
- packs.info[packs.nr].expired = 0;
- packs.nr++;
+ ctx.m = load_multi_pack_index(object_dir, 1);
+
+ ctx.nr = 0;
+ ctx.alloc = ctx.m ? ctx.m->num_packs : 16;
+ ctx.info = NULL;
+ ALLOC_ARRAY(ctx.info, ctx.alloc);
+
+ if (ctx.m) {
+ for (i = 0; i < ctx.m->num_packs; i++) {
+ ALLOC_GROW(ctx.info, ctx.nr + 1, ctx.alloc);
+
+ ctx.info[ctx.nr].orig_pack_int_id = i;
+ ctx.info[ctx.nr].pack_name = xstrdup(ctx.m->pack_names[i]);
+ ctx.info[ctx.nr].p = NULL;
+ ctx.info[ctx.nr].expired = 0;
+ ctx.nr++;
}
}
- packs.pack_paths_checked = 0;
+ ctx.pack_paths_checked = 0;
if (flags & MIDX_PROGRESS)
- packs.progress = start_delayed_progress(_("Adding packfiles to multi-pack-index"), 0);
+ ctx.progress = start_delayed_progress(_("Adding packfiles to multi-pack-index"), 0);
else
- packs.progress = NULL;
+ ctx.progress = NULL;
- for_each_file_in_pack_dir(object_dir, add_pack_to_midx, &packs);
- stop_progress(&packs.progress);
+ for_each_file_in_pack_dir(object_dir, add_pack_to_midx, &ctx);
+ stop_progress(&ctx.progress);
- if (packs.m && packs.nr == packs.m->num_packs && !packs_to_drop)
+ if (ctx.m && ctx.nr == ctx.m->num_packs && !packs_to_drop)
goto cleanup;
- entries = get_sorted_entries(packs.m, packs.info, packs.nr, &nr_entries);
+ ctx.entries = get_sorted_entries(ctx.m, ctx.info, ctx.nr, &ctx.entries_nr);
- for (i = 0; i < nr_entries; i++) {
- if (entries[i].offset > 0x7fffffff)
- num_large_offsets++;
- if (entries[i].offset > 0xffffffff)
- large_offsets_needed = 1;
+ ctx.large_offsets_needed = 0;
+ for (i = 0; i < ctx.entries_nr; i++) {
+ if (ctx.entries[i].offset > 0x7fffffff)
+ ctx.num_large_offsets++;
+ if (ctx.entries[i].offset > 0xffffffff)
+ ctx.large_offsets_needed = 1;
}
- QSORT(packs.info, packs.nr, pack_info_compare);
+ QSORT(ctx.info, ctx.nr, pack_info_compare);
if (packs_to_drop && packs_to_drop->nr) {
int drop_index = 0;
int missing_drops = 0;
- for (i = 0; i < packs.nr && drop_index < packs_to_drop->nr; i++) {
- int cmp = strcmp(packs.info[i].pack_name,
+ for (i = 0; i < ctx.nr && drop_index < packs_to_drop->nr; i++) {
+ int cmp = strcmp(ctx.info[i].pack_name,
packs_to_drop->items[drop_index].string);
if (!cmp) {
drop_index++;
- packs.info[i].expired = 1;
+ ctx.info[i].expired = 1;
} else if (cmp > 0) {
error(_("did not see pack-file %s to drop"),
packs_to_drop->items[drop_index].string);
@@ -882,7 +858,7 @@ static int write_midx_internal(const char *object_dir, struct multi_pack_index *
missing_drops++;
i--;
} else {
- packs.info[i].expired = 0;
+ ctx.info[i].expired = 0;
}
}
@@ -898,19 +874,19 @@ static int write_midx_internal(const char *object_dir, struct multi_pack_index *
*
* pack_perm[old_id] = new_id
*/
- ALLOC_ARRAY(pack_perm, packs.nr);
- for (i = 0; i < packs.nr; i++) {
- if (packs.info[i].expired) {
+ ALLOC_ARRAY(ctx.pack_perm, ctx.nr);
+ for (i = 0; i < ctx.nr; i++) {
+ if (ctx.info[i].expired) {
dropped_packs++;
- pack_perm[packs.info[i].orig_pack_int_id] = PACK_EXPIRED;
+ ctx.pack_perm[ctx.info[i].orig_pack_int_id] = PACK_EXPIRED;
} else {
- pack_perm[packs.info[i].orig_pack_int_id] = i - dropped_packs;
+ ctx.pack_perm[ctx.info[i].orig_pack_int_id] = i - dropped_packs;
}
}
- for (i = 0; i < packs.nr; i++) {
- if (!packs.info[i].expired)
- pack_name_concat_len += strlen(packs.info[i].pack_name) + 1;
+ for (i = 0; i < ctx.nr; i++) {
+ if (!ctx.info[i].expired)
+ pack_name_concat_len += strlen(ctx.info[i].pack_name) + 1;
}
if (pack_name_concat_len % MIDX_CHUNK_ALIGNMENT)
@@ -921,123 +897,52 @@ static int write_midx_internal(const char *object_dir, struct multi_pack_index *
f = hashfd(get_lock_file_fd(&lk), get_lock_file_path(&lk));
FREE_AND_NULL(midx_name);
- if (packs.m)
- close_midx(packs.m);
-
- cur_chunk = 0;
- num_chunks = large_offsets_needed ? 5 : 4;
+ if (ctx.m)
+ close_midx(ctx.m);
- if (packs.nr - dropped_packs == 0) {
+ if (ctx.nr - dropped_packs == 0) {
error(_("no pack files to index."));
result = 1;
goto cleanup;
}
- written = write_midx_header(f, num_chunks, packs.nr - dropped_packs);
-
- chunk_ids[cur_chunk] = MIDX_CHUNKID_PACKNAMES;
- chunk_offsets[cur_chunk] = written + (num_chunks + 1) * MIDX_CHUNKLOOKUP_WIDTH;
-
- cur_chunk++;
- chunk_ids[cur_chunk] = MIDX_CHUNKID_OIDFANOUT;
- chunk_offsets[cur_chunk] = chunk_offsets[cur_chunk - 1] + pack_name_concat_len;
-
- cur_chunk++;
- chunk_ids[cur_chunk] = MIDX_CHUNKID_OIDLOOKUP;
- chunk_offsets[cur_chunk] = chunk_offsets[cur_chunk - 1] + MIDX_CHUNK_FANOUT_SIZE;
-
- cur_chunk++;
- chunk_ids[cur_chunk] = MIDX_CHUNKID_OBJECTOFFSETS;
- chunk_offsets[cur_chunk] = chunk_offsets[cur_chunk - 1] + nr_entries * the_hash_algo->rawsz;
-
- cur_chunk++;
- chunk_offsets[cur_chunk] = chunk_offsets[cur_chunk - 1] + nr_entries * MIDX_CHUNK_OFFSET_WIDTH;
- if (large_offsets_needed) {
- chunk_ids[cur_chunk] = MIDX_CHUNKID_LARGEOFFSETS;
-
- cur_chunk++;
- chunk_offsets[cur_chunk] = chunk_offsets[cur_chunk - 1] +
- num_large_offsets * MIDX_CHUNK_LARGE_OFFSET_WIDTH;
- }
-
- chunk_ids[cur_chunk] = 0;
+ cf = init_chunkfile(f);
- for (i = 0; i <= num_chunks; i++) {
- if (i && chunk_offsets[i] < chunk_offsets[i - 1])
- BUG("incorrect chunk offsets: %"PRIu64" before %"PRIu64,
- chunk_offsets[i - 1],
- chunk_offsets[i]);
+ add_chunk(cf, MIDX_CHUNKID_PACKNAMES, pack_name_concat_len,
+ write_midx_pack_names);
+ add_chunk(cf, MIDX_CHUNKID_OIDFANOUT, MIDX_CHUNK_FANOUT_SIZE,
+ write_midx_oid_fanout);
+ add_chunk(cf, MIDX_CHUNKID_OIDLOOKUP,
+ (size_t)ctx.entries_nr * the_hash_algo->rawsz,
+ write_midx_oid_lookup);
+ add_chunk(cf, MIDX_CHUNKID_OBJECTOFFSETS,
+ (size_t)ctx.entries_nr * MIDX_CHUNK_OFFSET_WIDTH,
+ write_midx_object_offsets);
- if (chunk_offsets[i] % MIDX_CHUNK_ALIGNMENT)
- BUG("chunk offset %"PRIu64" is not properly aligned",
- chunk_offsets[i]);
-
- hashwrite_be32(f, chunk_ids[i]);
- hashwrite_be64(f, chunk_offsets[i]);
-
- written += MIDX_CHUNKLOOKUP_WIDTH;
- }
-
- if (flags & MIDX_PROGRESS)
- progress = start_delayed_progress(_("Writing chunks to multi-pack-index"),
- num_chunks);
- for (i = 0; i < num_chunks; i++) {
- if (written != chunk_offsets[i])
- BUG("incorrect chunk offset (%"PRIu64" != %"PRIu64") for chunk id %"PRIx32,
- chunk_offsets[i],
- written,
- chunk_ids[i]);
-
- switch (chunk_ids[i]) {
- case MIDX_CHUNKID_PACKNAMES:
- written += write_midx_pack_names(f, packs.info, packs.nr);
- break;
-
- case MIDX_CHUNKID_OIDFANOUT:
- written += write_midx_oid_fanout(f, entries, nr_entries);
- break;
-
- case MIDX_CHUNKID_OIDLOOKUP:
- written += write_midx_oid_lookup(f, the_hash_algo->rawsz, entries, nr_entries);
- break;
-
- case MIDX_CHUNKID_OBJECTOFFSETS:
- written += write_midx_object_offsets(f, large_offsets_needed, pack_perm, entries, nr_entries);
- break;
-
- case MIDX_CHUNKID_LARGEOFFSETS:
- written += write_midx_large_offsets(f, num_large_offsets, entries, nr_entries);
- break;
-
- default:
- BUG("trying to write unknown chunk id %"PRIx32,
- chunk_ids[i]);
- }
-
- display_progress(progress, i + 1);
- }
- stop_progress(&progress);
+ if (ctx.large_offsets_needed)
+ add_chunk(cf, MIDX_CHUNKID_LARGEOFFSETS,
+ (size_t)ctx.num_large_offsets * MIDX_CHUNK_LARGE_OFFSET_WIDTH,
+ write_midx_large_offsets);
- if (written != chunk_offsets[num_chunks])
- BUG("incorrect final offset %"PRIu64" != %"PRIu64,
- written,
- chunk_offsets[num_chunks]);
+ write_midx_header(f, get_num_chunks(cf), ctx.nr - dropped_packs);
+ write_chunkfile(cf, &ctx);
finalize_hashfile(f, NULL, CSUM_FSYNC | CSUM_HASH_IN_STREAM);
+ free_chunkfile(cf);
commit_lock_file(&lk);
cleanup:
- for (i = 0; i < packs.nr; i++) {
- if (packs.info[i].p) {
- close_pack(packs.info[i].p);
- free(packs.info[i].p);
+ for (i = 0; i < ctx.nr; i++) {
+ if (ctx.info[i].p) {
+ close_pack(ctx.info[i].p);
+ free(ctx.info[i].p);
}
- free(packs.info[i].pack_name);
+ free(ctx.info[i].pack_name);
}
- free(packs.info);
- free(entries);
- free(pack_perm);
+ free(ctx.info);
+ free(ctx.entries);
+ free(ctx.pack_perm);
free(midx_name);
return result;
}
diff --git a/pack-bitmap.c b/pack-bitmap.c
index 60fe20fb87..1f69b5fa85 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -1430,3 +1430,84 @@ int bitmap_has_oid_in_uninteresting(struct bitmap_index *bitmap_git,
return bitmap_git &&
bitmap_walk_contains(bitmap_git, bitmap_git->haves, oid);
}
+
+static off_t get_disk_usage_for_type(struct bitmap_index *bitmap_git,
+ enum object_type object_type)
+{
+ struct bitmap *result = bitmap_git->result;
+ struct packed_git *pack = bitmap_git->pack;
+ off_t total = 0;
+ struct ewah_iterator it;
+ eword_t filter;
+ size_t i;
+
+ init_type_iterator(&it, bitmap_git, object_type);
+ for (i = 0; i < result->word_alloc &&
+ ewah_iterator_next(&filter, &it); i++) {
+ eword_t word = result->words[i] & filter;
+ size_t base = (i * BITS_IN_EWORD);
+ unsigned offset;
+
+ if (!word)
+ continue;
+
+ for (offset = 0; offset < BITS_IN_EWORD; offset++) {
+ size_t pos;
+
+ if ((word >> offset) == 0)
+ break;
+
+ offset += ewah_bit_ctz64(word >> offset);
+ pos = base + offset;
+ total += pack_pos_to_offset(pack, pos + 1) -
+ pack_pos_to_offset(pack, pos);
+ }
+ }
+
+ return total;
+}
+
+static off_t get_disk_usage_for_extended(struct bitmap_index *bitmap_git)
+{
+ struct bitmap *result = bitmap_git->result;
+ struct packed_git *pack = bitmap_git->pack;
+ struct eindex *eindex = &bitmap_git->ext_index;
+ off_t total = 0;
+ struct object_info oi = OBJECT_INFO_INIT;
+ off_t object_size;
+ size_t i;
+
+ oi.disk_sizep = &object_size;
+
+ for (i = 0; i < eindex->count; i++) {
+ struct object *obj = eindex->objects[i];
+
+ if (!bitmap_get(result, pack->num_objects + i))
+ continue;
+
+ if (oid_object_info_extended(the_repository, &obj->oid, &oi, 0) < 0)
+ die(_("unable to get disk usage of %s"),
+ oid_to_hex(&obj->oid));
+
+ total += object_size;
+ }
+ return total;
+}
+
+off_t get_disk_usage_from_bitmap(struct bitmap_index *bitmap_git,
+ struct rev_info *revs)
+{
+ off_t total = 0;
+
+ total += get_disk_usage_for_type(bitmap_git, OBJ_COMMIT);
+ if (revs->tree_objects)
+ total += get_disk_usage_for_type(bitmap_git, OBJ_TREE);
+ if (revs->blob_objects)
+ total += get_disk_usage_for_type(bitmap_git, OBJ_BLOB);
+ if (revs->tag_objects)
+ total += get_disk_usage_for_type(bitmap_git, OBJ_TAG);
+
+ total += get_disk_usage_for_extended(bitmap_git);
+
+ return total;
+}
diff --git a/pack-bitmap.h b/pack-bitmap.h
index 25dfcf5615..36d99930d8 100644
--- a/pack-bitmap.h
+++ b/pack-bitmap.h
@@ -68,6 +68,8 @@ int bitmap_walk_contains(struct bitmap_index *,
*/
int bitmap_has_oid_in_uninteresting(struct bitmap_index *, const struct object_id *oid);
+off_t get_disk_usage_from_bitmap(struct bitmap_index *, struct rev_info *);
+
void bitmap_writer_show_progress(int show);
void bitmap_writer_set_checksum(unsigned char *sha1);
void bitmap_writer_build_type_index(struct packing_data *to_pack,
diff --git a/pack-write.c b/pack-write.c
index 680c36755d..2ca85a9d16 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -380,7 +380,7 @@ void fixup_pack_header_footer(int pack_fd,
fsync_or_die(pack_fd, pack_name);
}
-char *index_pack_lockfile(int ip_out)
+char *index_pack_lockfile(int ip_out, int *is_well_formed)
{
char packname[GIT_MAX_HEXSZ + 6];
const int len = the_hash_algo->hexsz + 6;
@@ -394,11 +394,17 @@ char *index_pack_lockfile(int ip_out)
*/
if (read_in_full(ip_out, packname, len) == len && packname[len-1] == '\n') {
const char *name;
+
+ if (is_well_formed)
+ *is_well_formed = 1;
packname[len-1] = 0;
if (skip_prefix(packname, "keep\t", &name))
return xstrfmt("%s/pack/pack-%s.keep",
get_object_directory(), name);
+ return NULL;
}
+ if (is_well_formed)
+ *is_well_formed = 0;
return NULL;
}
diff --git a/pack.h b/pack.h
index afdcf8f5c7..857cbd5bd4 100644
--- a/pack.h
+++ b/pack.h
@@ -87,7 +87,7 @@ int verify_pack_index(struct packed_git *);
int verify_pack(struct repository *, struct packed_git *, verify_fn fn, struct progress *, uint32_t);
off_t write_pack_header(struct hashfile *f, uint32_t);
void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t, unsigned char *, off_t);
-char *index_pack_lockfile(int fd);
+char *index_pack_lockfile(int fd, int *is_well_formed);
struct ref;
diff --git a/preload-index.c b/preload-index.c
index ed6eaa4738..e5529a5863 100644
--- a/preload-index.c
+++ b/preload-index.c
@@ -31,6 +31,7 @@ struct thread_data {
struct pathspec pathspec;
struct progress_data *progress;
int offset, nr;
+ int t2_nr_lstat;
};
static void *preload_thread(void *_data)
@@ -73,6 +74,7 @@ static void *preload_thread(void *_data)
continue;
if (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce)))
continue;
+ p->t2_nr_lstat++;
if (lstat(ce->name, &st))
continue;
if (ie_match_stat(index, ce, &st, CE_MATCH_RACY_IS_DIRTY|CE_MATCH_IGNORE_FSMONITOR))
@@ -98,6 +100,7 @@ void preload_index(struct index_state *index,
int threads, i, work, offset;
struct thread_data data[MAX_PARALLEL];
struct progress_data pd;
+ int t2_sum_lstat = 0;
if (!HAVE_THREADS || !core_preload_index)
return;
@@ -107,6 +110,9 @@ void preload_index(struct index_state *index,
threads = 2;
if (threads < 2)
return;
+
+ trace2_region_enter("index", "preload", NULL);
+
trace_performance_enter();
if (threads > MAX_PARALLEL)
threads = MAX_PARALLEL;
@@ -141,10 +147,14 @@ void preload_index(struct index_state *index,
struct thread_data *p = data+i;
if (pthread_join(p->pthread, NULL))
die("unable to join threaded lstat");
+ t2_sum_lstat += p->t2_nr_lstat;
}
stop_progress(&pd.progress);
trace_performance_leave("preload index");
+
+ trace2_data_intmax("index", NULL, "preload/sum_lstat", t2_sum_lstat);
+ trace2_region_leave("index", "preload", NULL);
}
int repo_read_index_preload(struct repository *repo,
diff --git a/read-cache.c b/read-cache.c
index 29144cf879..8a4c6c70a5 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1364,7 +1364,9 @@ int add_index_entry(struct index_state *istate, struct cache_entry *ce, int opti
static struct cache_entry *refresh_cache_ent(struct index_state *istate,
struct cache_entry *ce,
unsigned int options, int *err,
- int *changed_ret)
+ int *changed_ret,
+ int *t2_did_lstat,
+ int *t2_did_scan)
{
struct stat st;
struct cache_entry *updated;
@@ -1406,6 +1408,8 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
return NULL;
}
+ if (t2_did_lstat)
+ *t2_did_lstat = 1;
if (lstat(ce->name, &st) < 0) {
if (ignore_missing && errno == ENOENT)
return ce;
@@ -1442,6 +1446,8 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
}
}
+ if (t2_did_scan)
+ *t2_did_scan = 1;
if (ie_modified(istate, ce, &st, options)) {
if (err)
*err = EINVAL;
@@ -1519,6 +1525,8 @@ int refresh_index(struct index_state *istate, unsigned int flags,
const char *added_fmt;
const char *unmerged_fmt;
struct progress *progress = NULL;
+ int t2_sum_lstat = 0;
+ int t2_sum_scan = 0;
if (flags & REFRESH_PROGRESS && isatty(2))
progress = start_delayed_progress(_("Refresh index"),
@@ -1536,11 +1544,14 @@ int refresh_index(struct index_state *istate, unsigned int flags,
* we only have to do the special cases that are left.
*/
preload_index(istate, pathspec, 0);
+ trace2_region_enter("index", "refresh", NULL);
for (i = 0; i < istate->cache_nr; i++) {
struct cache_entry *ce, *new_entry;
int cache_errno = 0;
int changed = 0;
int filtered = 0;
+ int t2_did_lstat = 0;
+ int t2_did_scan = 0;
ce = istate->cache[i];
if (ignore_submodules && S_ISGITLINK(ce->ce_mode))
@@ -1566,7 +1577,11 @@ int refresh_index(struct index_state *istate, unsigned int flags,
if (filtered)
continue;
- new_entry = refresh_cache_ent(istate, ce, options, &cache_errno, &changed);
+ new_entry = refresh_cache_ent(istate, ce, options,
+ &cache_errno, &changed,
+ &t2_did_lstat, &t2_did_scan);
+ t2_sum_lstat += t2_did_lstat;
+ t2_sum_scan += t2_did_scan;
if (new_entry == ce)
continue;
if (progress)
@@ -1602,6 +1617,9 @@ int refresh_index(struct index_state *istate, unsigned int flags,
replace_index_entry(istate, i, new_entry);
}
+ trace2_data_intmax("index", NULL, "refresh/sum_lstat", t2_sum_lstat);
+ trace2_data_intmax("index", NULL, "refresh/sum_scan", t2_sum_scan);
+ trace2_region_leave("index", "refresh", NULL);
if (progress) {
display_progress(progress, istate->cache_nr);
stop_progress(&progress);
@@ -1614,7 +1632,7 @@ struct cache_entry *refresh_cache_entry(struct index_state *istate,
struct cache_entry *ce,
unsigned int options)
{
- return refresh_cache_ent(istate, ce, options, NULL, NULL);
+ return refresh_cache_ent(istate, ce, options, NULL, NULL, NULL, NULL);
}
diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index dea2cbef51..5ea8bc9f1d 100644
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -20,7 +20,7 @@ check() {
false
fi &&
test_cmp expect-stdout stdout &&
- test_i18ncmp expect-stderr stderr
+ test_cmp expect-stderr stderr
}
read_chunk() {
diff --git a/t/lib-log-graph.sh b/t/lib-log-graph.sh
index 1184cceef2..bf952ef920 100644
--- a/t/lib-log-graph.sh
+++ b/t/lib-log-graph.sh
@@ -12,13 +12,13 @@ sanitize_log_output () {
lib_test_cmp_graph () {
git log --graph "$@" >output &&
sed 's/ *$//' >output.sanitized <output &&
- test_i18ncmp expect output.sanitized
+ test_cmp expect output.sanitized
}
lib_test_cmp_short_graph () {
git log --graph --pretty=short "$@" >output &&
sanitize_log_output >output.sanitized <output &&
- test_i18ncmp expect output.sanitized
+ test_cmp expect output.sanitized
}
lib_test_cmp_colored_graph () {
diff --git a/t/perf/.gitignore b/t/perf/.gitignore
index 982eb8e3a9..72f5d0d314 100644
--- a/t/perf/.gitignore
+++ b/t/perf/.gitignore
@@ -1,3 +1,4 @@
/build/
/test-results/
+/test-trace/
/trash directory*/
diff --git a/t/perf/Makefile b/t/perf/Makefile
index fcb0e8865e..2465770a78 100644
--- a/t/perf/Makefile
+++ b/t/perf/Makefile
@@ -7,10 +7,10 @@ perf: pre-clean
./run
pre-clean:
- rm -rf test-results
+ rm -rf test-results test-trace
clean:
- rm -rf build "trash directory".* test-results
+ rm -rf build "trash directory".* test-results test-trace
test-lint:
$(MAKE) -C .. test-lint
diff --git a/t/perf/p7519-fsmonitor.sh b/t/perf/p7519-fsmonitor.sh
index 1e20a184c7..b657564aed 100755
--- a/t/perf/p7519-fsmonitor.sh
+++ b/t/perf/p7519-fsmonitor.sh
@@ -32,6 +32,8 @@ test_description="Test core.fsmonitor"
#
# GIT_PERF_7519_DROP_CACHE: if set, the OS caches are dropped between tests
#
+# GIT_PERF_7519_TRACE: if set, enable trace logging during the test.
+# Trace logs will be grouped by fsmonitor provider.
test_perf_large_repo
test_checkout_worktree
@@ -70,6 +72,32 @@ then
fi
fi
+trace_start() {
+ if test -n "$GIT_PERF_7519_TRACE"
+ then
+ name="$1"
+ TEST_TRACE_DIR="$TEST_OUTPUT_DIRECTORY/test-trace/p7519/"
+ echo "Writing trace logging to $TEST_TRACE_DIR"
+
+ mkdir -p "$TEST_TRACE_DIR"
+
+ # Start Trace2 logging and any other GIT_TRACE_* logs that you
+ # want for this named test case.
+
+ GIT_TRACE2_PERF="$TEST_TRACE_DIR/$name.trace2perf"
+ export GIT_TRACE2_PERF
+
+ >"$GIT_TRACE2_PERF"
+ fi
+}
+
+trace_stop() {
+ if test -n "$GIT_PERF_7519_TRACE"
+ then
+ unset GIT_TRACE2_PERF
+ fi
+}
+
test_expect_success "one time repo setup" '
# set untrackedCache depending on the environment
if test -n "$GIT_PERF_7519_UNTRACKED_CACHE"
@@ -101,7 +129,7 @@ test_expect_success "one time repo setup" '
# If Watchman exists, watch the work tree and attempt a query.
if test_have_prereq WATCHMAN; then
watchman watch "$GIT_WORK_TREE" &&
- watchman watch-list | grep -q -F "$GIT_WORK_TREE"
+ watchman watch-list | grep -q -F "p7519-fsmonitor"
fi
'
@@ -169,8 +197,18 @@ test_fsmonitor_suite() {
git status -uall
'
+ # Update the mtimes on upto 100k files to make status think
+ # that they are dirty. For simplicity, omit any files with
+ # LFs (i.e. anything that ls-files thinks it needs to dquote).
+ # Then fully backslash-quote the paths to capture any
+ # whitespace so that they pass thru xargs properly.
+ #
test_perf_w_drop_caches "status (dirty) ($DESC)" '
- git ls-files | head -100000 | xargs -d "\n" touch -h &&
+ git ls-files | \
+ head -100000 | \
+ grep -v \" | \
+ sed '\''s/\(.\)/\\\1/g'\'' | \
+ xargs test-tool chmtime -300 &&
git status
'
@@ -203,6 +241,12 @@ test_fsmonitor_suite() {
'
}
+#
+# Run a full set of perf tests using each Hook-based fsmonitor provider,
+# such as Watchman.
+#
+
+trace_start fsmonitor-watchman
if test -n "$GIT_PERF_7519_FSMONITOR"; then
for INTEGRATION_PATH in $GIT_PERF_7519_FSMONITOR; do
test_expect_success "setup for fsmonitor $INTEGRATION_PATH" 'setup_for_fsmonitor'
@@ -213,14 +257,6 @@ else
test_fsmonitor_suite
fi
-test_expect_success "setup without fsmonitor" '
- unset INTEGRATION_SCRIPT &&
- git config --unset core.fsmonitor &&
- git update-index --no-fsmonitor
-'
-
-test_fsmonitor_suite
-
if test_have_prereq WATCHMAN
then
watchman watch-del "$GIT_WORK_TREE" >/dev/null 2>&1 &&
@@ -229,5 +265,20 @@ then
# preventing the removal of the trash directory
watchman shutdown-server >/dev/null 2>&1
fi
+trace_stop
+
+#
+# Run a full set of perf tests with the fsmonitor feature disabled.
+#
+
+trace_start fsmonitor-disabled
+test_expect_success "setup without fsmonitor" '
+ unset INTEGRATION_SCRIPT &&
+ git config --unset core.fsmonitor &&
+ git update-index --no-fsmonitor
+'
+
+test_fsmonitor_suite
+trace_stop
test_done
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index a6e570d674..705d62cc27 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -271,7 +271,7 @@ test_expect_success 'pretend we have a mix of all possible results' '
EOF
'
-test_expect_success C_LOCALE_OUTPUT 'test --verbose' '
+test_expect_success 'test --verbose' '
run_sub_test_lib_test_err \
t1234-verbose "test verbose" --verbose <<-\EOF &&
test_expect_success "passing test" true
diff --git a/t/t0006-date.sh b/t/t0006-date.sh
index 75ee9a96b8..6b757d7169 100755
--- a/t/t0006-date.sh
+++ b/t/t0006-date.sh
@@ -11,7 +11,7 @@ check_relative() {
echo "$t -> $2" >expect
test_expect_${3:-success} "relative date ($2)" "
test-tool date relative $t >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
"
}
@@ -139,7 +139,7 @@ check_date_format_human() {
echo "$t -> $2" >expect
test_expect_success "human date $t" '
test-tool date human $t >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
}
diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh
index 370a389e5c..f7abde62f6 100755
--- a/t/t0008-ignores.sh
+++ b/t/t0008-ignores.sh
@@ -34,7 +34,7 @@ expect_from_stdin () {
test_stderr () {
expected="$1"
expect_in stderr "$1" &&
- test_i18ncmp "$HOME/expected-stderr" "$HOME/stderr"
+ test_cmp "$HOME/expected-stderr" "$HOME/stderr"
}
broken_c_unquote () {
diff --git a/t/t0012-help.sh b/t/t0012-help.sh
index e8ef7300ec..5679e29c62 100755
--- a/t/t0012-help.sh
+++ b/t/t0012-help.sh
@@ -55,7 +55,7 @@ test_expect_success "--help does not work for guides" "
git: 'revisions' is not a git command. See 'git --help'.
EOF
test_must_fail git revisions --help 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
"
test_expect_success 'git help' '
diff --git a/t/t0018-advice.sh b/t/t0018-advice.sh
index e03554d2f3..39e5e4b34f 100755
--- a/t/t0018-advice.sh
+++ b/t/t0018-advice.sh
@@ -10,7 +10,7 @@ test_expect_success 'advice should be printed when config variable is unset' '
hint: Disable this message with "git config advice.nestedTag false"
EOF
test-tool advise "This is a piece of advice" 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'advice should be printed when config variable is set to true' '
@@ -20,7 +20,7 @@ test_expect_success 'advice should be printed when config variable is set to tru
EOF
test_config advice.nestedTag true &&
test-tool advise "This is a piece of advice" 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'advice should not be printed when config variable is set to false' '
diff --git a/t/t0020-crlf.sh b/t/t0020-crlf.sh
index 375cf94398..f25ae8b5e1 100755
--- a/t/t0020-crlf.sh
+++ b/t/t0020-crlf.sh
@@ -87,10 +87,8 @@ test_expect_success 'safecrlf: print warning only once' '
git commit -m "nowarn" &&
for w in Oh here is CRLFQ in text; do echo $w; done | q_to_cr >doublewarn &&
git add doublewarn 2>err &&
- if test_have_prereq C_LOCALE_OUTPUT
- then
- test $(grep "CRLF will be replaced by LF" err | wc -l) = 1
- fi
+ grep "CRLF will be replaced by LF" err >err.warnings &&
+ test_line_count = 1 err.warnings
'
diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh
index 51f74a3ddf..d24d5acfbc 100755
--- a/t/t0027-auto-crlf.sh
+++ b/t/t0027-auto-crlf.sh
@@ -83,7 +83,7 @@ check_warning () {
*) echo >&2 "Illegal 1": "$1" ; return false ;;
esac
grep "will be replaced by" "$2" | sed -e "s/\(.*\) in [^ ]*$/\1/" | uniq >"$2".actual
- test_i18ncmp "$2".expect "$2".actual
+ test_cmp "$2".expect "$2".actual
}
commit_check_warn () {
diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index 14cafc138b..ad4746d899 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -61,7 +61,7 @@ EOF
test_expect_success 'test help' '
test_must_fail test-tool parse-options -h >output 2>output.err &&
test_must_be_empty output.err &&
- test_i18ncmp expect output
+ test_cmp expect output
'
mv expect expect.err
@@ -84,7 +84,7 @@ check_unknown_i18n() {
cat expect.err >>expect &&
test_must_fail test-tool parse-options $* >output 2>output.err &&
test_must_be_empty output &&
- test_i18ncmp expect output.err
+ test_cmp expect output.err
}
test_expect_success 'OPT_BOOL() #1' 'check boolean: 1 --yes'
@@ -250,7 +250,7 @@ EOF
test_expect_success 'detect possible typos' '
test_must_fail test-tool parse-options -boolean >output 2>output.err &&
test_must_be_empty output &&
- test_i18ncmp typo.err output.err
+ test_cmp typo.err output.err
'
cat >typo.err <<\EOF
@@ -260,7 +260,7 @@ EOF
test_expect_success 'detect possible typos' '
test_must_fail test-tool parse-options -ambiguous >output 2>output.err &&
test_must_be_empty output &&
- test_i18ncmp typo.err output.err
+ test_cmp typo.err output.err
'
test_expect_success 'keep some options as arguments' '
diff --git a/t/t0201-gettext-fallbacks.sh b/t/t0201-gettext-fallbacks.sh
index 90da1c7ddc..6c74df0dc6 100755
--- a/t/t0201-gettext-fallbacks.sh
+++ b/t/t0201-gettext-fallbacks.sh
@@ -18,7 +18,7 @@ test_expect_success 'sanity: $GIT_INTERNAL_GETTEXT_TEST_FALLBACKS is set' '
test -n "$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS"
'
-test_expect_success C_LOCALE_OUTPUT 'sanity: $GIT_INTERNAL_GETTEXT_SH_SCHEME" is fallthrough' '
+test_expect_success 'sanity: $GIT_INTERNAL_GETTEXT_SH_SCHEME" is fallthrough' '
echo fallthrough >expect &&
echo $GIT_INTERNAL_GETTEXT_SH_SCHEME >actual &&
test_cmp expect actual
@@ -27,25 +27,25 @@ test_expect_success C_LOCALE_OUTPUT 'sanity: $GIT_INTERNAL_GETTEXT_SH_SCHEME" is
test_expect_success 'gettext: our gettext() fallback has pass-through semantics' '
printf "test" >expect &&
gettext "test" >actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
printf "test more words" >expect &&
gettext "test more words" >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'eval_gettext: our eval_gettext() fallback has pass-through semantics' '
printf "test" >expect &&
eval_gettext "test" >actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
printf "test more words" >expect &&
eval_gettext "test more words" >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables' '
printf "test YesPlease" >expect &&
GIT_INTERNAL_GETTEXT_TEST_FALLBACKS=YesPlease eval_gettext "test \$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS" >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces' '
@@ -53,7 +53,7 @@ test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate v
export cmdline &&
printf "When you have resolved this problem, run git am --resolved." >expect &&
eval_gettext "When you have resolved this problem, run \$cmdline --resolved." >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces and quotes' '
@@ -61,7 +61,7 @@ test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate v
export cmdline &&
printf "When you have resolved this problem, run \"git am --resolved\"." >expect &&
eval_gettext "When you have resolved this problem, run \"\$cmdline --resolved\"." >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_done
diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh
index a18f8a473b..3485c0534e 100755
--- a/t/t0300-credentials.sh
+++ b/t/t0300-credentials.sh
@@ -578,7 +578,7 @@ test_expect_success 'helpers can abort the process' '
quit: host=example.com
fatal: credential helper '\''quit'\'' told us to quit
EOF
- test_i18ncmp expect stderr
+ test_cmp expect stderr
'
test_expect_success 'empty helper spec resets helper list' '
@@ -606,7 +606,7 @@ test_expect_success 'url parser rejects embedded newlines' '
warning: url contains a newline in its path component: https://one.example.com?%0ahost=two.example.com/
fatal: credential url cannot be parsed: https://one.example.com?%0ahost=two.example.com/
EOF
- test_i18ncmp expect stderr
+ test_cmp expect stderr
'
test_expect_success 'host-less URLs are parsed as empty host' '
@@ -633,7 +633,7 @@ test_expect_success 'credential system refuses to work with missing host' '
cat >expect <<-\EOF &&
fatal: refusing to work with credential missing host field
EOF
- test_i18ncmp expect stderr
+ test_cmp expect stderr
'
test_expect_success 'credential system refuses to work with missing protocol' '
@@ -643,7 +643,7 @@ test_expect_success 'credential system refuses to work with missing protocol' '
cat >expect <<-\EOF &&
fatal: refusing to work with credential missing protocol field
EOF
- test_i18ncmp expect stderr
+ test_cmp expect stderr
'
# usage: check_host_and_path <url> <expected-host> <expected-path>
diff --git a/t/t0500-progress-display.sh b/t/t0500-progress-display.sh
index 84cce345e7..22058b503a 100755
--- a/t/t0500-progress-display.sh
+++ b/t/t0500-progress-display.sh
@@ -29,7 +29,7 @@ test_expect_success 'simple progress display' '
test-tool progress "Working hard" <in 2>stderr &&
show_cr <stderr >out &&
- test_i18ncmp expect out
+ test_cmp expect out
'
test_expect_success 'progress display with total' '
@@ -48,7 +48,7 @@ test_expect_success 'progress display with total' '
test-tool progress --total=3 "Working hard" <in 2>stderr &&
show_cr <stderr >out &&
- test_i18ncmp expect out
+ test_cmp expect out
'
test_expect_success 'progress display breaks long lines #1' '
@@ -72,7 +72,7 @@ EOF
<in 2>stderr &&
show_cr <stderr >out &&
- test_i18ncmp expect out
+ test_cmp expect out
'
test_expect_success 'progress display breaks long lines #2' '
@@ -100,7 +100,7 @@ EOF
<in 2>stderr &&
show_cr <stderr >out &&
- test_i18ncmp expect out
+ test_cmp expect out
'
test_expect_success 'progress display breaks long lines #3 - even the first is too long' '
@@ -126,7 +126,7 @@ EOF
<in 2>stderr &&
show_cr <stderr >out &&
- test_i18ncmp expect out
+ test_cmp expect out
'
test_expect_success 'progress display breaks long lines #4 - title line matches terminal width' '
@@ -150,7 +150,7 @@ EOF
<in 2>stderr &&
show_cr <stderr >out &&
- test_i18ncmp expect out
+ test_cmp expect out
'
# Progress counter goes backwards, this should not happen in practice.
@@ -172,7 +172,7 @@ test_expect_success 'progress shortens - crazy caller' '
test-tool progress --total=1000 "Working hard" <in 2>stderr &&
show_cr <stderr >out &&
- test_i18ncmp expect out
+ test_cmp expect out
'
test_expect_success 'progress display with throughput' '
@@ -201,7 +201,7 @@ test_expect_success 'progress display with throughput' '
test-tool progress "Working hard" <in 2>stderr &&
show_cr <stderr >out &&
- test_i18ncmp expect out
+ test_cmp expect out
'
test_expect_success 'progress display with throughput and total' '
@@ -226,7 +226,7 @@ test_expect_success 'progress display with throughput and total' '
test-tool progress --total=40 "Working hard" <in 2>stderr &&
show_cr <stderr >out &&
- test_i18ncmp expect out
+ test_cmp expect out
'
test_expect_success 'cover up after throughput shortens' '
@@ -255,7 +255,7 @@ test_expect_success 'cover up after throughput shortens' '
test-tool progress "Working hard" <in 2>stderr &&
show_cr <stderr >out &&
- test_i18ncmp expect out
+ test_cmp expect out
'
test_expect_success 'cover up after throughput shortens a lot' '
@@ -280,7 +280,7 @@ test_expect_success 'cover up after throughput shortens a lot' '
test-tool progress "Working hard" <in 2>stderr &&
show_cr <stderr >out &&
- test_i18ncmp expect out
+ test_cmp expect out
'
test_expect_success 'progress generates traces' '
diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh
index dfe9794a74..24092c09a9 100755
--- a/t/t1011-read-tree-sparse-checkout.sh
+++ b/t/t1011-read-tree-sparse-checkout.sh
@@ -253,7 +253,7 @@ warning: The following paths were already present and thus not updated despite s
After fixing the above paths, you may want to run `git sparse-checkout reapply`.
EOF
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'checkout without --ignore-skip-worktree-bits' '
diff --git a/t/t1308-config-set.sh b/t/t1308-config-set.sh
index 3a527e3a84..88b119a0a3 100755
--- a/t/t1308-config-set.sh
+++ b/t/t1308-config-set.sh
@@ -208,14 +208,14 @@ test_expect_success 'proper error on error in default config files' '
echo "[" >>.git/config &&
echo "fatal: bad config line 34 in file .git/config" >expect &&
test_expect_code 128 test-tool config get_value foo.bar 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'proper error on error in custom config files' '
echo "[" >>syntax-error &&
echo "fatal: bad config line 1 in file syntax-error" >expect &&
test_expect_code 128 test-tool config configset_get_value foo.bar syntax-error 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'check line errors for malformed values' '
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 359d8731c8..e31f65f381 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -374,7 +374,7 @@ test_expect_success 'Query "main@{May 25 2005}" (before history)' '
echo "$C" >expect &&
test_cmp expect o &&
echo "warning: log for '\''main'\'' only goes back to $ed" >expect &&
- test_i18ncmp expect e
+ test_cmp expect e
'
test_expect_success 'Query main@{2005-05-25} (before history)' '
test_when_finished "rm -f o e" &&
@@ -382,7 +382,7 @@ test_expect_success 'Query main@{2005-05-25} (before history)' '
echo "$C" >expect &&
test_cmp expect o &&
echo "warning: log for '\''main'\'' only goes back to $ed" >expect &&
- test_i18ncmp expect e
+ test_cmp expect e
'
test_expect_success 'Query "main@{May 26 2005 23:31:59}" (1 second before history)' '
test_when_finished "rm -f o e" &&
@@ -390,7 +390,7 @@ test_expect_success 'Query "main@{May 26 2005 23:31:59}" (1 second before histor
echo "$C" >expect &&
test_cmp expect o &&
echo "warning: log for '\''main'\'' only goes back to $ed" >expect &&
- test_i18ncmp expect e
+ test_cmp expect e
'
test_expect_success 'Query "main@{May 26 2005 23:32:00}" (exactly history start)' '
test_when_finished "rm -f o e" &&
diff --git a/t/t1404-update-ref-errors.sh b/t/t1404-update-ref-errors.sh
index 2d142e5535..8b51c4efc1 100755
--- a/t/t1404-update-ref-errors.sh
+++ b/t/t1404-update-ref-errors.sh
@@ -101,7 +101,7 @@ df_test() {
printf "%s\n" "delete $delname" "create $addname $D"
fi >commands &&
test_must_fail git update-ref --stdin <commands 2>output.err &&
- test_i18ncmp expected-err output.err &&
+ test_cmp expected-err output.err &&
printf "%s\n" "$C $delref" >expected-refs &&
git for-each-ref --format="%(objectname) %(refname)" $prefix/r >actual-refs &&
test_cmp expected-refs actual-refs
diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh
index 354902e514..b1839e0877 100755
--- a/t/t1430-bad-ref-name.sh
+++ b/t/t1430-bad-ref-name.sh
@@ -125,7 +125,7 @@ test_expect_success 'push cannot create a badly named ref' '
! grep -e "broken\.\.\.ref" output
'
-test_expect_failure C_LOCALE_OUTPUT 'push --mirror can delete badly named ref' '
+test_expect_failure 'push --mirror can delete badly named ref' '
top=$(pwd) &&
git init src &&
git init dest &&
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 231243152b..5071ac63a5 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -376,7 +376,7 @@ test_expect_success 'tag with incorrect tag name & missing tagger' '
warning in tag $tag: badTagName: invalid '\''tag'\'' name: wrong name format
warning in tag $tag: missingTaggerEntry: invalid format - expected '\''tagger'\'' line
EOF
- test_i18ncmp expect out
+ test_cmp expect out
'
test_expect_success 'tag with bad tagger' '
@@ -804,7 +804,7 @@ test_expect_success 'fsck notices dangling objects' '
git fsck >actual &&
# the output order is non-deterministic, as it comes from a hash
sort <actual >actual.sorted &&
- test_i18ncmp expect actual.sorted
+ test_cmp expect actual.sorted
)
'
@@ -814,7 +814,7 @@ test_expect_success 'fsck --connectivity-only notices dangling objects' '
git fsck --connectivity-only >actual &&
# the output order is non-deterministic, as it comes from a hash
sort <actual >actual.sorted &&
- test_i18ncmp expect actual.sorted
+ test_cmp expect actual.sorted
)
'
diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh
index a859abedf5..b29563fc99 100755
--- a/t/t1502-rev-parse-parseopt.sh
+++ b/t/t1502-rev-parse-parseopt.sh
@@ -95,7 +95,7 @@ test_expect_success 'test --parseopt help output' '
|EOF
END_EXPECT
test_expect_code 129 git rev-parse --parseopt -- -h > output < optionspec &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'test --parseopt help output no switches' '
@@ -108,7 +108,7 @@ test_expect_success 'test --parseopt help output no switches' '
|EOF
END_EXPECT
test_expect_code 129 git rev-parse --parseopt -- -h > output < optionspec_no_switches &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'test --parseopt help output hidden switches' '
@@ -121,7 +121,7 @@ test_expect_success 'test --parseopt help output hidden switches' '
|EOF
END_EXPECT
test_expect_code 129 git rev-parse --parseopt -- -h > output < optionspec_only_hidden_switches &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'test --parseopt help-all output hidden switches' '
@@ -136,7 +136,7 @@ test_expect_success 'test --parseopt help-all output hidden switches' '
|EOF
END_EXPECT
test_expect_code 129 git rev-parse --parseopt -- --help-all > output < optionspec_only_hidden_switches &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'test --parseopt invalid switch help output' '
@@ -176,7 +176,7 @@ test_expect_success 'test --parseopt invalid switch help output' '
|
END_EXPECT
test_expect_code 129 git rev-parse --parseopt -- --does-not-exist 1>/dev/null 2>output < optionspec &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'setup expect.1' "
diff --git a/t/t1506-rev-parse-diagnosis.sh b/t/t1506-rev-parse-diagnosis.sh
index f6e6f23f7e..65a154a8a2 100755
--- a/t/t1506-rev-parse-diagnosis.sh
+++ b/t/t1506-rev-parse-diagnosis.sh
@@ -15,7 +15,7 @@ test_did_you_mean ()
fatal: path '$2$3' $4, but not ${5:-$SQ$3$SQ}
hint: Did you mean '$1:$2$3'${2:+ aka $SQ$1:./$3$SQ}?
EOF
- test_i18ncmp expected error
+ test_cmp expected error
}
HASH_file=
diff --git a/t/t1507-rev-parse-upstream.sh b/t/t1507-rev-parse-upstream.sh
index 73b4f34c6e..c34714ffe3 100755
--- a/t/t1507-rev-parse-upstream.sh
+++ b/t/t1507-rev-parse-upstream.sh
@@ -172,7 +172,7 @@ test_expect_success 'branch@{u} error message when no upstream' '
fatal: no upstream configured for branch ${SQ}non-tracking${SQ}
EOF
error_message non-tracking@{u} &&
- test_i18ncmp expect error
+ test_cmp expect error
'
test_expect_success '@{u} error message when no upstream' '
@@ -180,7 +180,7 @@ test_expect_success '@{u} error message when no upstream' '
fatal: no upstream configured for branch ${SQ}main${SQ}
EOF
test_must_fail git rev-parse --verify @{u} 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'branch@{u} error message with misspelt branch' '
@@ -188,7 +188,7 @@ test_expect_success 'branch@{u} error message with misspelt branch' '
fatal: no such branch: ${SQ}no-such-branch${SQ}
EOF
error_message no-such-branch@{u} &&
- test_i18ncmp expect error
+ test_cmp expect error
'
test_expect_success '@{u} error message when not on a branch' '
@@ -197,7 +197,7 @@ test_expect_success '@{u} error message when not on a branch' '
EOF
git checkout HEAD^0 &&
test_must_fail git rev-parse --verify @{u} 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'branch@{u} error message if upstream branch not fetched' '
@@ -205,7 +205,7 @@ test_expect_success 'branch@{u} error message if upstream branch not fetched' '
fatal: upstream branch ${SQ}refs/heads/side${SQ} not stored as a remote-tracking branch
EOF
error_message bad-upstream@{u} &&
- test_i18ncmp expect error
+ test_cmp expect error
'
test_expect_success 'pull works when tracking a local branch' '
diff --git a/t/t1509-root-work-tree.sh b/t/t1509-root-work-tree.sh
index fd2f7abf1c..553a3f601b 100755
--- a/t/t1509-root-work-tree.sh
+++ b/t/t1509-root-work-tree.sh
@@ -221,7 +221,7 @@ test_expect_success 'setup' '
rm -rf /.git &&
echo "Initialized empty Git repository in /.git/" > expected &&
git init > result &&
- test_i18ncmp expected result
+ test_cmp expected result
'
test_vars 'auto gitdir, root' ".git" "/" ""
@@ -246,7 +246,7 @@ test_expect_success 'setup' '
cd / &&
echo "Initialized empty Git repository in /" > expected &&
git init --bare > result &&
- test_i18ncmp expected result
+ test_cmp expected result
'
test_vars 'auto gitdir, root' "." "" ""
diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh
index 242abbfa0b..7891a6becf 100755
--- a/t/t1512-rev-parse-disambiguation.sh
+++ b/t/t1512-rev-parse-disambiguation.sh
@@ -314,39 +314,39 @@ test_expect_success 'ambiguous short sha1 ref' '
grep "refname.*${REF}.*ambiguous" err
'
-test_expect_success C_LOCALE_OUTPUT 'ambiguity errors are not repeated (raw)' '
+test_expect_success 'ambiguity errors are not repeated (raw)' '
test_must_fail git rev-parse 00000 2>stderr &&
grep "is ambiguous" stderr >errors &&
test_line_count = 1 errors
'
-test_expect_success C_LOCALE_OUTPUT 'ambiguity errors are not repeated (treeish)' '
+test_expect_success 'ambiguity errors are not repeated (treeish)' '
test_must_fail git rev-parse 00000:foo 2>stderr &&
grep "is ambiguous" stderr >errors &&
test_line_count = 1 errors
'
-test_expect_success C_LOCALE_OUTPUT 'ambiguity errors are not repeated (peel)' '
+test_expect_success 'ambiguity errors are not repeated (peel)' '
test_must_fail git rev-parse 00000^{commit} 2>stderr &&
grep "is ambiguous" stderr >errors &&
test_line_count = 1 errors
'
-test_expect_success C_LOCALE_OUTPUT 'ambiguity hints' '
+test_expect_success 'ambiguity hints' '
test_must_fail git rev-parse 000000000 2>stderr &&
grep ^hint: stderr >hints &&
# 16 candidates, plus one intro line
test_line_count = 17 hints
'
-test_expect_success C_LOCALE_OUTPUT 'ambiguity hints respect type' '
+test_expect_success 'ambiguity hints respect type' '
test_must_fail git rev-parse 000000000^{commit} 2>stderr &&
grep ^hint: stderr >hints &&
# 5 commits, 1 tag (which is a committish), plus intro line
test_line_count = 7 hints
'
-test_expect_success C_LOCALE_OUTPUT 'failed type-selector still shows hint' '
+test_expect_success 'failed type-selector still shows hint' '
# these two blobs share the same prefix "ee3d", but neither
# will pass for a commit
echo 851 | git hash-object --stdin -w &&
@@ -370,7 +370,7 @@ test_expect_success 'core.disambiguate does not override context' '
git -c core.disambiguate=committish rev-parse $sha1^{tree}
'
-test_expect_success C_LOCALE_OUTPUT 'ambiguous commits are printed by type first, then hash order' '
+test_expect_success 'ambiguous commits are printed by type first, then hash order' '
test_must_fail git rev-parse 0000 2>stderr &&
grep ^hint: stderr >hints &&
grep 0000 hints >objects &&
diff --git a/t/t1600-index.sh b/t/t1600-index.sh
index b7c31aa86a..c9b9e718b8 100755
--- a/t/t1600-index.sh
+++ b/t/t1600-index.sh
@@ -18,7 +18,7 @@ test_expect_success 'bogus GIT_INDEX_VERSION issues warning' '
warning: GIT_INDEX_VERSION set, but the value is invalid.
Using version Z
EOF
- test_i18ncmp expect.err actual.err
+ test_cmp expect.err actual.err
)
'
@@ -32,7 +32,7 @@ test_expect_success 'out of bounds GIT_INDEX_VERSION issues warning' '
warning: GIT_INDEX_VERSION set, but the value is invalid.
Using version Z
EOF
- test_i18ncmp expect.err actual.err
+ test_cmp expect.err actual.err
)
'
@@ -55,7 +55,7 @@ test_expect_success 'out of bounds index.version issues warning' '
warning: index.version set, but the value is invalid.
Using version Z
EOF
- test_i18ncmp expect.err actual.err
+ test_cmp expect.err actual.err
)
'
diff --git a/t/t2006-checkout-index-basic.sh b/t/t2006-checkout-index-basic.sh
index 8e181dbf01..7ff3edab05 100755
--- a/t/t2006-checkout-index-basic.sh
+++ b/t/t2006-checkout-index-basic.sh
@@ -32,4 +32,27 @@ test_expect_success 'checkout-index reports errors (stdin)' '
test_i18ngrep not.in.the.cache stderr
'
+test_expect_success 'checkout-index --temp correctly reports error on missing blobs' '
+ test_when_finished git reset --hard &&
+ missing_blob=$(echo "no such blob here" | git hash-object --stdin) &&
+ cat >objs <<-EOF &&
+ 100644 $missing_blob file
+ 120000 $missing_blob symlink
+ EOF
+ git update-index --index-info <objs &&
+
+ test_must_fail git checkout-index --temp symlink file 2>stderr &&
+ test_i18ngrep "unable to read sha1 file of file ($missing_blob)" stderr &&
+ test_i18ngrep "unable to read sha1 file of symlink ($missing_blob)" stderr
+'
+
+test_expect_success 'checkout-index --temp correctly reports error for submodules' '
+ git init sub &&
+ test_commit -C sub file &&
+ git submodule add ./sub &&
+ git commit -m sub &&
+ test_must_fail git checkout-index --temp sub 2>stderr &&
+ test_i18ngrep "cannot create temporary submodule sub" stderr
+'
+
test_done
diff --git a/t/t2018-checkout-branch.sh b/t/t2018-checkout-branch.sh
index 5f761bc616..93be1c0eae 100755
--- a/t/t2018-checkout-branch.sh
+++ b/t/t2018-checkout-branch.sh
@@ -150,7 +150,7 @@ test_expect_success 'checkout -b to @{-1} fails with the right branch name' '
git checkout branch2 &&
echo >expect "fatal: A branch named '\''branch1'\'' already exists." &&
test_must_fail git checkout -b @{-1} 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'checkout -B to an existing branch resets branch to HEAD' '
diff --git a/t/t2020-checkout-detach.sh b/t/t2020-checkout-detach.sh
index b432b6427b..bc46713a43 100755
--- a/t/t2020-checkout-detach.sh
+++ b/t/t2020-checkout-detach.sh
@@ -163,7 +163,7 @@ test_expect_success 'tracking count is accurate after orphan check' '
git config branch.child.merge refs/heads/main &&
git checkout child^ &&
git checkout child >stdout &&
- test_i18ncmp expect stdout
+ test_cmp expect stdout
'
test_expect_success 'no advice given for explicit detached head state' '
@@ -237,15 +237,15 @@ test_expect_success 'describe_detached_head prints no SHA-1 ellipsis when not as
sane_unset GIT_PRINT_SHA1_ELLIPSIS &&
git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 &&
check_detached &&
- test_i18ncmp 1st_detach actual &&
+ test_cmp 1st_detach actual &&
GIT_PRINT_SHA1_ELLIPSIS="no" git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 &&
check_detached &&
- test_i18ncmp 2nd_detach actual &&
+ test_cmp 2nd_detach actual &&
GIT_PRINT_SHA1_ELLIPSIS= git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 &&
check_detached &&
- test_i18ncmp 3rd_detach actual &&
+ test_cmp 3rd_detach actual &&
sane_unset GIT_PRINT_SHA1_ELLIPSIS &&
@@ -256,17 +256,17 @@ test_expect_success 'describe_detached_head prints no SHA-1 ellipsis when not as
# Make no mention of the env var at all
git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 &&
check_detached &&
- test_i18ncmp 1st_detach actual &&
+ test_cmp 1st_detach actual &&
GIT_PRINT_SHA1_ELLIPSIS='nope' &&
git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 &&
check_detached &&
- test_i18ncmp 2nd_detach actual &&
+ test_cmp 2nd_detach actual &&
GIT_PRINT_SHA1_ELLIPSIS=nein &&
git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 &&
check_detached &&
- test_i18ncmp 3rd_detach actual &&
+ test_cmp 3rd_detach actual &&
true
"
@@ -319,15 +319,15 @@ test_expect_success 'describe_detached_head does print SHA-1 ellipsis when asked
GIT_PRINT_SHA1_ELLIPSIS=yes git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 &&
check_detached &&
- test_i18ncmp 1st_detach actual &&
+ test_cmp 1st_detach actual &&
GIT_PRINT_SHA1_ELLIPSIS=Yes git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 &&
check_detached &&
- test_i18ncmp 2nd_detach actual &&
+ test_cmp 2nd_detach actual &&
GIT_PRINT_SHA1_ELLIPSIS=YES git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 &&
check_detached &&
- test_i18ncmp 3rd_detach actual &&
+ test_cmp 3rd_detach actual &&
true
"
diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh
index 7cb7a70382..45ca35d60a 100755
--- a/t/t2200-add-update.sh
+++ b/t/t2200-add-update.sh
@@ -135,7 +135,7 @@ test_expect_success 'add -n -u should not add but just report' '
after=$(git ls-files -s check top) &&
test "$before" = "$after" &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
diff --git a/t/t2401-worktree-prune.sh b/t/t2401-worktree-prune.sh
index aff877590d..a615d3b483 100755
--- a/t/t2401-worktree-prune.sh
+++ b/t/t2401-worktree-prune.sh
@@ -23,7 +23,7 @@ test_expect_success 'prune files inside $GIT_DIR/worktrees' '
cat >expect <<EOF &&
Removing worktrees/abc: not a valid directory
EOF
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
! test -f .git/worktrees/abc &&
! test -d .git/worktrees
'
@@ -35,7 +35,7 @@ test_expect_success 'prune directories without gitdir' '
Removing worktrees/def: gitdir file does not exist
EOF
git worktree prune --verbose >actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
! test -d .git/worktrees/def &&
! test -d .git/worktrees
'
diff --git a/t/t2402-worktree-list.sh b/t/t2402-worktree-list.sh
index 42d35d9ae8..fedcefe8de 100755
--- a/t/t2402-worktree-list.sh
+++ b/t/t2402-worktree-list.sh
@@ -167,7 +167,7 @@ test_expect_success '"list" all worktrees --verbose with prunable' '
rm -rf prunable &&
git worktree list --verbose >out &&
sed -n "s/ */ /g;/\/prunable *[0-9a-f].*$/,/prunable: .*$/p" <out >actual &&
- test_i18ncmp actual expect
+ test_cmp actual expect
'
test_expect_success 'bare repo setup' '
diff --git a/t/t3005-ls-files-relative.sh b/t/t3005-ls-files-relative.sh
index 2ec69a8a26..727e9ae1a4 100755
--- a/t/t3005-ls-files-relative.sh
+++ b/t/t3005-ls-files-relative.sh
@@ -46,7 +46,7 @@ test_expect_success 'ls-files -c' '
ls ../x* >expect.out &&
test_must_fail git ls-files -c --error-unmatch ../[xy]* >actual.out 2>actual.err &&
test_cmp expect.out actual.out &&
- test_i18ncmp expect.err actual.err
+ test_cmp expect.err actual.err
)
'
@@ -61,7 +61,7 @@ test_expect_success 'ls-files -o' '
ls ../y* >expect.out &&
test_must_fail git ls-files -o --error-unmatch ../[xy]* >actual.out 2>actual.err &&
test_cmp expect.out actual.out &&
- test_i18ncmp expect.err actual.err
+ test_cmp expect.err actual.err
)
'
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 00761e4080..cc4b10236e 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -695,7 +695,7 @@ test_expect_success 'deleting a symref' '
git branch -d symref >actual &&
test_path_is_file .git/refs/heads/target &&
test_path_is_missing .git/refs/heads/symref &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'deleting a dangling symref' '
@@ -704,7 +704,7 @@ test_expect_success 'deleting a dangling symref' '
echo "Deleted branch dangling-symref (was nowhere)." >expect &&
git branch -d dangling-symref >actual &&
test_path_is_missing .git/refs/heads/dangling-symref &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'deleting a self-referential symref' '
@@ -713,7 +713,7 @@ test_expect_success 'deleting a self-referential symref' '
echo "Deleted branch self-reference (was refs/heads/self-reference)." >expect &&
git branch -d self-reference >actual &&
test_path_is_missing .git/refs/heads/self-reference &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'renaming a symref is not allowed' '
@@ -808,7 +808,7 @@ test_expect_success 'test deleting branch without config' '
sha1=$(git rev-parse my7 | cut -c 1-7) &&
echo "Deleted branch my7 (was $sha1)." >expect &&
git branch -d my7 >actual 2>&1 &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'deleting currently checked out branch fails' '
@@ -843,7 +843,7 @@ test_expect_success 'branch from tag w/--track causes failure' '
test_expect_success '--set-upstream-to fails on multiple branches' '
echo "fatal: too many arguments to set new upstream" >expect &&
test_must_fail git branch --set-upstream-to main a b c 2>err &&
- test_i18ncmp expect err
+ test_cmp expect err
'
test_expect_success '--set-upstream-to fails on detached HEAD' '
@@ -851,13 +851,13 @@ test_expect_success '--set-upstream-to fails on detached HEAD' '
test_when_finished git checkout - &&
echo "fatal: could not set upstream of HEAD to main when it does not point to any branch." >expect &&
test_must_fail git branch --set-upstream-to main 2>err &&
- test_i18ncmp expect err
+ test_cmp expect err
'
test_expect_success '--set-upstream-to fails on a missing dst branch' '
echo "fatal: branch '"'"'does-not-exist'"'"' does not exist" >expect &&
test_must_fail git branch --set-upstream-to main does-not-exist 2>err &&
- test_i18ncmp expect err
+ test_cmp expect err
'
test_expect_success '--set-upstream-to fails on a missing src branch' '
@@ -868,7 +868,7 @@ test_expect_success '--set-upstream-to fails on a missing src branch' '
test_expect_success '--set-upstream-to fails on a non-ref' '
echo "fatal: Cannot setup tracking information; starting point '"'"'HEAD^{}'"'"' is not a branch." >expect &&
test_must_fail git branch --set-upstream-to HEAD^{} 2>err &&
- test_i18ncmp expect err
+ test_cmp expect err
'
test_expect_success '--set-upstream-to fails on locked config' '
@@ -899,7 +899,7 @@ test_expect_success 'use --set-upstream-to modify a particular branch' '
test_expect_success '--unset-upstream should fail if given a non-existent branch' '
echo "fatal: Branch '"'"'i-dont-exist'"'"' has no upstream information" >expect &&
test_must_fail git branch --unset-upstream i-dont-exist 2>err &&
- test_i18ncmp expect err
+ test_cmp expect err
'
test_expect_success '--unset-upstream should fail if config is locked' '
@@ -921,13 +921,13 @@ test_expect_success 'test --unset-upstream on HEAD' '
# fail for a branch without upstream set
echo "fatal: Branch '"'"'main'"'"' has no upstream information" >expect &&
test_must_fail git branch --unset-upstream 2>err &&
- test_i18ncmp expect err
+ test_cmp expect err
'
test_expect_success '--unset-upstream should fail on multiple branches' '
echo "fatal: too many arguments to unset upstream" >expect &&
test_must_fail git branch --unset-upstream a b c 2>err &&
- test_i18ncmp expect err
+ test_cmp expect err
'
test_expect_success '--unset-upstream should fail on detached HEAD' '
@@ -935,7 +935,7 @@ test_expect_success '--unset-upstream should fail on detached HEAD' '
test_when_finished git checkout - &&
echo "fatal: could not unset upstream of HEAD when it does not point to any branch." >expect &&
test_must_fail git branch --unset-upstream 2>err &&
- test_i18ncmp expect err
+ test_cmp expect err
'
test_expect_success 'test --unset-upstream on a particular branch' '
@@ -957,7 +957,7 @@ test_expect_success '--set-upstream-to notices an error to set branch as own ups
EOF
test_expect_code 1 git config branch.my13.remote &&
test_expect_code 1 git config branch.my13.merge &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
# Keep this test last, as it changes the current branch
diff --git a/t/t3201-branch-contains.sh b/t/t3201-branch-contains.sh
index 578b5f4825..349a810cee 100755
--- a/t/t3201-branch-contains.sh
+++ b/t/t3201-branch-contains.sh
@@ -264,7 +264,7 @@ test_expect_success 'branch --merged with --verbose' '
* topic $(git rev-parse --short topic ) [ahead 1] foo
zzz $(git rev-parse --short zzz ) second on main
EOF
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_done
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index b6fcd017af..5325b9f67a 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -160,7 +160,7 @@ test_expect_success 'git branch shows detached HEAD properly' '
EOF
git checkout HEAD^0 &&
git branch >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'git branch shows detached HEAD properly after checkout --detach' '
@@ -173,7 +173,7 @@ test_expect_success 'git branch shows detached HEAD properly after checkout --de
EOF
git checkout --detach &&
git branch >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'git branch shows detached HEAD properly after moving' '
@@ -185,7 +185,7 @@ test_expect_success 'git branch shows detached HEAD properly after moving' '
EOF
git reset --hard HEAD^1 &&
git branch >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'git branch shows detached HEAD properly from tag' '
@@ -198,7 +198,7 @@ EOF
git tag fromtag main &&
git checkout fromtag &&
git branch >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'git branch shows detached HEAD properly after moving from tag' '
@@ -210,7 +210,7 @@ test_expect_success 'git branch shows detached HEAD properly after moving from t
EOF
git reset --hard HEAD^1 &&
git branch >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'git branch `--sort=[-]objectsize` option' '
@@ -221,7 +221,7 @@ test_expect_success 'git branch `--sort=[-]objectsize` option' '
main
EOF
git branch --sort=objectsize >actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
cat >expect <<-\EOF &&
* (HEAD detached from fromtag)
@@ -230,7 +230,7 @@ test_expect_success 'git branch `--sort=[-]objectsize` option' '
branch-two
EOF
git branch --sort=-objectsize >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'git branch `--sort=[-]type` option' '
@@ -241,7 +241,7 @@ test_expect_success 'git branch `--sort=[-]type` option' '
main
EOF
git branch --sort=type >actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
cat >expect <<-\EOF &&
* (HEAD detached from fromtag)
@@ -250,7 +250,7 @@ test_expect_success 'git branch `--sort=[-]type` option' '
main
EOF
git branch --sort=-type >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'git branch `--sort=[-]version:refname` option' '
@@ -261,7 +261,7 @@ test_expect_success 'git branch `--sort=[-]version:refname` option' '
main
EOF
git branch --sort=version:refname >actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
cat >expect <<-\EOF &&
* (HEAD detached from fromtag)
@@ -270,7 +270,7 @@ test_expect_success 'git branch `--sort=[-]version:refname` option' '
branch-one
EOF
git branch --sort=-version:refname >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'git branch --points-at option' '
@@ -337,7 +337,7 @@ test_expect_success 'git branch --format option' '
Refname is refs/heads/ref-to-remote
EOF
git branch --format="Refname is %(refname)" >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'worktree colors correct' '
@@ -355,7 +355,7 @@ test_expect_success 'worktree colors correct' '
rm -r worktree_dir &&
git worktree prune &&
test_decode_color <actual.raw >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success "set up color tests" '
@@ -398,7 +398,7 @@ test_expect_success 'verbose output lists worktree path' '
git branch -vv >actual &&
rm -r worktree_dir &&
git worktree prune &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_done
diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh
index 04de03cad0..f5bf16abcd 100755
--- a/t/t3300-funny-names.sh
+++ b/t/t3300-funny-names.sh
@@ -181,7 +181,7 @@ test_expect_success 'diffstat for rename quotes funny filename' '
git diff-index -M -p $t0 >diff &&
git apply --stat <diff >diffstat &&
sed -e "s/|.*//" -e "s/ *\$//" <diffstat >current &&
- test_i18ncmp expected current
+ test_cmp expected current
'
test_expect_success 'numstat for rename quotes funny filename' '
diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh
index 4af881f0ba..d742be8840 100755
--- a/t/t3301-notes.sh
+++ b/t/t3301-notes.sh
@@ -1293,11 +1293,11 @@ test_expect_success 'GIT_NOTES_REWRITE_REF overrides config' '
grep "replacement note 3" actual
'
-test_expect_success 'git notes copy diagnoses too many or too few parameters' '
+test_expect_success 'git notes copy diagnoses too many or too few arguments' '
test_must_fail git notes copy 2>error &&
- test_i18ngrep "too few parameters" error &&
+ test_i18ngrep "too few arguments" error &&
test_must_fail git notes copy one two three 2>error &&
- test_i18ngrep "too many parameters" error
+ test_i18ngrep "too many arguments" error
'
test_expect_success 'git notes get-ref expands refs/heads/main to refs/notes/refs/heads/main' '
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 5e88a10f8d..587b408063 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -113,7 +113,7 @@ test_expect_success 'rebase off of the previous branch using "-"' '
test_cmp expect.forkpoint actual.forkpoint &&
# the next one is dubious---we may want to say "-",
# instead of @{-1}, in the message
- test_i18ncmp expect.messages actual.messages
+ test_cmp expect.messages actual.messages
'
test_expect_success 'rebase a single mode change' '
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 28c2d15d80..66bcbbf952 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -86,7 +86,7 @@ test_expect_success 'rebase -i with empty todo list' '
git rebase -i HEAD^ >output 2>&1
) &&
tail -n 1 output >actual && # Ignore output about changing todo list
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'rebase -i with the exec command' '
@@ -159,9 +159,9 @@ test_expect_success 'rebase -x with empty command fails' '
test_when_finished "git rebase --abort ||:" &&
test_must_fail env git rebase -x "" @ 2>actual &&
test_write_lines "error: empty exec command" >expected &&
- test_i18ncmp expected actual &&
+ test_cmp expected actual &&
test_must_fail env git rebase -x " " @ 2>actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'rebase -x with newline in command fails' '
@@ -169,7 +169,7 @@ test_expect_success 'rebase -x with newline in command fails' '
test_must_fail env git rebase -x "a${LF}b" @ 2>actual &&
test_write_lines "error: exec commands cannot contain newlines" \
>expected &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'rebase -i with exec of inexistent command' '
@@ -451,7 +451,7 @@ test_expect_success 'verbose flag is heeded, even after --continue' '
grep "^ file1 | 2 +-$" output
'
-test_expect_success C_LOCALE_OUTPUT 'multi-squash only fires up editor once' '
+test_expect_success 'multi-squash only fires up editor once' '
base=$(git rev-parse HEAD~4) &&
(
set_fake_editor &&
@@ -464,7 +464,7 @@ test_expect_success C_LOCALE_OUTPUT 'multi-squash only fires up editor once' '
test 1 = $(git show | grep ONCE | wc -l)
'
-test_expect_success C_LOCALE_OUTPUT 'multi-fixup does not fire up editor' '
+test_expect_success 'multi-fixup does not fire up editor' '
git checkout -b multi-fixup E &&
base=$(git rev-parse HEAD~4) &&
(
@@ -515,7 +515,7 @@ test_expect_success 'commit message retained after conflict' '
git branch -D conflict-squash
'
-test_expect_success C_LOCALE_OUTPUT 'squash and fixup generate correct log messages' '
+test_expect_success 'squash and fixup generate correct log messages' '
cat >expect-squash-fixup <<-\EOF &&
B
@@ -542,7 +542,7 @@ test_expect_success C_LOCALE_OUTPUT 'squash and fixup generate correct log messa
git branch -D squash-fixup
'
-test_expect_success C_LOCALE_OUTPUT 'squash ignores comments' '
+test_expect_success 'squash ignores comments' '
git checkout -b skip-comments E &&
base=$(git rev-parse HEAD~4) &&
(
@@ -558,7 +558,7 @@ test_expect_success C_LOCALE_OUTPUT 'squash ignores comments' '
git branch -D skip-comments
'
-test_expect_success C_LOCALE_OUTPUT 'squash ignores blank lines' '
+test_expect_success 'squash ignores blank lines' '
git checkout -b skip-blank-lines E &&
base=$(git rev-parse HEAD~4) &&
(
@@ -996,7 +996,7 @@ test_expect_success 'rebase -ix with several instances of --exec' '
test_cmp expected actual
'
-test_expect_success C_LOCALE_OUTPUT 'rebase -ix with --autosquash' '
+test_expect_success 'rebase -ix with --autosquash' '
git reset --hard execute &&
git checkout -b autosquash &&
echo second >second.txt &&
@@ -1137,7 +1137,7 @@ test_expect_success 'rebase -i --root reword root when root has untracked file c
test "$(git rev-list --count HEAD)" = 2
'
-test_expect_success C_LOCALE_OUTPUT 'rebase --edit-todo does not work on non-interactive rebase' '
+test_expect_success 'rebase --edit-todo does not work on non-interactive rebase' '
git checkout reword-original-root-branch &&
git reset --hard &&
git checkout conflict-branch &&
@@ -1466,7 +1466,7 @@ test_expect_success 'rebase -i respects rebase.missingCommitsCheck = warn' '
FAKE_LINES="1 2 3 4" git rebase -i --root 2>actual.2
) &&
head -n4 actual.2 >actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
test D = $(git cat-file commit HEAD | sed -ne \$p)
'
@@ -1490,7 +1490,7 @@ test_expect_success 'rebase -i respects rebase.missingCommitsCheck = error' '
set_fake_editor &&
test_must_fail env FAKE_LINES="1 2 4" \
git rebase -i --root 2>actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
cp .git/rebase-merge/git-rebase-todo.backup \
.git/rebase-merge/git-rebase-todo &&
FAKE_LINES="1 2 drop 3 4 drop 5" git rebase --edit-todo
@@ -1536,11 +1536,11 @@ test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = wa
cp .git/rebase-merge/git-rebase-todo.backup orig &&
FAKE_LINES="2 3 4" git rebase --edit-todo 2>actual.2 &&
head -n6 actual.2 >actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
cp orig .git/rebase-merge/git-rebase-todo &&
FAKE_LINES="1 2 3 4" git rebase --edit-todo 2>actual.2 &&
head -n4 actual.2 >actual &&
- test_i18ncmp expect.3 actual &&
+ test_cmp expect.3 actual &&
git rebase --continue 2>actual
) &&
test D = $(git cat-file commit HEAD | sed -ne \$p) &&
@@ -1576,16 +1576,16 @@ test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = er
cp .git/rebase-merge/git-rebase-todo.backup orig &&
test_must_fail env FAKE_LINES="2 3 4" \
git rebase --edit-todo 2>actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
test_must_fail git rebase --continue 2>actual &&
- test_i18ncmp expect.2 actual &&
+ test_cmp expect.2 actual &&
test_must_fail git rebase --edit-todo &&
cp orig .git/rebase-merge/git-rebase-todo &&
test_must_fail env FAKE_LINES="1 2 3 4" \
git rebase --edit-todo 2>actual &&
- test_i18ncmp expect.3 actual &&
+ test_cmp expect.3 actual &&
test_must_fail git rebase --continue 2>actual &&
- test_i18ncmp expect.3 actual &&
+ test_cmp expect.3 actual &&
cp orig .git/rebase-merge/git-rebase-todo &&
FAKE_LINES="1 2 3 4 drop 5" git rebase --edit-todo &&
git rebase --continue 2>actual
diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh
index 36f169d7f1..908016c2f8 100755
--- a/t/t3415-rebase-autosquash.sh
+++ b/t/t3415-rebase-autosquash.sh
@@ -306,23 +306,23 @@ test_auto_fixup_fixup () {
fi
}
-test_expect_success C_LOCALE_OUTPUT 'fixup! fixup!' '
+test_expect_success 'fixup! fixup!' '
test_auto_fixup_fixup fixup fixup
'
-test_expect_success C_LOCALE_OUTPUT 'fixup! squash!' '
+test_expect_success 'fixup! squash!' '
test_auto_fixup_fixup fixup squash
'
-test_expect_success C_LOCALE_OUTPUT 'squash! squash!' '
+test_expect_success 'squash! squash!' '
test_auto_fixup_fixup squash squash
'
-test_expect_success C_LOCALE_OUTPUT 'squash! fixup!' '
+test_expect_success 'squash! fixup!' '
test_auto_fixup_fixup squash fixup
'
-test_expect_success C_LOCALE_OUTPUT 'autosquash with custom inst format' '
+test_expect_success 'autosquash with custom inst format' '
git reset --hard base &&
git config --add rebase.instructionFormat "[%an @ %ar] %s" &&
echo 2 >file1 &&
diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh
index 4caa014c71..43fcb68f27 100755
--- a/t/t3420-rebase-autostash.sh
+++ b/t/t3420-rebase-autostash.sh
@@ -110,7 +110,7 @@ testrebase () {
fi &&
create_expected_success_$suffix &&
sed "$remove_progress_re" <actual >actual2 &&
- test_i18ncmp expected actual2
+ test_cmp expected actual2
'
test_expect_success "rebase$type: dirty index, non-conflicting rebase" '
@@ -231,7 +231,7 @@ testrebase () {
fi &&
create_expected_failure_$suffix &&
sed "$remove_progress_re" <actual >actual2 &&
- test_i18ncmp expected actual2
+ test_cmp expected actual2
'
}
diff --git a/t/t3431-rebase-fork-point.sh b/t/t3431-rebase-fork-point.sh
index 2dab893c75..4c98d99e7e 100755
--- a/t/t3431-rebase-fork-point.sh
+++ b/t/t3431-rebase-fork-point.sh
@@ -29,19 +29,23 @@ test_expect_success setup '
test_commit G
'
+do_test_rebase () {
+ expected="$1" &&
+ shift &&
+ git checkout main &&
+ git reset --hard E &&
+ git checkout side &&
+ git reset --hard G &&
+ git rebase $* &&
+ test_write_lines $expected >expect &&
+ git log --pretty=%s >actual &&
+ test_cmp expect actual
+}
+
test_rebase () {
expected="$1" &&
shift &&
- test_expect_success "git rebase $*" "
- git checkout main &&
- git reset --hard E &&
- git checkout side &&
- git reset --hard G &&
- git rebase $* &&
- test_write_lines $expected >expect &&
- git log --pretty=%s >actual &&
- test_cmp expect actual
- "
+ test_expect_success "git rebase $*" "do_test_rebase '$expected' $*"
}
test_rebase 'G F E D B A'
@@ -77,4 +81,35 @@ test_expect_success 'git rebase --fork-point with ambigous refname' '
test_must_fail git rebase --fork-point --onto D one
'
+test_expect_success '--fork-point and --root both given' '
+ test_must_fail git rebase --fork-point --root 2>err &&
+ test_i18ngrep "cannot combine" err
+'
+
+test_expect_success 'rebase.forkPoint set to false' '
+ test_config rebase.forkPoint false &&
+ do_test_rebase "G F C E D B A"
+'
+
+test_expect_success 'rebase.forkPoint set to false and then to true' '
+ test_config_global rebase.forkPoint false &&
+ test_config rebase.forkPoint true &&
+ do_test_rebase "G F E D B A"
+'
+
+test_expect_success 'rebase.forkPoint set to false and command line says --fork-point' '
+ test_config rebase.forkPoint false &&
+ do_test_rebase "G F E D B A" --fork-point
+'
+
+test_expect_success 'rebase.forkPoint set to true and command line says --no-fork-point' '
+ test_config rebase.forkPoint true &&
+ do_test_rebase "G F C E D B A" --no-fork-point
+'
+
+test_expect_success 'rebase.forkPoint set to true and --root given' '
+ test_config rebase.forkPoint true &&
+ git rebase --root
+'
+
test_done
diff --git a/t/t3504-cherry-pick-rerere.sh b/t/t3504-cherry-pick-rerere.sh
index 9198535874..4581ae98b8 100755
--- a/t/t3504-cherry-pick-rerere.sh
+++ b/t/t3504-cherry-pick-rerere.sh
@@ -74,10 +74,10 @@ test_expect_success 'cherry-pick --continue rejects --rerere-autoupdate' '
git diff-files --quiet &&
test_must_fail git cherry-pick --continue --rerere-autoupdate >actual 2>&1 &&
echo "fatal: cherry-pick: --rerere-autoupdate cannot be used with --continue" >expect &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
test_must_fail git cherry-pick --continue --no-rerere-autoupdate >actual 2>&1 &&
echo "fatal: cherry-pick: --no-rerere-autoupdate cannot be used with --continue" >expect &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
git cherry-pick --abort
'
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index 5f4564c830..014001b8f3 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -59,7 +59,7 @@ test_expect_success 'advice from failed cherry-pick' "
EOF
test_must_fail git cherry-pick picked 2>actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
"
test_expect_success 'advice from failed cherry-pick --no-commit' "
@@ -73,7 +73,7 @@ test_expect_success 'advice from failed cherry-pick --no-commit' "
EOF
test_must_fail git cherry-pick --no-commit picked 2>actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
"
test_expect_success 'failed cherry-pick sets CHERRY_PICK_HEAD' '
@@ -256,7 +256,7 @@ test_expect_success \
test_must_fail git cherry-pick picked &&
- test_i18ncmp expected .git/MERGE_MSG
+ test_cmp expected .git/MERGE_MSG
'
test_expect_success \
@@ -276,7 +276,7 @@ test_expect_success \
test_must_fail git cherry-pick --cleanup=scissors picked &&
- test_i18ncmp expected .git/MERGE_MSG
+ test_cmp expected .git/MERGE_MSG
'
test_expect_success 'failed cherry-pick describes conflict in work tree' '
@@ -465,7 +465,7 @@ test_expect_success \
test_must_fail git revert picked &&
sed "s/$OID_REGEX/OBJID/" .git/MERGE_MSG >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success \
@@ -488,7 +488,7 @@ test_expect_success \
test_must_fail git revert --cleanup=scissors picked &&
sed "s/$OID_REGEX/OBJID/" .git/MERGE_MSG >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'failed cherry-pick does not forget -s' '
diff --git a/t/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh
index ec7a2c9fcf..e8375d1c97 100755
--- a/t/t3508-cherry-pick-many-commits.sh
+++ b/t/t3508-cherry-pick-many-commits.sh
@@ -86,7 +86,7 @@ test_expect_success 'output to keep user entertained during multi-pick' '
git cherry-pick first..fourth >actual &&
sed -e "s/$_x05[0-9a-f][0-9a-f]/OBJID/" <actual >actual.fuzzy &&
test_line_count -ge 3 actual.fuzzy &&
- test_i18ncmp expected actual.fuzzy
+ test_cmp expected actual.fuzzy
'
test_expect_success 'cherry-pick --strategy resolve first..fourth works' '
@@ -123,7 +123,7 @@ test_expect_success 'output during multi-pick indicates merge strategy' '
test_tick &&
git cherry-pick --strategy resolve first..fourth >actual &&
sed -e "s/$_x05[0-9a-f][0-9a-f]/OBJID/" <actual >actual.fuzzy &&
- test_i18ncmp expected actual.fuzzy
+ test_cmp expected actual.fuzzy
'
test_expect_success 'cherry-pick --ff first..fourth works' '
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 5b94fdaa67..b76cb6de91 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -170,7 +170,7 @@ test_expect_success 'check advice when we move HEAD by committing' '
git commit -a &&
test_path_is_missing .git/CHERRY_PICK_HEAD &&
test_must_fail git cherry-pick --skip 2>advice &&
- test_i18ncmp expect advice
+ test_cmp expect advice
'
test_expect_success 'selectively advise --skip while launching another sequence' '
@@ -182,7 +182,7 @@ test_expect_success 'selectively advise --skip while launching another sequence'
EOF
test_must_fail git cherry-pick picked..yetanotherpick &&
test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
- test_i18ncmp expect advice &&
+ test_cmp expect advice &&
cat >expect <<-EOF &&
error: cherry-pick is already in progress
hint: try "git cherry-pick (--continue | --abort | --quit)"
@@ -190,7 +190,7 @@ test_expect_success 'selectively advise --skip while launching another sequence'
EOF
git reset --merge &&
test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
- test_i18ncmp expect advice
+ test_cmp expect advice
'
test_expect_success 'allow skipping commit but not abort for a new history' '
@@ -204,7 +204,7 @@ test_expect_success 'allow skipping commit but not abort for a new history' '
test_must_fail git cherry-pick anotherpick &&
test_must_fail git cherry-pick --abort 2>advice &&
git cherry-pick --skip &&
- test_i18ncmp expect advice
+ test_cmp expect advice
'
test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '
diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh
index 7547f11a5c..bb9ef35dac 100755
--- a/t/t3600-rm.sh
+++ b/t/t3600-rm.sh
@@ -454,7 +454,7 @@ test_expect_success 'rm issues a warning when section is not found in .gitmodule
git add .gitmodules &&
echo "warning: Could not find section in .gitmodules where path=submod" >expect.err &&
git rm submod >actual 2>actual.err &&
- test_i18ncmp expect.err actual.err &&
+ test_cmp expect.err actual.err &&
test_path_is_missing submod &&
test_path_is_missing submod/.git &&
git status -s -uno >actual &&
@@ -824,7 +824,7 @@ test_expect_success 'rm files with different staged content' '
echo content1 >foo.txt &&
echo content1 >bar.txt &&
test_must_fail git rm foo.txt bar.txt 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'rm files with different staged content without hints' '
@@ -837,7 +837,7 @@ test_expect_success 'rm files with different staged content without hints' '
echo content2 >foo.txt &&
echo content2 >bar.txt &&
test_must_fail git -c advice.rmhints=false rm foo.txt bar.txt 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'rm file with local modification' '
@@ -849,7 +849,7 @@ test_expect_success 'rm file with local modification' '
git commit -m "testing rm 3" &&
echo content3 >foo.txt &&
test_must_fail git rm foo.txt 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'rm file with local modification without hints' '
@@ -859,7 +859,7 @@ test_expect_success 'rm file with local modification without hints' '
EOF
echo content4 >bar.txt &&
test_must_fail git -c advice.rmhints=false rm bar.txt 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'rm file with changes in the index' '
@@ -872,7 +872,7 @@ test_expect_success 'rm file with changes in the index' '
echo content5 >foo.txt &&
git add foo.txt &&
test_must_fail git rm foo.txt 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'rm file with changes in the index without hints' '
@@ -881,7 +881,7 @@ test_expect_success 'rm file with changes in the index without hints' '
foo.txt
EOF
test_must_fail git -c advice.rmhints=false rm foo.txt 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'rm files with two different errors' '
@@ -900,7 +900,7 @@ test_expect_success 'rm files with two different errors' '
echo content6 >bar1.txt &&
git add bar1.txt &&
test_must_fail git rm bar1.txt foo1.txt 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'rm empty string should fail' '
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index b7d4ba608c..b3b122ff97 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -304,7 +304,7 @@ test_expect_success 'error on a repository with no commits' '
error: '"'empty/'"' does not have a commit checked out
fatal: adding files failed
EOF
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'git add --dry-run of existing changed file' "
@@ -320,7 +320,7 @@ test_expect_success 'git add --dry-run of non-existing file' "
test_expect_success 'git add --dry-run of an existing file output' "
echo \"fatal: pathspec 'ignored-file' did not match any files\" >expect &&
- test_i18ncmp expect actual
+ test_cmp expect actual
"
cat >expect.err <<\EOF
@@ -339,8 +339,8 @@ test_expect_success 'git add --dry-run --ignore-missing of non-existing file' '
'
test_expect_success 'git add --dry-run --ignore-missing of non-existing file output' '
- test_i18ncmp expect.out actual.out &&
- test_i18ncmp expect.err actual.err
+ test_cmp expect.out actual.out &&
+ test_cmp expect.err actual.err
'
test_expect_success 'git add empty string should fail' '
@@ -386,6 +386,36 @@ test_expect_success POSIXPERM 'git add --chmod=[+-]x does not change the working
! test -x foo4
'
+test_expect_success 'git add --chmod fails with non regular files (but updates the other paths)' '
+ git reset --hard &&
+ test_ln_s_add foo foo3 &&
+ touch foo4 &&
+ test_must_fail git add --chmod=+x foo3 foo4 2>stderr &&
+ test_i18ngrep "cannot chmod +x .foo3." stderr &&
+ test_mode_in_index 120000 foo3 &&
+ test_mode_in_index 100755 foo4
+'
+
+test_expect_success 'git add --chmod honors --dry-run' '
+ git reset --hard &&
+ echo foo >foo4 &&
+ git add foo4 &&
+ git add --chmod=+x --dry-run foo4 &&
+ test_mode_in_index 100644 foo4
+'
+
+test_expect_success 'git add --chmod --dry-run reports error for non regular files' '
+ git reset --hard &&
+ test_ln_s_add foo foo4 &&
+ test_must_fail git add --chmod=+x --dry-run foo4 2>stderr &&
+ test_i18ngrep "cannot chmod +x .foo4." stderr
+'
+
+test_expect_success 'git add --chmod --dry-run reports error for unmatched pathspec' '
+ test_must_fail git add --chmod=+x --dry-run nonexistent 2>stderr &&
+ test_i18ngrep "pathspec .nonexistent. did not match any files" stderr
+'
+
test_expect_success 'no file status change if no pathspec is given' '
>foo5 &&
>foo6 &&
@@ -409,11 +439,17 @@ test_expect_success 'no file status change if no pathspec is given in subdir' '
'
test_expect_success 'all statuses changed in folder if . is given' '
- rm -fr empty &&
- git add --chmod=+x . &&
- test $(git ls-files --stage | grep ^100644 | wc -l) -eq 0 &&
- git add --chmod=-x . &&
- test $(git ls-files --stage | grep ^100755 | wc -l) -eq 0
+ git init repo &&
+ (
+ cd repo &&
+ mkdir -p sub/dir &&
+ touch x y z sub/a sub/dir/b &&
+ git add -A &&
+ git add --chmod=+x . &&
+ test $(git ls-files --stage | grep ^100644 | wc -l) -eq 0 &&
+ git add --chmod=-x . &&
+ test $(git ls-files --stage | grep ^100755 | wc -l) -eq 0
+ )
'
test_expect_success CASE_INSENSITIVE_FS 'path is case-insensitive' '
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index b2f90997db..207714655f 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -370,7 +370,7 @@ test_expect_success 'setup expected' '
'
# Test splitting the first patch, then adding both
-test_expect_success C_LOCALE_OUTPUT 'add first line works' '
+test_expect_success 'add first line works' '
git commit -am "clear local changes" &&
git apply patch &&
printf "%s\n" s y y | git add -p file 2>error |
@@ -974,7 +974,7 @@ test_expect_success 'show help from add--helper' '
EOF
test_write_lines h | force_color git add -i >actual.colored &&
test_decode_color <actual.colored >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_done
diff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh
index 86bfeb271e..60a666da59 100755
--- a/t/t3800-mktag.sh
+++ b/t/t3800-mktag.sh
@@ -13,13 +13,11 @@ test_description='git mktag: tag object verify test'
check_verify_failure () {
test_expect_success "$1" "
- test_must_fail env GIT_TEST_GETTEXT_POISON=false \
- git mktag <tag.sig 2>message &&
+ test_must_fail git mktag <tag.sig 2>message &&
grep '$2' message &&
if test '$3' != '--no-strict'
then
- test_must_fail env GIT_TEST_GETTEXT_POISON=false \
- git mktag --no-strict <tag.sig 2>message.no-strict &&
+ test_must_fail git mktag --no-strict <tag.sig 2>message.no-strict &&xb
grep '$2' message.no-strict
fi
"
@@ -443,11 +441,9 @@ test_expect_success 'invalid header entry config & fsck' '
git -c fsck.extraHeaderEntry=ignore mktag --no-strict <tag.sig &&
git fsck &&
- env GIT_TEST_GETTEXT_POISON=false \
- git -c fsck.extraHeaderEntry=warn fsck 2>err &&
+ git -c fsck.extraHeaderEntry=warn fsck 2>err &&
grep "warning .*extraHeaderEntry:" err &&
- test_must_fail env GIT_TEST_GETTEXT_POISON=false \
- git -c fsck.extraHeaderEntry=error 2>err fsck &&
+ test_must_fail git -c fsck.extraHeaderEntry=error 2>err fsck &&
grep "error .* extraHeaderEntry:" err
'
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 84b039e573..5f282ecf61 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -564,7 +564,7 @@ test_expect_success 'stash show format defaults to --stat' '
1 file changed, 1 insertion(+)
EOF
git stash show ${STASH_ID} >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'stash show - stashes on stack, stash-like argument' '
@@ -792,7 +792,7 @@ test_expect_success 'apply: show same status as git status (relative to ./)' '
git stash apply
) |
sed -e 1d >actual && # drop "Saved..."
- test_i18ncmp expect actual
+ test_cmp expect actual
'
cat >expect <<EOF
@@ -1114,7 +1114,7 @@ test_expect_success 'stash push -p with pathspec shows no changes only once' '
git stash push -p foo >actual &&
echo "No local changes to save" >expect &&
git reset --hard HEAD~ &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'push <pathspec>: show no changes when there are none' '
@@ -1124,7 +1124,7 @@ test_expect_success 'push <pathspec>: show no changes when there are none' '
git stash push foo >actual &&
echo "No local changes to save" >expect &&
git reset --hard HEAD~ &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'push: <pathspec> not in the repository errors out' '
diff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh
index b26a97aef4..598b17f6d4 100755
--- a/t/t3905-stash-include-untracked.sh
+++ b/t/t3905-stash-include-untracked.sh
@@ -288,7 +288,7 @@ test_expect_success 'stash -u -- <ignored> leaves ignored file alone' '
test_expect_success 'stash -u -- <non-existent> shows no changes when there are none' '
git stash push -u -- non-existent >actual &&
echo "No local changes to save" >expect &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'stash -u with globs' '
diff --git a/t/t4001-diff-rename.sh b/t/t4001-diff-rename.sh
index 2f9700742a..68f2ebca58 100755
--- a/t/t4001-diff-rename.sh
+++ b/t/t4001-diff-rename.sh
@@ -262,4 +262,28 @@ test_expect_success 'diff-tree -l0 defaults to a big rename limit, not zero' '
grep "myotherfile.*myfile" actual
'
+test_expect_success 'basename similarity vs best similarity' '
+ mkdir subdir &&
+ test_write_lines line1 line2 line3 line4 line5 \
+ line6 line7 line8 line9 line10 >subdir/file.txt &&
+ git add subdir/file.txt &&
+ git commit -m "base txt" &&
+
+ git rm subdir/file.txt &&
+ test_write_lines line1 line2 line3 line4 line5 \
+ line6 line7 line8 >file.txt &&
+ test_write_lines line1 line2 line3 line4 line5 \
+ line6 line7 line8 line9 >file.md &&
+ git add file.txt file.md &&
+ git commit -a -m "rename" &&
+ git diff-tree -r -M --name-status HEAD^ HEAD >actual &&
+ # subdir/file.txt is 88% similar to file.md, 78% similar to file.txt,
+ # but since same basenames are checked first...
+ cat >expected <<-\EOF &&
+ A file.md
+ R078 subdir/file.txt file.txt
+ EOF
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t4006-diff-mode.sh b/t/t4006-diff-mode.sh
index 03489aff14..275ce5fa15 100755
--- a/t/t4006-diff-mode.sh
+++ b/t/t4006-diff-mode.sh
@@ -39,13 +39,13 @@ test_expect_success '--stat output after text chmod' '
1 file changed, 0 insertions(+), 0 deletions(-)
EOF
git diff HEAD --stat >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success '--shortstat output after text chmod' '
tail -n 1 <expect >expect.short &&
git diff HEAD --shortstat >actual &&
- test_i18ncmp expect.short actual
+ test_cmp expect.short actual
'
test_expect_success '--stat output after binary chmod' '
@@ -56,13 +56,13 @@ test_expect_success '--stat output after binary chmod' '
2 files changed, 0 insertions(+), 0 deletions(-)
EOF
git diff HEAD --stat >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success '--shortstat output after binary chmod' '
tail -n 1 <expect >expect.short &&
git diff HEAD --shortstat >actual &&
- test_i18ncmp expect.short actual
+ test_cmp expect.short actual
'
test_done
diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh
index 6579c81216..33ff588ebc 100755
--- a/t/t4012-diff-binary.sh
+++ b/t/t4012-diff-binary.sh
@@ -34,19 +34,19 @@ EOF
test_expect_success 'apply --stat output for binary file change' '
git diff >diff &&
git apply --stat --summary <diff >current &&
- test_i18ncmp expected current
+ test_cmp expected current
'
test_expect_success 'diff --shortstat output for binary file change' '
tail -n 1 expected >expect &&
git diff --shortstat >current &&
- test_i18ncmp expect current
+ test_cmp expect current
'
test_expect_success 'diff --shortstat output for binary file change only' '
echo " 1 file changed, 0 insertions(+), 0 deletions(-)" >expected &&
git diff --shortstat -- b >current &&
- test_i18ncmp expected current
+ test_cmp expected current
'
test_expect_success 'apply --numstat notices binary file change' '
@@ -63,7 +63,7 @@ test_expect_success 'apply --numstat understands diff --binary format' '
# apply needs to be able to skip the binary material correctly
# in order to report the line number of a corrupt patch.
-test_expect_success C_LOCALE_OUTPUT 'apply detecting corrupt patch correctly' '
+test_expect_success 'apply detecting corrupt patch correctly' '
git diff >output &&
sed -e "s/-CIT/xCIT/" <output >broken &&
test_must_fail git apply --stat --summary broken 2>detected &&
@@ -73,7 +73,7 @@ test_expect_success C_LOCALE_OUTPUT 'apply detecting corrupt patch correctly' '
test "$detected" = xCIT
'
-test_expect_success C_LOCALE_OUTPUT 'apply detecting corrupt patch correctly' '
+test_expect_success 'apply detecting corrupt patch correctly' '
git diff --binary | sed -e "s/-CIT/xCIT/" >broken &&
test_must_fail git apply --stat --summary broken 2>detected &&
detected=$(cat detected) &&
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index fcc30d8cc2..6cca8b84a6 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -222,7 +222,7 @@ do
process_diffs "$expect" >expect &&
case $cmd in
*format-patch* | *-stat*)
- test_i18ncmp expect actual;;
+ test_cmp expect actual;;
*)
test_cmp expect actual;;
esac &&
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 66630c8413..cdd3154e70 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -888,11 +888,11 @@ echo "fatal: --check does not make sense" >expect.check
test_expect_success 'options no longer allowed for format-patch' '
test_must_fail git format-patch --name-only 2>output &&
- test_i18ncmp expect.name-only output &&
+ test_cmp expect.name-only output &&
test_must_fail git format-patch --name-status 2>output &&
- test_i18ncmp expect.name-status output &&
+ test_cmp expect.name-status output &&
test_must_fail git format-patch --check 2>output &&
- test_i18ncmp expect.check output
+ test_cmp expect.check output
'
test_expect_success 'format-patch --numstat should produce a patch' '
diff --git a/t/t4016-diff-quote.sh b/t/t4016-diff-quote.sh
index 9c48e5c2c9..876271d682 100755
--- a/t/t4016-diff-quote.sh
+++ b/t/t4016-diff-quote.sh
@@ -82,7 +82,7 @@ test_expect_success 'git diff --stat -M HEAD' '
7 files changed, 0 insertions(+), 0 deletions(-)
EOF
git diff --stat -M HEAD >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_done
diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
index 4cb9f0e523..c906320b60 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -139,7 +139,7 @@ EOF
test_expect_success 'diffstat does not run textconv' '
echo file diff=fail >.gitattributes &&
git diff --stat HEAD^ HEAD >actual &&
- test_i18ncmp expect.stat actual &&
+ test_cmp expect.stat actual &&
head -n1 <expect.stat >expect.line1 &&
head -n1 <actual >actual.line1 &&
diff --git a/t/t4045-diff-relative.sh b/t/t4045-diff-relative.sh
index 7be1de736d..61ba5f707f 100755
--- a/t/t4045-diff-relative.sh
+++ b/t/t4045-diff-relative.sh
@@ -61,7 +61,7 @@ check_stat () {
EOF
test_expect_success "--stat $*" "
git -C '$dir' diff --stat $* HEAD^ >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
"
}
diff --git a/t/t4049-diff-stat-count.sh b/t/t4049-diff-stat-count.sh
index a34121740a..53061b104e 100755
--- a/t/t4049-diff-stat-count.sh
+++ b/t/t4049-diff-stat-count.sh
@@ -25,7 +25,7 @@ test_expect_success 'mode-only change show as a 0-line change' '
4 files changed, 2 insertions(+)
EOF
git diff --stat --stat-count=2 HEAD >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'binary changes do not count in lines' '
@@ -40,7 +40,7 @@ test_expect_success 'binary changes do not count in lines' '
3 files changed, 2 insertions(+)
EOF
git diff --stat --stat-count=2 >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'exclude unmerged entries from total file count' '
@@ -62,7 +62,7 @@ test_expect_success 'exclude unmerged entries from total file count' '
3 files changed, 3 insertions(+)
EOF
git diff --stat --stat-count=2 >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_done
diff --git a/t/t4056-diff-order.sh b/t/t4056-diff-order.sh
index 63ea7144bb..aec1d9d1b4 100755
--- a/t/t4056-diff-order.sh
+++ b/t/t4056-diff-order.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-test_description='diff order'
+test_description='diff order & rotate'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
@@ -127,4 +127,74 @@ do
'
done
+### rotate and skip
+
+test_expect_success 'rotate and skip setup' '
+ >sample1.t &&
+ >sample2.t &&
+ >sample3.t &&
+ >sample4.t &&
+ git add sample[1234].t &&
+ git commit -m "added" sample[1234].t &&
+ echo modified >>sample1.t &&
+ echo modified >>sample2.t &&
+ echo modified >>sample4.t &&
+ git commit -m "updated" sample[1234].t
+'
+
+test_expect_success 'diff --rotate-to' '
+ git diff --rotate-to=sample2.t --name-only HEAD^ >actual &&
+ test_write_lines sample2.t sample4.t sample1.t >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'diff --skip-to' '
+ git diff --skip-to=sample2.t --name-only HEAD^ >actual &&
+ test_write_lines sample2.t sample4.t >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'diff --rotate/skip-to error condition' '
+ test_must_fail git diff --rotate-to=sample3.t HEAD^ &&
+ test_must_fail git diff --skip-to=sample3.t HEAD^
+'
+
+test_expect_success 'log --rotate-to' '
+ git log --rotate-to=sample3.t --raw HEAD~2.. >raw &&
+ # just distill the commit header and paths
+ sed -n -e "s/^commit.*/commit/p" \
+ -e "/^:/s/^.* //p" raw >actual &&
+
+ cat >expect <<-\EOF &&
+ commit
+ sample4.t
+ sample1.t
+ sample2.t
+ commit
+ sample3.t
+ sample4.t
+ sample1.t
+ sample2.t
+ EOF
+
+ test_cmp expect actual
+'
+
+test_expect_success 'log --skip-to' '
+ git log --skip-to=sample3.t --raw HEAD~2.. >raw &&
+ # just distill the commit header and paths
+ sed -n -e "s/^commit.*/commit/p" \
+ -e "/^:/s/^.* //p" raw >actual &&
+
+ cat >expect <<-\EOF &&
+ commit
+ sample4.t
+ commit
+ sample3.t
+ sample4.t
+ EOF
+
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t4100-apply-stat.sh b/t/t4100-apply-stat.sh
index 744b8e51be..9b433de836 100755
--- a/t/t4100-apply-stat.sh
+++ b/t/t4100-apply-stat.sh
@@ -17,13 +17,13 @@ do
test_expect_success "$title" '
git apply --stat --summary \
<"$TEST_DIRECTORY/t4100/t-apply-$num.patch" >current &&
- test_i18ncmp "$TEST_DIRECTORY"/t4100/t-apply-$num.expect current
+ test_cmp "$TEST_DIRECTORY"/t4100/t-apply-$num.expect current
'
test_expect_success "$title with recount" '
sed -e "$UNC" <"$TEST_DIRECTORY/t4100/t-apply-$num.patch" |
git apply --recount --stat --summary >current &&
- test_i18ncmp "$TEST_DIRECTORY"/t4100/t-apply-$num.expect current
+ test_cmp "$TEST_DIRECTORY"/t4100/t-apply-$num.expect current
'
done <<\EOF
rename
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 99987515dc..2aaaa0d7de 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -906,7 +906,7 @@ test_expect_success 'am empty-file does not infloop' '
test_tick &&
test_must_fail git am empty-file 2>actual &&
echo Patch format detection failed. >expected &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'am --message-id really adds the message id' '
diff --git a/t/t4153-am-resume-override-opts.sh b/t/t4153-am-resume-override-opts.sh
index 8ea22d1bcb..b7c3861407 100755
--- a/t/t4153-am-resume-override-opts.sh
+++ b/t/t4153-am-resume-override-opts.sh
@@ -61,7 +61,7 @@ test_expect_success '--no-quiet overrides --quiet' '
# Applying side2 will be quiet.
git am --no-quiet --continue >out &&
echo "Applying: side1" >expected &&
- test_i18ncmp expected out
+ test_cmp expected out
'
test_expect_success '--signoff overrides --no-signoff' '
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index 749bc1431a..85432b80ff 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -123,10 +123,10 @@ test_expect_success 'NUL separation with --stat' '
stat1_part=$(git diff-tree --no-commit-id --stat --root HEAD^) &&
printf "add bar\n$stat0_part\n\0$(commit_msg)\n$stat1_part\n" >expected &&
git log -z --stat --pretty="format:%s" >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
-test_expect_failure C_LOCALE_OUTPUT 'NUL termination with --stat' '
+test_expect_failure 'NUL termination with --stat' '
stat0_part=$(git diff --stat HEAD^ HEAD) &&
stat1_part=$(git diff-tree --no-commit-id --stat --root HEAD^) &&
printf "add bar\n$stat0_part\n\0$(commit_msg)\n$stat1_part\n0" >expected &&
diff --git a/t/t4208-log-magic-pathspec.sh b/t/t4208-log-magic-pathspec.sh
index 5e10136e9a..7f0c1dcc0f 100755
--- a/t/t4208-log-magic-pathspec.sh
+++ b/t/t4208-log-magic-pathspec.sh
@@ -31,13 +31,8 @@ test_expect_success '"git log :/a -- " should not be ambiguous' '
test_expect_success '"git log :/detached -- " should find a commit only in HEAD' '
test_when_finished "git checkout main" &&
git checkout --detach &&
- # Must manually call `test_tick` instead of using `test_commit`,
- # because the latter additionally creates a tag, which would make
- # the commit reachable not only via HEAD.
- test_tick &&
- git commit --allow-empty -m detached &&
- test_tick &&
- git commit --allow-empty -m something-else &&
+ test_commit --no-tag detached &&
+ test_commit --no-tag something-else &&
git log :/detached --
'
diff --git a/t/t4254-am-corrupt.sh b/t/t4254-am-corrupt.sh
index daf01c309d..54be7da161 100755
--- a/t/t4254-am-corrupt.sh
+++ b/t/t4254-am-corrupt.sh
@@ -60,7 +60,7 @@ test_expect_success 'try to apply corrupted patch' '
test_must_fail git -c advice.amWorkDir=false am bad-patch.diff 2>actual &&
echo "error: git diff header lacks filename information (line 4)" >expected &&
test_path_is_file f &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success "NUL in commit message's body" '
diff --git a/t/t5150-request-pull.sh b/t/t5150-request-pull.sh
index db4e15fd59..cb67bac1c4 100755
--- a/t/t5150-request-pull.sh
+++ b/t/t5150-request-pull.sh
@@ -223,14 +223,14 @@ test_expect_success 'pull request format' '
git request-pull initial "$downstream_url" tags/full >../request
) &&
<request sed -nf fuzz.sed >request.fuzzy &&
- test_i18ncmp expect request.fuzzy &&
+ test_cmp expect request.fuzzy &&
(
cd local &&
git request-pull initial "$downstream_url" tags/full:refs/tags/full
) >request &&
sed -nf fuzz.sed <request >request.fuzzy &&
- test_i18ncmp expect request.fuzzy &&
+ test_cmp expect request.fuzzy &&
(
cd local &&
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 392201cabd..d586fdc7a9 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -427,7 +427,7 @@ test_expect_success 'index-pack --strict <pack> works in non-repo' '
test_path_is_file foo.idx
'
-test_expect_success !PTHREADS,C_LOCALE_OUTPUT 'index-pack --threads=N or pack.threads=N warns when no pthreads' '
+test_expect_success !PTHREADS 'index-pack --threads=N or pack.threads=N warns when no pthreads' '
test_must_fail git index-pack --threads=2 2>err &&
grep ^warning: err >warnings &&
test_line_count = 1 warnings &&
@@ -445,7 +445,7 @@ test_expect_success !PTHREADS,C_LOCALE_OUTPUT 'index-pack --threads=N or pack.th
grep -F "no threads support, ignoring pack.threads" err
'
-test_expect_success !PTHREADS,C_LOCALE_OUTPUT 'pack-objects --threads=N or pack.threads=N warns when no pthreads' '
+test_expect_success !PTHREADS 'pack-objects --threads=N or pack.threads=N warns when no pthreads' '
git pack-objects --threads=2 --stdout --all </dev/null >/dev/null 2>err &&
grep ^warning: err >warnings &&
test_line_count = 1 warnings &&
diff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh
index 0f06c40eb1..a8c1bc0f66 100755
--- a/t/t5316-pack-delta-depth.sh
+++ b/t/t5316-pack-delta-depth.sh
@@ -84,14 +84,14 @@ test_expect_success 'packing produces a long delta' '
pack=$(git pack-objects --all --window=0 </dev/null pack) &&
echo 9 >expect &&
max_chain pack-$pack.pack >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success '--depth limits depth' '
pack=$(git pack-objects --all --depth=5 </dev/null pack) &&
echo 5 >expect &&
max_chain pack-$pack.pack >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_done
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index fa2ba93fe8..edeb6d6d31 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -585,7 +585,7 @@ test_expect_success 'detect bad hash version' '
test_expect_success 'detect low chunk count' '
corrupt_graph_and_verify $GRAPH_BYTE_CHUNK_COUNT "\01" \
- "missing the .* chunk"
+ "final chunk has non-zero id"
'
test_expect_success 'detect missing OID fanout chunk' '
diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index 2fc3aadbd1..b4afab1dfc 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -314,12 +314,12 @@ test_expect_success 'verify bad OID version' '
test_expect_success 'verify truncated chunk count' '
corrupt_midx_and_verify $MIDX_BYTE_CHUNK_COUNT "\01" $objdir \
- "missing required"
+ "final chunk has non-zero id"
'
test_expect_success 'verify extended chunk count' '
corrupt_midx_and_verify $MIDX_BYTE_CHUNK_COUNT "\07" $objdir \
- "terminating multi-pack-index chunk id appears earlier than expected"
+ "terminating chunk id appears earlier than expected"
'
test_expect_success 'verify missing required chunk' '
@@ -329,7 +329,7 @@ test_expect_success 'verify missing required chunk' '
test_expect_success 'verify invalid chunk offset' '
corrupt_midx_and_verify $MIDX_BYTE_CHUNK_OFFSET "\01" $objdir \
- "invalid chunk offset (too large)"
+ "improper chunk offset(s)"
'
test_expect_success 'verify packnames out of order' '
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 1f4cc873a8..8a5d3492c7 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -547,7 +547,7 @@ test_expect_success 'test lonely missing ref' '
cd client &&
test_must_fail git fetch-pack --no-progress .. refs/heads/xyzzy 2>../error-m
) &&
- test_i18ncmp expect-error error-m
+ test_cmp expect-error error-m
'
test_expect_success 'test missing ref after existing' '
@@ -555,7 +555,7 @@ test_expect_success 'test missing ref after existing' '
cd client &&
test_must_fail git fetch-pack --no-progress .. refs/heads/A refs/heads/xyzzy 2>../error-em
) &&
- test_i18ncmp expect-error error-em
+ test_cmp expect-error error-em
'
test_expect_success 'test missing ref before existing' '
@@ -563,7 +563,7 @@ test_expect_success 'test missing ref before existing' '
cd client &&
test_must_fail git fetch-pack --no-progress .. refs/heads/xyzzy refs/heads/A 2>../error-me
) &&
- test_i18ncmp expect-error error-me
+ test_cmp expect-error error-me
'
test_expect_success 'test --all, --depth, and explicit head' '
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 045398b94e..8c462f20ae 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -59,7 +59,7 @@ test_expect_success 'add remote whose URL agrees with url.<...>.insteadOf' '
git remote add myremote git@host.com:team/repo.git
'
-test_expect_success C_LOCALE_OUTPUT 'remote information for the origin' '
+test_expect_success 'remote information for the origin' '
(
cd test &&
tokens_match origin "$(git remote)" &&
@@ -81,7 +81,7 @@ test_expect_success 'add another remote' '
)
'
-test_expect_success C_LOCALE_OUTPUT 'check remote-tracking' '
+test_expect_success 'check remote-tracking' '
(
cd test &&
check_remote_track origin main side &&
@@ -107,7 +107,7 @@ test_expect_success 'remove remote' '
)
'
-test_expect_success C_LOCALE_OUTPUT 'remove remote' '
+test_expect_success 'remove remote' '
(
cd test &&
tokens_match origin "$(git remote)" &&
@@ -140,8 +140,8 @@ test_expect_success 'remove remote protects local branches' '
git remote rm oops 2>actual2 &&
git branch -d foobranch &&
git tag -d footag &&
- test_i18ncmp expect1 actual1 &&
- test_i18ncmp expect2 actual2
+ test_cmp expect1 actual1 &&
+ test_cmp expect2 actual2
)
'
@@ -150,7 +150,7 @@ test_expect_success 'remove errors out early when deleting non-existent branch'
cd test &&
echo "error: No such remote: '\''foo'\''" >expect &&
test_expect_code 2 git remote rm foo 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
)
'
@@ -178,7 +178,7 @@ test_expect_success 'rename errors out early when deleting non-existent branch'
cd test &&
echo "error: No such remote: '\''foo'\''" >expect &&
test_expect_code 2 git remote rename foo bar 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
)
'
@@ -186,14 +186,14 @@ test_expect_success 'rename errors out early when 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 &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'add existing foreign_vcs remote' '
test_config remote.foo.vcs bar &&
echo "error: remote foo already exists." >expect &&
test_expect_code 3 git remote add foo bar 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'add existing foreign_vcs remote' '
@@ -201,13 +201,13 @@ test_expect_success 'add existing foreign_vcs remote' '
test_config remote.bar.vcs bar &&
echo "error: remote bar already exists." >expect &&
test_expect_code 3 git remote rename foo bar 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'add invalid foreign_vcs remote' '
echo "fatal: '\''invalid...name'\'' is not a valid remote name" >expect &&
test_must_fail git remote add invalid...name bar 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
cat >test/expect <<EOF
@@ -267,7 +267,7 @@ test_expect_success 'show' '
git config --add remote.two.push refs/heads/main:refs/heads/another &&
git remote show origin two >output &&
git branch -d rebase octopus &&
- test_i18ncmp expect output
+ test_cmp expect output
)
'
@@ -294,7 +294,7 @@ test_expect_success 'show -n' '
cd test &&
git remote show -n origin >output &&
mv ../one.unreachable ../one &&
- test_i18ncmp expect output
+ test_cmp expect output
)
'
@@ -337,7 +337,7 @@ test_expect_success 'set-head --auto has no problem w/multiple HEADs' '
git fetch two "refs/heads/*:refs/remotes/two/*" &&
git remote set-head --auto two >output 2>&1 &&
echo "two/HEAD set to main" >expect &&
- test_i18ncmp expect output
+ test_cmp expect output
)
'
@@ -369,7 +369,7 @@ test_expect_success 'prune --dry-run' '
git remote prune --dry-run origin >output &&
git rev-parse refs/remotes/origin/side2 &&
test_must_fail git rev-parse refs/remotes/origin/side &&
- test_i18ncmp expect output
+ test_cmp expect output
)
'
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index c1e0eb3923..e83b2a6506 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -1051,7 +1051,7 @@ test_expect_success 'fetch --prune prints the remotes url' '
git fetch --prune origin 2>&1 | head -n1 >../actual
) &&
echo "From ${D}/." >expect &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'branchname D/F conflict resolved by --prune' '
@@ -1097,7 +1097,7 @@ test_expect_success 'fetching with auto-gc does not lock up' '
)
'
-test_expect_success C_LOCALE_OUTPUT 'fetch aligned output' '
+test_expect_success 'fetch aligned output' '
git clone . full-output &&
test_commit looooooooooooong-tag &&
(
@@ -1112,7 +1112,7 @@ test_expect_success C_LOCALE_OUTPUT 'fetch aligned output' '
test_cmp expect actual
'
-test_expect_success C_LOCALE_OUTPUT 'fetch compact output' '
+test_expect_success 'fetch compact output' '
git clone . compact &&
test_commit extraaa &&
(
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index 4a568a2398..f53f58895a 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -150,7 +150,7 @@ test_expect_success 'confuses pattern as remote when no remote specified' '
# We could just as easily have used "main"; the "*" emphasizes its
# role as a pattern.
test_must_fail git ls-remote "$does_not_exist" >actual 2>&1 &&
- test_i18ncmp exp actual
+ test_cmp exp actual
'
test_expect_success 'die with non-2 for wrong repository even with --exit-code' '
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 15262b4192..f11742ed59 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -820,6 +820,11 @@ test_expect_success 'push --delete refuses src:dest refspecs' '
test_must_fail git push testrepo --delete main:foo
'
+test_expect_success 'push --delete refuses empty string' '
+ mk_test testrepo heads/master &&
+ test_must_fail git push testrepo --delete ""
+'
+
test_expect_success 'warn on push to HEAD of non-bare repository' '
mk_test testrepo heads/main &&
(
diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh
index 11513ec15e..ed11569d8d 100755
--- a/t/t5526-fetch-submodules.sh
+++ b/t/t5526-fetch-submodules.sh
@@ -74,7 +74,7 @@ test_expect_success "fetch --recurse-submodules recurses into submodules" '
git fetch --recurse-submodules >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_i18ncmp expect.err actual.err
+ test_cmp expect.err actual.err
'
test_expect_success "submodule.recurse option triggers recursive fetch" '
@@ -84,7 +84,7 @@ test_expect_success "submodule.recurse option triggers recursive fetch" '
git -c submodule.recurse fetch >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_i18ncmp expect.err actual.err
+ test_cmp expect.err actual.err
'
test_expect_success "fetch --recurse-submodules -j2 has the same output behaviour" '
@@ -94,7 +94,7 @@ test_expect_success "fetch --recurse-submodules -j2 has the same output behaviou
GIT_TRACE="$TRASH_DIRECTORY/trace.out" git fetch --recurse-submodules -j2 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_i18ncmp expect.err actual.err &&
+ test_cmp expect.err actual.err &&
grep "2 tasks" trace.out
'
@@ -124,7 +124,7 @@ test_expect_success "using fetchRecurseSubmodules=true in .gitmodules recurses i
git fetch >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_i18ncmp expect.err actual.err
+ test_cmp expect.err actual.err
'
test_expect_success "--no-recurse-submodules overrides .gitmodules config" '
@@ -155,7 +155,7 @@ test_expect_success "--recurse-submodules overrides fetchRecurseSubmodules setti
git config --unset submodule.submodule.fetchRecurseSubmodules
) &&
test_must_be_empty actual.out &&
- test_i18ncmp expect.err actual.err
+ test_cmp expect.err actual.err
'
test_expect_success "--quiet propagates to submodules" '
@@ -183,7 +183,7 @@ test_expect_success "--dry-run propagates to submodules" '
git fetch --recurse-submodules --dry-run >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_i18ncmp expect.err actual.err
+ test_cmp expect.err actual.err
'
test_expect_success "Without --dry-run propagates to submodules" '
@@ -192,7 +192,7 @@ test_expect_success "Without --dry-run propagates to submodules" '
git fetch --recurse-submodules >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_i18ncmp expect.err actual.err
+ test_cmp expect.err actual.err
'
test_expect_success "recurseSubmodules=true propagates into submodules" '
@@ -203,7 +203,7 @@ test_expect_success "recurseSubmodules=true propagates into submodules" '
git fetch >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_i18ncmp expect.err actual.err
+ test_cmp expect.err actual.err
'
test_expect_success "--recurse-submodules overrides config in submodule" '
@@ -217,7 +217,7 @@ test_expect_success "--recurse-submodules overrides config in submodule" '
git fetch --recurse-submodules >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_i18ncmp expect.err actual.err
+ test_cmp expect.err actual.err
'
test_expect_success "--no-recurse-submodules overrides config setting" '
@@ -257,7 +257,7 @@ test_expect_success "Recursion stops when no new submodule commits are fetched"
cd downstream &&
git fetch >../actual.out 2>../actual.err
) &&
- test_i18ncmp expect.err.sub actual.err &&
+ test_cmp expect.err.sub actual.err &&
test_must_be_empty actual.out
'
@@ -275,7 +275,7 @@ test_expect_success "Recursion doesn't happen when new superproject commits don'
git fetch >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_i18ncmp expect.err.file actual.err
+ test_cmp expect.err.file actual.err
'
test_expect_success "Recursion picks up config in submodule" '
@@ -303,7 +303,7 @@ test_expect_success "Recursion picks up config in submodule" '
git config --unset fetch.recurseSubmodules
)
) &&
- test_i18ncmp expect.err.sub actual.err &&
+ test_cmp expect.err.sub actual.err &&
test_must_be_empty actual.out
'
@@ -336,7 +336,7 @@ test_expect_success "Recursion picks up all submodules when necessary" '
cd downstream &&
git fetch >../actual.out 2>../actual.err
) &&
- test_i18ncmp expect.err.2 actual.err &&
+ test_cmp expect.err.2 actual.err &&
test_must_be_empty actual.out
'
@@ -392,7 +392,7 @@ test_expect_success "'--recurse-submodules=on-demand' recurses as deep as necess
)
) &&
test_must_be_empty actual.out &&
- test_i18ncmp expect.err actual.err
+ test_cmp expect.err actual.err
'
test_expect_success "'--recurse-submodules=on-demand' stops when no new submodule commits are found in the superproject (and ignores config)" '
@@ -409,7 +409,7 @@ test_expect_success "'--recurse-submodules=on-demand' stops when no new submodul
git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_i18ncmp expect.err.file actual.err
+ test_cmp expect.err.file actual.err
'
test_expect_success "'fetch.recurseSubmodules=on-demand' overrides global config" '
@@ -437,7 +437,7 @@ test_expect_success "'fetch.recurseSubmodules=on-demand' overrides global config
git config --unset fetch.recurseSubmodules
) &&
test_must_be_empty actual.out &&
- test_i18ncmp expect.err.2 actual.err
+ test_cmp expect.err.2 actual.err
'
test_expect_success "'submodule.<sub>.fetchRecurseSubmodules=on-demand' overrides fetch.recurseSubmodules" '
@@ -465,7 +465,7 @@ test_expect_success "'submodule.<sub>.fetchRecurseSubmodules=on-demand' override
git config --unset submodule.submodule.fetchRecurseSubmodules
) &&
test_must_be_empty actual.out &&
- test_i18ncmp expect.err.2 actual.err
+ test_cmp expect.err.2 actual.err
'
test_expect_success "don't fetch submodule when newly recorded commits are already present" '
@@ -484,7 +484,7 @@ test_expect_success "don't fetch submodule when newly recorded commits are alrea
git fetch >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_i18ncmp expect.err actual.err &&
+ test_cmp expect.err actual.err &&
(
cd submodule &&
git checkout -q sub
@@ -520,7 +520,7 @@ test_expect_success "'fetch.recurseSubmodules=on-demand' works also without .git
git reset --hard
) &&
test_must_be_empty actual.out &&
- test_i18ncmp expect.err.2 actual.err &&
+ test_cmp expect.err.2 actual.err &&
git checkout HEAD^ -- .gitmodules &&
git add .gitmodules &&
git commit -m "new submodule restored .gitmodules"
diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh
index bc5ccf233f..c024fa2818 100755
--- a/t/t5541-http-push-smart.sh
+++ b/t/t5541-http-push-smart.sh
@@ -118,7 +118,7 @@ test_expect_success 'rejected update prints status' '
git commit -m dev2 &&
test_must_fail git push origin dev2 2>act &&
sed -e "/^remote: /s/ *$//" <act >cmp &&
- test_i18ncmp exp cmp
+ test_cmp exp cmp
'
rm -f "$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update"
diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh
index 2ecb06bb63..6d9142afc3 100755
--- a/t/t5550-http-fetch-dumb.sh
+++ b/t/t5550-http-fetch-dumb.sh
@@ -227,7 +227,10 @@ test_expect_success 'http-fetch --packfile' '
git init packfileclient &&
p=$(cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git && ls objects/pack/pack-*.pack) &&
- git -C packfileclient http-fetch --packfile=$ARBITRARY "$HTTPD_URL"/dumb/repo_pack.git/$p >out &&
+ git -C packfileclient http-fetch --packfile=$ARBITRARY \
+ --index-pack-arg=index-pack --index-pack-arg=--stdin \
+ --index-pack-arg=--keep \
+ "$HTTPD_URL"/dumb/repo_pack.git/$p >out &&
grep "^keep.[0-9a-f]\{16,\}$" out &&
cut -c6- out >packhash &&
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 664c913866..e7e6c08955 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -40,7 +40,7 @@ test_expect_success 'clone with excess parameters (2)' '
'
-test_expect_success C_LOCALE_OUTPUT 'output from clone' '
+test_expect_success 'output from clone' '
rm -fr dst &&
git clone -n "file://$(pwd)/src" dst >output 2>&1 &&
test $(grep Clon output | wc -l) = 1
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index 9113d209c5..994a76ca3c 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -875,11 +875,10 @@ test_expect_success 'part of packfile response provided as URI' '
test -f hfound &&
test -f h2found &&
- # Ensure that there are exactly 6 files (3 .pack and 3 .idx).
- ls http_child/.git/objects/pack/*.pack >packlist &&
- ls http_child/.git/objects/pack/*.idx >idxlist &&
- test_line_count = 3 idxlist &&
- test_line_count = 3 packlist
+ # Ensure that there are exactly 3 packfiles with associated .idx
+ ls http_child/.git/objects/pack/*.pack \
+ http_child/.git/objects/pack/*.idx >filelist &&
+ test_line_count = 6 filelist
'
test_expect_success 'fetching with valid packfile URI but invalid hash fails' '
@@ -931,11 +930,10 @@ test_expect_success 'packfile-uri with transfer.fsckobjects' '
-c fetch.uriprotocols=http,https \
clone "$HTTPD_URL/smart/http_parent" http_child &&
- # Ensure that there are exactly 4 files (2 .pack and 2 .idx).
- ls http_child/.git/objects/pack/*.pack >packlist &&
- ls http_child/.git/objects/pack/*.idx >idxlist &&
- test_line_count = 2 idxlist &&
- test_line_count = 2 packlist
+ # Ensure that there are exactly 2 packfiles with associated .idx
+ ls http_child/.git/objects/pack/*.pack \
+ http_child/.git/objects/pack/*.idx >filelist &&
+ test_line_count = 4 filelist
'
test_expect_success 'packfile-uri with transfer.fsckobjects fails on bad object' '
@@ -968,6 +966,54 @@ test_expect_success 'packfile-uri with transfer.fsckobjects fails on bad object'
test_i18ngrep "invalid author/committer line - missing email" error
'
+test_expect_success 'packfile-uri with transfer.fsckobjects succeeds when .gitmodules is separate from tree' '
+ P="$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
+ rm -rf "$P" http_child &&
+
+ git init "$P" &&
+ git -C "$P" config "uploadpack.allowsidebandall" "true" &&
+
+ echo "[submodule libfoo]" >"$P/.gitmodules" &&
+ echo "path = include/foo" >>"$P/.gitmodules" &&
+ echo "url = git://example.com/git/lib.git" >>"$P/.gitmodules" &&
+ git -C "$P" add .gitmodules &&
+ git -C "$P" commit -m x &&
+
+ configure_exclusion "$P" .gitmodules >h &&
+
+ sane_unset GIT_TEST_SIDEBAND_ALL &&
+ git -c protocol.version=2 -c transfer.fsckobjects=1 \
+ -c fetch.uriprotocols=http,https \
+ clone "$HTTPD_URL/smart/http_parent" http_child &&
+
+ # Ensure that there are exactly 2 packfiles with associated .idx
+ ls http_child/.git/objects/pack/*.pack \
+ http_child/.git/objects/pack/*.idx >filelist &&
+ test_line_count = 4 filelist
+'
+
+test_expect_success 'packfile-uri with transfer.fsckobjects fails when .gitmodules separate from tree is invalid' '
+ P="$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
+ rm -rf "$P" http_child err &&
+
+ git init "$P" &&
+ git -C "$P" config "uploadpack.allowsidebandall" "true" &&
+
+ echo "[submodule \"..\"]" >"$P/.gitmodules" &&
+ echo "path = include/foo" >>"$P/.gitmodules" &&
+ echo "url = git://example.com/git/lib.git" >>"$P/.gitmodules" &&
+ git -C "$P" add .gitmodules &&
+ git -C "$P" commit -m x &&
+
+ configure_exclusion "$P" .gitmodules >h &&
+
+ sane_unset GIT_TEST_SIDEBAND_ALL &&
+ test_must_fail git -c protocol.version=2 -c transfer.fsckobjects=1 \
+ -c fetch.uriprotocols=http,https \
+ clone "$HTTPD_URL/smart/http_parent" http_child 2>err &&
+ test_i18ngrep "disallowed submodule name" 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/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh
index da5fe1ba6d..881f72fd44 100755
--- a/t/t6020-bundle-misc.sh
+++ b/t/t6020-bundle-misc.sh
@@ -175,7 +175,7 @@ test_expect_success 'create bundle from special rev: main^!' '
cat >expect <<-\EOF &&
<COMMIT-P> refs/heads/main
EOF
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
git bundle verify special-rev.bdl |
make_user_friendly_and_stable_output >actual &&
@@ -185,7 +185,7 @@ test_expect_success 'create bundle from special rev: main^!' '
The bundle requires this ref:
<COMMIT-O>
EOF
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
test_bundle_object_count special-rev.bdl 3
'
@@ -207,7 +207,7 @@ test_expect_success 'create bundle with --max-count option' '
The bundle requires this ref:
<COMMIT-O>
EOF
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
test_bundle_object_count max-count.bdl 4
'
@@ -236,7 +236,7 @@ test_expect_success 'create bundle with --since option' '
<COMMIT-M>
<COMMIT-K>
EOF
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
test_bundle_object_count --thin since.bdl 13
'
@@ -262,11 +262,11 @@ test_expect_success 'create bundle 1 - no prerequisites' '
# verify bundle, which has no prerequisites
git bundle verify 1.bdl |
make_user_friendly_and_stable_output >actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
git bundle verify stdin-1.bdl |
make_user_friendly_and_stable_output >actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
test_bundle_object_count 1.bdl 24 &&
test_bundle_object_count stdin-1.bdl 24
@@ -304,11 +304,11 @@ test_expect_success 'create bundle 2 - has prerequisites' '
git bundle verify 2.bdl |
make_user_friendly_and_stable_output >actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
git bundle verify stdin-2.bdl |
make_user_friendly_and_stable_output >actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
test_bundle_object_count 2.bdl 16 &&
test_bundle_object_count stdin-2.bdl 16
@@ -326,11 +326,11 @@ test_expect_success 'fail to verify bundle without prerequisites' '
test_must_fail git -C test1.git bundle verify ../2.bdl 2>&1 |
make_user_friendly_and_stable_output >actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
test_must_fail git -C test1.git bundle verify ../stdin-2.bdl 2>&1 |
make_user_friendly_and_stable_output >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'create bundle 3 - two refs, same object' '
@@ -363,11 +363,11 @@ test_expect_success 'create bundle 3 - two refs, same object' '
git bundle verify 3.bdl |
make_user_friendly_and_stable_output >actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
git bundle verify stdin-3.bdl |
make_user_friendly_and_stable_output >actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
test_bundle_object_count 3.bdl 4 &&
test_bundle_object_count stdin-3.bdl 4
@@ -404,11 +404,11 @@ test_expect_success 'create bundle 4 - with tags' '
git bundle verify 4.bdl |
make_user_friendly_and_stable_output >actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
git bundle verify stdin-4.bdl |
make_user_friendly_and_stable_output >actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
test_bundle_object_count 4.bdl 3 &&
test_bundle_object_count stdin-4.bdl 3
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 7bcde054d7..0ba5a91b4e 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -578,9 +578,9 @@ test_expect_success 'skipping away from skipped commit' '
test "$para3" = "$PARA_HASH3"
'
-test_expect_success 'erroring out when using bad path parameters' '
+test_expect_success 'erroring out when using bad path arguments' '
test_must_fail git bisect start $PARA_HASH7 $HASH1 -- foobar 2> error.txt &&
- test_i18ngrep "bad path parameters" error.txt
+ test_i18ngrep "bad path arguments" error.txt
'
test_expect_success 'test bisection on bare repo - --no-checkout specified' '
@@ -829,7 +829,7 @@ test_expect_success 'bisect terms needs 0 or 1 argument' '
test_must_fail git bisect terms 1 2 &&
test_must_fail git bisect terms 2>actual &&
echo "error: no terms defined" >expected &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'bisect terms shows good/bad after start' '
@@ -903,7 +903,7 @@ test_expect_success 'bisect start --term-* does store terms' '
Your current terms are two for the old state
and one for the new state.
EOF
- test_i18ncmp expected actual &&
+ test_cmp expected actual &&
git bisect terms --term-bad >actual &&
echo one >expected &&
test_cmp expected actual &&
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index a160b2bf99..a313849406 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -57,7 +57,7 @@ test_expect_success 'branch -v' '
git branch -v
) |
sed -n -e "$t6040_script" >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
cat >expect <<\EOF
@@ -75,7 +75,7 @@ test_expect_success 'branch -vv' '
git branch -vv
) |
sed -n -e "$t6040_script" >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'checkout (diverged from upstream)' '
@@ -146,7 +146,7 @@ test_expect_success 'status -s -b (diverged from upstream)' '
git checkout b1 >/dev/null &&
git status -s -b | head -1
) >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
cat >expect <<\EOF
@@ -159,7 +159,7 @@ test_expect_success 'status -s -b --no-ahead-behind (diverged from upstream)' '
git checkout b1 >/dev/null &&
git status -s -b --no-ahead-behind | head -1
) >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
cat >expect <<\EOF
@@ -172,7 +172,7 @@ test_expect_success 'status.aheadbehind=false status -s -b (diverged from upstre
git checkout b1 >/dev/null &&
git -c status.aheadbehind=false status -s -b | head -1
) >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
cat >expect <<\EOF
@@ -187,7 +187,7 @@ test_expect_success 'status --long --branch' '
git checkout b1 >/dev/null &&
git status --long -b | head -3
) >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'status --long --branch' '
@@ -196,7 +196,7 @@ test_expect_success 'status --long --branch' '
git checkout b1 >/dev/null &&
git -c status.aheadbehind=true status --long -b | head -3
) >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
cat >expect <<\EOF
@@ -210,7 +210,7 @@ test_expect_success 'status --long --branch --no-ahead-behind' '
git checkout b1 >/dev/null &&
git status --long -b --no-ahead-behind | head -2
) >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'status.aheadbehind=false status --long --branch' '
@@ -219,7 +219,7 @@ test_expect_success 'status.aheadbehind=false status --long --branch' '
git checkout b1 >/dev/null &&
git -c status.aheadbehind=false status --long -b | head -2
) >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
cat >expect <<\EOF
@@ -232,7 +232,7 @@ test_expect_success 'status -s -b (upstream is gone)' '
git checkout b5 >/dev/null &&
git status -s -b | head -1
) >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
cat >expect <<\EOF
@@ -245,7 +245,7 @@ test_expect_success 'status -s -b (up-to-date with upstream)' '
git checkout b6 >/dev/null &&
git status -s -b | head -1
) >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'fail to track lightweight tags' '
diff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh
new file mode 100755
index 0000000000..b4aef32b71
--- /dev/null
+++ b/t/t6115-rev-list-du.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+test_description='basic tests of rev-list --disk-usage'
+. ./test-lib.sh
+
+# we want a mix of reachable and unreachable, as well as
+# objects in the bitmapped pack and some outside of it
+test_expect_success 'set up repository' '
+ test_commit --no-tag one &&
+ test_commit --no-tag two &&
+ git repack -adb &&
+ git reset --hard HEAD^ &&
+ test_commit --no-tag three &&
+ test_commit --no-tag four &&
+ git reset --hard HEAD^
+'
+
+# We don't want to hardcode sizes, because they depend on the exact details of
+# packing, zlib, etc. We'll assume that the regular rev-list and cat-file
+# machinery works and compare the --disk-usage output to that.
+disk_usage_slow () {
+ git rev-list --no-object-names "$@" |
+ git cat-file --batch-check="%(objectsize:disk)" |
+ perl -lne '$total += $_; END { print $total}'
+}
+
+# check behavior with given rev-list options; note that
+# whitespace is not preserved in args
+check_du () {
+ args=$*
+
+ test_expect_success "generate expected size ($args)" "
+ disk_usage_slow $args >expect
+ "
+
+ test_expect_success "rev-list --disk-usage without bitmaps ($args)" "
+ git rev-list --disk-usage $args >actual &&
+ test_cmp expect actual
+ "
+
+ test_expect_success "rev-list --disk-usage with bitmaps ($args)" "
+ git rev-list --disk-usage --use-bitmap-index $args >actual &&
+ test_cmp expect actual
+ "
+}
+
+check_du HEAD
+check_du --objects HEAD
+check_du --objects HEAD^..HEAD
+
+test_done
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 546796f847..e89b6747be 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -136,7 +136,7 @@ warning: tag 'Q' is externally known as 'A'
EOF
check_describe A-* HEAD
test_expect_success 'warning was displayed for Q' '
- test_i18ncmp err.expect err.actual
+ test_cmp err.expect err.actual
'
test_expect_success 'misnamed annotated tag forces long output' '
description=$(git describe --no-long Q^0) &&
diff --git a/t/t6134-pathspec-in-submodule.sh b/t/t6134-pathspec-in-submodule.sh
index c670668409..0f1cb49ced 100755
--- a/t/t6134-pathspec-in-submodule.sh
+++ b/t/t6134-pathspec-in-submodule.sh
@@ -21,7 +21,7 @@ EOF
test_expect_success 'error message for path inside submodule' '
echo a >sub/a &&
test_must_fail git add sub/a 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'error message for path inside submodule from within submodule' '
diff --git a/t/t6301-for-each-ref-errors.sh b/t/t6301-for-each-ref-errors.sh
index 809854fc0c..40edf9dab5 100755
--- a/t/t6301-for-each-ref-errors.sh
+++ b/t/t6301-for-each-ref-errors.sh
@@ -20,8 +20,8 @@ test_expect_success 'Broken refs are reported correctly' '
test_when_finished "rm -f .git/$r" &&
echo "warning: ignoring broken ref $r" >broken-err &&
git for-each-ref >out 2>err &&
- test_i18ncmp full-list out &&
- test_i18ncmp broken-err err
+ test_cmp full-list out &&
+ test_cmp broken-err err
'
test_expect_success 'NULL_SHA1 refs are reported correctly' '
@@ -31,10 +31,10 @@ test_expect_success 'NULL_SHA1 refs are reported correctly' '
echo "warning: ignoring broken ref $r" >zeros-err &&
git for-each-ref >out 2>err &&
test_cmp full-list out &&
- test_i18ncmp zeros-err err &&
+ test_cmp zeros-err err &&
git for-each-ref --format="%(objectname) %(refname)" >brief-out 2>brief-err &&
test_cmp brief-list brief-out &&
- test_i18ncmp zeros-err brief-err
+ test_cmp zeros-err brief-err
'
test_expect_success 'Missing objects are reported correctly' '
@@ -43,7 +43,7 @@ test_expect_success 'Missing objects are reported correctly' '
test_when_finished "rm -f .git/$r" &&
echo "fatal: missing object $MISSING for $r" >missing-err &&
test_must_fail git for-each-ref 2>err &&
- test_i18ncmp missing-err err &&
+ test_cmp missing-err err &&
(
cat brief-list &&
echo "$MISSING $r"
diff --git a/t/t6423-merge-rename-directories.sh b/t/t6423-merge-rename-directories.sh
index 4ab133f489..5d3b711fe6 100755
--- a/t/t6423-merge-rename-directories.sh
+++ b/t/t6423-merge-rename-directories.sh
@@ -2905,7 +2905,7 @@ test_setup_9e () {
)
}
-test_expect_success C_LOCALE_OUTPUT '9e: N-to-1 whammo' '
+test_expect_success '9e: N-to-1 whammo' '
test_setup_9e &&
(
cd 9e &&
diff --git a/t/t6436-merge-overwrite.sh b/t/t6436-merge-overwrite.sh
index 362ae37a12..84b4aacf49 100755
--- a/t/t6436-merge-overwrite.sh
+++ b/t/t6436-merge-overwrite.sh
@@ -139,7 +139,7 @@ test_expect_success 'will not overwrite untracked file in leading path' '
cp important sub &&
cp important sub2 &&
test_must_fail git merge sub 2>out &&
- test_i18ncmp out expect &&
+ test_cmp out expect &&
test_path_is_missing .git/MERGE_HEAD &&
test_cmp important sub &&
test_cmp important sub2 &&
@@ -174,7 +174,7 @@ test_expect_success 'will not overwrite untracked file on unborn branch' '
git checkout --orphan new &&
cp important c0.c &&
test_must_fail git merge c0 2>out &&
- test_i18ncmp out expect
+ test_cmp out expect
'
test_expect_success 'will not overwrite untracked file on unborn branch .git/MERGE_HEAD sanity etc.' '
diff --git a/t/t6439-merge-co-error-msgs.sh b/t/t6439-merge-co-error-msgs.sh
index e176475ed5..5bfb027099 100755
--- a/t/t6439-merge-co-error-msgs.sh
+++ b/t/t6439-merge-co-error-msgs.sh
@@ -40,14 +40,14 @@ EOF
test_expect_success 'untracked files overwritten by merge (fast and non-fast forward)' '
test_must_fail git merge branch 2>out &&
- test_i18ncmp out expect &&
+ test_cmp out expect &&
git commit --allow-empty -m empty &&
(
GIT_MERGE_VERBOSITY=0 &&
export GIT_MERGE_VERBOSITY &&
test_must_fail git merge branch 2>out2
) &&
- test_i18ncmp out2 expect &&
+ test_cmp out2 expect &&
git reset --hard HEAD^
'
@@ -68,7 +68,7 @@ test_expect_success 'untracked files or local changes ovewritten by merge' '
git add three &&
git add four &&
test_must_fail git merge branch 2>out &&
- test_i18ncmp out expect
+ test_cmp out expect
'
cat >expect <<\EOF
@@ -90,7 +90,7 @@ test_expect_success 'cannot switch branches because of local changes' '
echo uno >rep/one &&
echo dos >rep/two &&
test_must_fail git checkout branch 2>out &&
- test_i18ncmp out expect
+ test_cmp out expect
'
cat >expect <<\EOF
@@ -104,7 +104,7 @@ EOF
test_expect_success 'not uptodate file porcelain checkout error' '
git add rep/one rep/two &&
test_must_fail git checkout branch 2>out &&
- test_i18ncmp out expect
+ test_cmp out expect
'
cat >expect <<\EOF
@@ -135,7 +135,7 @@ test_expect_success 'not_uptodate_dir porcelain checkout error' '
>rep/untracked-file &&
>rep2/untracked-file &&
test_must_fail git checkout branch 2>out &&
- test_i18ncmp out ../expect
+ test_cmp out ../expect
'
test_done
diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh
index 63d5f41a12..25bb9bbb89 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -3,74 +3,74 @@
test_description='git mv in subdirs'
. ./test-lib.sh
-test_expect_success \
- 'prepare reference tree' \
- 'mkdir path0 path1 &&
- cp "$TEST_DIRECTORY"/../COPYING path0/COPYING &&
- git add path0/COPYING &&
- git commit -m add -a'
+test_expect_success 'prepare reference tree' '
+ mkdir path0 path1 &&
+ cp "$TEST_DIRECTORY"/../COPYING path0/COPYING &&
+ git add path0/COPYING &&
+ git commit -m add -a
+'
-test_expect_success \
- 'moving the file out of subdirectory' \
- 'cd path0 && git mv COPYING ../path1/COPYING'
+test_expect_success 'moving the file out of subdirectory' '
+ git -C path0 mv COPYING ../path1/COPYING
+'
# in path0 currently
-test_expect_success \
- 'commiting the change' \
- 'cd .. && git commit -m move-out -a'
+test_expect_success 'commiting the change' '
+ git commit -m move-out -a
+'
-test_expect_success \
- 'checking the commit' \
- 'git diff-tree -r -M --name-status HEAD^ HEAD >actual &&
- grep "^R100..*path0/COPYING..*path1/COPYING" actual'
+test_expect_success 'checking the commit' '
+ git diff-tree -r -M --name-status HEAD^ HEAD >actual &&
+ grep "^R100..*path0/COPYING..*path1/COPYING" actual
+'
-test_expect_success \
- 'moving the file back into subdirectory' \
- 'cd path0 && git mv ../path1/COPYING COPYING'
+test_expect_success 'moving the file back into subdirectory' '
+ git -C path0 mv ../path1/COPYING COPYING
+'
# in path0 currently
-test_expect_success \
- 'commiting the change' \
- 'cd .. && git commit -m move-in -a'
-
-test_expect_success \
- 'checking the commit' \
- 'git diff-tree -r -M --name-status HEAD^ HEAD >actual &&
- grep "^R100..*path1/COPYING..*path0/COPYING" actual'
-
-test_expect_success \
- 'mv --dry-run does not move file' \
- 'git mv -n path0/COPYING MOVED &&
- test -f path0/COPYING &&
- test ! -f MOVED'
-
-test_expect_success \
- 'checking -k on non-existing file' \
- 'git mv -k idontexist path0'
-
-test_expect_success \
- 'checking -k on untracked file' \
- 'touch untracked1 &&
- git mv -k untracked1 path0 &&
- test -f untracked1 &&
- test ! -f path0/untracked1'
-
-test_expect_success \
- 'checking -k on multiple untracked files' \
- 'touch untracked2 &&
- git mv -k untracked1 untracked2 path0 &&
- test -f untracked1 &&
- test -f untracked2 &&
- test ! -f path0/untracked1 &&
- test ! -f path0/untracked2'
-
-test_expect_success \
- 'checking -f on untracked file with existing target' \
- 'touch path0/untracked1 &&
- test_must_fail git mv -f untracked1 path0 &&
- test ! -f .git/index.lock &&
- test -f untracked1 &&
- test -f path0/untracked1'
+test_expect_success 'commiting the change' '
+ git commit -m move-in -a
+'
+
+test_expect_success 'checking the commit' '
+ git diff-tree -r -M --name-status HEAD^ HEAD >actual &&
+ grep "^R100..*path1/COPYING..*path0/COPYING" actual
+'
+
+test_expect_success 'mv --dry-run does not move file' '
+ git mv -n path0/COPYING MOVED &&
+ test -f path0/COPYING &&
+ test ! -f MOVED
+'
+
+test_expect_success 'checking -k on non-existing file' '
+ git mv -k idontexist path0
+'
+
+test_expect_success 'checking -k on untracked file' '
+ >untracked1 &&
+ git mv -k untracked1 path0 &&
+ test -f untracked1 &&
+ test ! -f path0/untracked1
+'
+
+test_expect_success 'checking -k on multiple untracked files' '
+ >untracked2 &&
+ git mv -k untracked1 untracked2 path0 &&
+ test -f untracked1 &&
+ test -f untracked2 &&
+ test ! -f path0/untracked1 &&
+ test ! -f path0/untracked2
+'
+
+test_expect_success 'checking -f on untracked file with existing target' '
+ >path0/untracked1 &&
+ test_must_fail git mv -f untracked1 path0 &&
+ test ! -f .git/index.lock &&
+ test -f untracked1 &&
+ test -f path0/untracked1
+'
# clean up the mess in case bad things happen
rm -f idontexist untracked1 untracked2 \
@@ -78,87 +78,89 @@ rm -f idontexist untracked1 untracked2 \
.git/index.lock
rmdir path1
-test_expect_success \
- 'moving to absent target with trailing slash' \
- 'test_must_fail git mv path0/COPYING no-such-dir/ &&
- test_must_fail git mv path0/COPYING no-such-dir// &&
- git mv path0/ no-such-dir/ &&
- test_path_is_dir no-such-dir'
-
-test_expect_success \
- 'clean up' \
- 'git reset --hard'
-
-test_expect_success \
- 'moving to existing untracked target with trailing slash' \
- 'mkdir path1 &&
- git mv path0/ path1/ &&
- test_path_is_dir path1/path0/'
-
-test_expect_success \
- 'moving to existing tracked target with trailing slash' \
- 'mkdir path2 &&
- >path2/file && git add path2/file &&
- git mv path1/path0/ path2/ &&
- test_path_is_dir path2/path0/'
-
-test_expect_success \
- 'clean up' \
- 'git reset --hard'
-
-test_expect_success \
- 'adding another file' \
- 'cp "$TEST_DIRECTORY"/../README.md path0/README &&
- git add path0/README &&
- git commit -m add2 -a'
-
-test_expect_success \
- 'moving whole subdirectory' \
- 'git mv path0 path2'
-
-test_expect_success \
- 'commiting the change' \
- 'git commit -m dir-move -a'
-
-test_expect_success \
- 'checking the commit' \
- 'git diff-tree -r -M --name-status HEAD^ HEAD >actual &&
- grep "^R100..*path0/COPYING..*path2/COPYING" actual &&
- grep "^R100..*path0/README..*path2/README" actual'
-
-test_expect_success \
- 'succeed when source is a prefix of destination' \
- 'git mv path2/COPYING path2/COPYING-renamed'
-
-test_expect_success \
- 'moving whole subdirectory into subdirectory' \
- 'git mv path2 path1'
-
-test_expect_success \
- 'commiting the change' \
- 'git commit -m dir-move -a'
-
-test_expect_success \
- 'checking the commit' \
- 'git diff-tree -r -M --name-status HEAD^ HEAD >actual &&
- grep "^R100..*path2/COPYING..*path1/path2/COPYING" actual &&
- grep "^R100..*path2/README..*path1/path2/README" actual'
-
-test_expect_success \
- 'do not move directory over existing directory' \
- 'mkdir path0 && mkdir path0/path2 && test_must_fail git mv path2 path0'
-
-test_expect_success \
- 'move into "."' \
- 'git mv path1/path2/ .'
+test_expect_success 'moving to absent target with trailing slash' '
+ test_must_fail git mv path0/COPYING no-such-dir/ &&
+ test_must_fail git mv path0/COPYING no-such-dir// &&
+ git mv path0/ no-such-dir/ &&
+ test_path_is_dir no-such-dir
+'
+
+test_expect_success 'clean up' '
+ git reset --hard
+'
+
+test_expect_success 'moving to existing untracked target with trailing slash' '
+ mkdir path1 &&
+ git mv path0/ path1/ &&
+ test_path_is_dir path1/path0/
+'
+
+test_expect_success 'moving to existing tracked target with trailing slash' '
+ mkdir path2 &&
+ >path2/file && git add path2/file &&
+ git mv path1/path0/ path2/ &&
+ test_path_is_dir path2/path0/
+'
+
+test_expect_success 'clean up' '
+ git reset --hard
+'
+
+test_expect_success 'adding another file' '
+ cp "$TEST_DIRECTORY"/../README.md path0/README &&
+ git add path0/README &&
+ git commit -m add2 -a
+'
+
+test_expect_success 'moving whole subdirectory' '
+ git mv path0 path2
+'
+
+test_expect_success 'commiting the change' '
+ git commit -m dir-move -a
+'
+
+test_expect_success 'checking the commit' '
+ git diff-tree -r -M --name-status HEAD^ HEAD >actual &&
+ grep "^R100..*path0/COPYING..*path2/COPYING" actual &&
+ grep "^R100..*path0/README..*path2/README" actual
+'
+
+test_expect_success 'succeed when source is a prefix of destination' '
+ git mv path2/COPYING path2/COPYING-renamed
+'
+
+test_expect_success 'moving whole subdirectory into subdirectory' '
+ git mv path2 path1
+'
+
+test_expect_success 'commiting the change' '
+ git commit -m dir-move -a
+'
+
+test_expect_success 'checking the commit' '
+ git diff-tree -r -M --name-status HEAD^ HEAD >actual &&
+ grep "^R100..*path2/COPYING..*path1/path2/COPYING" actual &&
+ grep "^R100..*path2/README..*path1/path2/README" actual
+'
+
+test_expect_success 'do not move directory over existing directory' '
+ mkdir path0 &&
+ mkdir path0/path2 &&
+ test_must_fail git mv path2 path0
+'
+
+test_expect_success 'move into "."' '
+ git mv path1/path2/ .
+'
test_expect_success "Michael Cassar's test case" '
rm -fr .git papers partA &&
git init &&
mkdir -p papers/unsorted papers/all-papers partA &&
- echo a > papers/unsorted/Thesis.pdf &&
- echo b > partA/outline.txt &&
- echo c > papers/unsorted/_another &&
+ echo a >papers/unsorted/Thesis.pdf &&
+ echo b >partA/outline.txt &&
+ echo c >papers/unsorted/_another &&
git add papers partA &&
T1=$(git write-tree) &&
@@ -181,43 +183,42 @@ test_expect_success "Sergey Vlasov's test case" '
git mv ab a
'
-test_expect_success 'absolute pathname' '(
-
- rm -fr mine &&
- mkdir mine &&
- cd mine &&
- test_create_repo one &&
- cd one &&
- mkdir sub &&
- >sub/file &&
- git add sub/file &&
-
- git mv sub "$(pwd)/in" &&
- ! test -d sub &&
- test -d in &&
- git ls-files --error-unmatch in/file
-
-
-)'
-
-test_expect_success 'absolute pathname outside should fail' '(
-
- rm -fr mine &&
- mkdir mine &&
- cd mine &&
- out=$(pwd) &&
- test_create_repo one &&
- cd one &&
- mkdir sub &&
- >sub/file &&
- git add sub/file &&
-
- test_must_fail git mv sub "$out/out" &&
- test -d sub &&
- ! test -d ../in &&
- git ls-files --error-unmatch sub/file
+test_expect_success 'absolute pathname' '
+ (
+ rm -fr mine &&
+ mkdir mine &&
+ cd mine &&
+ test_create_repo one &&
+ cd one &&
+ mkdir sub &&
+ >sub/file &&
+ git add sub/file &&
+
+ git mv sub "$(pwd)/in" &&
+ ! test -d sub &&
+ test -d in &&
+ git ls-files --error-unmatch in/file
+ )
+'
-)'
+test_expect_success 'absolute pathname outside should fail' '
+ (
+ rm -fr mine &&
+ mkdir mine &&
+ cd mine &&
+ out=$(pwd) &&
+ test_create_repo one &&
+ cd one &&
+ mkdir sub &&
+ >sub/file &&
+ git add sub/file &&
+
+ test_must_fail git mv sub "$out/out" &&
+ test -d sub &&
+ ! test -d ../in &&
+ git ls-files --error-unmatch sub/file
+ )
+'
test_expect_success 'git mv to move multiple sources into a directory' '
rm -fr .git && git init &&
@@ -227,23 +228,24 @@ test_expect_success 'git mv to move multiple sources into a directory' '
git add dir/?.txt &&
git mv dir/a.txt dir/b.txt other &&
git ls-files >actual &&
- { echo other/a.txt; echo other/b.txt; } >expect &&
+ cat >expect <<-\EOF &&
+ other/a.txt
+ other/b.txt
+ EOF
test_cmp expect actual
'
test_expect_success 'git mv should not change sha1 of moved cache entry' '
-
rm -fr .git &&
git init &&
echo 1 >dirty &&
git add dirty &&
entry="$(git ls-files --stage dirty | cut -f 1)" &&
git mv dirty dirty2 &&
- [ "$entry" = "$(git ls-files --stage dirty2 | cut -f 1)" ] &&
+ test "$entry" = "$(git ls-files --stage dirty2 | cut -f 1)" &&
echo 2 >dirty2 &&
git mv dirty2 dirty &&
- [ "$entry" = "$(git ls-files --stage dirty | cut -f 1)" ]
-
+ test "$entry" = "$(git ls-files --stage dirty | cut -f 1)"
'
rm -f dirty dirty2
@@ -266,7 +268,6 @@ test_expect_success 'git mv error on conflicted file' '
'
test_expect_success 'git mv should overwrite symlink to a file' '
-
rm -fr .git &&
git init &&
echo 1 >moved &&
@@ -279,13 +280,11 @@ test_expect_success 'git mv should overwrite symlink to a file' '
test "$(cat symlink)" = 1 &&
git update-index --refresh &&
git diff-files --quiet
-
'
rm -f moved symlink
test_expect_success 'git mv should overwrite file with a symlink' '
-
rm -fr .git &&
git init &&
echo 1 >moved &&
@@ -296,11 +295,9 @@ test_expect_success 'git mv should overwrite file with a symlink' '
! test -e symlink &&
git update-index --refresh &&
git diff-files --quiet
-
'
test_expect_success SYMLINKS 'check moved symlink' '
-
test -h moved
'
@@ -335,11 +332,8 @@ test_expect_success 'git mv moves a submodule with a .git directory and no .gitm
mkdir mod &&
git mv sub mod/sub &&
! test -e sub &&
- [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
- (
- cd mod/sub &&
- git status
- ) &&
+ test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+ git -C mod/sub status &&
git update-index --refresh &&
git diff-files --quiet
'
@@ -358,11 +352,8 @@ test_expect_success 'git mv moves a submodule with a .git directory and .gitmodu
mkdir mod &&
git mv sub mod/sub &&
! test -e sub &&
- [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
- (
- cd mod/sub &&
- git status
- ) &&
+ test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+ git -C mod/sub status &&
echo mod/sub >expected &&
git config -f .gitmodules submodule.sub.path >actual &&
test_cmp expected actual &&
@@ -376,16 +367,10 @@ test_expect_success 'git mv moves a submodule with gitfile' '
git submodule update &&
entry="$(git ls-files --stage sub | cut -f 1)" &&
mkdir mod &&
- (
- cd mod &&
- git mv ../sub/ .
- ) &&
+ git -C mod mv ../sub/ . &&
! test -e sub &&
- [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
- (
- cd mod/sub &&
- git status
- ) &&
+ test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+ git -C mod/sub status &&
echo mod/sub >expected &&
git config -f .gitmodules submodule.sub.path >actual &&
test_cmp expected actual &&
@@ -403,11 +388,8 @@ test_expect_success 'mv does not complain when no .gitmodules file is found' '
git mv sub mod/sub 2>actual.err &&
test_must_be_empty actual.err &&
! test -e sub &&
- [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
- (
- cd mod/sub &&
- git status
- ) &&
+ test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+ git -C mod/sub status &&
git update-index --refresh &&
git diff-files --quiet
'
@@ -427,11 +409,8 @@ test_expect_success 'mv will error out on a modified .gitmodules file unless sta
git mv sub mod/sub 2>actual.err &&
test_must_be_empty actual.err &&
! test -e sub &&
- [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
- (
- cd mod/sub &&
- git status
- ) &&
+ test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+ git -C mod/sub status &&
git update-index --refresh &&
git diff-files --quiet
'
@@ -446,13 +425,10 @@ test_expect_success 'mv issues a warning when section is not found in .gitmodule
echo "warning: Could not find section in .gitmodules where path=sub" >expect.err &&
mkdir mod &&
git mv sub mod/sub 2>actual.err &&
- test_i18ncmp expect.err actual.err &&
+ test_cmp expect.err actual.err &&
! test -e sub &&
- [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
- (
- cd mod/sub &&
- git status
- ) &&
+ test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+ git -C mod/sub status &&
git update-index --refresh &&
git diff-files --quiet
'
@@ -515,15 +491,17 @@ test_expect_success 'moving a submodule in nested directories' '
test_expect_success 'moving nested submodules' '
git commit -am "cleanup commit" &&
mkdir sub_nested_nested &&
- (cd sub_nested_nested &&
- touch nested_level2 &&
+ (
+ cd sub_nested_nested &&
+ >nested_level2 &&
git init &&
git add . &&
git commit -m "nested level 2"
) &&
mkdir sub_nested &&
- (cd sub_nested &&
- touch nested_level1 &&
+ (
+ cd sub_nested &&
+ >nested_level1 &&
git init &&
git add . &&
git commit -m "nested level 1" &&
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 400b83a49e..2f72c5c688 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -98,7 +98,7 @@ test_expect_success 'creating a tag with --create-reflog should create reflog' '
git tag --create-reflog tag_with_reflog &&
git reflog exists refs/tags/tag_with_reflog &&
sed -e "s/^.* //" .git/logs/refs/tags/tag_with_reflog >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'annotated tag with --create-reflog has correct message' '
@@ -109,7 +109,7 @@ test_expect_success 'annotated tag with --create-reflog has correct message' '
git tag -m "annotated tag" --create-reflog tag_with_reflog &&
git reflog exists refs/tags/tag_with_reflog &&
sed -e "s/^.* //" .git/logs/refs/tags/tag_with_reflog >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success '--create-reflog does not create reflog on failure' '
@@ -1434,7 +1434,7 @@ test_expect_success 'message in editor has initial comment: first line' '
# check the first line --- should be empty
echo >first.expect &&
sed -e 1q <actual >first.actual &&
- test_i18ncmp first.expect first.actual
+ test_cmp first.expect first.actual
'
test_expect_success \
@@ -1757,7 +1757,7 @@ test_expect_success 'recursive tagging should give advice' '
hint: Disable this message with "git config advice.nestedTag false"
EOF
git tag -m nested nested annotated-v4.0 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'multiple --points-at are OR-ed together' '
diff --git a/t/t7011-skip-worktree-reading.sh b/t/t7011-skip-worktree-reading.sh
index 37525cae3a..26852586ac 100755
--- a/t/t7011-skip-worktree-reading.sh
+++ b/t/t7011-skip-worktree-reading.sh
@@ -109,15 +109,6 @@ test_expect_success 'ls-files --modified' '
test -z "$(git ls-files -m)"
'
-test_expect_success 'grep with skip-worktree file' '
- git update-index --no-skip-worktree 1 &&
- echo test > 1 &&
- git update-index 1 &&
- git update-index --skip-worktree 1 &&
- rm 1 &&
- test "$(git grep --no-ext-grep test)" = "1:test"
-'
-
echo ":000000 100644 $ZERO_OID $EMPTY_BLOB A 1" > expected
test_expect_success 'diff-index does not examine skip-worktree absent entries' '
setup_absent &&
diff --git a/t/t7012-skip-worktree-writing.sh b/t/t7012-skip-worktree-writing.sh
index e5c6a038fb..f2a8e76511 100755
--- a/t/t7012-skip-worktree-writing.sh
+++ b/t/t7012-skip-worktree-writing.sh
@@ -125,13 +125,13 @@ EOF
test_expect_success 'git-clean, absent case' '
setup_absent &&
git clean -n > result &&
- test_i18ncmp expected result
+ test_cmp expected result
'
test_expect_success 'git-clean, dirty case' '
setup_dirty &&
git clean -n > result &&
- test_i18ncmp expected result
+ test_cmp expected result
'
test_expect_success '--ignore-skip-worktree-entries leaves worktree alone' '
diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh
index 72fb418b89..0f4344c55e 100755
--- a/t/t7060-wtstatus.sh
+++ b/t/t7060-wtstatus.sh
@@ -56,9 +56,9 @@ EOF
git commit -m delete &&
test_must_fail git merge main &&
test_must_fail git commit --dry-run >../actual &&
- test_i18ncmp ../expect ../actual &&
+ test_cmp ../expect ../actual &&
git status >../actual &&
- test_i18ncmp ../expect ../actual
+ test_cmp ../expect ../actual
)
'
@@ -151,7 +151,7 @@ Unmerged paths:
no changes added to commit (use "git add" and/or "git commit -a")
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -185,7 +185,7 @@ Unmerged paths:
no changes added to commit (use "git add" and/or "git commit -a")
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -210,7 +210,7 @@ Unmerged paths:
Untracked files not listed (use -u option to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual &&
+ test_cmp expected actual &&
git reset --hard &&
git checkout main
'
@@ -227,7 +227,7 @@ test_expect_success 'status --branch with detached HEAD' '
?? expected
?? mdconflict/
EOF
- test_i18ncmp expected actual
+ test_cmp expected actual
'
## Duplicate the above test and verify --porcelain=v1 arg parsing.
@@ -243,7 +243,7 @@ test_expect_success 'status --porcelain=v1 --branch with detached HEAD' '
?? expected
?? mdconflict/
EOF
- test_i18ncmp expected actual
+ test_cmp expected actual
'
## Verify parser error on invalid --porcelain argument.
diff --git a/t/t7063-status-untracked-cache.sh b/t/t7063-status-untracked-cache.sh
index f01bf27727..accefde72f 100755
--- a/t/t7063-status-untracked-cache.sh
+++ b/t/t7063-status-untracked-cache.sh
@@ -731,7 +731,7 @@ test_expect_success 'test ident field is working' '
cp -R done dthree dtwo four three ../other_worktree &&
GIT_WORK_TREE=../other_worktree git status 2>../err &&
echo "warning: untracked cache is disabled on this system or location" >../expect &&
- test_i18ncmp ../expect ../err
+ test_cmp ../expect ../err
'
test_expect_success 'untracked cache survives a checkout' '
diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh
index 7d8fb188ee..601b2bf97f 100755
--- a/t/t7102-reset.sh
+++ b/t/t7102-reset.sh
@@ -75,14 +75,14 @@ test_expect_success 'reset --hard message' '
hex=$(git log -1 --format="%h") &&
git reset --hard >.actual &&
echo HEAD is now at $hex $(commit_msg) >.expected &&
- test_i18ncmp .expected .actual
+ test_cmp .expected .actual
'
test_expect_success 'reset --hard message (ISO8859-1 logoutputencoding)' '
hex=$(git log -1 --format="%h") &&
git -c "i18n.logOutputEncoding=$test_encoding" reset --hard >.actual &&
echo HEAD is now at $hex $(commit_msg $test_encoding) >.expected &&
- test_i18ncmp .expected .actual
+ test_cmp .expected .actual
'
test_expect_success 'giving a non existing revision should fail' '
@@ -469,7 +469,7 @@ test_expect_success '--mixed refreshes the index' '
EOF
echo 123 >>file2 &&
git reset --mixed HEAD >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'resetting specific path that is unmerged' '
diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index cb5e34d94c..a74816ca8b 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -110,7 +110,7 @@ test_expect_success 'git clean with prefix' '
'
-test_expect_success C_LOCALE_OUTPUT 'git clean with relative prefix' '
+test_expect_success 'git clean with relative prefix' '
mkdir -p build docs &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
@@ -123,7 +123,7 @@ test_expect_success C_LOCALE_OUTPUT 'git clean with relative prefix' '
verbose test "$would_clean" = ../src/part3.c
'
-test_expect_success C_LOCALE_OUTPUT 'git clean with absolute path' '
+test_expect_success 'git clean with absolute path' '
mkdir -p build docs &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
@@ -407,7 +407,7 @@ test_expect_success 'clean.requireForce and -f' '
'
-test_expect_success C_LOCALE_OUTPUT 'core.excludesfile' '
+test_expect_success 'core.excludesfile' '
echo excludes >excludes &&
echo included >included &&
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index d44f696293..a924fdb7a6 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -55,7 +55,7 @@ test_expect_success 'add aborts on repository with no commits' '
EOF
git init repo-no-commits &&
test_must_fail git submodule add ../a ./repo-no-commits 2>actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'status should ignore inner git repo when not added' '
@@ -185,7 +185,7 @@ test_expect_success 'submodule add to .gitignored path fails' '
git add --force .gitignore &&
git commit -m"Ignore everything" &&
! git submodule add "$submodurl" submod >actual 2>&1 &&
- test_i18ncmp expect actual
+ test_cmp expect actual
)
'
diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh
index 7608814708..9c3cc4cf40 100755
--- a/t/t7401-submodule-summary.sh
+++ b/t/t7401-submodule-summary.sh
@@ -190,7 +190,7 @@ test_expect_success 'typechanged submodule(submodule->blob), --cached' "
< Add foo5
EOF
- test_i18ncmp expected actual
+ test_cmp expected actual
"
test_expect_success 'typechanged submodule(submodule->blob), --files' "
@@ -200,7 +200,7 @@ test_expect_success 'typechanged submodule(submodule->blob), --files' "
> Add foo5
EOF
- test_i18ncmp expected actual
+ test_cmp expected actual
"
rm -rf sm1 &&
@@ -211,7 +211,7 @@ test_expect_success 'typechanged submodule(submodule->blob)' "
* sm1 $head4(submodule)->$head5(blob):
EOF
- test_i18ncmp expected actual
+ test_cmp expected actual
"
rm -f sm1 &&
@@ -224,7 +224,7 @@ test_expect_success 'nonexistent commit' "
Warn: sm1 doesn't contain commit $head4_full
EOF
- test_i18ncmp expected actual
+ test_cmp expected actual
"
commit_file
@@ -235,7 +235,7 @@ test_expect_success 'typechanged submodule(blob->submodule)' "
> Add foo7
EOF
- test_i18ncmp expected actual
+ test_cmp expected actual
"
commit_file sm1 &&
@@ -292,7 +292,7 @@ test_expect_success 'given commit' "
test_expect_success '--for-status' "
git submodule summary --for-status HEAD^ >actual &&
- test_i18ncmp - actual <<-EOF
+ test_cmp - actual <<-EOF
* sm1 $head6...0000000:
* sm2 0000000...$head7 (2):
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index b9c1624fba..ff3ba5422e 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -155,9 +155,9 @@ test_expect_success 'submodule update --init --recursive from subdirectory' '
cd tmp &&
git submodule update --init --recursive ../super >../../actual 2>../../actual2
) &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
sort actual2 >actual2.sorted &&
- test_i18ncmp expect2 actual2.sorted
+ test_cmp expect2 actual2.sorted
'
cat <<EOF >expect2
@@ -174,7 +174,7 @@ test_expect_success 'submodule update --init from and of subdirectory' '
git submodule update --init sub 2>../../actual2
)
) &&
- test_i18ncmp expect2 actual2
+ test_cmp expect2 actual2
'
test_expect_success 'submodule update does not fetch already present commits' '
@@ -192,7 +192,7 @@ test_expect_success 'submodule update does not fetch already present commits' '
(cd super &&
git submodule update > ../actual 2> ../actual.err
) &&
- test_i18ncmp expected actual &&
+ test_cmp expected actual &&
test_must_be_empty actual.err
'
@@ -461,7 +461,7 @@ test_expect_success 'submodule update - command in .git/config catches failure'
(cd super &&
test_must_fail git submodule update submodule 2>../actual
) &&
- test_i18ncmp actual expect
+ test_cmp actual expect
'
cat << EOF >expect
@@ -479,7 +479,7 @@ test_expect_success 'submodule update - command in .git/config catches failure -
mkdir tmp && cd tmp &&
test_must_fail git submodule update ../submodule 2>../../actual
) &&
- test_i18ncmp actual expect
+ test_cmp actual expect
'
test_expect_success 'submodule update - command run for initial population of submodule' '
@@ -488,7 +488,7 @@ test_expect_success 'submodule update - command run for initial population of su
EOF
rm -rf super/submodule &&
test_must_fail git -C super submodule update 2>actual &&
- test_i18ncmp expect actual &&
+ test_cmp expect actual &&
git -C super submodule update --checkout
'
@@ -509,7 +509,7 @@ test_expect_success 'recursive submodule update - command in .git/config catches
mkdir -p tmp && cd tmp &&
test_must_fail git submodule update --recursive ../super 2>../../actual
) &&
- test_i18ncmp actual expect
+ test_cmp actual expect
'
test_expect_success 'submodule init does not copy command into .git/config' '
diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 79981b51eb..e2f110b786 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -80,7 +80,7 @@ test_expect_success 'test basic "submodule foreach" usage' '
git config foo.bar zar &&
git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
) &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
cat >expect <<EOF
@@ -96,7 +96,7 @@ test_expect_success 'test "submodule foreach" from subdirectory' '
cd clone/sub &&
git submodule foreach "echo \$toplevel-\$name-\$sm_path-\$displaypath-\$sha1" >../../actual
) &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'setup nested submodules' '
@@ -177,7 +177,7 @@ test_expect_success 'test messages from "foreach --recursive"' '
cd clone2 &&
git submodule foreach --recursive "true" > ../actual
) &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
cat > expect <<EOF
@@ -197,7 +197,7 @@ test_expect_success 'test messages from "foreach --recursive" from subdirectory'
cd untracked &&
git submodule foreach --recursive >../../actual
) &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
sub1sha1=$(cd clone2/sub1 && git rev-parse HEAD)
sub2sha1=$(cd clone2/sub2 && git rev-parse HEAD)
@@ -229,7 +229,7 @@ test_expect_success 'test "submodule foreach --recursive" from subdirectory' '
cd clone2/untracked &&
git submodule foreach --recursive "echo toplevel: \$toplevel name: \$name path: \$sm_path displaypath: \$displaypath hash: \$sha1" >../../actual
) &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
cat > expect <<EOF
diff --git a/t/t7500-commit-template-squash-signoff.sh b/t/t7500-commit-template-squash-signoff.sh
index 6d19ece05d..e41ac18e7e 100755
--- a/t/t7500-commit-template-squash-signoff.sh
+++ b/t/t7500-commit-template-squash-signoff.sh
@@ -15,7 +15,7 @@ commit_msg_is () {
printf "%s" "$(git log --pretty=format:%s%b -1)" >"$actual" &&
printf "%s" "$1" >"$expect" &&
- test_i18ncmp "$expect" "$actual"
+ test_cmp "$expect" "$actual"
}
# A sanity check to see if commit is working at all.
@@ -356,7 +356,7 @@ test_expect_success 'new line found before status message in commit template' '
touch commit-template-check &&
git add commit-template-check &&
GIT_EDITOR="cat >editor-input" git commit --untracked-files=no --allow-empty-message &&
- test_i18ncmp expected-template editor-input
+ test_cmp expected-template editor-input
'
test_expect_success 'setup empty commit with unstaged rename and copy' '
diff --git a/t/t7502-commit-porcelain.sh b/t/t7502-commit-porcelain.sh
index e5332adc9a..6396897cc8 100755
--- a/t/t7502-commit-porcelain.sh
+++ b/t/t7502-commit-porcelain.sh
@@ -13,7 +13,7 @@ commit_msg_is () {
printf "%s" "$(git log --pretty=format:%s%b -1)" >$actual &&
printf "%s" "$1" >$expect &&
- test_i18ncmp $expect $actual
+ test_cmp $expect $actual
}
# Arguments: [<prefix] [<commit message>] [<commit options>]
@@ -35,7 +35,7 @@ check_summary_oneline() {
SUMMARY_POSTFIX="$(git log -1 --pretty='format:%h')"
echo "[$SUMMARY_PREFIX $SUMMARY_POSTFIX] $2" >exp &&
- test_i18ncmp exp act
+ test_cmp exp act
}
test_expect_success 'output summary format' '
@@ -300,7 +300,7 @@ echo "sample
# with '#' will be ignored, and an empty message aborts the commit." >expect
test_expect_success 'cleanup commit messages (strip option,-F,-e): output' '
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'cleanup commit message (fail on invalid cleanup mode option)' '
diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh
index 321b4bc0fc..7a8194ce72 100755
--- a/t/t7505-prepare-commit-msg-hook.sh
+++ b/t/t7505-prepare-commit-msg-hook.sh
@@ -218,7 +218,7 @@ test_expect_success 'with hook and editor (merge)' '
test_rebase () {
expect=$1 &&
mode=$2 &&
- test_expect_$expect C_LOCALE_OUTPUT "with hook (rebase ${mode:--i})" '
+ test_expect_$expect "with hook (rebase ${mode:--i})" '
test_when_finished "\
git rebase --abort
git checkout -f main
@@ -307,7 +307,7 @@ test_expect_success 'with failing hook (merge)' '
'
-test_expect_success C_LOCALE_OUTPUT 'with failing hook (cherry-pick)' '
+test_expect_success 'with failing hook (cherry-pick)' '
test_when_finished "git checkout -f main" &&
git checkout -B other b &&
test_must_fail git cherry-pick rebase-1 2>actual &&
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index d01aacb66b..2b72451ba3 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -109,13 +109,13 @@ test_expect_success 'status --column' '
#
EOF
COLUMNS=50 git -c status.displayCommentPrefix=true status --column="column dense" >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'status --column status.displayCommentPrefix=false' '
strip_comments expect &&
COLUMNS=49 git -c status.displayCommentPrefix=false status --column="column dense" >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
cat >expect <<\EOF
@@ -144,19 +144,19 @@ EOF
test_expect_success 'status with status.displayCommentPrefix=true' '
git -c status.displayCommentPrefix=true status >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'status with status.displayCommentPrefix=false' '
strip_comments expect &&
git -c status.displayCommentPrefix=false status >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'status -v' '
(cat expect && git diff --cached) >expect-with-v &&
git status -v >output &&
- test_i18ncmp expect-with-v output
+ test_cmp expect-with-v output
'
test_expect_success 'status -v -v' '
@@ -167,7 +167,7 @@ test_expect_success 'status -v -v' '
echo "Changes not staged for commit:" &&
git -c diff.mnemonicprefix=true diff) >expect-with-v &&
git status -v -v >output &&
- test_i18ncmp expect-with-v output
+ test_cmp expect-with-v output
'
test_expect_success 'setup fake editor' '
@@ -214,7 +214,7 @@ EOF
test_expect_success 'status (advice.statusHints false)' '
test_config advice.statusHints false &&
git status >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
@@ -296,7 +296,7 @@ Ignored files:
EOF
git status --ignored >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'status with gitignore (nothing untracked)' '
@@ -358,7 +358,7 @@ Ignored files:
EOF
git status --ignored >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
cat >.gitignore <<\EOF
@@ -380,7 +380,7 @@ EOF
test_expect_success 'status -s -b' '
git status -s -b >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
@@ -390,7 +390,7 @@ test_expect_success 'status -s -z -b' '
git status -s -z -b >output &&
nul_to_q <output >output.q &&
mv output.q output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'setup dir3' '
@@ -418,13 +418,13 @@ Changes not staged for commit:
Untracked files not listed (use -u option to show untracked files)
EOF
git status -uno >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'status (status.showUntrackedFiles no)' '
test_config status.showuntrackedfiles no &&
git status >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'status -uno (advice.statusHints false)' '
@@ -443,7 +443,7 @@ Untracked files not listed
EOF
test_config advice.statusHints false &&
git status -uno >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
cat >expect << EOF
@@ -487,13 +487,13 @@ Untracked files:
EOF
git status -unormal >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'status (status.showUntrackedFiles normal)' '
test_config status.showuntrackedfiles normal &&
git status >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
cat >expect <<EOF
@@ -543,13 +543,13 @@ Untracked files:
EOF
git status -uall >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'status (status.showUntrackedFiles all)' '
test_config status.showuntrackedfiles all &&
git status >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'teardown dir3' '
@@ -601,7 +601,7 @@ Untracked files:
EOF
(cd dir1 && git status) >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
cat >expect <<\EOF
@@ -670,13 +670,13 @@ Untracked files:
EOF
test_config color.ui auto &&
test_terminal git status | test_decode_color >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success TTY 'status with color.status' '
test_config color.status auto &&
test_terminal git status | test_decode_color >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
cat >expect <<\EOF
@@ -718,7 +718,7 @@ EOF
test_expect_success TTY 'status -s -b with color.status' '
test_terminal git status -s -b | test_decode_color >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
@@ -793,7 +793,7 @@ Untracked files:
EOF
test_config status.relativePaths false &&
(cd dir1 && git status) >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
@@ -860,7 +860,7 @@ Untracked files:
EOF
git commit --dry-run dir1/modified >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
cat >expect <<EOF
@@ -921,13 +921,13 @@ Untracked files:
EOF
git status >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
# we expect the same as the previous test
test_expect_success 'status --untracked-files=all does not show submodule' '
git status --untracked-files=all >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
cat >expect <<EOF
@@ -984,13 +984,13 @@ Untracked files:
EOF
git config status.submodulesummary 10 &&
git status >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'status submodule summary with status.displayCommentPrefix=false' '
strip_comments expect &&
git -c status.displayCommentPrefix=false status >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'commit with submodule summary ignores status.displayCommentPrefix' '
@@ -1035,9 +1035,9 @@ EOF
git commit -m "commit submodule" &&
git config status.submodulesummary 10 &&
test_must_fail git commit --dry-run >output &&
- test_i18ncmp expect output &&
+ test_cmp expect output &&
git status >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
cat >expect <<EOF
@@ -1091,7 +1091,7 @@ Untracked files:
EOF
git config status.submodulesummary 10 &&
git commit --dry-run --amend >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success POSIXPERM,SANITY 'status succeeds in a read-only repository' '
@@ -1143,17 +1143,17 @@ Untracked files:
EOF
echo modified sm/untracked &&
git status --ignore-submodules=untracked >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success '.gitmodules ignore=untracked suppresses submodules with untracked content' '
test_config diff.ignoreSubmodules dirty &&
git status >output &&
- test_i18ncmp expect output &&
+ test_cmp expect output &&
git config --add -f .gitmodules submodule.subname.ignore untracked &&
git config --add -f .gitmodules submodule.subname.path sm &&
git status >output &&
- test_i18ncmp expect output &&
+ test_cmp expect output &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -1163,14 +1163,14 @@ test_expect_success '.git/config ignore=untracked suppresses submodules with unt
git config --add submodule.subname.ignore untracked &&
git config --add submodule.subname.path sm &&
git status >output &&
- test_i18ncmp expect output &&
+ test_cmp expect output &&
git config --remove-section submodule.subname &&
git config --remove-section -f .gitmodules submodule.subname
'
test_expect_success '--ignore-submodules=dirty suppresses submodules with untracked content' '
git status --ignore-submodules=dirty >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success '.gitmodules ignore=dirty suppresses submodules with untracked content' '
@@ -1180,7 +1180,7 @@ test_expect_success '.gitmodules ignore=dirty suppresses submodules with untrack
git config --add -f .gitmodules submodule.subname.ignore dirty &&
git config --add -f .gitmodules submodule.subname.path sm &&
git status >output &&
- test_i18ncmp expect output &&
+ test_cmp expect output &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -1190,7 +1190,7 @@ test_expect_success '.git/config ignore=dirty suppresses submodules with untrack
git config --add submodule.subname.ignore dirty &&
git config --add submodule.subname.path sm &&
git status >output &&
- test_i18ncmp expect output &&
+ test_cmp expect output &&
git config --remove-section submodule.subname &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -1198,14 +1198,14 @@ test_expect_success '.git/config ignore=dirty suppresses submodules with untrack
test_expect_success '--ignore-submodules=dirty suppresses submodules with modified content' '
echo modified >sm/foo &&
git status --ignore-submodules=dirty >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success '.gitmodules ignore=dirty suppresses submodules with modified content' '
git config --add -f .gitmodules submodule.subname.ignore dirty &&
git config --add -f .gitmodules submodule.subname.path sm &&
git status >output &&
- test_i18ncmp expect output &&
+ test_cmp expect output &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -1215,7 +1215,7 @@ test_expect_success '.git/config ignore=dirty suppresses submodules with modifie
git config --add submodule.subname.ignore dirty &&
git config --add submodule.subname.path sm &&
git status >output &&
- test_i18ncmp expect output &&
+ test_cmp expect output &&
git config --remove-section submodule.subname &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -1253,14 +1253,14 @@ Untracked files:
EOF
git status --ignore-submodules=untracked > output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success ".gitmodules ignore=untracked doesn't suppress submodules with modified content" '
git config --add -f .gitmodules submodule.subname.ignore untracked &&
git config --add -f .gitmodules submodule.subname.path sm &&
git status >output &&
- test_i18ncmp expect output &&
+ test_cmp expect output &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -1270,7 +1270,7 @@ test_expect_success ".git/config ignore=untracked doesn't suppress submodules wi
git config --add submodule.subname.ignore untracked &&
git config --add submodule.subname.path sm &&
git status >output &&
- test_i18ncmp expect output &&
+ test_cmp expect output &&
git config --remove-section submodule.subname &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -1314,14 +1314,14 @@ Untracked files:
EOF
git status --ignore-submodules=untracked > output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success ".gitmodules ignore=untracked doesn't suppress submodule summary" '
git config --add -f .gitmodules submodule.subname.ignore untracked &&
git config --add -f .gitmodules submodule.subname.path sm &&
git status >output &&
- test_i18ncmp expect output &&
+ test_cmp expect output &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -1331,20 +1331,20 @@ test_expect_success ".git/config ignore=untracked doesn't suppress submodule sum
git config --add submodule.subname.ignore untracked &&
git config --add submodule.subname.path sm &&
git status >output &&
- test_i18ncmp expect output &&
+ test_cmp expect output &&
git config --remove-section submodule.subname &&
git config -f .gitmodules --remove-section submodule.subname
'
test_expect_success "--ignore-submodules=dirty doesn't suppress submodule summary" '
git status --ignore-submodules=dirty > output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success ".gitmodules ignore=dirty doesn't suppress submodule summary" '
git config --add -f .gitmodules submodule.subname.ignore dirty &&
git config --add -f .gitmodules submodule.subname.path sm &&
git status >output &&
- test_i18ncmp expect output &&
+ test_cmp expect output &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -1354,7 +1354,7 @@ test_expect_success ".git/config ignore=dirty doesn't suppress submodule summary
git config --add submodule.subname.ignore dirty &&
git config --add submodule.subname.path sm &&
git status >output &&
- test_i18ncmp expect output &&
+ test_cmp expect output &&
git config --remove-section submodule.subname &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -1398,7 +1398,7 @@ EOF
test_expect_success "status (core.commentchar with submodule summary)" '
test_config core.commentchar ";" &&
git -c status.displayCommentPrefix=true status >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success "status (core.commentchar with two chars with submodule summary)" '
@@ -1429,7 +1429,7 @@ Untracked files:
no changes added to commit (use "git add" and/or "git commit -a")
EOF
git status --ignore-submodules=all > output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success '.gitmodules ignore=all suppresses unstaged submodule summary' '
@@ -1460,7 +1460,7 @@ EOF
git config --add -f .gitmodules submodule.subname.ignore all &&
git config --add -f .gitmodules submodule.subname.path sm &&
git status > output &&
- test_i18ncmp expect output &&
+ test_cmp expect output &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -1470,7 +1470,7 @@ test_expect_success '.git/config ignore=all suppresses unstaged submodule summar
git config --add submodule.subname.ignore all &&
git config --add submodule.subname.path sm &&
git status > output &&
- test_i18ncmp expect output &&
+ test_cmp expect output &&
git config --remove-section submodule.subname &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -1571,7 +1571,7 @@ Changes not staged for commit:
Untracked files not listed (use -u option to show untracked files)
EOF
git commit -uno --dry-run >output &&
- test_i18ncmp expect output &&
+ test_cmp expect output &&
git status -s --ignore-submodules=dirty >output &&
test_i18ngrep "^M. sm" output
'
diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh
index 9f5e3ce793..7f2956d77a 100755
--- a/t/t7512-status-help.sh
+++ b/t/t7512-status-help.sh
@@ -41,7 +41,7 @@ Unmerged paths:
no changes added to commit (use "git add" and/or "git commit -a")
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -61,7 +61,7 @@ Changes to be committed:
Untracked files not listed (use -u option to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -93,7 +93,7 @@ Unmerged paths:
no changes added to commit (use "git add" and/or "git commit -a")
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -116,7 +116,7 @@ Changes to be committed:
Untracked files not listed (use -u option to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -154,7 +154,7 @@ Unmerged paths:
no changes added to commit (use "git add" and/or "git commit -a")
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -180,7 +180,7 @@ Changes to be committed:
Untracked files not listed (use -u option to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -210,7 +210,7 @@ You are currently editing a commit while rebasing branch '\''rebase_i_edit'\'' o
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -249,7 +249,7 @@ Changes not staged for commit:
no changes added to commit (use "git add" and/or "git commit -a")
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -282,7 +282,7 @@ You are currently editing a commit while rebasing branch '\''amend_last'\'' on '
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -321,7 +321,7 @@ You are currently editing a commit while rebasing branch '\''several_edits'\'' o
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -356,7 +356,7 @@ Changes not staged for commit:
no changes added to commit (use "git add" and/or "git commit -a")
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -387,7 +387,7 @@ You are currently editing a commit while rebasing branch '\''several_edits'\'' o
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -418,7 +418,7 @@ You are currently editing a commit while rebasing branch '\''several_edits'\'' o
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -454,7 +454,7 @@ Changes not staged for commit:
no changes added to commit (use "git add" and/or "git commit -a")
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -486,7 +486,7 @@ You are currently editing a commit while rebasing branch '\''several_edits'\'' o
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -519,7 +519,7 @@ You are currently editing a commit while rebasing branch '\''several_edits'\'' o
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -557,7 +557,7 @@ Changes not staged for commit:
no changes added to commit (use "git add" and/or "git commit -a")
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -591,7 +591,7 @@ You are currently editing a commit while rebasing branch '\''several_edits'\'' o
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -619,7 +619,7 @@ You are in the middle of an am session.
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -641,7 +641,7 @@ You are in the middle of an am session.
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -664,7 +664,7 @@ The current patch is empty.
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -687,7 +687,7 @@ You are currently bisecting, started from branch '\''bisect'\''.
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -712,7 +712,7 @@ Unmerged paths:
no changes added to commit
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -746,7 +746,7 @@ Unmerged paths:
no changes added to commit (use "git add" and/or "git commit -a")
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
@@ -770,7 +770,7 @@ Changes to be committed:
Untracked files not listed (use -u option to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'status when cherry-picking after committing conflict resolution' '
@@ -789,7 +789,7 @@ Cherry-pick currently in progress.
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'status shows cherry-pick with invalid oid' '
@@ -798,7 +798,7 @@ test_expect_success 'status shows cherry-pick with invalid oid' '
git status --untracked-files=no >actual 2>err &&
git cherry-pick --quit &&
test_must_be_empty err &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'status does not show error if .git/sequencer is a file' '
@@ -816,7 +816,7 @@ HEAD detached at atag
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual &&
+ test_cmp expected actual &&
git reset --hard HEAD^ &&
cat >expected <<\EOF &&
@@ -824,7 +824,7 @@ HEAD detached from atag
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'status while reverting commit (conflicts)' '
@@ -852,7 +852,7 @@ Unmerged paths:
no changes added to commit (use "git add" and/or "git commit -a")
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'status while reverting commit (conflicts resolved)' '
@@ -872,7 +872,7 @@ Changes to be committed:
Untracked files not listed (use -u option to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'status after reverting commit' '
@@ -882,7 +882,7 @@ On branch main
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'status while reverting after committing conflict resolution' '
@@ -901,7 +901,7 @@ Revert currently in progress.
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'prepare for different number of commits rebased' '
@@ -931,7 +931,7 @@ You are currently editing a commit while rebasing branch '\''several_commits'\''
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'status: two commands done with some white lines in done file' '
@@ -959,7 +959,7 @@ You are currently editing a commit while rebasing branch '\''several_commits'\''
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'status: two remaining commands with some white lines in todo file' '
@@ -988,7 +988,7 @@ You are currently editing a commit while rebasing branch '\''several_commits'\''
nothing to commit (use -u to show untracked files)
EOF
git status --untracked-files=no >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_expect_success 'status: handle not-yet-started rebase -i gracefully' '
@@ -1007,7 +1007,7 @@ You are currently editing a commit while rebasing branch '\''several_commits'\''
nothing to commit (use -u to show untracked files)
EOF
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_done
diff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh
index fbfdcca000..45d025f960 100755
--- a/t/t7519-status-fsmonitor.sh
+++ b/t/t7519-status-fsmonitor.sh
@@ -236,7 +236,7 @@ test_expect_success 'refresh_index() invalidates fsmonitor cache' '
git reset HEAD~1 &&
git status >actual &&
git -c core.fsmonitor= status >expect &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
# test fsmonitor with and without preloadIndex
@@ -273,7 +273,7 @@ do
git add dir2/new &&
git status >actual &&
git -c core.fsmonitor= status >expect &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
# Make sure it's actually skipping the check for modified and untracked
diff --git a/t/t7521-ignored-mode.sh b/t/t7521-ignored-mode.sh
index 91790943c3..a88b02b06e 100755
--- a/t/t7521-ignored-mode.sh
+++ b/t/t7521-ignored-mode.sh
@@ -30,7 +30,7 @@ test_expect_success 'Verify behavior of status on directories with ignored files
dir/ignored/ignored_1.ign dir/ignored/ignored_2.ign &&
git status --porcelain=v2 --ignored=matching --untracked-files=all >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'Verify status behavior on directory with tracked & ignored files' '
@@ -55,7 +55,7 @@ test_expect_success 'Verify status behavior on directory with tracked & ignored
git commit -m "commit tracked files" &&
git status --porcelain=v2 --ignored=matching --untracked-files=all >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'Verify status behavior on directory with untracked and ignored files' '
@@ -80,7 +80,7 @@ test_expect_success 'Verify status behavior on directory with untracked and igno
dir/untracked_ignored/ignored_1.ign dir/untracked_ignored/ignored_2.ign &&
git status --porcelain=v2 --ignored=matching --untracked-files=all >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'Verify status matching ignored files on ignored directory' '
@@ -96,7 +96,7 @@ test_expect_success 'Verify status matching ignored files on ignored directory'
ignored_dir/ignored_1.ign ignored_dir/ignored_2.ign &&
git status --porcelain=v2 --ignored=matching --untracked-files=all >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'Verify status behavior on ignored directory containing tracked file' '
@@ -117,7 +117,7 @@ test_expect_success 'Verify status behavior on ignored directory containing trac
git add -f ignored_dir/tracked &&
git commit -m "Force add file in ignored directory" &&
git status --porcelain=v2 --ignored=matching --untracked-files=all >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'Verify matching ignored files with --untracked-files=normal' '
@@ -136,7 +136,7 @@ test_expect_success 'Verify matching ignored files with --untracked-files=normal
ignored_files/ignored_1.ign ignored_files/ignored_2.ign \
untracked_dir/untracked &&
git status --porcelain=v2 --ignored=matching --untracked-files=normal >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'Verify matching ignored files with --untracked-files=normal' '
@@ -155,7 +155,7 @@ test_expect_success 'Verify matching ignored files with --untracked-files=normal
ignored_files/ignored_1.ign ignored_files/ignored_2.ign \
untracked_dir/untracked &&
git status --porcelain=v2 --ignored=matching --untracked-files=normal >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'Verify status behavior on ignored directory containing tracked file' '
@@ -176,7 +176,7 @@ test_expect_success 'Verify status behavior on ignored directory containing trac
git add -f ignored_dir/tracked &&
git commit -m "Force add file in ignored directory" &&
git status --porcelain=v2 --ignored=matching --untracked-files=normal >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'Verify behavior of status with --ignored=no' '
@@ -191,7 +191,7 @@ test_expect_success 'Verify behavior of status with --ignored=no' '
dir/ignored/ignored_1.ign dir/ignored/ignored_2.ign &&
git status --porcelain=v2 --ignored=no --untracked-files=all >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'Verify behavior of status with --ignored=traditional and --untracked-files=all' '
@@ -210,7 +210,7 @@ test_expect_success 'Verify behavior of status with --ignored=traditional and --
dir/ignored/ignored_1.ign dir/ignored/ignored_2.ign &&
git status --porcelain=v2 --ignored=traditional --untracked-files=all >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_expect_success 'Verify behavior of status with --ignored=traditional and --untracked-files=normal' '
@@ -227,7 +227,7 @@ test_expect_success 'Verify behavior of status with --ignored=traditional and --
dir/ignored/ignored_1.ign dir/ignored/ignored_2.ign &&
git status --porcelain=v2 --ignored=traditional --untracked-files=normal >output &&
- test_i18ncmp expect output
+ test_cmp expect output
'
test_done
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index b2c1d861dc..1cbc9715a8 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -272,7 +272,7 @@ test_expect_success 'merge c3 with c7 with commit.cleanup = scissors' '
EOF
git cat-file commit HEAD >raw &&
sed -e "1,/^$/d" raw >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_expect_success 'merge c3 with c7 with --squash commit.cleanup = scissors' '
@@ -296,7 +296,7 @@ test_expect_success 'merge c3 with c7 with --squash commit.cleanup = scissors' '
EOF
git cat-file commit HEAD >raw &&
sed -e "1,/^$/d" raw >actual &&
- test_i18ncmp expect actual
+ test_cmp expect actual
'
test_debug 'git log --graph --decorate --oneline --all'
diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index 13859ec859..a9c816b47f 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -66,7 +66,7 @@ EOF
test_expect_success 'merge output uses pretty names' '
git reset --hard c1 &&
git merge c2 c3 c4 >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
cat >expected <<\EOF
@@ -84,7 +84,7 @@ test_expect_success 'merge reduces irrelevant remote heads' '
rm expected.tmp
fi &&
GIT_MERGE_VERBOSITY=0 git merge c4 c5 >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
cat >expected <<\EOF
@@ -101,7 +101,7 @@ EOF
test_expect_success 'merge fast-forward output uses pretty names' '
git reset --hard c0 &&
git merge c1 c2 >actual &&
- test_i18ncmp expected actual
+ test_cmp expected actual
'
test_done
diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
index 9192c141ff..3e041e83ae 100755
--- a/t/t7800-difftool.sh
+++ b/t/t7800-difftool.sh
@@ -762,4 +762,36 @@ test_expect_success 'difftool --gui, --tool and --extcmd are mutually exclusive'
test_must_fail git difftool --gui --tool=test-tool --extcmd=cat
'
+test_expect_success 'difftool --rotate-to' '
+ difftool_test_setup &&
+ test_when_finished git reset --hard &&
+ echo 1 >1 &&
+ echo 2 >2 &&
+ echo 4 >4 &&
+ git add 1 2 4 &&
+ git commit -a -m "124" &&
+ git difftool --no-prompt --extcmd=cat --rotate-to="2" HEAD^ >output&&
+ cat >expect <<-\EOF &&
+ 2
+ 4
+ 1
+ EOF
+ test_cmp output expect
+'
+
+test_expect_success 'difftool --skip-to' '
+ difftool_test_setup &&
+ test_when_finished git reset --hard &&
+ git difftool --no-prompt --extcmd=cat --skip-to="2" HEAD^ >output &&
+ cat >expect <<-\EOF &&
+ 2
+ 4
+ EOF
+ test_cmp output expect
+'
+
+test_expect_success 'difftool --rotate/skip-to error condition' '
+ test_must_fail git difftool --no-prompt --extcmd=cat --rotate-to="3" HEAD^ &&
+ test_must_fail git difftool --no-prompt --extcmd=cat --skip-to="3" HEAD^
+'
test_done
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index 8f7591c9cc..edfaa9a6d1 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -969,7 +969,7 @@ do
"
done
-test_expect_success !PTHREADS,C_LOCALE_OUTPUT 'grep --threads=N or pack.threads=N warns when no pthreads' '
+test_expect_success !PTHREADS 'grep --threads=N or pack.threads=N warns when no pthreads' '
git grep --threads=2 Hello hello_world 2>err &&
grep ^warning: err >warnings &&
test_line_count = 1 warnings &&
diff --git a/t/t7817-grep-sparse-checkout.sh b/t/t7817-grep-sparse-checkout.sh
new file mode 100755
index 0000000000..590b99bbb6
--- /dev/null
+++ b/t/t7817-grep-sparse-checkout.sh
@@ -0,0 +1,174 @@
+#!/bin/sh
+
+test_description='grep in sparse checkout
+
+This test creates a repo with the following structure:
+
+.
+|-- a
+|-- b
+|-- dir
+| `-- c
+|-- sub
+| |-- A
+| | `-- a
+| `-- B
+| `-- b
+`-- sub2
+ `-- a
+
+Where the outer repository has non-cone mode sparsity patterns, sub is a
+submodule with cone mode sparsity patterns and sub2 is a submodule that is
+excluded by the superproject sparsity patterns. The resulting sparse checkout
+should leave the following structure in the working tree:
+
+.
+|-- a
+|-- sub
+| `-- B
+| `-- b
+`-- sub2
+ `-- a
+
+But note that sub2 should have the SKIP_WORKTREE bit set.
+'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ echo "text" >a &&
+ echo "text" >b &&
+ mkdir dir &&
+ echo "text" >dir/c &&
+
+ git init sub &&
+ (
+ cd sub &&
+ mkdir A B &&
+ echo "text" >A/a &&
+ echo "text" >B/b &&
+ git add A B &&
+ git commit -m sub &&
+ git sparse-checkout init --cone &&
+ git sparse-checkout set B
+ ) &&
+
+ git init sub2 &&
+ (
+ cd sub2 &&
+ echo "text" >a &&
+ git add a &&
+ git commit -m sub2
+ ) &&
+
+ git submodule add ./sub &&
+ git submodule add ./sub2 &&
+ git add a b dir &&
+ git commit -m super &&
+ git sparse-checkout init --no-cone &&
+ git sparse-checkout set "/*" "!b" "!/*/" "sub" &&
+
+ git tag -am tag-to-commit tag-to-commit HEAD &&
+ tree=$(git rev-parse HEAD^{tree}) &&
+ git tag -am tag-to-tree tag-to-tree $tree &&
+
+ test_path_is_missing b &&
+ test_path_is_missing dir &&
+ test_path_is_missing sub/A &&
+ test_path_is_file a &&
+ test_path_is_file sub/B/b &&
+ test_path_is_file sub2/a &&
+ git branch -m main
+'
+
+# The test below covers a special case: the sparsity patterns exclude '/b' and
+# sparse checkout is enabled, but the path exists in the working tree (e.g.
+# manually created after `git sparse-checkout init`). git grep should skip it.
+test_expect_success 'working tree grep honors sparse checkout' '
+ cat >expect <<-EOF &&
+ a:text
+ EOF
+ test_when_finished "rm -f b" &&
+ echo "new-text" >b &&
+ git grep "text" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'grep searches unmerged file despite not matching sparsity patterns' '
+ cat >expect <<-EOF &&
+ b:modified-b-in-branchX
+ b:modified-b-in-branchY
+ EOF
+ test_when_finished "test_might_fail git merge --abort && \
+ git checkout main && git sparse-checkout init" &&
+
+ git sparse-checkout disable &&
+ git checkout -b branchY main &&
+ test_commit modified-b-in-branchY b &&
+ git checkout -b branchX main &&
+ test_commit modified-b-in-branchX b &&
+
+ git sparse-checkout init &&
+ test_path_is_missing b &&
+ test_must_fail git merge branchY &&
+ git grep "modified-b" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'grep --cached searches entries with the SKIP_WORKTREE bit' '
+ cat >expect <<-EOF &&
+ a:text
+ b:text
+ dir/c:text
+ EOF
+ git grep --cached "text" >actual &&
+ test_cmp expect actual
+'
+
+# Note that sub2/ is present in the worktree but it is excluded by the sparsity
+# patterns, so grep should not recurse into it.
+test_expect_success 'grep --recurse-submodules honors sparse checkout in submodule' '
+ cat >expect <<-EOF &&
+ a:text
+ sub/B/b:text
+ EOF
+ git grep --recurse-submodules "text" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'grep --recurse-submodules --cached searches entries with the SKIP_WORKTREE bit' '
+ cat >expect <<-EOF &&
+ a:text
+ b:text
+ dir/c:text
+ sub/A/a:text
+ sub/B/b:text
+ sub2/a:text
+ EOF
+ git grep --recurse-submodules --cached "text" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'working tree grep does not search the index with CE_VALID and SKIP_WORKTREE' '
+ cat >expect <<-EOF &&
+ a:text
+ EOF
+ test_when_finished "git update-index --no-assume-unchanged b" &&
+ git update-index --assume-unchanged b &&
+ git grep text >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'grep --cached searches index entries with both CE_VALID and SKIP_WORKTREE' '
+ cat >expect <<-EOF &&
+ a:text
+ b:text
+ dir/c:text
+ EOF
+ test_when_finished "git update-index --no-assume-unchanged b" &&
+ git update-index --assume-unchanged b &&
+ git grep --cached text >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh
index 286b18db3c..2412d8c5c0 100755
--- a/t/t7900-maintenance.sh
+++ b/t/t7900-maintenance.sh
@@ -632,4 +632,17 @@ test_expect_success 'fails when running outside of a repository' '
nongit test_must_fail git maintenance unregister
'
+test_expect_success 'register and unregister bare repo' '
+ test_when_finished "git config --global --unset-all maintenance.repo || :" &&
+ test_might_fail git config --global --unset-all maintenance.repo &&
+ git init --bare barerepo &&
+ (
+ cd barerepo &&
+ git maintenance register &&
+ git config --get --global --fixed-value maintenance.repo "$(pwd)" &&
+ git maintenance unregister &&
+ test_must_fail git config --global --get-all maintenance.repo
+ )
+'
+
test_done
diff --git a/t/t9003-help-autocorrect.sh b/t/t9003-help-autocorrect.sh
index 03cd5c5423..f00deaf381 100755
--- a/t/t9003-help-autocorrect.sh
+++ b/t/t9003-help-autocorrect.sh
@@ -56,11 +56,8 @@ test_expect_success 'autocorrect can be declined altogether' '
git config help.autocorrect never &&
test_must_fail git lfg 2>actual &&
- if test_have_prereq C_LOCALE_OUTPUT
- then
- grep "is not a git command" actual &&
- test_line_count = 1 actual
- fi
+ grep "is not a git command" actual &&
+ test_line_count = 1 actual
'
test_done
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index c96a555ace..6348e8d733 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -190,6 +190,7 @@ test_commit () {
author= &&
signoff= &&
indir= &&
+ no_tag= &&
while test $# != 0
do
case "$1" in
@@ -216,6 +217,9 @@ test_commit () {
indir="$2"
shift
;;
+ --no-tag)
+ no_tag=yes
+ ;;
*)
break
;;
@@ -238,7 +242,10 @@ test_commit () {
git ${indir:+ -C "$indir"} commit \
${author:+ --author "$author"} \
$signoff -m "$1" &&
- git ${indir:+ -C "$indir"} tag "${4:-$1}"
+ if test -z "$no_tag"
+ then
+ git ${indir:+ -C "$indir"} tag "${4:-$1}"
+ fi
}
# Call test_merge with the arguments "<message> <commit>", where <commit>
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 987a6c1936..d3f6af6a65 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1489,11 +1489,6 @@ test -n "$USE_LIBPCRE2" && test_set_prereq PCRE
test -n "$USE_LIBPCRE2" && test_set_prereq LIBPCRE2
test -z "$NO_GETTEXT" && test_set_prereq GETTEXT
-# Used to be used for GIT_TEST_GETTEXT_POISON=false. Only here as a
-# shim for other in-flight changes. Should not be used and will be
-# removed soon.
-test_set_prereq C_LOCALE_OUTPUT
-
if test -z "$GIT_TEST_CHECK_CACHE_TREE"
then
GIT_TEST_CHECK_CACHE_TREE=true