Merge branch 'es/maintenance-of-bare-repositories'

The "git maintenance register" command had trouble registering bare
repositories, which had been corrected.

* es/maintenance-of-bare-repositories:
  maintenance: fix incorrect `maintenance.repo` path with bare repository
diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt
index 7f7a07d..214f31b 100644
--- a/Documentation/config/rebase.txt
+++ b/Documentation/config/rebase.txt
@@ -68,3 +68,6 @@
 	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/diff-options.txt b/Documentation/diff-options.txt
index e5733cc..aa2b5c1 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -700,6 +700,14 @@
 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-branch.txt b/Documentation/git-branch.txt
index eb815c2..94dc9a5 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -153,7 +153,7 @@
 --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 484c485..143b0c4 100644
--- a/Documentation/git-difftool.txt
+++ b/Documentation/git-difftool.txt
@@ -34,6 +34,14 @@
 	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 0c114ad..853967d 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.txt
@@ -117,12 +117,14 @@
 '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-pack-objects.txt b/Documentation/git-pack-objects.txt
index 54d715e..f85cb7e 100644
--- a/Documentation/git-pack-objects.txt
+++ b/Documentation/git-pack-objects.txt
@@ -400,6 +400,17 @@
 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 92f146d..fbd4b4a 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.txt
@@ -165,9 +165,12 @@
 	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 @@
 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 5da6623..20bb8e8 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -31,6 +31,99 @@
 
 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 c0764e8..83f38e3 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -130,7 +130,7 @@
 --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 56656d1..31a97a1 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -134,7 +134,7 @@
 --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 d36e6fd..3a9c449 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -88,7 +88,7 @@
 	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 c970d9f..2bd1220 100644
--- a/Documentation/gitdiffcore.txt
+++ b/Documentation/gitdiffcore.txt
@@ -74,6 +74,7 @@
 - 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
@@ -276,6 +277,26 @@
 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 052209b..3fb39f8 100644
--- a/Documentation/gitmailmap.txt
+++ b/Documentation/gitmailmap.txt
@@ -50,9 +50,9 @@
 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@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/rev-list-options.txt b/Documentation/rev-list-options.txt
index 96cc89d..b1c8f86 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -129,10 +129,10 @@
 	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 @@
 	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/protocol-v2.txt b/Documentation/technical/protocol-v2.txt
index f772d90..a7c806a 100644
--- a/Documentation/technical/protocol-v2.txt
+++ b/Documentation/technical/protocol-v2.txt
@@ -33,8 +33,8 @@
 
   * '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/Makefile b/Makefile
index 5a239ca..9b1bde2 100644
--- a/Makefile
+++ b/Makefile
@@ -863,6 +863,7 @@
 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/builtin/add.c b/builtin/add.c
index a825887..ea762a4 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -38,19 +38,27 @@
 	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 @@
 		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 b66e938..641523f 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -425,13 +425,11 @@
 	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 @@
 	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 4bbfc92..023e49e 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -23,22 +23,35 @@
 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('.');
-		}
-	} else
-		fputs(topath[checkout_stage], stdout);
+		for (i = 1; i < 4; i++)
+			if (topath[i][0]) {
+				have_tempname = 1;
+				break;
+			}
 
-	putchar('\t');
-	write_name_quoted_relative(name, prefix, stdout,
-				   nul_term_line ? '\0' : '\n');
+		if (have_tempname) {
+			for (i = 1; i < 4; i++) {
+				if (i > 1)
+					putchar(' ');
+				if (topath[i][0])
+					fputs(topath[i], stdout);
+				else
+					putchar('.');
+			}
+		}
+	} else if (topath[checkout_stage][0]) {
+		have_tempname = 1;
+		fputs(topath[checkout_stage], stdout);
+	}
+
+	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 bb85266..70103c4 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -54,6 +54,7 @@
 	}
 	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 c33d7af..176fe7f 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -41,6 +41,8 @@
 	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 178d12f..f33d30d 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -156,6 +156,8 @@
 	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 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 0f4859a..617b9a4 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -491,6 +491,7 @@
 	}
 
 	rev.diffopt.flags.recursive = 1;
+	rev.diffopt.rotate_to_strict = 1;
 
 	setup_diff_pager(&rev.diffopt);
 
diff --git a/builtin/grep.c b/builtin/grep.c
index e348e6b..4e91a25 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -506,6 +506,10 @@
 
 	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 @@
 			 * 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/rebase.c b/builtin/rebase.c
index 840dbd7..de400f9 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -102,6 +102,7 @@
 	int reschedule_failed_exec;
 	int use_legacy_rebase;
 	int reapply_cherry_picks;
+	int fork_point;
 };
 
 #define REBASE_OPTIONS_INIT {			  	\
@@ -111,7 +112,8 @@
 		.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 @@
 		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 @@
 	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 @@
 			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 @@
 			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 @@
 								    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 @@
 	} 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/rev-list.c b/builtin/rev-list.c
index 25c6c3b..b4d8ea0 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -80,6 +80,19 @@
 
 #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 @@
 
 	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 @@
 	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 @@
 	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 @@
 			continue;
 		}
 
+		if (!strcmp(arg, "--disk-usage")) {
+			show_disk_usage = 1;
+			info.flags |= REV_LIST_QUIET;
+			continue;
+		}
+
 		usage(rev_list_usage);
 
 	}
@@ -626,6 +667,8 @@
 	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 @@
 			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/commit-graph.c b/commit-graph.c
index ed31843..7a5f15b 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -2471,6 +2471,7 @@
 	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 e38771c..2ea84d3 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 @@
 	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 @@
 	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 @@
 	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 bf2cbf1..6956f5e 100644
--- a/diff.c
+++ b/diff.c
@@ -5348,6 +5348,19 @@
 	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 @@
 			  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 @@
 		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 527fb56..c8f3fae 100644
--- a/diff.h
+++ b/diff.h
@@ -237,6 +237,27 @@
 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-rotate.c b/diffcore-rotate.c
new file mode 100644
index 0000000..445f060
--- /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 d2a63c5..c1592bc 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -164,6 +164,7 @@
 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 a0532f1..7b9f437 100644
--- a/entry.c
+++ b/entry.c
@@ -282,7 +282,7 @@
 		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 @@
 			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 @@
 
 	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 @@
 		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/pack-bitmap.c b/pack-bitmap.c
index 60fe20f..1f69b5f 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -1430,3 +1430,84 @@
 	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 25dfcf5..36d9993 100644
--- a/pack-bitmap.h
+++ b/pack-bitmap.h
@@ -68,6 +68,8 @@
  */
 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/t/lib-credential.sh b/t/lib-credential.sh
index dea2cbe..5ea8bc9 100644
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -20,7 +20,7 @@
 		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 1184cce..bf952ef 100644
--- a/t/lib-log-graph.sh
+++ b/t/lib-log-graph.sh
@@ -12,13 +12,13 @@
 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/t0000-basic.sh b/t/t0000-basic.sh
index a6e570d..705d62c 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -271,7 +271,7 @@
 	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 75ee9a9..6b757d7 100755
--- a/t/t0006-date.sh
+++ b/t/t0006-date.sh
@@ -11,7 +11,7 @@
 	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 @@
 	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 370a389..f7abde6 100755
--- a/t/t0008-ignores.sh
+++ b/t/t0008-ignores.sh
@@ -34,7 +34,7 @@
 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 e8ef730..5679e29 100755
--- a/t/t0012-help.sh
+++ b/t/t0012-help.sh
@@ -55,7 +55,7 @@
 		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 e03554d..39e5e4b 100755
--- a/t/t0018-advice.sh
+++ b/t/t0018-advice.sh
@@ -10,7 +10,7 @@
 	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 @@
 	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 375cf94..f25ae8b 100755
--- a/t/t0020-crlf.sh
+++ b/t/t0020-crlf.sh
@@ -87,10 +87,8 @@
 	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 51f74a3..d24d5ac 100755
--- a/t/t0027-auto-crlf.sh
+++ b/t/t0027-auto-crlf.sh
@@ -83,7 +83,7 @@
 	*) 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 14cafc1..ad4746d 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -61,7 +61,7 @@
 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 @@
 	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 @@
 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 @@
 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 90da1c7..6c74df0 100755
--- a/t/t0201-gettext-fallbacks.sh
+++ b/t/t0201-gettext-fallbacks.sh
@@ -18,7 +18,7 @@
     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 '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 @@
     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 @@
     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 a18f8a4..3485c05 100755
--- a/t/t0300-credentials.sh
+++ b/t/t0300-credentials.sh
@@ -578,7 +578,7 @@
 	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 @@
 	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 @@
 	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 @@
 	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 84cce34..22058b5 100755
--- a/t/t0500-progress-display.sh
+++ b/t/t0500-progress-display.sh
@@ -29,7 +29,7 @@
 	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-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 @@
 		<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 @@
 		<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 @@
 		<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 @@
 		<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-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-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-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-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-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 dfe9794..24092c0 100755
--- a/t/t1011-read-tree-sparse-checkout.sh
+++ b/t/t1011-read-tree-sparse-checkout.sh
@@ -253,7 +253,7 @@
 
 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 3a527e3..88b119a 100755
--- a/t/t1308-config-set.sh
+++ b/t/t1308-config-set.sh
@@ -208,14 +208,14 @@
 	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 359d873..e31f65f 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -374,7 +374,7 @@
 	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 @@
 	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 @@
 	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 2d142e5..8b51c4e 100755
--- a/t/t1404-update-ref-errors.sh
+++ b/t/t1404-update-ref-errors.sh
@@ -101,7 +101,7 @@
 		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 354902e..b1839e0 100755
--- a/t/t1430-bad-ref-name.sh
+++ b/t/t1430-bad-ref-name.sh
@@ -125,7 +125,7 @@
 	! 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 2312431..5071ac6 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -376,7 +376,7 @@
 	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 @@
 		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 @@
 		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 a859abe..b29563f 100755
--- a/t/t1502-rev-parse-parseopt.sh
+++ b/t/t1502-rev-parse-parseopt.sh
@@ -95,7 +95,7 @@
 |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 @@
 |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 @@
 |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 @@
 |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 @@
 |
 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 f6e6f23..65a154a 100755
--- a/t/t1506-rev-parse-diagnosis.sh
+++ b/t/t1506-rev-parse-diagnosis.sh
@@ -15,7 +15,7 @@
 	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 73b4f34..c34714f 100755
--- a/t/t1507-rev-parse-upstream.sh
+++ b/t/t1507-rev-parse-upstream.sh
@@ -172,7 +172,7 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 fd2f7ab..553a3f6 100755
--- a/t/t1509-root-work-tree.sh
+++ b/t/t1509-root-work-tree.sh
@@ -221,7 +221,7 @@
 	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 @@
 	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 242abbf..7891a6b 100755
--- a/t/t1512-rev-parse-disambiguation.sh
+++ b/t/t1512-rev-parse-disambiguation.sh
@@ -314,39 +314,39 @@
 	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 @@
 		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 b7c31aa..c9b9e71 100755
--- a/t/t1600-index.sh
+++ b/t/t1600-index.sh
@@ -18,7 +18,7 @@
 			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 @@
 			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 @@
 			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 8e181db..7ff3eda 100755
--- a/t/t2006-checkout-index-basic.sh
+++ b/t/t2006-checkout-index-basic.sh
@@ -32,4 +32,27 @@
 	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 5f761bc..93be1c0 100755
--- a/t/t2018-checkout-branch.sh
+++ b/t/t2018-checkout-branch.sh
@@ -150,7 +150,7 @@
 	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 b432b64..bc46713 100755
--- a/t/t2020-checkout-detach.sh
+++ b/t/t2020-checkout-detach.sh
@@ -163,7 +163,7 @@
 	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 @@
 	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 @@
 	# 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 @@
 
 	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 7cb7a70..45ca35d 100755
--- a/t/t2200-add-update.sh
+++ b/t/t2200-add-update.sh
@@ -135,7 +135,7 @@
 	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 aff8775..a615d3b 100755
--- a/t/t2401-worktree-prune.sh
+++ b/t/t2401-worktree-prune.sh
@@ -23,7 +23,7 @@
 	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 @@
 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 42d35d9..fedcefe 100755
--- a/t/t2402-worktree-list.sh
+++ b/t/t2402-worktree-list.sh
@@ -167,7 +167,7 @@
 	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 2ec69a8..727e9ae 100755
--- a/t/t3005-ls-files-relative.sh
+++ b/t/t3005-ls-files-relative.sh
@@ -46,7 +46,7 @@
 		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 @@
 		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 00761e4..cc4b102 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -695,7 +695,7 @@
 	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 @@
 	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 @@
 	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 @@
 	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 '--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_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 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 '--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 @@
 	# 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_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 @@
 	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 578b5f4..349a810 100755
--- a/t/t3201-branch-contains.sh
+++ b/t/t3201-branch-contains.sh
@@ -264,7 +264,7 @@
 	* 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 b6fcd01..5325b9f 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -160,7 +160,7 @@
 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 @@
 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 @@
 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 @@
 	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 @@
 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 @@
 	  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 @@
 	  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 @@
 	  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 @@
 	  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 @@
 	  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 @@
 	  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 @@
 	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 @@
 	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 @@
 	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 04de03c..f5bf16a 100755
--- a/t/t3300-funny-names.sh
+++ b/t/t3300-funny-names.sh
@@ -181,7 +181,7 @@
 	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/t3400-rebase.sh b/t/t3400-rebase.sh
index 5e88a10..587b408 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -113,7 +113,7 @@
 	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 28c2d15..66bcbbf 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -86,7 +86,7 @@
 			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_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_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 @@
 	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 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 @@
 	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 @@
 	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 @@
 	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_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 "$(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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 36f169d..908016c 100755
--- a/t/t3415-rebase-autosquash.sh
+++ b/t/t3415-rebase-autosquash.sh
@@ -306,23 +306,23 @@
 	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 4caa014..43fcb68 100755
--- a/t/t3420-rebase-autostash.sh
+++ b/t/t3420-rebase-autostash.sh
@@ -110,7 +110,7 @@
 		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 @@
 		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 2dab893..4c98d99 100755
--- a/t/t3431-rebase-fork-point.sh
+++ b/t/t3431-rebase-fork-point.sh
@@ -29,19 +29,23 @@
 	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_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 9198535..4581ae9 100755
--- a/t/t3504-cherry-pick-rerere.sh
+++ b/t/t3504-cherry-pick-rerere.sh
@@ -74,10 +74,10 @@
 	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 5f4564c..014001b 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -59,7 +59,7 @@
 	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 @@
 	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_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_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_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_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 ec7a2c9..e8375d1 100755
--- a/t/t3508-cherry-pick-many-commits.sh
+++ b/t/t3508-cherry-pick-many-commits.sh
@@ -86,7 +86,7 @@
 	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_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 5b94fda..b76cb6d 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -170,7 +170,7 @@
 	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 @@
 	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 @@
 	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_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 7547f11..bb9ef35 100755
--- a/t/t3600-rm.sh
+++ b/t/t3600-rm.sh
@@ -454,7 +454,7 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	    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 @@
 	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 b7d4ba6..b3b122f 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -304,7 +304,7 @@
 	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 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 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 -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 '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 b2f9099..2077146 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -370,7 +370,7 @@
 '
 
 # 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 @@
 	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 86bfeb2..60a666d 100755
--- a/t/t3800-mktag.sh
+++ b/t/t3800-mktag.sh
@@ -13,13 +13,11 @@
 
 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 @@
 	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 84b039e..5f282ec 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -564,7 +564,7 @@
 	 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 @@
 		git stash apply
 	) |
 	sed -e 1d >actual && # drop "Saved..."
-	test_i18ncmp expect actual
+	test_cmp expect actual
 '
 
 cat >expect <<EOF
@@ -1114,7 +1114,7 @@
 	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 @@
 	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 b26a97a..598b17f 100755
--- a/t/t3905-stash-include-untracked.sh
+++ b/t/t3905-stash-include-untracked.sh
@@ -288,7 +288,7 @@
 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/t4006-diff-mode.sh b/t/t4006-diff-mode.sh
index 03489af..275ce5f 100755
--- a/t/t4006-diff-mode.sh
+++ b/t/t4006-diff-mode.sh
@@ -39,13 +39,13 @@
 	 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 @@
 	 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 6579c81..33ff588 100755
--- a/t/t4012-diff-binary.sh
+++ b/t/t4012-diff-binary.sh
@@ -34,19 +34,19 @@
 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 @@
 
 # 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 "$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 fcc30d8..6cca8b8 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -222,7 +222,7 @@
 			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 66630c8..cdd3154 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -888,11 +888,11 @@
 
 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 9c48e5c..876271d 100755
--- a/t/t4016-diff-quote.sh
+++ b/t/t4016-diff-quote.sh
@@ -82,7 +82,7 @@
 	 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 4cb9f0e..c906320 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -139,7 +139,7 @@
 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 7be1de7..61ba5f7 100755
--- a/t/t4045-diff-relative.sh
+++ b/t/t4045-diff-relative.sh
@@ -61,7 +61,7 @@
 	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 a341217..53061b1 100755
--- a/t/t4049-diff-stat-count.sh
+++ b/t/t4049-diff-stat-count.sh
@@ -25,7 +25,7 @@
 	 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 @@
 	 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 @@
 	 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 63ea714..aec1d9d 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 @@
 	'
 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 744b8e5..9b433de 100755
--- a/t/t4100-apply-stat.sh
+++ b/t/t4100-apply-stat.sh
@@ -17,13 +17,13 @@
 	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 9998751..2aaaa0d 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -906,7 +906,7 @@
 	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 8ea22d1..b7c3861 100755
--- a/t/t4153-am-resume-override-opts.sh
+++ b/t/t4153-am-resume-override-opts.sh
@@ -61,7 +61,7 @@
 	# 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 749bc14..85432b8 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -123,10 +123,10 @@
 	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 5e10136..7f0c1dc 100755
--- a/t/t4208-log-magic-pathspec.sh
+++ b/t/t4208-log-magic-pathspec.sh
@@ -31,13 +31,8 @@
 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 daf01c3..54be7da 100755
--- a/t/t4254-am-corrupt.sh
+++ b/t/t4254-am-corrupt.sh
@@ -60,7 +60,7 @@
 	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 db4e15f..cb67bac 100755
--- a/t/t5150-request-pull.sh
+++ b/t/t5150-request-pull.sh
@@ -223,14 +223,14 @@
 		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 392201c..d586fdc 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -427,7 +427,7 @@
 	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 @@
 	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 0f06c40..a8c1bc0 100755
--- a/t/t5316-pack-delta-depth.sh
+++ b/t/t5316-pack-delta-depth.sh
@@ -84,14 +84,14 @@
 	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/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 1f4cc87..8a5d349 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -547,7 +547,7 @@
 		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 @@
 		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 @@
 		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 045398b..8c462f2 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -59,7 +59,7 @@
 	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 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 C_LOCALE_OUTPUT 'remove remote' '
+test_expect_success 'remove remote' '
 	(
 		cd test &&
 		tokens_match origin "$(git remote)" &&
@@ -140,8 +140,8 @@
 		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 @@
 		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 @@
 		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_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_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 @@
 		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 @@
 		cd test &&
 		git remote show -n origin >output &&
 		mv ../one.unreachable ../one &&
-		test_i18ncmp expect output
+		test_cmp expect output
 	)
 '
 
@@ -337,7 +337,7 @@
 		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 @@
 		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 c1e0eb3..e83b2a6 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -1051,7 +1051,7 @@
 		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 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_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 4a568a2..f53f588 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -150,7 +150,7 @@
 	# 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/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh
index 11513ec1..ed11569 100755
--- a/t/t5526-fetch-submodules.sh
+++ b/t/t5526-fetch-submodules.sh
@@ -74,7 +74,7 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 			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 @@
 		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_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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 bc5ccf2..c024fa2 100755
--- a/t/t5541-http-push-smart.sh
+++ b/t/t5541-http-push-smart.sh
@@ -118,7 +118,7 @@
 	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/t5601-clone.sh b/t/t5601-clone.sh
index 664c913..e7e6c08 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -40,7 +40,7 @@
 
 '
 
-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/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh
index da5fe1b..881f72f 100755
--- a/t/t6020-bundle-misc.sh
+++ b/t/t6020-bundle-misc.sh
@@ -175,7 +175,7 @@
 	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 @@
 	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 @@
 	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 @@
 	<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 @@
 	# 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 @@
 
 	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_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 @@
 
 	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 @@
 
 	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 7bcde05..ef7bdce 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -829,7 +829,7 @@
 	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 @@
 	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 a160b2b..a313849 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -57,7 +57,7 @@
 		git branch -v
 	) |
 	sed -n -e "$t6040_script" >actual &&
-	test_i18ncmp expect actual
+	test_cmp expect actual
 '
 
 cat >expect <<\EOF
@@ -75,7 +75,7 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 0000000..b4aef32
--- /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 546796f..e89b674 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -136,7 +136,7 @@
 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 c670668..0f1cb49 100755
--- a/t/t6134-pathspec-in-submodule.sh
+++ b/t/t6134-pathspec-in-submodule.sh
@@ -21,7 +21,7 @@
 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 809854f..40edf9d 100755
--- a/t/t6301-for-each-ref-errors.sh
+++ b/t/t6301-for-each-ref-errors.sh
@@ -20,8 +20,8 @@
 	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 @@
 	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_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 4ab133f..5d3b711 100755
--- a/t/t6423-merge-rename-directories.sh
+++ b/t/t6423-merge-rename-directories.sh
@@ -2905,7 +2905,7 @@
 	)
 }
 
-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 362ae37..84b4aac 100755
--- a/t/t6436-merge-overwrite.sh
+++ b/t/t6436-merge-overwrite.sh
@@ -139,7 +139,7 @@
 	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 @@
 	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 e176475..5bfb027 100755
--- a/t/t6439-merge-co-error-msgs.sh
+++ b/t/t6439-merge-co-error-msgs.sh
@@ -40,14 +40,14 @@
 
 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 @@
 	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 @@
 	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 @@
 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 @@
 	>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 63d5f41..080a653 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -446,7 +446,7 @@
 	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)" ] &&
 	(
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 400b83a..2f72c5c 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -98,7 +98,7 @@
 	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 @@
 	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 @@
 	# 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 @@
 	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 37525ca..2685258 100755
--- a/t/t7011-skip-worktree-reading.sh
+++ b/t/t7011-skip-worktree-reading.sh
@@ -109,15 +109,6 @@
 	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 e5c6a03..f2a8e76 100755
--- a/t/t7012-skip-worktree-writing.sh
+++ b/t/t7012-skip-worktree-writing.sh
@@ -125,13 +125,13 @@
 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 72fb418..0f4344c 100755
--- a/t/t7060-wtstatus.sh
+++ b/t/t7060-wtstatus.sh
@@ -56,9 +56,9 @@
 		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 @@
 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 @@
 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 @@
 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 @@
 	?? 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 @@
 	?? 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 f01bf27..accefde 100755
--- a/t/t7063-status-untracked-cache.sh
+++ b/t/t7063-status-untracked-cache.sh
@@ -731,7 +731,7 @@
 	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 7d8fb18..601b2bf 100755
--- a/t/t7102-reset.sh
+++ b/t/t7102-reset.sh
@@ -75,14 +75,14 @@
 	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 @@
 	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 cb5e34d..a74816c 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -110,7 +110,7 @@
 
 '
 
-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 @@
 	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 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 d44f696..a924fdb 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -55,7 +55,7 @@
 	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 @@
 		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 7608814..9c3cc4c 100755
--- a/t/t7401-submodule-summary.sh
+++ b/t/t7401-submodule-summary.sh
@@ -190,7 +190,7 @@
 	  < Add foo5
 
 	EOF
-	test_i18ncmp expected actual
+	test_cmp expected actual
 "
 
 test_expect_success 'typechanged submodule(submodule->blob), --files' "
@@ -200,7 +200,7 @@
 	  > Add foo5
 
 	EOF
-	test_i18ncmp expected actual
+	test_cmp expected actual
 "
 
 rm -rf sm1 &&
@@ -211,7 +211,7 @@
 	* sm1 $head4(submodule)->$head5(blob):
 
 	EOF
-	test_i18ncmp expected actual
+	test_cmp expected actual
 "
 
 rm -f sm1 &&
@@ -224,7 +224,7 @@
 	  Warn: sm1 doesn't contain commit $head4_full
 
 	EOF
-	test_i18ncmp expected actual
+	test_cmp expected actual
 "
 
 commit_file
@@ -235,7 +235,7 @@
 	  > Add foo7
 
 	EOF
-	test_i18ncmp expected actual
+	test_cmp expected actual
 "
 
 commit_file sm1 &&
@@ -292,7 +292,7 @@
 
 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 b9c1624..ff3ba54 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -155,9 +155,9 @@
 	 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 @@
 	  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 @@
 	(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 @@
 	(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 @@
 	 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 @@
 	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 @@
 	 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 79981b5..e2f110b 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -80,7 +80,7 @@
 		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 @@
 		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 @@
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
-	test_i18ncmp expect actual
+	test_cmp expect actual
 '
 
 cat > expect <<EOF
@@ -197,7 +197,7 @@
 		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 @@
 		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 6d19ece..e41ac18 100755
--- a/t/t7500-commit-template-squash-signoff.sh
+++ b/t/t7500-commit-template-squash-signoff.sh
@@ -15,7 +15,7 @@
 
 	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 @@
 	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 e5332ad..6396897 100755
--- a/t/t7502-commit-porcelain.sh
+++ b/t/t7502-commit-porcelain.sh
@@ -13,7 +13,7 @@
 
 	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 @@
 	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 @@
 # 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 321b4bc..7a8194c 100755
--- a/t/t7505-prepare-commit-msg-hook.sh
+++ b/t/t7505-prepare-commit-msg-hook.sh
@@ -218,7 +218,7 @@
 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 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 d01aacb..2b72451 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -109,13 +109,13 @@
 #
 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 @@
 
 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 @@
 	 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 @@
 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 @@
 
 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 @@
 
 EOF
 	git status --ignored >output &&
-	test_i18ncmp expect output
+	test_cmp expect output
 '
 
 cat >.gitignore <<\EOF
@@ -380,7 +380,7 @@
 test_expect_success 'status -s -b' '
 
 	git status -s -b >output &&
-	test_i18ncmp expect output
+	test_cmp expect output
 
 '
 
@@ -390,7 +390,7 @@
 	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 @@
 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 @@
 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 @@
 
 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 @@
 
 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 @@
 
 EOF
 	(cd dir1 && git status) >output &&
-	test_i18ncmp expect output
+	test_cmp expect output
 '
 
 cat >expect <<\EOF
@@ -670,13 +670,13 @@
 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 @@
 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 @@
 EOF
 	test_config status.relativePaths false &&
 	(cd dir1 && git status) >output &&
-	test_i18ncmp expect output
+	test_cmp expect output
 
 '
 
@@ -860,7 +860,7 @@
 
 EOF
 	git commit --dry-run dir1/modified >output &&
-	test_i18ncmp expect output
+	test_cmp expect output
 '
 
 cat >expect <<EOF
@@ -921,13 +921,13 @@
 
 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 @@
 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 @@
 	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 @@
 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 @@
 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 @@
 	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 @@
 	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 @@
 	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 '--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 @@
 	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 @@
 
 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 @@
 	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 @@
 
 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 @@
 	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 @@
 	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 @@
 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 @@
 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 @@
 	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 @@
 	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 @@
 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 9f5e3ce..7f2956d 100755
--- a/t/t7512-status-help.sh
+++ b/t/t7512-status-help.sh
@@ -41,7 +41,7 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 no changes added to commit
 EOF
 	git status --untracked-files=no >actual &&
-	test_i18ncmp expected actual
+	test_cmp expected actual
 '
 
 
@@ -746,7 +746,7 @@
 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 @@
 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 @@
 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 @@
 	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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 
 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 fbfdcca..45d025f 100755
--- a/t/t7519-status-fsmonitor.sh
+++ b/t/t7519-status-fsmonitor.sh
@@ -236,7 +236,7 @@
 	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 @@
 			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 9179094..a88b02b 100755
--- a/t/t7521-ignored-mode.sh
+++ b/t/t7521-ignored-mode.sh
@@ -30,7 +30,7 @@
 		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 @@
 	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 @@
 		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 @@
 		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 @@
 	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 @@
 		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 @@
 		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 @@
 	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 @@
 		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 @@
 		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 @@
 		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 b2c1d86..1cbc971 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -272,7 +272,7 @@
 	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 @@
 	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 13859ec..a9c816b 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -66,7 +66,7 @@
 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 @@
 		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 @@
 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 9192c14..3e041e8 100755
--- a/t/t7800-difftool.sh
+++ b/t/t7800-difftool.sh
@@ -762,4 +762,36 @@
 	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 8f7591c..edfaa9a 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -969,7 +969,7 @@
 	"
 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 0000000..590b99b
--- /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/t9003-help-autocorrect.sh b/t/t9003-help-autocorrect.sh
index 03cd5c5..f00deaf 100755
--- a/t/t9003-help-autocorrect.sh
+++ b/t/t9003-help-autocorrect.sh
@@ -56,11 +56,8 @@
 	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 c96a555..6348e8d 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -190,6 +190,7 @@
 	author= &&
 	signoff= &&
 	indir= &&
+	no_tag= &&
 	while test $# != 0
 	do
 		case "$1" in
@@ -216,6 +217,9 @@
 			indir="$2"
 			shift
 			;;
+		--no-tag)
+			no_tag=yes
+			;;
 		*)
 			break
 			;;
@@ -238,7 +242,10 @@
 	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 987a6c1..d3f6af6 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1489,11 +1489,6 @@
 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