summaryrefslogtreecommitdiff
path: root/t
diff options
context:
space:
mode:
Diffstat (limited to 't')
-rw-r--r--t/Makefile3
-rw-r--r--t/README4
-rw-r--r--t/helper/test-chmtime.c15
-rw-r--r--t/helper/test-csprng.c29
-rw-r--r--t/helper/test-date.c5
-rw-r--r--t/helper/test-fsmonitor-client.c116
-rw-r--r--t/helper/test-progress.c50
-rw-r--r--t/helper/test-read-graph.c13
-rw-r--r--t/helper/test-ref-store.c3
-rw-r--r--t/helper/test-reftable.c9
-rw-r--r--t/helper/test-run-command.c14
-rw-r--r--t/helper/test-tool.c2
-rw-r--r--t/helper/test-tool.h2
-rw-r--r--t/interop/Makefile3
-rw-r--r--t/lib-bitmap.sh185
-rwxr-xr-xt/lib-commit-graph.sh58
-rw-r--r--t/lib-gpg.sh11
-rw-r--r--t/lib-read-tree-m-3way.sh168
-rw-r--r--t/perf/Makefile3
-rwxr-xr-xt/perf/p1006-cat-file.sh12
-rwxr-xr-xt/perf/p2000-sparse-operations.sh3
-rwxr-xr-xt/perf/p7519-fsmonitor.sh68
-rw-r--r--t/perf/perf-lib.sh2
-rwxr-xr-xt/t0000-basic.sh23
-rwxr-xr-xt/t0001-init.sh3
-rwxr-xr-xt/t0002-gitfile.sh6
-rwxr-xr-xt/t0003-attributes.sh9
-rwxr-xr-xt/t0006-date.sh2
-rwxr-xr-xt/t0012-help.sh101
-rwxr-xr-xt/t0015-hash.sh6
-rwxr-xr-xt/t0022-crlf-rename.sh4
-rwxr-xr-xt/t0025-crlf-renormalize.sh4
-rwxr-xr-xt/t0027-auto-crlf.sh18
-rwxr-xr-xt/t0029-core-unsetenvvars.sh3
-rwxr-xr-xt/t0030-stripspace.sh75
-rwxr-xr-xt/t0050-filesystem.sh3
-rwxr-xr-xt/t0051-windows-named-pipe.sh7
-rwxr-xr-xt/t0091-bugreport.sh26
-rw-r--r--t/t0211/scrub_perf.perl4
-rwxr-xr-xt/t0410-partial-clone.sh19
-rwxr-xr-xt/t0500-progress-display.sh109
-rwxr-xr-xt/t1001-read-tree-m-2way.sh6
-rwxr-xr-xt/t1002-read-tree-m-u-2way.sh6
-rwxr-xr-xt/t1003-read-tree-prefix.sh10
-rwxr-xr-xt/t1006-cat-file.sh227
-rwxr-xr-xt/t1007-hash-object.sh1
-rwxr-xr-xt/t1011-read-tree-sparse-checkout.sh23
-rwxr-xr-xt/t1090-sparse-checkout-scope.sh19
-rwxr-xr-xt/t1091-sparse-checkout-builtin.sh183
-rwxr-xr-xt/t1092-sparse-checkout-compatibility.sh453
-rwxr-xr-xt/t1300-config.sh118
-rwxr-xr-xt/t1350-config-hooks-path.sh4
-rwxr-xr-xt/t1405-main-ref-store.sh8
-rwxr-xr-xt/t1410-reflog.sh36
-rwxr-xr-xt/t1411-reflog-show.sh5
-rwxr-xr-xt/t1416-ref-transaction-hooks.sh73
-rwxr-xr-xt/t1418-reflog-exists.sh37
-rwxr-xr-xt/t1503-rev-parse-verify.sh5
-rwxr-xr-xt/t1512-rev-parse-disambiguation.sh81
-rwxr-xr-xt/t1800-hook.sh123
-rwxr-xr-xt/t2012-checkout-last.sh51
-rwxr-xr-xt/t2060-switch.sh11
-rwxr-xr-xt/t2108-update-index-refresh-racy.sh64
-rwxr-xr-xt/t2200-add-update.sh33
-rwxr-xr-xt/t2400-worktree-add.sh63
-rwxr-xr-xt/t2402-worktree-list.sh19
-rwxr-xr-xt/t3007-ls-files-recurse-submodules.sh18
-rwxr-xr-xt/t3101-ls-tree-dirname.sh55
-rwxr-xr-xt/t3103-ls-tree-misc.sh15
-rwxr-xr-xt/t3104-ls-tree-format.sh76
-rwxr-xr-xt/t3200-branch.sh35
-rwxr-xr-xt/t3207-branch-submodule.sh328
-rwxr-xr-xt/t3302-notes-index-expensive.sh6
-rwxr-xr-xt/t3303-notes-subtrees.sh9
-rwxr-xr-xt/t3305-notes-fanout.sh14
-rwxr-xr-xt/t3400-rebase.sh39
-rwxr-xr-xt/t3404-rebase-interactive.sh10
-rwxr-xr-xt/t3406-rebase-message.sh23
-rwxr-xr-xt/t3412-rebase-root.sh20
-rwxr-xr-xt/t3413-rebase-hook.sh18
-rwxr-xr-xt/t3418-rebase-continue.sh26
-rwxr-xr-xt/t3430-rebase-merges.sh6
-rwxr-xr-xt/t3701-add-interactive.sh48
-rwxr-xr-xt/t3705-add-sparse-checkout.sh2
-rwxr-xr-xt/t3903-stash.sh123
-rwxr-xr-xt/t4015-diff-whitespace.sh12
-rw-r--r--t/t4018/kotlin-class5
-rw-r--r--t/t4018/kotlin-enum-class5
-rw-r--r--t/t4018/kotlin-fun5
-rw-r--r--t/t4018/kotlin-inheritace-class5
-rw-r--r--t/t4018/kotlin-inline-class5
-rw-r--r--t/t4018/kotlin-interface5
-rw-r--r--t/t4018/kotlin-nested-fun9
-rw-r--r--t/t4018/kotlin-public-class5
-rw-r--r--t/t4018/kotlin-sealed-class5
-rwxr-xr-xt/t4020-diff-external.sh153
-rwxr-xr-xt/t4027-diff-submodule.sh7
-rwxr-xr-xt/t4034-diff-words.sh1
-rw-r--r--t/t4034/kotlin/expect43
-rw-r--r--t/t4034/kotlin/post30
-rw-r--r--t/t4034/kotlin/pre30
-rwxr-xr-xt/t4069-remerge-diff.sh291
-rwxr-xr-xt/t4123-apply-shrink.sh18
-rwxr-xr-xt/t4128-apply-root.sh36
-rwxr-xr-xt/t4150-am.sh26
-rwxr-xr-xt/t4202-log.sh110
-rwxr-xr-xt/t4204-patch-id.sh95
-rwxr-xr-xt/t4216-log-bloom.sh1
-rwxr-xr-xt/t5300-pack-object.sh4
-rwxr-xr-xt/t5302-pack-index.sh8
-rwxr-xr-xt/t5310-pack-bitmaps.sh28
-rwxr-xr-xt/t5312-prune-corruption.sh10
-rwxr-xr-xt/t5316-pack-delta-depth.sh6
-rwxr-xr-xt/t5318-commit-graph.sh55
-rwxr-xr-xt/t5324-split-commit-graph.sh10
-rwxr-xr-xt/t5326-multi-pack-bitmaps.sh186
-rwxr-xr-xt/t5327-multi-pack-bitmaps-rev.sh23
-rwxr-xr-xt/t5328-commit-graph-64bit-time.sh66
-rwxr-xr-xt/t5401-update-hooks.sh64
-rwxr-xr-xt/t5402-post-merge-hook.sh16
-rwxr-xr-xt/t5403-post-checkout-hook.sh70
-rwxr-xr-xt/t5406-remote-rejects.sh2
-rwxr-xr-xt/t5407-post-rewrite-hook.sh14
-rwxr-xr-xt/t5409-colorize-remote-messages.sh2
-rwxr-xr-xt/t5411-proc-receive-hook.sh4
-rw-r--r--t/t5411/once-0010-report-status-v1.sh2
-rw-r--r--t/t5411/test-0002-pre-receive-declined.sh4
-rw-r--r--t/t5411/test-0003-pre-receive-declined--porcelain.sh2
-rw-r--r--t/t5411/test-0013-bad-protocol.sh20
-rw-r--r--t/t5411/test-0014-bad-protocol--porcelain.sh18
-rw-r--r--t/t5411/test-0020-report-ng.sh4
-rw-r--r--t/t5411/test-0021-report-ng--porcelain.sh4
-rw-r--r--t/t5411/test-0022-report-unexpect-ref.sh2
-rw-r--r--t/t5411/test-0023-report-unexpect-ref--porcelain.sh2
-rw-r--r--t/t5411/test-0024-report-unknown-ref.sh2
-rw-r--r--t/t5411/test-0025-report-unknown-ref--porcelain.sh2
-rw-r--r--t/t5411/test-0026-push-options.sh6
-rw-r--r--t/t5411/test-0027-push-options--porcelain.sh6
-rw-r--r--t/t5411/test-0030-report-ok.sh2
-rw-r--r--t/t5411/test-0031-report-ok--porcelain.sh2
-rw-r--r--t/t5411/test-0032-report-with-options.sh14
-rw-r--r--t/t5411/test-0033-report-with-options--porcelain.sh14
-rw-r--r--t/t5411/test-0034-report-ft.sh2
-rw-r--r--t/t5411/test-0035-report-ft--porcelain.sh2
-rw-r--r--t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh6
-rw-r--r--t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh6
-rw-r--r--t/t5411/test-0038-report-mixed-refs.sh2
-rw-r--r--t/t5411/test-0039-report-mixed-refs--porcelain.sh2
-rw-r--r--t/t5411/test-0040-process-all-refs.sh2
-rw-r--r--t/t5411/test-0041-process-all-refs--porcelain.sh2
-rw-r--r--t/t5411/test-0050-proc-receive-refs-with-modifiers.sh4
-rwxr-xr-xt/t5500-fetch-pack.sh24
-rwxr-xr-xt/t5503-tagfollow.sh64
-rwxr-xr-xt/t5505-remote.sh4
-rwxr-xr-xt/t5510-fetch.sh46
-rwxr-xr-xt/t5511-refspec.sh1
-rwxr-xr-xt/t5516-fetch-push.sh212
-rwxr-xr-xt/t5520-pull.sh13
-rwxr-xr-xt/t5521-pull-options.sh4
-rwxr-xr-xt/t5526-fetch-submodules.sh545
-rwxr-xr-xt/t5534-push-signed.sh26
-rwxr-xr-xt/t5537-fetch-shallow.sh9
-rwxr-xr-xt/t5540-http-push-webdav.sh4
-rwxr-xr-xt/t5541-http-push-smart.sh32
-rwxr-xr-xt/t5543-atomic-push.sh14
-rwxr-xr-xt/t5547-push-quarantine.sh4
-rwxr-xr-xt/t5548-push-porcelain.sh2
-rwxr-xr-xt/t5550-http-fetch-dumb.sh25
-rwxr-xr-xt/t5571-pre-push-hook.sh128
-rwxr-xr-xt/t5601-clone.sh4
-rwxr-xr-xt/t5616-partial-clone.sh81
-rwxr-xr-xt/t5617-clone-submodules-remote.sh41
-rwxr-xr-xt/t5700-protocol-v1.sh15
-rwxr-xr-xt/t5702-protocol-v2.sh14
-rwxr-xr-xt/t6005-rev-list-count.sh43
-rwxr-xr-xt/t6007-rev-list-cherry-pick-file.sh26
-rwxr-xr-xt/t6012-rev-list-simplify.sh30
-rwxr-xr-xt/t6020-bundle-misc.sh98
-rwxr-xr-xt/t6030-bisect-porcelain.sh45
-rwxr-xr-xt/t6102-rev-list-unexpected-objects.sh13
-rwxr-xr-xt/t6111-rev-list-treesame.sh3
-rwxr-xr-xt/t6120-describe.sh127
-rwxr-xr-xt/t6404-recursive-merge.sh9
-rwxr-xr-xt/t6406-merge-attr.sh9
-rwxr-xr-xt/t6407-merge-binary.sh22
-rwxr-xr-xt/t6423-merge-rename-directories.sh10
-rwxr-xr-xt/t6428-merge-conflicts-sparse.sh23
-rwxr-xr-xt/t6429-merge-sequence-rename-caching.sh67
-rwxr-xr-xt/t6500-gc.sh22
-rwxr-xr-xt/t7001-mv.sh19
-rwxr-xr-xt/t7012-skip-worktree-writing.sh44
-rwxr-xr-xt/t7063-status-untracked-cache.sh21
-rwxr-xr-xt/t7102-reset.sh40
-rwxr-xr-xt/t7103-reset-bare.sh7
-rwxr-xr-xt/t7113-post-index-change-hook.sh7
-rwxr-xr-xt/t7406-submodule-update.sh26
-rwxr-xr-xt/t7408-submodule-reference.sh14
-rwxr-xr-xt/t7500-commit-template-squash-signoff.sh2
-rwxr-xr-xt/t7503-pre-commit-and-pre-merge-commit-hooks.sh150
-rwxr-xr-xt/t7504-commit-msg-hook.sh43
-rwxr-xr-xt/t7505-prepare-commit-msg-hook.sh43
-rwxr-xr-xt/t7508-status.sh30
-rwxr-xr-xt/t7519-status-fsmonitor.sh27
-rwxr-xr-xt/t7520-ignored-hook-warning.sh11
-rwxr-xr-xt/t7527-builtin-fsmonitor.sh609
-rwxr-xr-xt/t7700-repack.sh111
-rwxr-xr-xt/t7810-grep.sh186
-rwxr-xr-xt/t7812-grep-icase-non-ascii.sh16
-rwxr-xr-xt/t7814-grep-recurse-submodules.sh41
-rwxr-xr-xt/t7817-grep-sparse-checkout.sh11
-rwxr-xr-xt/t8007-cat-file-textconv.sh42
-rwxr-xr-xt/t9001-send-email.sh8
-rwxr-xr-xt/t9102-git-svn-deep-rmdir.sh1
-rwxr-xr-xt/t9123-git-svn-rebuild-with-rewriteroot.sh1
-rwxr-xr-xt/t9128-git-svn-cmd-branch.sh1
-rwxr-xr-xt/t9167-git-svn-cmd-branch-subproject.sh1
-rwxr-xr-xt/t9502-gitweb-standalone-parse-output.sh15
-rwxr-xr-xt/t9800-git-p4-basic.sh23
-rwxr-xr-xt/t9902-completion.sh81
-rw-r--r--t/test-lib-functions.sh174
-rw-r--r--t/test-lib.sh83
221 files changed, 7230 insertions, 1851 deletions
diff --git a/t/Makefile b/t/Makefile
index 46cd5fc..056ce55 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -1,3 +1,6 @@
+# Import tree-wide shared Makefile behavior and libraries
+include ../shared.mak
+
# Run tests
#
# Copyright (c) 2005 Junio C Hamano
diff --git a/t/README b/t/README
index f48e054..9ffea1d 100644
--- a/t/README
+++ b/t/README
@@ -405,8 +405,8 @@ every 'git commit-graph write', as if the `--changed-paths` option was
passed in.
GIT_TEST_FSMONITOR=$PWD/t7519/fsmonitor-all exercises the fsmonitor
-code path for utilizing a file system monitor to speed up detecting
-new or changed files.
+code paths for utilizing a (hook based) file system monitor to speed up
+detecting new or changed files.
GIT_TEST_INDEX_VERSION=<n> exercises the index read/write code path
for the index version specified. Can be set to any valid version
diff --git a/t/helper/test-chmtime.c b/t/helper/test-chmtime.c
index 524b55c..dc28890 100644
--- a/t/helper/test-chmtime.c
+++ b/t/helper/test-chmtime.c
@@ -134,6 +134,21 @@ int cmd__chmtime(int argc, const char **argv)
}
if (utb.modtime != sb.st_mtime && utime(argv[i], &utb) < 0) {
+#ifdef GIT_WINDOWS_NATIVE
+ if (S_ISDIR(sb.st_mode)) {
+ /*
+ * NEEDSWORK: The Windows version of `utime()`
+ * (aka `mingw_utime()`) does not correctly
+ * handle directory arguments, since it uses
+ * `_wopen()`. Ignore it for now since this
+ * is just a test.
+ */
+ fprintf(stderr,
+ ("Failed to modify time on directory %s. "
+ "Skipping\n"), argv[i]);
+ continue;
+ }
+#endif
fprintf(stderr, "Failed to modify time on %s: %s\n",
argv[i], strerror(errno));
return 1;
diff --git a/t/helper/test-csprng.c b/t/helper/test-csprng.c
new file mode 100644
index 0000000..65d1497
--- /dev/null
+++ b/t/helper/test-csprng.c
@@ -0,0 +1,29 @@
+#include "test-tool.h"
+#include "git-compat-util.h"
+
+
+int cmd__csprng(int argc, const char **argv)
+{
+ unsigned long count;
+ unsigned char buf[1024];
+
+ if (argc > 2) {
+ fprintf(stderr, "usage: %s [<size>]\n", argv[0]);
+ return 2;
+ }
+
+ count = (argc == 2) ? strtoul(argv[1], NULL, 0) : -1L;
+
+ while (count) {
+ unsigned long chunk = count < sizeof(buf) ? count : sizeof(buf);
+ if (csprng_bytes(buf, chunk) < 0) {
+ perror("failed to read");
+ return 5;
+ }
+ if (fwrite(buf, chunk, 1, stdout) != chunk)
+ return 1;
+ count -= chunk;
+ }
+
+ return 0;
+}
diff --git a/t/helper/test-date.c b/t/helper/test-date.c
index 099eff4..45951b1 100644
--- a/t/helper/test-date.c
+++ b/t/helper/test-date.c
@@ -1,5 +1,6 @@
#include "test-tool.h"
#include "cache.h"
+#include "date.h"
static const char *usage_msg = "\n"
" test-tool date relative [time_t]...\n"
@@ -34,7 +35,7 @@ static void show_human_dates(const char **argv)
static void show_dates(const char **argv, const char *format)
{
- struct date_mode mode;
+ struct date_mode mode = DATE_MODE_INIT;
parse_date_format(format, &mode);
for (; *argv; argv++) {
@@ -53,6 +54,8 @@ static void show_dates(const char **argv, const char *format)
printf("%s -> %s\n", *argv, show_date(t, tz, &mode));
}
+
+ date_mode_release(&mode);
}
static void parse_dates(const char **argv)
diff --git a/t/helper/test-fsmonitor-client.c b/t/helper/test-fsmonitor-client.c
new file mode 100644
index 0000000..3062c8a
--- /dev/null
+++ b/t/helper/test-fsmonitor-client.c
@@ -0,0 +1,116 @@
+/*
+ * test-fsmonitor-client.c: client code to send commands/requests to
+ * a `git fsmonitor--daemon` daemon.
+ */
+
+#include "test-tool.h"
+#include "cache.h"
+#include "parse-options.h"
+#include "fsmonitor-ipc.h"
+
+#ifndef HAVE_FSMONITOR_DAEMON_BACKEND
+int cmd__fsmonitor_client(int argc, const char **argv)
+{
+ die("fsmonitor--daemon not available on this platform");
+}
+#else
+
+/*
+ * Read the `.git/index` to get the last token written to the
+ * FSMonitor Index Extension.
+ */
+static const char *get_token_from_index(void)
+{
+ struct index_state *istate = the_repository->index;
+
+ if (do_read_index(istate, the_repository->index_file, 0) < 0)
+ die("unable to read index file");
+ if (!istate->fsmonitor_last_update)
+ die("index file does not have fsmonitor extension");
+
+ return istate->fsmonitor_last_update;
+}
+
+/*
+ * Send an IPC query to a `git-fsmonitor--daemon` daemon and
+ * ask for the changes since the given token or from the last
+ * token in the index extension.
+ *
+ * This will implicitly start a daemon process if necessary. The
+ * daemon process will persist after we exit.
+ */
+static int do_send_query(const char *token)
+{
+ struct strbuf answer = STRBUF_INIT;
+ int ret;
+
+ if (!token || !*token)
+ token = get_token_from_index();
+
+ ret = fsmonitor_ipc__send_query(token, &answer);
+ if (ret < 0)
+ die("could not query fsmonitor--daemon");
+
+ write_in_full(1, answer.buf, answer.len);
+ strbuf_release(&answer);
+
+ return 0;
+}
+
+/*
+ * Send a "flush" command to the `git-fsmonitor--daemon` (if running)
+ * and tell it to flush its cache.
+ *
+ * This feature is primarily used by the test suite to simulate a loss of
+ * sync with the filesystem where we miss kernel events.
+ */
+static int do_send_flush(void)
+{
+ struct strbuf answer = STRBUF_INIT;
+ int ret;
+
+ ret = fsmonitor_ipc__send_command("flush", &answer);
+ if (ret)
+ return ret;
+
+ write_in_full(1, answer.buf, answer.len);
+ strbuf_release(&answer);
+
+ return 0;
+}
+
+int cmd__fsmonitor_client(int argc, const char **argv)
+{
+ const char *subcmd;
+ const char *token = NULL;
+
+ const char * const fsmonitor_client_usage[] = {
+ "test-tool fsmonitor-client query [<token>]",
+ "test-tool fsmonitor-client flush",
+ NULL,
+ };
+
+ struct option options[] = {
+ OPT_STRING(0, "token", &token, "token",
+ "command token to send to the server"),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, NULL, options, fsmonitor_client_usage, 0);
+
+ if (argc != 1)
+ usage_with_options(fsmonitor_client_usage, options);
+
+ subcmd = argv[0];
+
+ setup_git_directory();
+
+ if (!strcmp(subcmd, "query"))
+ return !!do_send_query(token);
+
+ if (!strcmp(subcmd, "flush"))
+ return !!do_send_flush();
+
+ die("Unhandled subcommand: '%s'", subcmd);
+}
+#endif
diff --git a/t/helper/test-progress.c b/t/helper/test-progress.c
index 5d05cbe..6cc9735 100644
--- a/t/helper/test-progress.c
+++ b/t/helper/test-progress.c
@@ -3,6 +3,9 @@
*
* Reads instructions from standard input, one instruction per line:
*
+ * "start <total>[ <title>]" - Call start_progress(title, total),
+ * Uses the default title of "Working hard"
+ * if the " <title>" is omitted.
* "progress <items>" - Call display_progress() with the given item count
* as parameter.
* "throughput <bytes> <millis> - Call display_throughput() with the given
@@ -10,6 +13,7 @@
* specify the time elapsed since the
* start_progress() call.
* "update" - Set the 'progress_update' flag.
+ * "stop" - Call stop_progress().
*
* See 't0500-progress-display.sh' for examples.
*/
@@ -19,34 +23,50 @@
#include "parse-options.h"
#include "progress.h"
#include "strbuf.h"
+#include "string-list.h"
int cmd__progress(int argc, const char **argv)
{
- int total = 0;
- const char *title;
+ const char *const default_title = "Working hard";
+ struct string_list titles = STRING_LIST_INIT_DUP;
struct strbuf line = STRBUF_INIT;
- struct progress *progress;
+ struct progress *progress = NULL;
const char *usage[] = {
- "test-tool progress [--total=<n>] <progress-title>",
+ "test-tool progress <stdin",
NULL
};
struct option options[] = {
- OPT_INTEGER(0, "total", &total, "total number of items"),
OPT_END(),
};
argc = parse_options(argc, argv, NULL, options, usage, 0);
- if (argc != 1)
- die("need a title for the progress output");
- title = argv[0];
+ if (argc)
+ usage_with_options(usage, options);
progress_testing = 1;
- progress = start_progress(title, total);
while (strbuf_getline(&line, stdin) != EOF) {
char *end;
- if (skip_prefix(line.buf, "progress ", (const char **) &end)) {
+ if (skip_prefix(line.buf, "start ", (const char **) &end)) {
+ uint64_t total = strtoull(end, &end, 10);
+ const char *title;
+
+ /*
+ * We can't use "end + 1" as an argument to
+ * start_progress(), it doesn't xstrdup() its
+ * "title" argument. We need to hold onto a
+ * valid "char *" for it until the end.
+ */
+ if (!*end)
+ title = default_title;
+ else if (*end == ' ')
+ title = string_list_insert(&titles, end + 1)->string;
+ else
+ die("invalid input: '%s'\n", line.buf);
+
+ progress = start_progress(title, total);
+ } else if (skip_prefix(line.buf, "progress ", (const char **) &end)) {
uint64_t item_count = strtoull(end, &end, 10);
if (*end != '\0')
die("invalid input: '%s'\n", line.buf);
@@ -63,12 +83,16 @@ int cmd__progress(int argc, const char **argv)
die("invalid input: '%s'\n", line.buf);
progress_test_ns = test_ms * 1000 * 1000;
display_throughput(progress, byte_count);
- } else if (!strcmp(line.buf, "update"))
+ } else if (!strcmp(line.buf, "update")) {
progress_test_force_update();
- else
+ } else if (!strcmp(line.buf, "stop")) {
+ stop_progress(&progress);
+ } else {
die("invalid input: '%s'\n", line.buf);
+ }
}
- stop_progress(&progress);
+ strbuf_release(&line);
+ string_list_clear(&titles, 0);
return 0;
}
diff --git a/t/helper/test-read-graph.c b/t/helper/test-read-graph.c
index 75927b2..98b73bb 100644
--- a/t/helper/test-read-graph.c
+++ b/t/helper/test-read-graph.c
@@ -3,6 +3,7 @@
#include "commit-graph.h"
#include "repository.h"
#include "object-store.h"
+#include "bloom.h"
int cmd__read_graph(int argc, const char **argv)
{
@@ -45,6 +46,18 @@ int cmd__read_graph(int argc, const char **argv)
printf(" bloom_data");
printf("\n");
+ printf("options:");
+ if (graph->bloom_filter_settings)
+ printf(" bloom(%"PRIu32",%"PRIu32",%"PRIu32")",
+ graph->bloom_filter_settings->hash_version,
+ graph->bloom_filter_settings->bits_per_entry,
+ graph->bloom_filter_settings->num_hashes);
+ if (graph->read_generation_data)
+ printf(" read_generation_data");
+ if (graph->topo_levels)
+ printf(" topo_levels");
+ printf("\n");
+
UNLEAK(graph);
return 0;
diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c
index 3e4ddae..9646d85 100644
--- a/t/helper/test-ref-store.c
+++ b/t/helper/test-ref-store.c
@@ -180,10 +180,9 @@ static int cmd_resolve_ref(struct ref_store *refs, const char **argv)
int resolve_flags = arg_flags(*argv++, "resolve-flags", empty_flags);
int flags;
const char *ref;
- int ignore_errno;
ref = refs_resolve_ref_unsafe(refs, refname, resolve_flags,
- &oid, &flags, &ignore_errno);
+ &oid, &flags);
printf("%s %s 0x%x\n", oid_to_hex(&oid), ref ? ref : "(null)", flags);
return ref ? 0 : 1;
}
diff --git a/t/helper/test-reftable.c b/t/helper/test-reftable.c
index 26b03d7..1f0a28c 100644
--- a/t/helper/test-reftable.c
+++ b/t/helper/test-reftable.c
@@ -3,15 +3,16 @@
int cmd__reftable(int argc, const char **argv)
{
+ /* test from simple to complex. */
basics_test_main(argc, argv);
+ record_test_main(argc, argv);
block_test_main(argc, argv);
- merged_test_main(argc, argv);
+ tree_test_main(argc, argv);
pq_test_main(argc, argv);
- record_test_main(argc, argv);
- refname_test_main(argc, argv);
readwrite_test_main(argc, argv);
+ merged_test_main(argc, argv);
stack_test_main(argc, argv);
- tree_test_main(argc, argv);
+ refname_test_main(argc, argv);
return 0;
}
diff --git a/t/helper/test-run-command.c b/t/helper/test-run-command.c
index 913775a..f3b90aa 100644
--- a/t/helper/test-run-command.c
+++ b/t/helper/test-run-command.c
@@ -19,7 +19,6 @@
#include "thread-utils.h"
#include "wildmatch.h"
#include "gettext.h"
-#include "parse-options.h"
static int number_callbacks;
static int parallel_next(struct child_process *cp,
@@ -180,15 +179,16 @@ static int testsuite(int argc, const char **argv)
if (max_jobs > suite.tests.nr)
max_jobs = suite.tests.nr;
- fprintf(stderr, "Running %d tests (%d at a time)\n",
- suite.tests.nr, max_jobs);
+ fprintf(stderr, "Running %"PRIuMAX" tests (%d at a time)\n",
+ (uintmax_t)suite.tests.nr, max_jobs);
ret = run_processes_parallel(max_jobs, next_test, test_failed,
test_finished, &suite);
if (suite.failed.nr > 0) {
ret = 1;
- fprintf(stderr, "%d tests failed:\n\n", suite.failed.nr);
+ fprintf(stderr, "%"PRIuMAX" tests failed:\n\n",
+ (uintmax_t)suite.failed.nr);
for (i = 0; i < suite.failed.nr; i++)
fprintf(stderr, "\t%s\n", suite.failed.items[i].string);
}
@@ -221,9 +221,9 @@ static int quote_stress_test(int argc, const char **argv)
struct strbuf out = STRBUF_INIT;
struct strvec args = STRVEC_INIT;
struct option options[] = {
- OPT_INTEGER('n', "trials", &trials, "Number of trials"),
- OPT_INTEGER('s', "skip", &skip, "Skip <n> trials"),
- OPT_BOOL('m', "msys2", &msys2, "Test quoting for MSYS2's sh"),
+ OPT_INTEGER('n', "trials", &trials, "number of trials"),
+ OPT_INTEGER('s', "skip", &skip, "skip <n> trials"),
+ OPT_BOOL('m', "msys2", &msys2, "test quoting for MSYS2's sh"),
OPT_END()
};
const char * const usage[] = {
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index 338a57b..0424f7a 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -20,6 +20,7 @@ static struct test_cmd cmds[] = {
{ "chmtime", cmd__chmtime },
{ "config", cmd__config },
{ "crontab", cmd__crontab },
+ { "csprng", cmd__csprng },
{ "ctype", cmd__ctype },
{ "date", cmd__date },
{ "delta", cmd__delta },
@@ -31,6 +32,7 @@ static struct test_cmd cmds[] = {
{ "dump-untracked-cache", cmd__dump_untracked_cache },
{ "example-decorate", cmd__example_decorate },
{ "fast-rebase", cmd__fast_rebase },
+ { "fsmonitor-client", cmd__fsmonitor_client },
{ "genrandom", cmd__genrandom },
{ "genzeros", cmd__genzeros },
{ "getcwd", cmd__getcwd },
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index 48cee1f..c876e82 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -10,6 +10,7 @@ int cmd__bloom(int argc, const char **argv);
int cmd__chmtime(int argc, const char **argv);
int cmd__config(int argc, const char **argv);
int cmd__crontab(int argc, const char **argv);
+int cmd__csprng(int argc, const char **argv);
int cmd__ctype(int argc, const char **argv);
int cmd__date(int argc, const char **argv);
int cmd__delta(int argc, const char **argv);
@@ -22,6 +23,7 @@ int cmd__dump_untracked_cache(int argc, const char **argv);
int cmd__dump_reftable(int argc, const char **argv);
int cmd__example_decorate(int argc, const char **argv);
int cmd__fast_rebase(int argc, const char **argv);
+int cmd__fsmonitor_client(int argc, const char **argv);
int cmd__genrandom(int argc, const char **argv);
int cmd__genzeros(int argc, const char **argv);
int cmd__getcwd(int argc, const char **argv);
diff --git a/t/interop/Makefile b/t/interop/Makefile
index 31a4bbc..6911c29 100644
--- a/t/interop/Makefile
+++ b/t/interop/Makefile
@@ -1,3 +1,6 @@
+# Import tree-wide shared Makefile behavior and libraries
+include ../../shared.mak
+
-include ../../config.mak
export GIT_TEST_OPTIONS
diff --git a/t/lib-bitmap.sh b/t/lib-bitmap.sh
index 21d0392..a95537e 100644
--- a/t/lib-bitmap.sh
+++ b/t/lib-bitmap.sh
@@ -1,6 +1,9 @@
# Helpers for scripts testing bitmap functionality; see t5310 for
# example usage.
+objdir=.git/objects
+midx=$objdir/pack/multi-pack-index
+
# Compare a file containing rev-list bitmap traversal output to its non-bitmap
# counterpart. You can't just use test_cmp for this, because the two produce
# subtly different output:
@@ -264,3 +267,185 @@ have_delta () {
midx_checksum () {
test-tool read-midx --checksum "$1"
}
+
+# midx_pack_source <obj>
+midx_pack_source () {
+ test-tool read-midx --show-objects .git/objects | grep "^$1 " | cut -f2
+}
+
+test_rev_exists () {
+ commit="$1"
+ kind="$2"
+
+ test_expect_success "reverse index exists ($kind)" '
+ GIT_TRACE2_EVENT=$(pwd)/event.trace \
+ git rev-list --test-bitmap "$commit" &&
+
+ if test "rev" = "$kind"
+ then
+ test_path_is_file $midx-$(midx_checksum $objdir).rev
+ fi &&
+ grep "\"category\":\"load_midx_revindex\",\"key\":\"source\",\"value\":\"$kind\"" event.trace
+ '
+}
+
+midx_bitmap_core () {
+ rev_kind="${1:-midx}"
+
+ setup_bitmap_history
+
+ test_expect_success 'create single-pack midx with bitmaps' '
+ git repack -ad &&
+ git multi-pack-index write --bitmap &&
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap
+ '
+
+ test_rev_exists HEAD "$rev_kind"
+
+ basic_bitmap_tests
+
+ test_expect_success 'create new additional packs' '
+ for i in $(test_seq 1 16)
+ do
+ test_commit "$i" &&
+ git repack -d || return 1
+ done &&
+
+ git checkout -b other2 HEAD~8 &&
+ for i in $(test_seq 1 8)
+ do
+ test_commit "side-$i" &&
+ git repack -d || return 1
+ done &&
+ git checkout second
+ '
+
+ test_expect_success 'create multi-pack midx with bitmaps' '
+ git multi-pack-index write --bitmap &&
+
+ ls $objdir/pack/pack-*.pack >packs &&
+ test_line_count = 25 packs &&
+
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap
+ '
+
+ test_rev_exists HEAD "$rev_kind"
+
+ basic_bitmap_tests
+
+ test_expect_success '--no-bitmap is respected when bitmaps exist' '
+ git multi-pack-index write --bitmap &&
+
+ test_commit respect--no-bitmap &&
+ git repack -d &&
+
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+
+ git multi-pack-index write --no-bitmap &&
+
+ test_path_is_file $midx &&
+ test_path_is_missing $midx-$(midx_checksum $objdir).bitmap &&
+ test_path_is_missing $midx-$(midx_checksum $objdir).rev
+ '
+
+ test_expect_success 'setup midx with base from later pack' '
+ # Write a and b so that "a" is a delta on top of base "b", since Git
+ # prefers to delete contents out of a base rather than add to a shorter
+ # object.
+ test_seq 1 128 >a &&
+ test_seq 1 130 >b &&
+
+ git add a b &&
+ git commit -m "initial commit" &&
+
+ a=$(git rev-parse HEAD:a) &&
+ b=$(git rev-parse HEAD:b) &&
+
+ # In the first pack, "a" is stored as a delta to "b".
+ p1=$(git pack-objects .git/objects/pack/pack <<-EOF
+ $a
+ $b
+ EOF
+ ) &&
+
+ # In the second pack, "a" is missing, and "b" is not a delta nor base to
+ # any other object.
+ p2=$(git pack-objects .git/objects/pack/pack <<-EOF
+ $b
+ $(git rev-parse HEAD)
+ $(git rev-parse HEAD^{tree})
+ EOF
+ ) &&
+
+ git prune-packed &&
+ # Use the second pack as the preferred source, so that "b" occurs
+ # earlier in the MIDX object order, rendering "a" unusable for pack
+ # reuse.
+ git multi-pack-index write --bitmap --preferred-pack=pack-$p2.idx &&
+
+ have_delta $a $b &&
+ test $(midx_pack_source $a) != $(midx_pack_source $b)
+ '
+
+ rev_list_tests 'full bitmap with backwards delta'
+
+ test_expect_success 'clone with bitmaps enabled' '
+ git clone --no-local --bare . clone-reverse-delta.git &&
+ test_when_finished "rm -fr clone-reverse-delta.git" &&
+
+ git rev-parse HEAD >expect &&
+ git --git-dir=clone-reverse-delta.git rev-parse HEAD >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success 'changing the preferred pack does not corrupt bitmaps' '
+ rm -fr repo &&
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit A &&
+ test_commit B &&
+
+ git rev-list --objects --no-object-names HEAD^ >A.objects &&
+ git rev-list --objects --no-object-names HEAD^.. >B.objects &&
+
+ A=$(git pack-objects $objdir/pack/pack <A.objects) &&
+ B=$(git pack-objects $objdir/pack/pack <B.objects) &&
+
+ cat >indexes <<-EOF &&
+ pack-$A.idx
+ pack-$B.idx
+ EOF
+
+ git multi-pack-index write --bitmap --stdin-packs \
+ --preferred-pack=pack-$A.pack <indexes &&
+ git rev-list --test-bitmap A &&
+
+ git multi-pack-index write --bitmap --stdin-packs \
+ --preferred-pack=pack-$B.pack <indexes &&
+ git rev-list --test-bitmap A
+ )
+ '
+}
+
+midx_bitmap_partial_tests () {
+ rev_kind="${1:-midx}"
+
+ test_expect_success 'setup partial bitmaps' '
+ test_commit packed &&
+ git repack &&
+ test_commit loose &&
+ git multi-pack-index write --bitmap 2>err &&
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap
+ '
+
+ test_rev_exists HEAD~ "$rev_kind"
+
+ basic_bitmap_tests HEAD~
+}
diff --git a/t/lib-commit-graph.sh b/t/lib-commit-graph.sh
new file mode 100755
index 0000000..5d79e1a
--- /dev/null
+++ b/t/lib-commit-graph.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+# Helper functions for testing commit-graphs.
+
+# Initialize OID cache with oid_version
+test_oid_cache <<-EOF
+oid_version sha1:1
+oid_version sha256:2
+EOF
+
+graph_git_two_modes() {
+ git -c core.commitGraph=true $1 >output &&
+ git -c core.commitGraph=false $1 >expect &&
+ test_cmp expect output
+}
+
+graph_git_behavior() {
+ MSG=$1
+ DIR=$2
+ BRANCH=$3
+ COMPARE=$4
+ test_expect_success "check normal git operations: $MSG" '
+ cd "$TRASH_DIRECTORY/$DIR" &&
+ graph_git_two_modes "log --oneline $BRANCH" &&
+ graph_git_two_modes "log --topo-order $BRANCH" &&
+ graph_git_two_modes "log --graph $COMPARE..$BRANCH" &&
+ graph_git_two_modes "branch -vv" &&
+ graph_git_two_modes "merge-base -a $BRANCH $COMPARE"
+ '
+}
+
+graph_read_expect() {
+ OPTIONAL=""
+ NUM_CHUNKS=3
+ if test -n "$2"
+ then
+ OPTIONAL=" $2"
+ NUM_CHUNKS=$((3 + $(echo "$2" | wc -w)))
+ fi
+ GENERATION_VERSION=2
+ if test -n "$3"
+ then
+ GENERATION_VERSION=$3
+ fi
+ OPTIONS=
+ if test $GENERATION_VERSION -gt 1
+ then
+ OPTIONS=" read_generation_data"
+ fi
+ cat >expect <<- EOF
+ header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0
+ num_commits: $1
+ chunks: oid_fanout oid_lookup commit_metadata$OPTIONAL
+ options:$OPTIONS
+ EOF
+ test-tool read-graph >output &&
+ test_cmp expect output
+}
diff --git a/t/lib-gpg.sh b/t/lib-gpg.sh
index 3e7ee13..1147855 100644
--- a/t/lib-gpg.sh
+++ b/t/lib-gpg.sh
@@ -40,7 +40,7 @@ test_lazy_prereq GPG '
# > lib-gpg/ownertrust
mkdir "$GNUPGHOME" &&
chmod 0700 "$GNUPGHOME" &&
- (gpgconf --kill gpg-agent || : ) &&
+ (gpgconf --kill all || : ) &&
gpg --homedir "${GNUPGHOME}" --import \
"$TEST_DIRECTORY"/lib-gpg/keyring.gpg &&
gpg --homedir "${GNUPGHOME}" --import-ownertrust \
@@ -72,12 +72,11 @@ test_lazy_prereq GPGSM '
--passphrase-fd 0 --pinentry-mode loopback \
--import "$TEST_DIRECTORY"/lib-gpg/gpgsm_cert.p12 &&
- gpgsm --homedir "${GNUPGHOME}" -K |
- grep fingerprint: |
- cut -d" " -f4 |
- tr -d "\\n" >"${GNUPGHOME}/trustlist.txt" &&
+ gpgsm --homedir "${GNUPGHOME}" -K --with-colons |
+ awk -F ":" "/^fpr:/ {printf \"%s S relax\\n\", \$10}" \
+ >"${GNUPGHOME}/trustlist.txt" &&
+ (gpgconf --reload all || : ) &&
- echo " S relax" >>"${GNUPGHOME}/trustlist.txt" &&
echo hello | gpgsm --homedir "${GNUPGHOME}" >/dev/null \
-u committer@example.com -o /dev/null --sign -
'
diff --git a/t/lib-read-tree-m-3way.sh b/t/lib-read-tree-m-3way.sh
index 168329a..2da25b3 100644
--- a/t/lib-read-tree-m-3way.sh
+++ b/t/lib-read-tree-m-3way.sh
@@ -3,21 +3,21 @@
mkdir Z
for a in N D M
do
- for b in N D M
- do
- p=$a$b
+ for b in N D M
+ do
+ p=$a$b
echo This is $p from the original tree. >$p
echo This is Z/$p from the original tree. >Z/$p
- test_expect_success \
- "adding test file $p and Z/$p" \
- 'git update-index --add $p &&
- git update-index --add Z/$p'
+ test_expect_success "adding test file $p and Z/$p" '
+ git update-index --add $p &&
+ git update-index --add Z/$p
+ '
done
done
echo This is SS from the original tree. >SS
-test_expect_success \
- 'adding test file SS' \
- 'git update-index --add SS'
+test_expect_success 'adding test file SS' '
+ git update-index --add SS
+'
cat >TT <<\EOF
This is a trivial merge sample text.
Branch A is expected to upcase this word, here.
@@ -30,12 +30,12 @@ At the very end, here comes another line, that is
the word, expected to be upcased by Branch B.
This concludes the trivial merge sample file.
EOF
-test_expect_success \
- 'adding test file TT' \
- 'git update-index --add TT'
-test_expect_success \
- 'prepare initial tree' \
- 'tree_O=$(git write-tree)'
+test_expect_success 'adding test file TT' '
+ git update-index --add TT
+'
+test_expect_success 'prepare initial tree' '
+ tree_O=$(git write-tree)
+'
################################################################
# Branch A and B makes the changes according to the above matrix.
@@ -45,48 +45,48 @@ test_expect_success \
to_remove=$(echo D? Z/D?)
rm -f $to_remove
-test_expect_success \
- 'change in branch A (removal)' \
- 'git update-index --remove $to_remove'
+test_expect_success 'change in branch A (removal)' '
+ git update-index --remove $to_remove
+'
for p in M? Z/M?
do
- echo This is modified $p in the branch A. >$p
- test_expect_success \
- 'change in branch A (modification)' \
- "git update-index $p"
+ echo This is modified $p in the branch A. >$p
+ test_expect_success 'change in branch A (modification)' '
+ git update-index $p
+ '
done
for p in AN AA Z/AN Z/AA
do
- echo This is added $p in the branch A. >$p
- test_expect_success \
- 'change in branch A (addition)' \
- "git update-index --add $p"
+ echo This is added $p in the branch A. >$p
+ test_expect_success 'change in branch A (addition)' '
+ git update-index --add $p
+ '
done
echo This is SS from the modified tree. >SS
echo This is LL from the modified tree. >LL
-test_expect_success \
- 'change in branch A (addition)' \
- 'git update-index --add LL &&
- git update-index SS'
+test_expect_success 'change in branch A (addition)' '
+ git update-index --add LL &&
+ git update-index SS
+'
mv TT TT-
sed -e '/Branch A/s/word/WORD/g' <TT- >TT
rm -f TT-
-test_expect_success \
- 'change in branch A (edit)' \
- 'git update-index TT'
+test_expect_success 'change in branch A (edit)' '
+ git update-index TT
+'
mkdir DF
echo Branch A makes a file at DF/DF, creating a directory DF. >DF/DF
-test_expect_success \
- 'change in branch A (change file to directory)' \
- 'git update-index --add DF/DF'
+test_expect_success 'change in branch A (change file to directory)' '
+ git update-index --add DF/DF
+'
-test_expect_success \
- 'recording branch A tree' \
- 'tree_A=$(git write-tree)'
+test_expect_success 'recording branch A tree' '
+ tree_A=$(git write-tree)
+'
################################################################
# Branch B
@@ -94,65 +94,65 @@ test_expect_success \
rm -rf [NDMASLT][NDMASLT] Z DF
mkdir Z
-test_expect_success \
- 'reading original tree and checking out' \
- 'git read-tree $tree_O &&
- git checkout-index -a'
+test_expect_success 'reading original tree and checking out' '
+ git read-tree $tree_O &&
+ git checkout-index -a
+'
to_remove=$(echo ?D Z/?D)
rm -f $to_remove
-test_expect_success \
- 'change in branch B (removal)' \
- "git update-index --remove $to_remove"
+test_expect_success 'change in branch B (removal)' '
+ git update-index --remove $to_remove
+'
for p in ?M Z/?M
do
- echo This is modified $p in the branch B. >$p
- test_expect_success \
- 'change in branch B (modification)' \
- "git update-index $p"
+ echo This is modified $p in the branch B. >$p
+ test_expect_success 'change in branch B (modification)' '
+ git update-index $p
+ '
done
for p in NA AA Z/NA Z/AA
do
- echo This is added $p in the branch B. >$p
- test_expect_success \
- 'change in branch B (addition)' \
- "git update-index --add $p"
+ echo This is added $p in the branch B. >$p
+ test_expect_success 'change in branch B (addition)' '
+ git update-index --add $p
+ '
done
echo This is SS from the modified tree. >SS
echo This is LL from the modified tree. >LL
-test_expect_success \
- 'change in branch B (addition and modification)' \
- 'git update-index --add LL &&
- git update-index SS'
+test_expect_success 'change in branch B (addition and modification)' '
+ git update-index --add LL &&
+ git update-index SS
+'
mv TT TT-
sed -e '/Branch B/s/word/WORD/g' <TT- >TT
rm -f TT-
-test_expect_success \
- 'change in branch B (modification)' \
- 'git update-index TT'
+test_expect_success 'change in branch B (modification)' '
+ git update-index TT
+'
echo Branch B makes a file at DF. >DF
-test_expect_success \
- 'change in branch B (addition of a file to conflict with directory)' \
- 'git update-index --add DF'
-
-test_expect_success \
- 'recording branch B tree' \
- 'tree_B=$(git write-tree)'
-
-test_expect_success \
- 'keep contents of 3 trees for easy access' \
- 'rm -f .git/index &&
- git read-tree $tree_O &&
- mkdir .orig-O &&
- git checkout-index --prefix=.orig-O/ -f -q -a &&
- rm -f .git/index &&
- git read-tree $tree_A &&
- mkdir .orig-A &&
- git checkout-index --prefix=.orig-A/ -f -q -a &&
- rm -f .git/index &&
- git read-tree $tree_B &&
- mkdir .orig-B &&
- git checkout-index --prefix=.orig-B/ -f -q -a'
+test_expect_success 'change in branch B (addition of a file to conflict with directory)' '
+ git update-index --add DF
+'
+
+test_expect_success 'recording branch B tree' '
+ tree_B=$(git write-tree)
+'
+
+test_expect_success 'keep contents of 3 trees for easy access' '
+ rm -f .git/index &&
+ git read-tree $tree_O &&
+ mkdir .orig-O &&
+ git checkout-index --prefix=.orig-O/ -f -q -a &&
+ rm -f .git/index &&
+ git read-tree $tree_A &&
+ mkdir .orig-A &&
+ git checkout-index --prefix=.orig-A/ -f -q -a &&
+ rm -f .git/index &&
+ git read-tree $tree_B &&
+ mkdir .orig-B &&
+ git checkout-index --prefix=.orig-B/ -f -q -a
+'
diff --git a/t/perf/Makefile b/t/perf/Makefile
index 2465770..e4808ae 100644
--- a/t/perf/Makefile
+++ b/t/perf/Makefile
@@ -1,3 +1,6 @@
+# Import tree-wide shared Makefile behavior and libraries
+include ../../shared.mak
+
-include ../../config.mak
export GIT_TEST_OPTIONS
diff --git a/t/perf/p1006-cat-file.sh b/t/perf/p1006-cat-file.sh
new file mode 100755
index 0000000..dcd8015
--- /dev/null
+++ b/t/perf/p1006-cat-file.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+test_description='Tests listing object info performance'
+. ./perf-lib.sh
+
+test_perf_large_repo
+
+test_perf 'cat-file --batch-check' '
+ git cat-file --batch-all-objects --batch-check
+'
+
+test_done
diff --git a/t/perf/p2000-sparse-operations.sh b/t/perf/p2000-sparse-operations.sh
index cb777c7..382716c 100755
--- a/t/perf/p2000-sparse-operations.sh
+++ b/t/perf/p2000-sparse-operations.sh
@@ -117,5 +117,8 @@ test_perf_on_all git diff
test_perf_on_all git diff --cached
test_perf_on_all git blame $SPARSE_CONE/a
test_perf_on_all git blame $SPARSE_CONE/f3/a
+test_perf_on_all git read-tree -mu HEAD
+test_perf_on_all git checkout-index -f --all
+test_perf_on_all git update-index --add --remove $SPARSE_CONE/a
test_done
diff --git a/t/perf/p7519-fsmonitor.sh b/t/perf/p7519-fsmonitor.sh
index c8be58f..0b9129c 100755
--- a/t/perf/p7519-fsmonitor.sh
+++ b/t/perf/p7519-fsmonitor.sh
@@ -72,7 +72,7 @@ then
fi
fi
-trace_start() {
+trace_start () {
if test -n "$GIT_PERF_7519_TRACE"
then
name="$1"
@@ -91,13 +91,20 @@ trace_start() {
fi
}
-trace_stop() {
+trace_stop () {
if test -n "$GIT_PERF_7519_TRACE"
then
unset GIT_TRACE2_PERF
fi
}
+touch_files () {
+ n=$1 &&
+ d="$n"_files &&
+
+ (cd $d && test_seq 1 $n | xargs touch )
+}
+
test_expect_success "one time repo setup" '
# set untrackedCache depending on the environment
if test -n "$GIT_PERF_7519_UNTRACKED_CACHE"
@@ -119,10 +126,11 @@ test_expect_success "one time repo setup" '
fi &&
mkdir 1_file 10_files 100_files 1000_files 10000_files &&
- for i in $(test_seq 1 10); do touch 10_files/$i || return 1; done &&
- for i in $(test_seq 1 100); do touch 100_files/$i || return 1; done &&
- for i in $(test_seq 1 1000); do touch 1000_files/$i || return 1; done &&
- for i in $(test_seq 1 10000); do touch 10000_files/$i || return 1; done &&
+ : 1_file directory should be left empty &&
+ touch_files 10 &&
+ touch_files 100 &&
+ touch_files 1000 &&
+ touch_files 10000 &&
git add 1_file 10_files 100_files 1000_files 10000_files &&
git commit -qm "Add files" &&
@@ -133,7 +141,7 @@ test_expect_success "one time repo setup" '
fi
'
-setup_for_fsmonitor() {
+setup_for_fsmonitor_hook () {
# set INTEGRATION_SCRIPT depending on the environment
if test -n "$INTEGRATION_PATH"
then
@@ -173,8 +181,12 @@ test_perf_w_drop_caches () {
test_perf "$@"
}
-test_fsmonitor_suite() {
- if test -n "$INTEGRATION_SCRIPT"; then
+test_fsmonitor_suite () {
+ if test -n "$USE_FSMONITOR_DAEMON"
+ then
+ DESC="builtin fsmonitor--daemon"
+ elif test -n "$INTEGRATION_SCRIPT"
+ then
DESC="fsmonitor=$(basename $INTEGRATION_SCRIPT)"
else
DESC="fsmonitor=disabled"
@@ -199,15 +211,15 @@ test_fsmonitor_suite() {
# Update the mtimes on upto 100k files to make status think
# that they are dirty. For simplicity, omit any files with
- # LFs (i.e. anything that ls-files thinks it needs to dquote).
- # Then fully backslash-quote the paths to capture any
- # whitespace so that they pass thru xargs properly.
+ # LFs (i.e. anything that ls-files thinks it needs to dquote)
+ # and any files with whitespace so that they pass thru xargs
+ # properly.
#
test_perf_w_drop_caches "status (dirty) ($DESC)" '
git ls-files | \
head -100000 | \
grep -v \" | \
- sed '\''s/\(.\)/\\\1/g'\'' | \
+ grep -v " ." | \
xargs test-tool chmtime -300 &&
git status
'
@@ -253,11 +265,11 @@ test_fsmonitor_suite() {
trace_start fsmonitor-watchman
if test -n "$GIT_PERF_7519_FSMONITOR"; then
for INTEGRATION_PATH in $GIT_PERF_7519_FSMONITOR; do
- test_expect_success "setup for fsmonitor $INTEGRATION_PATH" 'setup_for_fsmonitor'
+ test_expect_success "setup for fsmonitor $INTEGRATION_PATH" 'setup_for_fsmonitor_hook'
test_fsmonitor_suite
done
else
- test_expect_success "setup for fsmonitor" 'setup_for_fsmonitor'
+ test_expect_success "setup for fsmonitor hook" 'setup_for_fsmonitor_hook'
test_fsmonitor_suite
fi
@@ -285,4 +297,30 @@ test_expect_success "setup without fsmonitor" '
test_fsmonitor_suite
trace_stop
+#
+# Run a full set of perf tests using the built-in fsmonitor--daemon.
+# It does not use the Hook API, so it has a different setup.
+# Explicitly start the daemon here and before we start client commands
+# so that we can later add custom tracing.
+#
+if test_have_prereq FSMONITOR_DAEMON
+then
+ USE_FSMONITOR_DAEMON=t
+
+ test_expect_success "setup for builtin fsmonitor" '
+ trace_start fsmonitor--daemon--server &&
+ git fsmonitor--daemon start &&
+
+ trace_start fsmonitor--daemon--client &&
+
+ git config core.fsmonitor true &&
+ git update-index --fsmonitor
+ '
+
+ test_fsmonitor_suite
+
+ git fsmonitor--daemon stop
+ trace_stop
+fi
+
test_done
diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh
index 407252b..932105c 100644
--- a/t/perf/perf-lib.sh
+++ b/t/perf/perf-lib.sh
@@ -78,7 +78,7 @@ test_perf_copy_repo_contents () {
for stuff in "$1"/*
do
case "$stuff" in
- */objects|*/hooks|*/config|*/commondir|*/gitdir|*/worktrees)
+ */objects|*/hooks|*/config|*/commondir|*/gitdir|*/worktrees|*/fsmonitor--daemon*)
;;
*)
cp -R "$stuff" "$repo/.git/" || exit 1
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index b007f0e..17a268c 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -101,6 +101,19 @@ test_expect_success 'subtest: 2/3 tests passing' '
EOF
'
+test_expect_success 'subtest: --immediate' '
+ run_sub_test_lib_test_err partial-pass \
+ --immediate &&
+ check_sub_test_lib_test_err partial-pass \
+ <<-\EOF_OUT 3<<-EOF_ERR
+ > ok 1 - passing test #1
+ > not ok 2 - failing test #2
+ > # false
+ > 1..2
+ EOF_OUT
+ EOF_ERR
+'
+
test_expect_success 'subtest: a failing TODO test' '
write_and_run_sub_test_lib_test failing-todo <<-\EOF &&
test_expect_success "passing test" "true"
@@ -1089,7 +1102,8 @@ test_expect_success 'update-index D/F conflict' '
mv path2 path0 &&
mv tmp path2 &&
git update-index --add --replace path2 path0/file2 &&
- numpath0=$(git ls-files path0 | wc -l) &&
+ git ls-files path0 >tmp &&
+ numpath0=$(wc -l <tmp) &&
test $numpath0 = 1
'
@@ -1103,13 +1117,14 @@ test_expect_success 'very long name in the index handled sanely' '
>path4 &&
git update-index --add path4 &&
+ git ls-files -s path4 >tmp &&
(
- git ls-files -s path4 |
- sed -e "s/ .*/ /" |
+ sed -e "s/ .*/ /" tmp |
tr -d "\012" &&
echo "$a"
) | git update-index --index-info &&
- len=$(git ls-files "a*" | wc -c) &&
+ git ls-files "a*" >tmp &&
+ len=$(wc -c <tmp) &&
test $len = 4098
'
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index 3235ab4..d479303 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -6,7 +6,8 @@ TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
check_config () {
- if test -d "$1" && test -f "$1/config" && test -d "$1/refs"
+ if test_path_is_dir "$1" &&
+ test_path_is_file "$1/config" && test_path_is_dir "$1/refs"
then
: happy
else
diff --git a/t/t0002-gitfile.sh b/t/t0002-gitfile.sh
index 76052cb..f6356db 100755
--- a/t/t0002-gitfile.sh
+++ b/t/t0002-gitfile.sh
@@ -65,9 +65,11 @@ test_expect_success 'check commit-tree' '
test_path_is_file "$REAL/objects/$(objpath $SHA)"
'
-test_expect_success 'check rev-list' '
+test_expect_success !SANITIZE_LEAK 'check rev-list' '
git update-ref "HEAD" "$SHA" &&
- test "$SHA" = "$(git rev-list HEAD)"
+ git rev-list HEAD >actual &&
+ echo $SHA >expected &&
+ test_cmp expected actual
'
test_expect_success 'setup_git_dir twice in subdir' '
diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
index b9ed612..143f100 100755
--- a/t/t0003-attributes.sh
+++ b/t/t0003-attributes.sh
@@ -205,15 +205,18 @@ test_expect_success 'attribute test: read paths from stdin' '
test_expect_success 'attribute test: --all option' '
grep -v unspecified <expect-all | sort >specified-all &&
sed -e "s/:.*//" <expect-all | uniq >stdin-all &&
- git check-attr --stdin --all <stdin-all | sort >actual &&
+ git check-attr --stdin --all <stdin-all >tmp &&
+ sort tmp >actual &&
test_cmp specified-all actual
'
test_expect_success 'attribute test: --cached option' '
- git check-attr --cached --stdin --all <stdin-all | sort >actual &&
+ git check-attr --cached --stdin --all <stdin-all >tmp &&
+ sort tmp >actual &&
test_must_be_empty actual &&
git add .gitattributes a/.gitattributes a/b/.gitattributes &&
- git check-attr --cached --stdin --all <stdin-all | sort >actual &&
+ git check-attr --cached --stdin --all <stdin-all >tmp &&
+ sort tmp >actual &&
test_cmp specified-all actual
'
diff --git a/t/t0006-date.sh b/t/t0006-date.sh
index 7941869..2490162 100755
--- a/t/t0006-date.sh
+++ b/t/t0006-date.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='test date parsing and printing'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# arbitrary reference time: 2009-08-30 19:20:00
diff --git a/t/t0012-help.sh b/t/t0012-help.sh
index 91b68c7..6c3e1f7 100755
--- a/t/t0012-help.sh
+++ b/t/t0012-help.sh
@@ -35,6 +35,9 @@ test_expect_success 'basic help commands' '
'
test_expect_success 'invalid usage' '
+ test_expect_code 129 git help -a add &&
+ test_expect_code 129 git help --all add &&
+
test_expect_code 129 git help -g add &&
test_expect_code 129 git help -a -c &&
@@ -46,6 +49,29 @@ test_expect_success 'invalid usage' '
test_expect_code 129 git help --config-sections-for-completion add
'
+for opt in '-a' '-g' '-c' '--config-for-completion' '--config-sections-for-completion'
+do
+ test_expect_success "invalid usage of '$opt' with [-i|-m|-w]" '
+ git help $opt &&
+ test_expect_code 129 git help $opt -i &&
+ test_expect_code 129 git help $opt -m &&
+ test_expect_code 129 git help $opt -w
+ '
+
+ if test "$opt" = "-a"
+ then
+ continue
+ fi
+
+ test_expect_success "invalid usage of '$opt' with --no-external-commands" '
+ test_expect_code 129 git help $opt --no-external-commands
+ '
+
+ test_expect_success "invalid usage of '$opt' with --no-aliases" '
+ test_expect_code 129 git help $opt --no-external-commands
+ '
+done
+
test_expect_success "works for commands and guides by default" '
configure_help &&
git help status &&
@@ -138,14 +164,87 @@ test_expect_success 'git help --config-sections-for-completion' '
test_cmp human.munged sections
'
+test_section_spacing () {
+ cat >expect &&
+ "$@" >out &&
+ grep -E "(^[^ ]|^$)" out >actual
+}
+
+test_section_spacing_trailer () {
+ test_section_spacing "$@" &&
+ test_expect_code 1 git >out &&
+ sed -n '/list available subcommands/,$p' <out >>expect
+}
+
+
+for cmd in git "git help"
+do
+ test_expect_success "'$cmd' section spacing" '
+ test_section_spacing_trailer git help <<-\EOF &&
+ usage: git [--version] [--help] [-C <path>] [-c <name>=<value>]
+
+ These are common Git commands used in various situations:
+
+ start a working area (see also: git help tutorial)
+
+ work on the current change (see also: git help everyday)
+
+ examine the history and state (see also: git help revisions)
+
+ grow, mark and tweak your common history
+
+ collaborate (see also: git help workflows)
+
+ EOF
+ test_cmp expect actual
+ '
+done
+
+test_expect_success "'git help -a' section spacing" '
+ test_section_spacing \
+ git help -a --no-external-commands --no-aliases <<-\EOF &&
+ See '\''git help <command>'\'' to read about a specific subcommand
+
+ Main Porcelain Commands
+
+ Ancillary Commands / Manipulators
+
+ Ancillary Commands / Interrogators
+
+ Interacting with Others
+
+ Low-level Commands / Manipulators
+
+ Low-level Commands / Interrogators
+
+ Low-level Commands / Syncing Repositories
+
+ Low-level Commands / Internal Helpers
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "'git help -g' section spacing" '
+ test_section_spacing_trailer git help -g <<-\EOF &&
+ The Git concept guides are:
+
+ EOF
+ test_cmp expect actual
+'
+
test_expect_success 'generate builtin list' '
+ mkdir -p sub &&
git --list-cmds=builtins >builtins
'
while read builtin
do
test_expect_success "$builtin can handle -h" '
- test_expect_code 129 git $builtin -h >output 2>&1 &&
+ (
+ GIT_CEILING_DIRECTORIES=$(pwd) &&
+ export GIT_CEILING_DIRECTORIES &&
+ test_expect_code 129 git -C sub $builtin -h >output 2>&1
+ ) &&
test_i18ngrep usage output
'
done <builtins
diff --git a/t/t0015-hash.sh b/t/t0015-hash.sh
index 291e906..086822f 100755
--- a/t/t0015-hash.sh
+++ b/t/t0015-hash.sh
@@ -15,7 +15,7 @@ test_expect_success 'test basic SHA-1 hash values' '
grep c12252ceda8be8994d5fa0290a47231c1d16aae3 actual &&
printf "abcdefghijklmnopqrstuvwxyz" | test-tool sha1 >actual &&
grep 32d10c7b8cf96570ca04ce37f2a19d84240d3a89 actual &&
- perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" | \
+ perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" |
test-tool sha1 >actual &&
grep 34aa973cd4c4daa4f61eeb2bdbad27316534016f actual &&
printf "blob 0\0" | test-tool sha1 >actual &&
@@ -38,10 +38,10 @@ test_expect_success 'test basic SHA-256 hash values' '
printf "abcdefghijklmnopqrstuvwxyz" | test-tool sha256 >actual &&
grep 71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73 actual &&
# Try to exercise the chunking code by turning autoflush on.
- perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" | \
+ perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" |
test-tool sha256 >actual &&
grep cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0 actual &&
- perl -e "$| = 1; print q{abcdefghijklmnopqrstuvwxyz} for 1..100000;" | \
+ perl -e "$| = 1; print q{abcdefghijklmnopqrstuvwxyz} for 1..100000;" |
test-tool sha256 >actual &&
grep e406ba321ca712ad35a698bf0af8d61fc4dc40eca6bdcea4697962724ccbde35 actual &&
printf "blob 0\0" | test-tool sha256 >actual &&
diff --git a/t/t0022-crlf-rename.sh b/t/t0022-crlf-rename.sh
index c1a331e..9fe9891 100755
--- a/t/t0022-crlf-rename.sh
+++ b/t/t0022-crlf-rename.sh
@@ -24,8 +24,8 @@ test_expect_success setup '
test_expect_success 'diff -M' '
- git diff-tree -M -r --name-status HEAD^ HEAD |
- sed -e "s/R[0-9]*/RNUM/" >actual &&
+ git diff-tree -M -r --name-status HEAD^ HEAD >tmp &&
+ sed -e "s/R[0-9]*/RNUM/" tmp >actual &&
echo "RNUM sample elpmas" >expect &&
test_cmp expect actual
diff --git a/t/t0025-crlf-renormalize.sh b/t/t0025-crlf-renormalize.sh
index 8144797..f7202c1 100755
--- a/t/t0025-crlf-renormalize.sh
+++ b/t/t0025-crlf-renormalize.sh
@@ -22,8 +22,8 @@ test_expect_success 'renormalize CRLF in repo' '
i/lf w/lf attr/text=auto LF.txt
i/lf w/mixed attr/text=auto CRLF_mix_LF.txt
EOF
- git ls-files --eol |
- sed -e "s/ / /g" -e "s/ */ /g" |
+ git ls-files --eol >tmp &&
+ sed -e "s/ / /g" -e "s/ */ /g" tmp |
sort >actual &&
test_cmp expect actual
'
diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh
index 4a5c5c6..0feb41a 100755
--- a/t/t0027-auto-crlf.sh
+++ b/t/t0027-auto-crlf.sh
@@ -311,8 +311,8 @@ checkout_files () {
i/-text w/$(stats_ascii $crlfnul) attr/$(attr_ascii $attr $aeol) crlf_false_attr__CRLF_nul.txt
i/-text w/$(stats_ascii $crlfnul) attr/$(attr_ascii $attr $aeol) crlf_false_attr__LF_nul.txt
EOF
- git ls-files --eol crlf_false_attr__* |
- sed -e "s/ / /g" -e "s/ */ /g" |
+ git ls-files --eol crlf_false_attr__* >tmp &&
+ sed -e "s/ / /g" -e "s/ */ /g" tmp |
sort >actual &&
test_cmp expect actual
'
@@ -359,12 +359,12 @@ test_expect_success 'ls-files --eol -o Text/Binary' '
i/ w/crlf TeBi_126_CL
i/ w/-text TeBi_126_CLC
EOF
- git ls-files --eol -o |
+ git ls-files --eol -o >tmp &&
sed -n -e "/TeBi_/{s!attr/[ ]*!!g
s! ! !g
s! *! !g
p
- }" | sort >actual &&
+ }" tmp | sort >actual &&
test_cmp expect actual
'
@@ -597,6 +597,12 @@ do
# auto: core.autocrlf=false and core.eol unset(or native) uses native eol
checkout_files auto "$id" "" false "" $NL CRLF CRLF_mix_LF LF_mix_CR LF_nul
checkout_files auto "$id" "" false native $NL CRLF CRLF_mix_LF LF_mix_CR LF_nul
+ # core.autocrlf false, .gitattributes sets eol
+ checkout_files "" "$id" "lf" false "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul
+ checkout_files "" "$id" "crlf" false "" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul
+ # core.autocrlf true, .gitattributes sets eol
+ checkout_files "" "$id" "lf" true "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul
+ checkout_files "" "$id" "crlf" true "" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul
done
# The rest of the tests are unique; do the usual linting.
@@ -611,8 +617,8 @@ test_expect_success 'ls-files --eol -d -z' '
i/lf w/ crlf_false_attr__LF.txt
i/mixed w/ crlf_false_attr__CRLF_mix_LF.txt
EOF
- git ls-files --eol -d |
- sed -e "s!attr/[^ ]*!!g" -e "s/ / /g" -e "s/ */ /g" |
+ git ls-files --eol -d >tmp &&
+ sed -e "s!attr/[^ ]*!!g" -e "s/ / /g" -e "s/ */ /g" tmp |
sort >actual &&
test_cmp expect actual
'
diff --git a/t/t0029-core-unsetenvvars.sh b/t/t0029-core-unsetenvvars.sh
index b138e1d..4e8e90d 100755
--- a/t/t0029-core-unsetenvvars.sh
+++ b/t/t0029-core-unsetenvvars.sh
@@ -12,8 +12,7 @@ then
fi
test_expect_success 'setup' '
- mkdir -p "$TRASH_DIRECTORY/.git/hooks" &&
- write_script "$TRASH_DIRECTORY/.git/hooks/pre-commit" <<-\EOF
+ test_hook --setup pre-commit <<-\EOF
echo $HOBBES >&2
EOF
'
diff --git a/t/t0030-stripspace.sh b/t/t0030-stripspace.sh
index ae1ca38..0a5713c 100755
--- a/t/t0030-stripspace.sh
+++ b/t/t0030-stripspace.sh
@@ -13,6 +13,10 @@ s40=' '
sss="$s40$s40$s40$s40$s40$s40$s40$s40$s40$s40" # 400
ttt="$t40$t40$t40$t40$t40$t40$t40$t40$t40$t40" # 400
+printf_git_stripspace () {
+ printf "$1" | git stripspace
+}
+
test_expect_success \
'long lines without spaces should be unchanged' '
echo "$ttt" >expect &&
@@ -225,32 +229,38 @@ test_expect_success \
test_expect_success \
'text without newline at end should end with newline' '
- test $(printf "$ttt" | git stripspace | wc -l) -gt 0 &&
- test $(printf "$ttt$ttt" | git stripspace | wc -l) -gt 0 &&
- test $(printf "$ttt$ttt$ttt" | git stripspace | wc -l) -gt 0 &&
- test $(printf "$ttt$ttt$ttt$ttt" | git stripspace | wc -l) -gt 0
+ test_stdout_line_count -gt 0 printf_git_stripspace "$ttt" &&
+ test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt" &&
+ test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$ttt" &&
+ test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$ttt$ttt"
'
# text plus spaces at the end:
test_expect_success \
'text plus spaces without newline at end should end with newline' '
- test $(printf "$ttt$sss" | git stripspace | wc -l) -gt 0 &&
- test $(printf "$ttt$ttt$sss" | git stripspace | wc -l) -gt 0 &&
- test $(printf "$ttt$ttt$ttt$sss" | git stripspace | wc -l) -gt 0 &&
- test $(printf "$ttt$sss$sss" | git stripspace | wc -l) -gt 0 &&
- test $(printf "$ttt$ttt$sss$sss" | git stripspace | wc -l) -gt 0 &&
- test $(printf "$ttt$sss$sss$sss" | git stripspace | wc -l) -gt 0
+ test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$sss" &&
+ test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$sss" &&
+ test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$ttt$sss" &&
+ test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$sss$sss" &&
+ test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$sss$sss" &&
+ test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$sss$sss$sss"
'
test_expect_success \
'text plus spaces without newline at end should not show spaces' '
- ! (printf "$ttt$sss" | git stripspace | grep " " >/dev/null) &&
- ! (printf "$ttt$ttt$sss" | git stripspace | grep " " >/dev/null) &&
- ! (printf "$ttt$ttt$ttt$sss" | git stripspace | grep " " >/dev/null) &&
- ! (printf "$ttt$sss$sss" | git stripspace | grep " " >/dev/null) &&
- ! (printf "$ttt$ttt$sss$sss" | git stripspace | grep " " >/dev/null) &&
- ! (printf "$ttt$sss$sss$sss" | git stripspace | grep " " >/dev/null)
+ printf "$ttt$sss" | git stripspace >tmp &&
+ ! grep " " tmp >/dev/null &&
+ printf "$ttt$ttt$sss" | git stripspace >tmp &&
+ ! grep " " tmp >/dev/null &&
+ printf "$ttt$ttt$ttt$sss" | git stripspace >tmp &&
+ ! grep " " tmp >/dev/null &&
+ printf "$ttt$sss$sss" | git stripspace >tmp &&
+ ! grep " " tmp >/dev/null &&
+ printf "$ttt$ttt$sss$sss" | git stripspace >tmp &&
+ ! grep " " tmp >/dev/null &&
+ printf "$ttt$sss$sss$sss" | git stripspace >tmp &&
+ ! grep " " tmp >/dev/null
'
test_expect_success \
@@ -282,12 +292,18 @@ test_expect_success \
test_expect_success \
'text plus spaces at end should not show spaces' '
- ! (echo "$ttt$sss" | git stripspace | grep " " >/dev/null) &&
- ! (echo "$ttt$ttt$sss" | git stripspace | grep " " >/dev/null) &&
- ! (echo "$ttt$ttt$ttt$sss" | git stripspace | grep " " >/dev/null) &&
- ! (echo "$ttt$sss$sss" | git stripspace | grep " " >/dev/null) &&
- ! (echo "$ttt$ttt$sss$sss" | git stripspace | grep " " >/dev/null) &&
- ! (echo "$ttt$sss$sss$sss" | git stripspace | grep " " >/dev/null)
+ echo "$ttt$sss" | git stripspace >tmp &&
+ ! grep " " tmp >/dev/null &&
+ echo "$ttt$ttt$sss" | git stripspace >tmp &&
+ ! grep " " tmp >/dev/null &&
+ echo "$ttt$ttt$ttt$sss" | git stripspace >tmp &&
+ ! grep " " tmp >/dev/null &&
+ echo "$ttt$sss$sss" | git stripspace >tmp &&
+ ! grep " " tmp >/dev/null &&
+ echo "$ttt$ttt$sss$sss" | git stripspace >tmp &&
+ ! grep " " tmp >/dev/null &&
+ echo "$ttt$sss$sss$sss" | git stripspace >tmp &&
+ ! grep " " tmp >/dev/null
'
test_expect_success \
@@ -339,11 +355,16 @@ test_expect_success \
test_expect_success \
'spaces without newline at end should not show spaces' '
- ! (printf "" | git stripspace | grep " " >/dev/null) &&
- ! (printf "$sss" | git stripspace | grep " " >/dev/null) &&
- ! (printf "$sss$sss" | git stripspace | grep " " >/dev/null) &&
- ! (printf "$sss$sss$sss" | git stripspace | grep " " >/dev/null) &&
- ! (printf "$sss$sss$sss$sss" | git stripspace | grep " " >/dev/null)
+ printf "" | git stripspace >tmp &&
+ ! grep " " tmp >/dev/null &&
+ printf "$sss" | git stripspace >tmp &&
+ ! grep " " tmp >/dev/null &&
+ printf "$sss$sss" | git stripspace >tmp &&
+ ! grep " " tmp >/dev/null &&
+ printf "$sss$sss$sss" | git stripspace >tmp &&
+ ! grep " " tmp >/dev/null &&
+ printf "$sss$sss$sss$sss" | git stripspace >tmp &&
+ ! grep " " tmp >/dev/null
'
test_expect_success \
diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh
index afc343c..5c9dc90 100755
--- a/t/t0050-filesystem.sh
+++ b/t/t0050-filesystem.sh
@@ -104,7 +104,8 @@ test_expect_failure CASE_INSENSITIVE_FS 'add (with different case)' '
rm camelcase &&
echo 1 >CamelCase &&
git add CamelCase &&
- camel=$(git ls-files | grep -i camelcase) &&
+ git ls-files >tmp &&
+ camel=$(grep -i camelcase tmp) &&
test $(echo "$camel" | wc -l) = 1 &&
test "z$(git cat-file blob :$camel)" = z1
'
diff --git a/t/t0051-windows-named-pipe.sh b/t/t0051-windows-named-pipe.sh
index 10ac92d..412f413 100755
--- a/t/t0051-windows-named-pipe.sh
+++ b/t/t0051-windows-named-pipe.sh
@@ -3,8 +3,13 @@
test_description='Windows named pipes'
. ./test-lib.sh
+if ! test_have_prereq MINGW
+then
+ skip_all='skipping Windows-specific tests'
+ test_done
+fi
-test_expect_success MINGW 'o_append write to named pipe' '
+test_expect_success 'o_append write to named pipe' '
GIT_TRACE="$(pwd)/expect" git status >/dev/null 2>&1 &&
{ test-tool windows-named-pipe t0051 >actual 2>&1 & } &&
pid=$! &&
diff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh
index eeedbfa..08f5fe9 100755
--- a/t/t0091-bugreport.sh
+++ b/t/t0091-bugreport.sh
@@ -60,18 +60,22 @@ test_expect_success 'can create leading directories outside of a git dir' '
test_expect_success 'indicates populated hooks' '
test_when_finished rm git-bugreport-hooks.txt &&
- test_when_finished rm -fr .git/hooks &&
- rm -fr .git/hooks &&
- mkdir .git/hooks &&
- for hook in applypatch-msg prepare-commit-msg.sample
- do
- write_script ".git/hooks/$hook" <<-EOF || return 1
- echo "hook $hook exists"
- EOF
- done &&
+
+ test_hook applypatch-msg <<-\EOF &&
+ true
+ EOF
+ test_hook unknown-hook <<-\EOF &&
+ true
+ EOF
git bugreport -s hooks &&
- grep applypatch-msg git-bugreport-hooks.txt &&
- ! grep prepare-commit-msg git-bugreport-hooks.txt
+
+ sort >expect <<-\EOF &&
+ [Enabled Hooks]
+ applypatch-msg
+ EOF
+
+ sed -ne "/^\[Enabled Hooks\]$/,/^$/p" <git-bugreport-hooks.txt >actual &&
+ test_cmp expect actual
'
test_done
diff --git a/t/t0211/scrub_perf.perl b/t/t0211/scrub_perf.perl
index d164b750..299999f 100644
--- a/t/t0211/scrub_perf.perl
+++ b/t/t0211/scrub_perf.perl
@@ -59,6 +59,10 @@ while (<>) {
# and highly variable. Just omit them.
goto SKIP_LINE;
}
+ if ($tokens[$col_category] =~ m/fsync/) {
+ # fsync events aren't interesting for the test
+ goto SKIP_LINE;
+ }
}
# t_abs and t_rel are either blank or a float. Replace the float
diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh
index f17abd2..1e864cf 100755
--- a/t/t0410-partial-clone.sh
+++ b/t/t0410-partial-clone.sh
@@ -618,6 +618,25 @@ test_expect_success 'do not fetch when checking existence of tree we construct o
git -C repo cherry-pick side1
'
+test_expect_success 'exact rename does not need to fetch the blob lazily' '
+ rm -rf repo partial.git &&
+ test_create_repo repo &&
+ content="some dummy content" &&
+ test_commit -C repo create-a-file file.txt "$content" &&
+ git -C repo mv file.txt new-file.txt &&
+ git -C repo commit -m rename-the-file &&
+ FILE_HASH=$(git -C repo rev-parse HEAD:new-file.txt) &&
+ test_config -C repo uploadpack.allowfilter 1 &&
+ test_config -C repo uploadpack.allowanysha1inwant 1 &&
+
+ git clone --filter=blob:none --bare "file://$(pwd)/repo" partial.git &&
+ git -C partial.git rev-list --objects --missing=print HEAD >out &&
+ grep "[?]$FILE_HASH" out &&
+ git -C partial.git log --follow -- new-file.txt &&
+ git -C partial.git rev-list --objects --missing=print HEAD >out &&
+ grep "[?]$FILE_HASH" out
+'
+
test_expect_success 'lazy-fetch when accessing object not in the_repository' '
rm -rf full partial.git &&
test_create_repo full &&
diff --git a/t/t0500-progress-display.sh b/t/t0500-progress-display.sh
index 22058b5..1eb3a83 100755
--- a/t/t0500-progress-display.sh
+++ b/t/t0500-progress-display.sh
@@ -2,6 +2,7 @@
test_description='progress display'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
show_cr () {
@@ -17,6 +18,7 @@ test_expect_success 'simple progress display' '
EOF
cat >in <<-\EOF &&
+ start 0
update
progress 1
update
@@ -25,8 +27,9 @@ test_expect_success 'simple progress display' '
progress 4
update
progress 5
+ stop
EOF
- test-tool progress "Working hard" <in 2>stderr &&
+ test-tool progress <in 2>stderr &&
show_cr <stderr >out &&
test_cmp expect out
@@ -41,11 +44,13 @@ test_expect_success 'progress display with total' '
EOF
cat >in <<-\EOF &&
+ start 3
progress 1
progress 2
progress 3
+ stop
EOF
- test-tool progress --total=3 "Working hard" <in 2>stderr &&
+ test-tool progress <in 2>stderr &&
show_cr <stderr >out &&
test_cmp expect out
@@ -62,14 +67,14 @@ Working hard.......2.........3.........4.........5.........6:
EOF
cat >in <<-\EOF &&
+ start 100000 Working hard.......2.........3.........4.........5.........6
progress 100
progress 1000
progress 10000
progress 100000
+ stop
EOF
- test-tool progress --total=100000 \
- "Working hard.......2.........3.........4.........5.........6" \
- <in 2>stderr &&
+ test-tool progress <in 2>stderr &&
show_cr <stderr >out &&
test_cmp expect out
@@ -88,16 +93,16 @@ Working hard.......2.........3.........4.........5.........6:
EOF
cat >in <<-\EOF &&
+ start 100000 Working hard.......2.........3.........4.........5.........6
update
progress 1
update
progress 2
progress 10000
progress 100000
+ stop
EOF
- test-tool progress --total=100000 \
- "Working hard.......2.........3.........4.........5.........6" \
- <in 2>stderr &&
+ test-tool progress <in 2>stderr &&
show_cr <stderr >out &&
test_cmp expect out
@@ -116,14 +121,14 @@ Working hard.......2.........3.........4.........5.........6:
EOF
cat >in <<-\EOF &&
+ start 100000 Working hard.......2.........3.........4.........5.........6
progress 25000
progress 50000
progress 75000
progress 100000
+ stop
EOF
- test-tool progress --total=100000 \
- "Working hard.......2.........3.........4.........5.........6" \
- <in 2>stderr &&
+ test-tool progress <in 2>stderr &&
show_cr <stderr >out &&
test_cmp expect out
@@ -140,14 +145,14 @@ Working hard.......2.........3.........4.........5.........6.........7.........:
EOF
cat >in <<-\EOF &&
+ start 100000 Working hard.......2.........3.........4.........5.........6.........7.........
progress 25000
progress 50000
progress 75000
progress 100000
+ stop
EOF
- test-tool progress --total=100000 \
- "Working hard.......2.........3.........4.........5.........6.........7........." \
- <in 2>stderr &&
+ test-tool progress <in 2>stderr &&
show_cr <stderr >out &&
test_cmp expect out
@@ -164,12 +169,14 @@ test_expect_success 'progress shortens - crazy caller' '
EOF
cat >in <<-\EOF &&
+ start 1000
progress 100
progress 200
progress 1
progress 1000
+ stop
EOF
- test-tool progress --total=1000 "Working hard" <in 2>stderr &&
+ test-tool progress <in 2>stderr &&
show_cr <stderr >out &&
test_cmp expect out
@@ -185,6 +192,7 @@ test_expect_success 'progress display with throughput' '
EOF
cat >in <<-\EOF &&
+ start 0
throughput 102400 1000
update
progress 10
@@ -197,8 +205,9 @@ test_expect_success 'progress display with throughput' '
throughput 409600 4000
update
progress 40
+ stop
EOF
- test-tool progress "Working hard" <in 2>stderr &&
+ test-tool progress <in 2>stderr &&
show_cr <stderr >out &&
test_cmp expect out
@@ -214,6 +223,7 @@ test_expect_success 'progress display with throughput and total' '
EOF
cat >in <<-\EOF &&
+ start 40
throughput 102400 1000
progress 10
throughput 204800 2000
@@ -222,8 +232,9 @@ test_expect_success 'progress display with throughput and total' '
progress 30
throughput 409600 4000
progress 40
+ stop
EOF
- test-tool progress --total=40 "Working hard" <in 2>stderr &&
+ test-tool progress <in 2>stderr &&
show_cr <stderr >out &&
test_cmp expect out
@@ -239,6 +250,7 @@ test_expect_success 'cover up after throughput shortens' '
EOF
cat >in <<-\EOF &&
+ start 0
throughput 409600 1000
update
progress 1
@@ -251,8 +263,9 @@ test_expect_success 'cover up after throughput shortens' '
throughput 1638400 4000
update
progress 4
+ stop
EOF
- test-tool progress "Working hard" <in 2>stderr &&
+ test-tool progress <in 2>stderr &&
show_cr <stderr >out &&
test_cmp expect out
@@ -267,6 +280,7 @@ test_expect_success 'cover up after throughput shortens a lot' '
EOF
cat >in <<-\EOF &&
+ start 0
throughput 1 1000
update
progress 1
@@ -276,8 +290,9 @@ test_expect_success 'cover up after throughput shortens a lot' '
throughput 3145728 3000
update
progress 3
+ stop
EOF
- test-tool progress "Working hard" <in 2>stderr &&
+ test-tool progress <in 2>stderr &&
show_cr <stderr >out &&
test_cmp expect out
@@ -285,6 +300,7 @@ test_expect_success 'cover up after throughput shortens a lot' '
test_expect_success 'progress generates traces' '
cat >in <<-\EOF &&
+ start 40
throughput 102400 1000
update
progress 10
@@ -297,10 +313,11 @@ test_expect_success 'progress generates traces' '
throughput 409600 4000
update
progress 40
+ stop
EOF
- GIT_TRACE2_EVENT="$(pwd)/trace.event" test-tool progress --total=40 \
- "Working hard" <in 2>stderr &&
+ GIT_TRACE2_EVENT="$(pwd)/trace.event" test-tool progress \
+ <in 2>stderr &&
# t0212/parse_events.perl intentionally omits regions and data.
test_region progress "Working hard" trace.event &&
@@ -308,4 +325,54 @@ test_expect_success 'progress generates traces' '
grep "\"key\":\"total_bytes\",\"value\":\"409600\"" trace.event
'
+test_expect_success 'progress generates traces: stop / start' '
+ cat >in <<-\EOF &&
+ start 0
+ stop
+ EOF
+
+ GIT_TRACE2_EVENT="$PWD/trace-startstop.event" test-tool progress \
+ <in 2>stderr &&
+ test_region progress "Working hard" trace-startstop.event
+'
+
+test_expect_success 'progress generates traces: start without stop' '
+ cat >in <<-\EOF &&
+ start 0
+ EOF
+
+ GIT_TRACE2_EVENT="$PWD/trace-start.event" \
+ LSAN_OPTIONS=detect_leaks=0 \
+ test-tool progress \
+ <in 2>stderr &&
+ grep region_enter.*progress trace-start.event &&
+ ! grep region_leave.*progress trace-start.event
+'
+
+test_expect_success 'progress generates traces: stop without start' '
+ cat >in <<-\EOF &&
+ stop
+ EOF
+
+ GIT_TRACE2_EVENT="$PWD/trace-stop.event" test-tool progress \
+ <in 2>stderr &&
+ ! grep region_enter.*progress trace-stop.event &&
+ ! grep region_leave.*progress trace-stop.event
+'
+
+test_expect_success 'progress generates traces: start with active progress bar (no stops)' '
+ cat >in <<-\EOF &&
+ start 0 One
+ start 0 Two
+ EOF
+
+ GIT_TRACE2_EVENT="$PWD/trace-2start.event" \
+ LSAN_OPTIONS=detect_leaks=0 \
+ test-tool progress \
+ <in 2>stderr &&
+ grep region_enter.*progress.*One trace-2start.event &&
+ grep region_enter.*progress.*Two trace-2start.event &&
+ ! grep region_leave trace-2start.event
+'
+
test_done
diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh
index d111552..0710b1f 100755
--- a/t/t1001-read-tree-m-2way.sh
+++ b/t/t1001-read-tree-m-2way.sh
@@ -21,7 +21,6 @@ In the test, these paths are used:
yomin - not in H or M
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-read-tree.sh
@@ -38,11 +37,12 @@ compare_change () {
}
check_cache_at () {
- clean_if_empty=$(git diff-files -- "$1")
+ git diff-files -- "$1" >out &&
+ clean_if_empty=$(cat out) &&
case "$clean_if_empty" in
'') echo "$1: clean" ;;
?*) echo "$1: dirty" ;;
- esac
+ esac &&
case "$2,$clean_if_empty" in
clean,) : ;;
clean,?*) false ;;
diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh
index ca5c551..46cbd55 100755
--- a/t/t1002-read-tree-m-u-2way.sh
+++ b/t/t1002-read-tree-m-u-2way.sh
@@ -9,7 +9,6 @@ This is identical to t1001, but uses -u to update the work tree as well.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-read-tree.sh
@@ -23,11 +22,12 @@ compare_change () {
}
check_cache_at () {
- clean_if_empty=$(git diff-files -- "$1")
+ git diff-files -- "$1" >out &&
+ clean_if_empty=$(cat out) &&
case "$clean_if_empty" in
'') echo "$1: clean" ;;
?*) echo "$1: dirty" ;;
- esac
+ esac &&
case "$2,$clean_if_empty" in
clean,) : ;;
clean,?*) false ;;
diff --git a/t/t1003-read-tree-prefix.sh b/t/t1003-read-tree-prefix.sh
index e0db206..c860c08 100755
--- a/t/t1003-read-tree-prefix.sh
+++ b/t/t1003-read-tree-prefix.sh
@@ -25,4 +25,14 @@ test_expect_success 'read-tree --prefix' '
cmp expect actual
'
+test_expect_success 'read-tree --prefix with leading slash exits with error' '
+ git rm -rf . &&
+ test_must_fail git read-tree --prefix=/two/ $tree &&
+ git read-tree --prefix=two/ $tree &&
+
+ git rm -rf . &&
+ test_must_fail git read-tree --prefix=/ $tree &&
+ git read-tree --prefix= $tree
+'
+
test_done
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index 39382fa..1b85207 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -4,6 +4,98 @@ test_description='git cat-file'
. ./test-lib.sh
+test_cmdmode_usage () {
+ test_expect_code 129 "$@" 2>err &&
+ grep "^error:.*is incompatible with" err
+}
+
+for switches in \
+ '-e -p' \
+ '-p -t' \
+ '-t -s' \
+ '-s --textconv' \
+ '--textconv --filters' \
+ '--batch-all-objects -e'
+do
+ test_expect_success "usage: cmdmode $switches" '
+ test_cmdmode_usage git cat-file $switches
+ '
+done
+
+test_incompatible_usage () {
+ test_expect_code 129 "$@" 2>err &&
+ grep -E "^(fatal|error):.*(requires|incompatible with|needs)" err
+}
+
+for opt in --batch --batch-check
+do
+ test_expect_success "usage: incompatible options: --path with $opt" '
+ test_incompatible_usage git cat-file --path=foo $opt
+ '
+done
+
+test_missing_usage () {
+ test_expect_code 129 "$@" 2>err &&
+ grep -E "^fatal:.*required" err
+}
+
+short_modes="-e -p -t -s"
+cw_modes="--textconv --filters"
+
+for opt in $cw_modes
+do
+ test_expect_success "usage: $opt requires another option" '
+ test_missing_usage git cat-file $opt
+ '
+done
+
+for opt in $short_modes
+do
+ test_expect_success "usage: $opt requires another option" '
+ test_missing_usage git cat-file $opt
+ '
+
+ for opt2 in --batch \
+ --batch-check \
+ --follow-symlinks \
+ "--path=foo HEAD:some-path.txt"
+ do
+ test_expect_success "usage: incompatible options: $opt and $opt2" '
+ test_incompatible_usage git cat-file $opt $opt2
+ '
+ done
+done
+
+test_too_many_arguments () {
+ test_expect_code 129 "$@" 2>err &&
+ grep -E "^fatal: too many arguments$" err
+}
+
+for opt in $short_modes $cw_modes
+do
+ args="one two three"
+ test_expect_success "usage: too many arguments: $opt $args" '
+ test_too_many_arguments git cat-file $opt $args
+ '
+
+ for opt2 in --buffer --follow-symlinks
+ do
+ test_expect_success "usage: incompatible arguments: $opt with batch option $opt2" '
+ test_incompatible_usage git cat-file $opt $opt2
+ '
+ done
+done
+
+for opt in --buffer \
+ --follow-symlinks \
+ --batch-all-objects
+do
+ test_expect_success "usage: bad option combination: $opt without batch mode" '
+ test_incompatible_usage git cat-file $opt &&
+ test_incompatible_usage git cat-file $opt commit HEAD
+ '
+done
+
echo_without_newline () {
printf '%s' "$*"
}
@@ -13,13 +105,18 @@ strlen () {
}
maybe_remove_timestamp () {
- if test -z "$2"; then
- echo_without_newline "$1"
- else
- echo_without_newline "$(printf '%s\n' "$1" | sed -e 's/ [0-9][0-9]* [-+][0-9][0-9][0-9][0-9]$//')"
- fi
+ if test -z "$2"; then
+ echo_without_newline "$1"
+ else
+ echo_without_newline "$(printf '%s\n' "$1" | remove_timestamp)"
+ fi
+}
+
+remove_timestamp () {
+ sed -e 's/ [0-9][0-9]* [-+][0-9][0-9][0-9][0-9]$//'
}
+
run_tests () {
type=$1
sha1=$2
@@ -85,12 +182,36 @@ $content"
test_cmp expect actual
'
+ for opt in --buffer --no-buffer
+ do
+ test -z "$content" ||
+ test_expect_success "--batch-command $opt output of $type content is correct" '
+ maybe_remove_timestamp "$batch_output" $no_ts >expect &&
+ maybe_remove_timestamp "$(test_write_lines "contents $sha1" |
+ git cat-file --batch-command $opt)" $no_ts >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "--batch-command $opt output of $type info is correct" '
+ echo "$sha1 $type $size" >expect &&
+ test_write_lines "info $sha1" |
+ git cat-file --batch-command $opt >actual &&
+ test_cmp expect actual
+ '
+ done
+
test_expect_success "custom --batch-check format" '
echo "$type $sha1" >expect &&
echo $sha1 | git cat-file --batch-check="%(objecttype) %(objectname)" >actual &&
test_cmp expect actual
'
+ test_expect_success "custom --batch-command format" '
+ echo "$type $sha1" >expect &&
+ echo "info $sha1" | git cat-file --batch-command="%(objecttype) %(objectname)" >actual &&
+ test_cmp expect actual
+ '
+
test_expect_success '--batch-check with %(rest)' '
echo "$type this is some extra content" >expect &&
echo "$sha1 this is some extra content" |
@@ -132,6 +253,22 @@ test_expect_success "setup" '
run_tests 'blob' $hello_sha1 $hello_size "$hello_content" "$hello_content"
+test_expect_success '--batch-command --buffer with flush for blob info' '
+ echo "$hello_sha1 blob $hello_size" >expect &&
+ test_write_lines "info $hello_sha1" "flush" |
+ GIT_TEST_CAT_FILE_NO_FLUSH_ON_EXIT=1 \
+ git cat-file --batch-command --buffer >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--batch-command --buffer without flush for blob info' '
+ touch output &&
+ test_write_lines "info $hello_sha1" |
+ GIT_TEST_CAT_FILE_NO_FLUSH_ON_EXIT=1 \
+ git cat-file --batch-command --buffer >>output &&
+ test_must_be_empty output
+'
+
test_expect_success '--batch-check without %(rest) considers whole line' '
echo "$hello_sha1 blob $hello_size" >expect &&
git update-index --add --cacheinfo 100644 $hello_sha1 "white space" &&
@@ -175,7 +312,7 @@ test_expect_success \
"Reach a blob from a tag pointing to it" \
"test '$hello_content' = \"\$(git cat-file blob $tag_sha1)\""
-for batch in batch batch-check
+for batch in batch batch-check batch-command
do
for opt in t s e p
do
@@ -281,6 +418,49 @@ test_expect_success "--batch-check with multiple sha1s gives correct format" '
"$(echo_without_newline "$batch_check_input" | git cat-file --batch-check)"
'
+test_expect_success '--batch-command with multiple info calls gives correct format' '
+ cat >expect <<-EOF &&
+ $hello_sha1 blob $hello_size
+ $tree_sha1 tree $tree_size
+ $commit_sha1 commit $commit_size
+ $tag_sha1 tag $tag_size
+ deadbeef missing
+ EOF
+
+ git cat-file --batch-command --buffer >actual <<-EOF &&
+ info $hello_sha1
+ info $tree_sha1
+ info $commit_sha1
+ info $tag_sha1
+ info deadbeef
+ EOF
+
+ test_cmp expect actual
+'
+
+test_expect_success '--batch-command with multiple command calls gives correct format' '
+ remove_timestamp >expect <<-EOF &&
+ $hello_sha1 blob $hello_size
+ $hello_content
+ $commit_sha1 commit $commit_size
+ $commit_content
+ $tag_sha1 tag $tag_size
+ $tag_content
+ deadbeef missing
+ EOF
+
+ git cat-file --batch-command --buffer >actual_raw <<-EOF &&
+ contents $hello_sha1
+ contents $commit_sha1
+ contents $tag_sha1
+ contents deadbeef
+ flush
+ EOF
+
+ remove_timestamp <actual_raw >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'setup blobs which are likely to delta' '
test-tool genrandom foo 10240 >foo &&
{ cat foo && echo plus; } >foo-plus &&
@@ -871,5 +1051,40 @@ test_expect_success 'cat-file --batch-all-objects --batch-check ignores replace'
echo "$orig commit $orig_size" >expect &&
test_cmp expect actual
'
+test_expect_success 'batch-command empty command' '
+ echo "" >cmd &&
+ test_expect_code 128 git cat-file --batch-command <cmd 2>err &&
+ grep "^fatal:.*empty command in input.*" err
+'
+
+test_expect_success 'batch-command whitespace before command' '
+ echo " info deadbeef" >cmd &&
+ test_expect_code 128 git cat-file --batch-command <cmd 2>err &&
+ grep "^fatal:.*whitespace before command.*" err
+'
+
+test_expect_success 'batch-command unknown command' '
+ echo unknown_command >cmd &&
+ test_expect_code 128 git cat-file --batch-command <cmd 2>err &&
+ grep "^fatal:.*unknown command.*" err
+'
+
+test_expect_success 'batch-command missing arguments' '
+ echo "info" >cmd &&
+ test_expect_code 128 git cat-file --batch-command <cmd 2>err &&
+ grep "^fatal:.*info requires arguments.*" err
+'
+
+test_expect_success 'batch-command flush with arguments' '
+ echo "flush arg" >cmd &&
+ test_expect_code 128 git cat-file --batch-command --buffer <cmd 2>err &&
+ grep "^fatal:.*flush takes no arguments.*" err
+'
+
+test_expect_success 'batch-command flush without --buffer' '
+ echo "flush" >cmd &&
+ test_expect_code 128 git cat-file --batch-command <cmd 2>err &&
+ grep "^fatal:.*flush is only for --buffer mode.*" err
+'
test_done
diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh
index 64b340f..ac5ad8c 100755
--- a/t/t1007-hash-object.sh
+++ b/t/t1007-hash-object.sh
@@ -2,6 +2,7 @@
test_description="git hash-object"
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
echo_without_newline() {
diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh
index 24092c0..dd957be 100755
--- a/t/t1011-read-tree-sparse-checkout.sh
+++ b/t/t1011-read-tree-sparse-checkout.sh
@@ -187,11 +187,32 @@ test_expect_success 'read-tree updates worktree, absent case' '
test ! -f init.t
'
+test_expect_success 'read-tree will not throw away dirty changes, non-sparse' '
+ echo "/*" >.git/info/sparse-checkout &&
+ read_tree_u_must_succeed -m -u HEAD &&
+
+ echo dirty >init.t &&
+ read_tree_u_must_fail -m -u HEAD^ &&
+ test_path_is_file init.t &&
+ grep -q dirty init.t
+'
+
+test_expect_success 'read-tree will not throw away dirty changes, sparse' '
+ echo "/*" >.git/info/sparse-checkout &&
+ read_tree_u_must_succeed -m -u HEAD &&
+
+ echo dirty >init.t &&
+ echo sub/added >.git/info/sparse-checkout &&
+ read_tree_u_must_fail -m -u HEAD^ &&
+ test_path_is_file init.t &&
+ grep -q dirty init.t
+'
+
test_expect_success 'read-tree updates worktree, dirty case' '
echo sub/added >.git/info/sparse-checkout &&
git checkout -f top &&
echo dirty >init.t &&
- read_tree_u_must_succeed -m -u HEAD^ &&
+ read_tree_u_must_fail -m -u HEAD^ &&
grep -q dirty init.t &&
rm init.t
'
diff --git a/t/t1090-sparse-checkout-scope.sh b/t/t1090-sparse-checkout-scope.sh
index 3deb490..d1833c0 100755
--- a/t/t1090-sparse-checkout-scope.sh
+++ b/t/t1090-sparse-checkout-scope.sh
@@ -52,6 +52,25 @@ test_expect_success 'return to full checkout of main' '
test "$(cat b)" = "modified"
'
+test_expect_success 'skip-worktree on files outside sparse patterns' '
+ git sparse-checkout disable &&
+ git sparse-checkout set --no-cone "a*" &&
+ git checkout-index --all --ignore-skip-worktree-bits &&
+
+ git ls-files -t >output &&
+ ! grep ^S output >actual &&
+ test_must_be_empty actual &&
+
+ test_config sparse.expectFilesOutsideOfPatterns true &&
+ cat <<-\EOF >expect &&
+ S b
+ S c
+ EOF
+ git ls-files -t >output &&
+ grep ^S output >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'in partial clone, sparse checkout only fetches needed blobs' '
test_create_repo server &&
git clone "file://$(pwd)/server" client &&
diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh
index 4277698..9a90031 100755
--- a/t/t1091-sparse-checkout-builtin.sh
+++ b/t/t1091-sparse-checkout-builtin.sh
@@ -5,6 +5,9 @@ test_description='sparse checkout builtin tests'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+GIT_TEST_SPLIT_INDEX=false
+export GIT_TEST_SPLIT_INDEX
+
. ./test-lib.sh
list_files() {
@@ -79,6 +82,12 @@ test_expect_success 'git sparse-checkout init' '
check_files repo a
'
+test_expect_success 'git sparse-checkout init in empty repo' '
+ test_when_finished rm -rf empty-repo blank-template &&
+ git init --template= empty-repo &&
+ git -C empty-repo sparse-checkout init
+'
+
test_expect_success 'git sparse-checkout list after init' '
git -C repo sparse-checkout list >actual &&
cat >expect <<-\EOF &&
@@ -117,7 +126,7 @@ test_expect_success 'switching to cone mode with non-cone mode patterns' '
cd bad-patterns &&
git sparse-checkout init &&
git sparse-checkout add dir &&
- git config core.sparseCheckoutCone true &&
+ git config --worktree core.sparseCheckoutCone true &&
test_must_fail git sparse-checkout add dir 2>err &&
grep "existing sparse-checkout patterns do not use cone mode" err
)
@@ -146,9 +155,9 @@ test_expect_success 'interaction with clone --no-checkout (unborn index)' '
'
test_expect_success 'set enables config' '
- git init empty-config &&
+ git init worktree-config &&
(
- cd empty-config &&
+ cd worktree-config &&
test_commit test file &&
test_path_is_missing .git/config.worktree &&
git sparse-checkout set nothing &&
@@ -201,6 +210,21 @@ test_expect_success 'add to sparse-checkout' '
check_files repo "a folder1 folder2"
'
+test_expect_success 'worktree: add copies sparse-checkout patterns' '
+ cat repo/.git/info/sparse-checkout >old &&
+ test_when_finished cp old repo/.git/info/sparse-checkout &&
+ test_when_finished git -C repo worktree remove ../worktree &&
+ git -C repo sparse-checkout set --no-cone "/*" &&
+ git -C repo worktree add --quiet ../worktree 2>err &&
+ test_must_be_empty err &&
+ new="$(git -C worktree rev-parse --git-path info/sparse-checkout)" &&
+ test_path_is_file "$new" &&
+ test_cmp repo/.git/info/sparse-checkout "$new" &&
+ git -C worktree sparse-checkout set --cone &&
+ test_cmp_config -C worktree true core.sparseCheckoutCone &&
+ test_must_fail git -C repo core.sparseCheckoutCone
+'
+
test_expect_success 'cone mode: match patterns' '
git -C repo config --worktree core.sparseCheckoutCone true &&
rm -rf repo/a repo/folder1 repo/folder2 &&
@@ -228,36 +252,31 @@ test_expect_success 'sparse-checkout disable' '
'
test_expect_success 'sparse-index enabled and disabled' '
- (
- sane_unset GIT_TEST_SPLIT_INDEX &&
- git -C repo update-index --no-split-index &&
-
- git -C repo sparse-checkout init --cone --sparse-index &&
- test_cmp_config -C repo true index.sparse &&
- git -C repo ls-files --sparse >sparse &&
- git -C repo sparse-checkout disable &&
- git -C repo ls-files --sparse >full &&
-
- cat >expect <<-\EOF &&
- @@ -1,4 +1,7 @@
- a
- -deep/
- -folder1/
- -folder2/
- +deep/a
- +deep/deeper1/a
- +deep/deeper1/deepest/a
- +deep/deeper2/a
- +folder1/a
- +folder2/a
- EOF
+ git -C repo sparse-checkout init --cone --sparse-index &&
+ test_cmp_config -C repo true index.sparse &&
+ git -C repo ls-files --sparse >sparse &&
+ git -C repo sparse-checkout disable &&
+ git -C repo ls-files --sparse >full &&
- diff -u sparse full | tail -n +3 >actual &&
- test_cmp expect actual &&
+ cat >expect <<-\EOF &&
+ @@ -1,4 +1,7 @@
+ a
+ -deep/
+ -folder1/
+ -folder2/
+ +deep/a
+ +deep/deeper1/a
+ +deep/deeper1/deepest/a
+ +deep/deeper2/a
+ +folder1/a
+ +folder2/a
+ EOF
+
+ diff -u sparse full | tail -n +3 >actual &&
+ test_cmp expect actual &&
- git -C repo config --list >config &&
- ! grep index.sparse config
- )
+ git -C repo config --list >config &&
+ test_cmp_config -C repo false index.sparse
'
test_expect_success 'cone mode: init and set' '
@@ -491,6 +510,37 @@ test_expect_failure 'sparse-checkout reapply' '
git -C tweak sparse-checkout disable
'
+test_expect_success 'reapply can handle config options' '
+ git -C repo sparse-checkout init --cone --no-sparse-index &&
+ git -C repo config --worktree --list >actual &&
+ cat >expect <<-\EOF &&
+ core.sparsecheckout=true
+ core.sparsecheckoutcone=true
+ index.sparse=false
+ EOF
+ test_cmp expect actual &&
+
+ git -C repo sparse-checkout reapply --no-cone --no-sparse-index &&
+ git -C repo config --worktree --list >actual &&
+ cat >expect <<-\EOF &&
+ core.sparsecheckout=true
+ core.sparsecheckoutcone=false
+ index.sparse=false
+ EOF
+ test_cmp expect actual &&
+
+ git -C repo sparse-checkout reapply --cone --sparse-index &&
+ git -C repo config --worktree --list >actual &&
+ cat >expect <<-\EOF &&
+ core.sparsecheckout=true
+ core.sparsecheckoutcone=true
+ index.sparse=true
+ EOF
+ test_cmp expect actual &&
+
+ git -C repo sparse-checkout disable
+'
+
test_expect_success 'cone mode: set with core.ignoreCase=true' '
rm repo/.git/info/sparse-checkout &&
git -C repo sparse-checkout init --cone &&
@@ -520,17 +570,17 @@ test_expect_success 'interaction with submodules' '
'
test_expect_success 'different sparse-checkouts with worktrees' '
+ git -C repo sparse-checkout set --cone deep folder1 &&
git -C repo worktree add --detach ../worktree &&
- check_files worktree "a deep folder1 folder2" &&
- git -C worktree sparse-checkout init --cone &&
- git -C repo sparse-checkout set folder1 &&
- git -C worktree sparse-checkout set deep/deeper1 &&
- check_files repo a folder1 &&
- check_files worktree a deep
+ check_files worktree "a deep folder1" &&
+ git -C repo sparse-checkout set --cone folder1 &&
+ git -C worktree sparse-checkout set --cone deep/deeper1 &&
+ check_files repo "a folder1" &&
+ check_files worktree "a deep"
'
test_expect_success 'set using filename keeps file on-disk' '
- git -C repo sparse-checkout set a deep &&
+ git -C repo sparse-checkout set --skip-checks a deep &&
cat >expect <<-\EOF &&
/*
!/*/
@@ -641,7 +691,7 @@ test_expect_success BSLASHPSPEC 'pattern-checks: escaped characters' '
git -C escaped reset --hard $COMMIT &&
check_files escaped "a deep folder1 folder2 zbad\\dir zdoes*exist" zglob[!a]? &&
git -C escaped sparse-checkout init --cone &&
- git -C escaped sparse-checkout set zbad\\dir/bogus "zdoes*not*exist" "zdoes*exist" "zglob[!a]?" &&
+ git -C escaped sparse-checkout set --skip-checks zbad\\dir/bogus "zdoes*not*exist" "zdoes*exist" "zglob[!a]?" &&
cat >expect <<-\EOF &&
/*
!/*/
@@ -766,4 +816,59 @@ test_expect_success 'malformed cone-mode patterns' '
grep "warning: disabling cone pattern matching" err
'
+test_expect_success 'set from subdir pays attention to prefix' '
+ git -C repo sparse-checkout disable &&
+ git -C repo/deep sparse-checkout set --cone deeper2 ../folder1 &&
+
+ git -C repo sparse-checkout list >actual &&
+
+ cat >expect <<-\EOF &&
+ deep/deeper2
+ folder1
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'add from subdir pays attention to prefix' '
+ git -C repo sparse-checkout set --cone deep/deeper2 &&
+ git -C repo/deep sparse-checkout add deeper1/deepest ../folder1 &&
+
+ git -C repo sparse-checkout list >actual &&
+
+ cat >expect <<-\EOF &&
+ deep/deeper1/deepest
+ deep/deeper2
+ folder1
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'set from subdir in non-cone mode throws an error' '
+ git -C repo sparse-checkout disable &&
+ test_must_fail git -C repo/deep sparse-checkout set --no-cone deeper2 ../folder1 2>error &&
+
+ grep "run from the toplevel directory in non-cone mode" error
+'
+
+test_expect_success 'set from subdir in non-cone mode throws an error' '
+ git -C repo sparse-checkout set --no-cone deep/deeper2 &&
+ test_must_fail git -C repo/deep sparse-checkout add deeper1/deepest ../folder1 2>error &&
+
+ grep "run from the toplevel directory in non-cone mode" error
+'
+
+test_expect_success 'by default, cone mode will error out when passed files' '
+ git -C repo sparse-checkout reapply --cone &&
+ test_must_fail git -C repo sparse-checkout add .gitignore 2>error &&
+
+ grep ".gitignore.*is not a directory" error
+'
+
+test_expect_success 'by default, non-cone mode will warn on individual files' '
+ git -C repo sparse-checkout reapply --no-cone &&
+ git -C repo sparse-checkout add .gitignore 2>warning &&
+
+ grep "pass a leading slash before paths.*if you want a single file" warning
+'
+
test_done
diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh
index 4ba1617..236ab53 100755
--- a/t/t1092-sparse-checkout-compatibility.sh
+++ b/t/t1092-sparse-checkout-compatibility.sh
@@ -16,7 +16,9 @@ test_expect_success 'setup' '
echo "after deep" >e &&
echo "after folder1" >g &&
echo "after x" >z &&
- mkdir folder1 folder2 deep x &&
+ mkdir folder1 folder2 deep before x &&
+ echo "before deep" >before/a &&
+ echo "before deep again" >before/b &&
mkdir deep/deeper1 deep/deeper2 deep/before deep/later &&
mkdir deep/deeper1/deepest &&
mkdir deep/deeper1/deepest2 &&
@@ -244,6 +246,25 @@ test_expect_success 'expanded in-memory index matches full index' '
test_sparse_match git ls-files --stage
'
+test_expect_success 'root directory cannot be sparse' '
+ init_repos &&
+
+ # Remove all in-cone files and directories from the index, collapse index
+ # with `git sparse-checkout reapply`
+ git -C sparse-index rm -r . &&
+ git -C sparse-index sparse-checkout reapply &&
+
+ # Verify sparse directories still present, root directory is not sparse
+ cat >expect <<-EOF &&
+ before/
+ folder1/
+ folder2/
+ x/
+ EOF
+ git -C sparse-index ls-files --sparse >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'status with options' '
init_repos &&
test_sparse_match ls &&
@@ -260,6 +281,13 @@ test_expect_success 'status with options' '
test_all_match git status --porcelain=v2 -uno
'
+test_expect_success 'status with diff in unexpanded sparse directory' '
+ init_repos &&
+ test_all_match git checkout rename-base &&
+ test_all_match git reset --soft rename-out-to-out &&
+ test_all_match git status --porcelain=v2
+'
+
test_expect_success 'status reports sparse-checkout' '
init_repos &&
git -C sparse-checkout status >full &&
@@ -367,7 +395,7 @@ test_expect_success 'status/add: outside sparse cone' '
write_script edit-contents <<-\EOF &&
echo text >>$1
EOF
- run_on_sparse ../edit-contents folder1/a &&
+ run_on_all ../edit-contents folder1/a &&
run_on_all ../edit-contents folder1/new &&
test_sparse_match git status --porcelain=v2 &&
@@ -376,8 +404,8 @@ test_expect_success 'status/add: outside sparse cone' '
test_sparse_match test_must_fail git add folder1/a &&
grep "Disable or modify the sparsity rules" sparse-checkout-err &&
test_sparse_unstaged folder1/a &&
- test_sparse_match test_must_fail git add --refresh folder1/a &&
- grep "Disable or modify the sparsity rules" sparse-checkout-err &&
+ test_all_match git add --refresh folder1/a &&
+ test_must_be_empty sparse-checkout-err &&
test_sparse_unstaged folder1/a &&
test_sparse_match test_must_fail git add folder1/new &&
grep "Disable or modify the sparsity rules" sparse-checkout-err &&
@@ -593,13 +621,11 @@ test_expect_success 'reset with pathspecs outside sparse definition' '
test_sparse_match git reset update-folder1 -- folder1 &&
git -C full-checkout reset update-folder1 -- folder1 &&
- test_sparse_match git status --porcelain=v2 &&
- test_all_match git rev-parse HEAD:folder1 &&
+ test_all_match git ls-files -s -- folder1 &&
test_sparse_match git reset update-folder2 -- folder2/a &&
git -C full-checkout reset update-folder2 -- folder2/a &&
- test_sparse_match git status --porcelain=v2 &&
- test_all_match git rev-parse HEAD:folder2/a
+ test_all_match git ls-files -s -- folder2/a
'
test_expect_success 'reset with wildcard pathspec' '
@@ -629,6 +655,260 @@ test_expect_success 'reset with wildcard pathspec' '
test_all_match git ls-files -s -- folder1
'
+test_expect_success 'update-index modify outside sparse definition' '
+ init_repos &&
+
+ write_script edit-contents <<-\EOF &&
+ echo text >>$1
+ EOF
+
+ # Create & modify folder1/a
+ # Note that this setup is a manual way of reaching the erroneous
+ # condition in which a `skip-worktree` enabled, outside-of-cone file
+ # exists on disk. It is used here to ensure `update-index` is stable
+ # and behaves predictably if such a condition occurs.
+ run_on_sparse mkdir -p folder1 &&
+ run_on_sparse cp ../initial-repo/folder1/a folder1/a &&
+ run_on_all ../edit-contents folder1/a &&
+
+ # If file has skip-worktree enabled, but the file is present, it is
+ # treated the same as if skip-worktree is disabled
+ test_all_match git status --porcelain=v2 &&
+ test_all_match git update-index folder1/a &&
+ test_all_match git status --porcelain=v2 &&
+
+ # When skip-worktree is disabled (even on files outside sparse cone), file
+ # is updated in the index
+ test_sparse_match git update-index --no-skip-worktree folder1/a &&
+ test_all_match git status --porcelain=v2 &&
+ test_all_match git update-index folder1/a &&
+ test_all_match git status --porcelain=v2
+'
+
+test_expect_success 'update-index --add outside sparse definition' '
+ init_repos &&
+
+ write_script edit-contents <<-\EOF &&
+ echo text >>$1
+ EOF
+
+ # Create folder1, add new file
+ run_on_sparse mkdir -p folder1 &&
+ run_on_all ../edit-contents folder1/b &&
+
+ # The *untracked* out-of-cone file is added to the index because it does
+ # not have a `skip-worktree` bit to signal that it should be ignored
+ # (unlike in `git add`, which will fail due to the file being outside
+ # the sparse checkout definition).
+ test_all_match git update-index --add folder1/b &&
+ test_all_match git status --porcelain=v2
+'
+
+# NEEDSWORK: `--remove`, unlike the rest of `update-index`, does not ignore
+# `skip-worktree` entries by default and will remove them from the index.
+# The `--ignore-skip-worktree-entries` flag must be used in conjunction with
+# `--remove` to ignore the `skip-worktree` entries and prevent their removal
+# from the index.
+test_expect_success 'update-index --remove outside sparse definition' '
+ init_repos &&
+
+ # When --ignore-skip-worktree-entries is _not_ specified:
+ # out-of-cone, not-on-disk files are removed from the index
+ test_sparse_match git update-index --remove folder1/a &&
+ cat >expect <<-EOF &&
+ D folder1/a
+ EOF
+ test_sparse_match git diff --cached --name-status &&
+ test_cmp expect sparse-checkout-out &&
+
+ # Reset the state
+ test_all_match git reset --hard &&
+
+ # When --ignore-skip-worktree-entries is specified, out-of-cone
+ # (skip-worktree) files are ignored
+ test_sparse_match git update-index --remove --ignore-skip-worktree-entries folder1/a &&
+ test_sparse_match git diff --cached --name-status &&
+ test_must_be_empty sparse-checkout-out &&
+
+ # Reset the state
+ test_all_match git reset --hard &&
+
+ # --force-remove supercedes --ignore-skip-worktree-entries, removing
+ # a skip-worktree file from the index (and disk) when both are specified
+ # with --remove
+ test_sparse_match git update-index --force-remove --ignore-skip-worktree-entries folder1/a &&
+ cat >expect <<-EOF &&
+ D folder1/a
+ EOF
+ test_sparse_match git diff --cached --name-status &&
+ test_cmp expect sparse-checkout-out
+'
+
+test_expect_success 'update-index with directories' '
+ init_repos &&
+
+ # update-index will exit silently when provided with a directory name
+ # containing a trailing slash
+ test_all_match git update-index deep/ folder1/ &&
+ grep "Ignoring path deep/" sparse-checkout-err &&
+ grep "Ignoring path folder1/" sparse-checkout-err &&
+
+ # When update-index is given a directory name WITHOUT a trailing slash, it will
+ # behave in different ways depending on the status of the directory on disk:
+ # * if it exists, the command exits with an error ("add individual files instead")
+ # * if it does NOT exist (e.g., in a sparse-checkout), it is assumed to be a
+ # file and either triggers an error ("does not exist and --remove not passed")
+ # or is ignored completely (when using --remove)
+ test_all_match test_must_fail git update-index deep &&
+ run_on_all test_must_fail git update-index folder1 &&
+ test_must_fail git -C full-checkout update-index --remove folder1 &&
+ test_sparse_match git update-index --remove folder1 &&
+ test_all_match git status --porcelain=v2
+'
+
+test_expect_success 'update-index --again file outside sparse definition' '
+ init_repos &&
+
+ test_all_match git checkout -b test-reupdate &&
+
+ # Update HEAD without modifying the index to introduce a difference in
+ # folder1/a
+ test_sparse_match git reset --soft update-folder1 &&
+
+ # Because folder1/a differs in the index vs HEAD,
+ # `git update-index --no-skip-worktree --again` will effectively perform
+ # `git update-index --no-skip-worktree folder1/a` and remove the skip-worktree
+ # flag from folder1/a
+ test_sparse_match git update-index --no-skip-worktree --again &&
+ test_sparse_match git status --porcelain=v2 &&
+
+ cat >expect <<-EOF &&
+ D folder1/a
+ EOF
+ test_sparse_match git diff --name-status &&
+ test_cmp expect sparse-checkout-out
+'
+
+test_expect_success 'update-index --cacheinfo' '
+ init_repos &&
+
+ deep_a_oid=$(git -C full-checkout rev-parse update-deep:deep/a) &&
+ folder2_oid=$(git -C full-checkout rev-parse update-folder2:folder2) &&
+ folder1_a_oid=$(git -C full-checkout rev-parse update-folder1:folder1/a) &&
+
+ test_all_match git update-index --cacheinfo 100644 $deep_a_oid deep/a &&
+ test_all_match git status --porcelain=v2 &&
+
+ # Cannot add sparse directory, even in sparse index case
+ test_all_match test_must_fail git update-index --add --cacheinfo 040000 $folder2_oid folder2/ &&
+
+ # Sparse match only: the new outside-of-cone entry is added *without* skip-worktree,
+ # so `git status` reports it as "deleted" in the worktree
+ test_sparse_match git update-index --add --cacheinfo 100644 $folder1_a_oid folder1/a &&
+ test_sparse_match git status --porcelain=v2 &&
+ cat >expect <<-EOF &&
+ MD folder1/a
+ EOF
+ test_sparse_match git status --short -- folder1/a &&
+ test_cmp expect sparse-checkout-out &&
+
+ # To return folder1/a to "normal" for a sparse checkout (ignored &
+ # outside-of-cone), add the skip-worktree flag.
+ test_sparse_match git update-index --skip-worktree folder1/a &&
+ cat >expect <<-EOF &&
+ S folder1/a
+ EOF
+ test_sparse_match git ls-files -t -- folder1/a &&
+ test_cmp expect sparse-checkout-out
+'
+
+for MERGE_TREES in "base HEAD update-folder2" \
+ "update-folder1 update-folder2" \
+ "update-folder2"
+do
+ test_expect_success "'read-tree -mu $MERGE_TREES' with files outside sparse definition" '
+ init_repos &&
+
+ # Although the index matches, without --no-sparse-checkout, outside-of-
+ # definition files will not exist on disk for sparse checkouts
+ test_all_match git read-tree -mu $MERGE_TREES &&
+ test_all_match git status --porcelain=v2 &&
+ test_path_is_missing sparse-checkout/folder2 &&
+ test_path_is_missing sparse-index/folder2 &&
+
+ test_all_match git read-tree --reset -u HEAD &&
+ test_all_match git status --porcelain=v2 &&
+
+ test_all_match git read-tree -mu --no-sparse-checkout $MERGE_TREES &&
+ test_all_match git status --porcelain=v2 &&
+ test_cmp sparse-checkout/folder2/a sparse-index/folder2/a &&
+ test_cmp sparse-checkout/folder2/a full-checkout/folder2/a
+
+ '
+done
+
+test_expect_success 'read-tree --merge with edit/edit conflicts in sparse directories' '
+ init_repos &&
+
+ # Merge of multiple changes to same directory (but not same files) should
+ # succeed
+ test_all_match git read-tree -mu base rename-base update-folder1 &&
+ test_all_match git status --porcelain=v2 &&
+
+ test_all_match git reset --hard &&
+
+ test_all_match git read-tree -mu rename-base update-folder2 &&
+ test_all_match git status --porcelain=v2 &&
+
+ test_all_match git reset --hard &&
+
+ test_all_match test_must_fail git read-tree -mu base update-folder1 rename-out-to-in &&
+ test_all_match test_must_fail git read-tree -mu rename-out-to-in update-folder1
+'
+
+test_expect_success 'read-tree --prefix' '
+ init_repos &&
+
+ # If files differing between the index and target <commit-ish> exist
+ # inside the prefix, `read-tree --prefix` should fail
+ test_all_match test_must_fail git read-tree --prefix=deep/ deepest &&
+ test_all_match test_must_fail git read-tree --prefix=folder1/ update-folder1 &&
+
+ # If no differing index entries exist matching the prefix,
+ # `read-tree --prefix` updates the index successfully
+ test_all_match git rm -rf deep/deeper1/deepest/ &&
+ test_all_match git read-tree --prefix=deep/deeper1/deepest -u deepest &&
+ test_all_match git status --porcelain=v2 &&
+
+ test_all_match git rm -rf --sparse folder1/ &&
+ test_all_match git read-tree --prefix=folder1/ -u update-folder1 &&
+ test_all_match git status --porcelain=v2 &&
+
+ test_all_match git rm -rf --sparse folder2/0 &&
+ test_all_match git read-tree --prefix=folder2/0/ -u rename-out-to-out &&
+ test_all_match git status --porcelain=v2
+'
+
+test_expect_success 'read-tree --merge with directory-file conflicts' '
+ init_repos &&
+
+ test_all_match git checkout -b test-branch rename-base &&
+
+ # Although the index matches, without --no-sparse-checkout, outside-of-
+ # definition files will not exist on disk for sparse checkouts
+ test_sparse_match git read-tree -mu rename-out-to-out &&
+ test_sparse_match git status --porcelain=v2 &&
+ test_path_is_missing sparse-checkout/folder2 &&
+ test_path_is_missing sparse-index/folder2 &&
+
+ test_sparse_match git read-tree --reset -u HEAD &&
+ test_sparse_match git status --porcelain=v2 &&
+
+ test_sparse_match git read-tree -mu --no-sparse-checkout rename-out-to-out &&
+ test_sparse_match git status --porcelain=v2 &&
+ test_cmp sparse-checkout/folder2/0/1 sparse-index/folder2/0/1
+'
+
test_expect_success 'merge, cherry-pick, and rebase' '
init_repos &&
@@ -754,6 +1034,74 @@ test_expect_success 'cherry-pick with conflicts' '
test_all_match test_must_fail git cherry-pick to-cherry-pick
'
+test_expect_success 'checkout-index inside sparse definition' '
+ init_repos &&
+
+ run_on_all rm -f deep/a &&
+ test_all_match git checkout-index -- deep/a &&
+ test_all_match git status --porcelain=v2 &&
+
+ echo test >>new-a &&
+ run_on_all cp ../new-a a &&
+ test_all_match test_must_fail git checkout-index -- a &&
+ test_all_match git checkout-index -f -- a &&
+ test_all_match git status --porcelain=v2
+'
+
+test_expect_success 'checkout-index outside sparse definition' '
+ init_repos &&
+
+ # Without --ignore-skip-worktree-bits, outside-of-cone files will trigger
+ # an error
+ test_sparse_match test_must_fail git checkout-index -- folder1/a &&
+ test_i18ngrep "folder1/a has skip-worktree enabled" sparse-checkout-err &&
+ test_path_is_missing folder1/a &&
+
+ # With --ignore-skip-worktree-bits, outside-of-cone files are checked out
+ test_sparse_match git checkout-index --ignore-skip-worktree-bits -- folder1/a &&
+ test_cmp sparse-checkout/folder1/a sparse-index/folder1/a &&
+ test_cmp sparse-checkout/folder1/a full-checkout/folder1/a &&
+
+ run_on_sparse rm -rf folder1 &&
+ echo test >new-a &&
+ run_on_sparse mkdir -p folder1 &&
+ run_on_all cp ../new-a folder1/a &&
+
+ test_all_match test_must_fail git checkout-index --ignore-skip-worktree-bits -- folder1/a &&
+ test_all_match git checkout-index -f --ignore-skip-worktree-bits -- folder1/a &&
+ test_cmp sparse-checkout/folder1/a sparse-index/folder1/a &&
+ test_cmp sparse-checkout/folder1/a full-checkout/folder1/a
+'
+
+test_expect_success 'checkout-index with folders' '
+ init_repos &&
+
+ # Inside checkout definition
+ test_all_match test_must_fail git checkout-index -f -- deep/ &&
+
+ # Outside checkout definition
+ # Note: although all tests fail (as expected), the messaging differs. For
+ # non-sparse index checkouts, the error is that the "file" does not appear
+ # in the index; for sparse checkouts, the error is explicitly that the
+ # entry is a sparse directory.
+ run_on_all test_must_fail git checkout-index -f -- folder1/ &&
+ test_cmp full-checkout-err sparse-checkout-err &&
+ ! test_cmp full-checkout-err sparse-index-err &&
+ grep "is a sparse directory" sparse-index-err
+'
+
+test_expect_success 'checkout-index --all' '
+ init_repos &&
+
+ test_all_match git checkout-index --all &&
+ test_sparse_match test_path_is_missing folder1 &&
+
+ # --ignore-skip-worktree-bits will cause `skip-worktree` files to be
+ # checked out, causing the outside-of-cone `folder1` to exist on-disk
+ test_all_match git checkout-index --ignore-skip-worktree-bits --all &&
+ test_all_match test_path_exists folder1
+'
+
test_expect_success 'clean' '
init_repos &&
@@ -763,23 +1111,42 @@ test_expect_success 'clean' '
test_all_match git commit -m "ignore bogus files" &&
run_on_sparse mkdir folder1 &&
+ run_on_all mkdir -p deep/untracked-deep &&
run_on_all touch folder1/bogus &&
+ run_on_all touch folder1/untracked &&
+ run_on_all touch deep/untracked-deep/bogus &&
+ run_on_all touch deep/untracked-deep/untracked &&
test_all_match git status --porcelain=v2 &&
test_all_match git clean -f &&
test_all_match git status --porcelain=v2 &&
test_sparse_match ls &&
test_sparse_match ls folder1 &&
+ run_on_all test_path_exists folder1/bogus &&
+ run_on_all test_path_is_missing folder1/untracked &&
+ run_on_all test_path_exists deep/untracked-deep/bogus &&
+ run_on_all test_path_exists deep/untracked-deep/untracked &&
+
+ test_all_match git clean -fd &&
+ test_all_match git status --porcelain=v2 &&
+ test_sparse_match ls &&
+ test_sparse_match ls folder1 &&
+ run_on_all test_path_exists folder1/bogus &&
+ run_on_all test_path_exists deep/untracked-deep/bogus &&
+ run_on_all test_path_is_missing deep/untracked-deep/untracked &&
test_all_match git clean -xf &&
test_all_match git status --porcelain=v2 &&
test_sparse_match ls &&
test_sparse_match ls folder1 &&
+ run_on_all test_path_is_missing folder1/bogus &&
+ run_on_all test_path_exists deep/untracked-deep/bogus &&
test_all_match git clean -xdf &&
test_all_match git status --porcelain=v2 &&
test_sparse_match ls &&
test_sparse_match ls folder1 &&
+ run_on_all test_path_is_missing deep/untracked-deep/bogus &&
test_sparse_match test_path_is_dir folder1
'
@@ -898,6 +1265,8 @@ test_expect_success 'sparse-index is not expanded' '
echo >>sparse-index/untracked.txt &&
ensure_not_expanded add . &&
+ ensure_not_expanded checkout-index -f a &&
+ ensure_not_expanded checkout-index -f --all &&
for ref in update-deep update-folder1 update-folder2 update-deep
do
echo >>sparse-index/README.md &&
@@ -926,6 +1295,8 @@ test_expect_success 'sparse-index is not expanded' '
# Wildcard identifies only full sparse directories, no index expansion
ensure_not_expanded reset deepest -- folder\* &&
+ ensure_not_expanded clean -fd &&
+
ensure_not_expanded checkout -f update-deep &&
test_config -C sparse-index pull.twohead ort &&
(
@@ -1001,6 +1372,24 @@ test_expect_success 'sparse index is not expanded: diff' '
ensure_not_expanded diff --cached
'
+test_expect_success 'sparse index is not expanded: update-index' '
+ init_repos &&
+
+ deep_a_oid=$(git -C full-checkout rev-parse update-deep:deep/a) &&
+ ensure_not_expanded update-index --cacheinfo 100644 $deep_a_oid deep/a &&
+
+ echo "test" >sparse-index/README.md &&
+ echo "test2" >sparse-index/a &&
+ rm -f sparse-index/deep/a &&
+
+ ensure_not_expanded update-index --add README.md &&
+ ensure_not_expanded update-index a &&
+ ensure_not_expanded update-index --remove deep/a &&
+
+ ensure_not_expanded reset --soft update-deep &&
+ ensure_not_expanded update-index --add --remove --again
+'
+
test_expect_success 'sparse index is not expanded: blame' '
init_repos &&
@@ -1023,6 +1412,27 @@ test_expect_success 'sparse index is not expanded: fetch/pull' '
ensure_not_expanded pull full base
'
+test_expect_success 'sparse index is not expanded: read-tree' '
+ init_repos &&
+
+ ensure_not_expanded checkout -b test-branch update-folder1 &&
+ for MERGE_TREES in "base HEAD update-folder2" \
+ "base HEAD rename-base" \
+ "base update-folder2" \
+ "base rename-base" \
+ "update-folder2"
+ do
+ ensure_not_expanded read-tree -mu $MERGE_TREES &&
+ ensure_not_expanded reset --hard || return 1
+ done &&
+
+ rm -rf sparse-index/deep/deeper2 &&
+ ensure_not_expanded add . &&
+ ensure_not_expanded commit -m "test" &&
+
+ ensure_not_expanded read-tree --prefix=deep/deeper2 -u deepest
+'
+
test_expect_success 'ls-files' '
init_repos &&
@@ -1037,6 +1447,7 @@ test_expect_success 'ls-files' '
cat >expect <<-\EOF &&
a
+ before/
deep/
e
folder1-
@@ -1057,36 +1468,34 @@ test_expect_success 'ls-files' '
test_cmp dense sparse &&
# Set up a strange condition of having a file edit
- # outside of the sparse-checkout cone. This is just
- # to verify that sparse-checkout and sparse-index
- # behave the same in this case.
+ # outside of the sparse-checkout cone. We want to verify
+ # that all modes handle this the same, and detect the
+ # modification.
write_script edit-content <<-\EOF &&
- mkdir folder1 &&
+ mkdir -p folder1 &&
echo content >>folder1/a
EOF
- run_on_sparse ../edit-content &&
+ run_on_all ../edit-content &&
- # ls-files does not currently notice modified files whose
- # cache entries are marked SKIP_WORKTREE. This may change
- # in the future, but here we test that sparse index does
- # not accidentally create a change of behavior.
- test_sparse_match git ls-files --modified &&
- test_must_be_empty sparse-checkout-out &&
- test_must_be_empty sparse-index-out &&
+ test_all_match git ls-files --modified &&
git -C sparse-index ls-files --sparse --modified >sparse-index-out &&
- test_must_be_empty sparse-index-out &&
+ cat >expect <<-\EOF &&
+ folder1/a
+ EOF
+ test_cmp expect sparse-index-out &&
# Add folder1 to the sparse-checkout cone and
# check that ls-files shows the expanded files.
test_sparse_match git sparse-checkout add folder1 &&
- test_sparse_match git ls-files --modified &&
+ test_all_match git ls-files --modified &&
test_all_match git ls-files &&
git -C sparse-index ls-files --sparse >actual &&
cat >expect <<-\EOF &&
a
+ before/
deep/
e
folder1-
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 78359f1..7dd9b32 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -2388,4 +2388,122 @@ test_expect_success '--get and --get-all with --fixed-value' '
test_must_fail git config --file=config --get-regexp --fixed-value fixed+ non-existent
'
+test_expect_success 'includeIf.hasconfig:remote.*.url' '
+ git init hasremoteurlTest &&
+ test_when_finished "rm -rf hasremoteurlTest" &&
+
+ cat >include-this <<-\EOF &&
+ [user]
+ this = this-is-included
+ EOF
+ cat >dont-include-that <<-\EOF &&
+ [user]
+ that = that-is-not-included
+ EOF
+ cat >>hasremoteurlTest/.git/config <<-EOF &&
+ [includeIf "hasconfig:remote.*.url:foourl"]
+ path = "$(pwd)/include-this"
+ [includeIf "hasconfig:remote.*.url:barurl"]
+ path = "$(pwd)/dont-include-that"
+ [remote "foo"]
+ url = foourl
+ EOF
+
+ echo this-is-included >expect-this &&
+ git -C hasremoteurlTest config --get user.this >actual-this &&
+ test_cmp expect-this actual-this &&
+
+ test_must_fail git -C hasremoteurlTest config --get user.that
+'
+
+test_expect_success 'includeIf.hasconfig:remote.*.url respects last-config-wins' '
+ git init hasremoteurlTest &&
+ test_when_finished "rm -rf hasremoteurlTest" &&
+
+ cat >include-two-three <<-\EOF &&
+ [user]
+ two = included-config
+ three = included-config
+ EOF
+ cat >>hasremoteurlTest/.git/config <<-EOF &&
+ [remote "foo"]
+ url = foourl
+ [user]
+ one = main-config
+ two = main-config
+ [includeIf "hasconfig:remote.*.url:foourl"]
+ path = "$(pwd)/include-two-three"
+ [user]
+ three = main-config
+ EOF
+
+ echo main-config >expect-main-config &&
+ echo included-config >expect-included-config &&
+
+ git -C hasremoteurlTest config --get user.one >actual &&
+ test_cmp expect-main-config actual &&
+
+ git -C hasremoteurlTest config --get user.two >actual &&
+ test_cmp expect-included-config actual &&
+
+ git -C hasremoteurlTest config --get user.three >actual &&
+ test_cmp expect-main-config actual
+'
+
+test_expect_success 'includeIf.hasconfig:remote.*.url globs' '
+ git init hasremoteurlTest &&
+ test_when_finished "rm -rf hasremoteurlTest" &&
+
+ printf "[user]\ndss = yes\n" >double-star-start &&
+ printf "[user]\ndse = yes\n" >double-star-end &&
+ printf "[user]\ndsm = yes\n" >double-star-middle &&
+ printf "[user]\nssm = yes\n" >single-star-middle &&
+ printf "[user]\nno = no\n" >no &&
+
+ cat >>hasremoteurlTest/.git/config <<-EOF &&
+ [remote "foo"]
+ url = https://foo/bar/baz
+ [includeIf "hasconfig:remote.*.url:**/baz"]
+ path = "$(pwd)/double-star-start"
+ [includeIf "hasconfig:remote.*.url:**/nomatch"]
+ path = "$(pwd)/no"
+ [includeIf "hasconfig:remote.*.url:https:/**"]
+ path = "$(pwd)/double-star-end"
+ [includeIf "hasconfig:remote.*.url:nomatch:/**"]
+ path = "$(pwd)/no"
+ [includeIf "hasconfig:remote.*.url:https:/**/baz"]
+ path = "$(pwd)/double-star-middle"
+ [includeIf "hasconfig:remote.*.url:https:/**/nomatch"]
+ path = "$(pwd)/no"
+ [includeIf "hasconfig:remote.*.url:https://*/bar/baz"]
+ path = "$(pwd)/single-star-middle"
+ [includeIf "hasconfig:remote.*.url:https://*/baz"]
+ path = "$(pwd)/no"
+ EOF
+
+ git -C hasremoteurlTest config --get user.dss &&
+ git -C hasremoteurlTest config --get user.dse &&
+ git -C hasremoteurlTest config --get user.dsm &&
+ git -C hasremoteurlTest config --get user.ssm &&
+ test_must_fail git -C hasremoteurlTest config --get user.no
+'
+
+test_expect_success 'includeIf.hasconfig:remote.*.url forbids remote url in such included files' '
+ git init hasremoteurlTest &&
+ test_when_finished "rm -rf hasremoteurlTest" &&
+
+ cat >include-with-url <<-\EOF &&
+ [remote "bar"]
+ url = barurl
+ EOF
+ cat >>hasremoteurlTest/.git/config <<-EOF &&
+ [includeIf "hasconfig:remote.*.url:foourl"]
+ path = "$(pwd)/include-with-url"
+ EOF
+
+ # test with any Git command
+ test_must_fail git -C hasremoteurlTest status 2>err &&
+ grep "fatal: remote URLs cannot be configured in file directly or indirectly included by includeIf.hasconfig:remote.*.url" err
+'
+
test_done
diff --git a/t/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh
index fa9647a..f6dc83e 100755
--- a/t/t1350-config-hooks-path.sh
+++ b/t/t1350-config-hooks-path.sh
@@ -6,11 +6,11 @@ test_description='Test the core.hooksPath configuration variable'
test_expect_success 'set up a pre-commit hook in core.hooksPath' '
>actual &&
- mkdir -p .git/custom-hooks .git/hooks &&
+ mkdir -p .git/custom-hooks &&
write_script .git/custom-hooks/pre-commit <<-\EOF &&
echo CUSTOM >>actual
EOF
- write_script .git/hooks/pre-commit <<-\EOF
+ test_hook --setup pre-commit <<-\EOF
echo NORMAL >>actual
EOF
'
diff --git a/t/t1405-main-ref-store.sh b/t/t1405-main-ref-store.sh
index 1a3ee88..51f8291 100755
--- a/t/t1405-main-ref-store.sh
+++ b/t/t1405-main-ref-store.sh
@@ -40,6 +40,12 @@ test_expect_success 'delete_refs(FOO, refs/tags/new-tag)' '
test_must_fail git rev-parse refs/tags/new-tag --
'
+# In reftable, we keep the reflogs around for deleted refs.
+test_expect_success !REFFILES 'delete-reflog(FOO, refs/tags/new-tag)' '
+ $RUN delete-reflog FOO &&
+ $RUN delete-reflog refs/tags/new-tag
+'
+
test_expect_success 'rename_refs(main, new-main)' '
git rev-parse main >expected &&
$RUN rename-ref refs/heads/main refs/heads/new-main &&
@@ -105,7 +111,7 @@ test_expect_success 'delete_reflog(HEAD)' '
test_must_fail git reflog exists HEAD
'
-test_expect_success 'create-reflog(HEAD)' '
+test_expect_success REFFILES 'create-reflog(HEAD)' '
$RUN create-reflog HEAD &&
git reflog exists HEAD
'
diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh
index d7ddf76..aa59954 100755
--- a/t/t1410-reflog.sh
+++ b/t/t1410-reflog.sh
@@ -106,6 +106,28 @@ test_expect_success setup '
test_line_count = 4 output
'
+test_expect_success 'correct usage on sub-command -h' '
+ test_expect_code 129 git reflog expire -h >err &&
+ grep "git reflog expire" err
+'
+
+test_expect_success 'correct usage on "git reflog show -h"' '
+ test_expect_code 129 git reflog show -h >err &&
+ grep -F "git reflog [show]" err
+'
+
+test_expect_success 'pass through -- to sub-command' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_commit -C repo message --a-file contents dash-tag &&
+
+ git -C repo reflog show -- --does-not-exist >out &&
+ test_must_be_empty out &&
+ git -C repo reflog show >expect &&
+ git -C repo reflog show -- --a-file >actual &&
+ test_cmp expect actual
+'
+
test_expect_success rewind '
test_tick && git reset --hard HEAD~2 &&
test -f C &&
@@ -341,7 +363,7 @@ test_expect_success 'stale dirs do not cause d/f conflicts (reflogs off)' '
# Each line is 114 characters, so we need 75 to still have a few before the
# last 8K. The 89-character padding on the final entry lines up our
# newline exactly.
-test_expect_success SHA1 'parsing reverse reflogs at BUFSIZ boundaries' '
+test_expect_success REFFILES,SHA1 'parsing reverse reflogs at BUFSIZ boundaries' '
git checkout -b reflogskip &&
zf=$(test_oid zero_2) &&
ident="abc <xyz> 0000000001 +0000" &&
@@ -418,8 +440,18 @@ test_expect_success 'expire with multiple worktrees' '
test_commit -C link-wt foobar &&
test_tick &&
git reflog expire --verbose --all --expire=$test_tick &&
- test_must_be_empty .git/worktrees/link-wt/logs/HEAD
+ test-tool ref-store worktree:link-wt for-each-reflog-ent HEAD >actual &&
+ test_must_be_empty actual
)
'
+test_expect_success REFFILES 'empty reflog' '
+ test_when_finished "rm -rf empty" &&
+ git init empty &&
+ test_commit -C empty A &&
+ >empty/.git/logs/refs/heads/foo &&
+ git -C empty reflog expire --all 2>err &&
+ test_must_be_empty err
+'
+
test_done
diff --git a/t/t1411-reflog-show.sh b/t/t1411-reflog-show.sh
index 0bb319b..975c4ea 100755
--- a/t/t1411-reflog-show.sh
+++ b/t/t1411-reflog-show.sh
@@ -169,9 +169,4 @@ test_expect_success 'git log -g -p shows diffs vs. parents' '
test_cmp expect actual
'
-test_expect_success 'reflog exists works' '
- git reflog exists refs/heads/main &&
- ! git reflog exists refs/heads/nonexistent
-'
-
test_done
diff --git a/t/t1416-ref-transaction-hooks.sh b/t/t1416-ref-transaction-hooks.sh
index 6c94102..085a7a4 100755
--- a/t/t1416-ref-transaction-hooks.sh
+++ b/t/t1416-ref-transaction-hooks.sh
@@ -8,7 +8,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
test_expect_success setup '
- mkdir -p .git/hooks &&
test_commit PRE &&
PRE_OID=$(git rev-parse PRE) &&
test_commit POST &&
@@ -16,9 +15,8 @@ test_expect_success setup '
'
test_expect_success 'hook allows updating ref if successful' '
- test_when_finished "rm .git/hooks/reference-transaction" &&
git reset --hard PRE &&
- write_script .git/hooks/reference-transaction <<-\EOF &&
+ test_hook reference-transaction <<-\EOF &&
echo "$*" >>actual
EOF
cat >expect <<-EOF &&
@@ -30,9 +28,8 @@ test_expect_success 'hook allows updating ref if successful' '
'
test_expect_success 'hook aborts updating ref in prepared state' '
- test_when_finished "rm .git/hooks/reference-transaction" &&
git reset --hard PRE &&
- write_script .git/hooks/reference-transaction <<-\EOF &&
+ test_hook reference-transaction <<-\EOF &&
if test "$1" = prepared
then
exit 1
@@ -43,9 +40,9 @@ test_expect_success 'hook aborts updating ref in prepared state' '
'
test_expect_success 'hook gets all queued updates in prepared state' '
- test_when_finished "rm .git/hooks/reference-transaction actual" &&
+ test_when_finished "rm actual" &&
git reset --hard PRE &&
- write_script .git/hooks/reference-transaction <<-\EOF &&
+ test_hook reference-transaction <<-\EOF &&
if test "$1" = prepared
then
while read -r line
@@ -66,9 +63,9 @@ test_expect_success 'hook gets all queued updates in prepared state' '
'
test_expect_success 'hook gets all queued updates in committed state' '
- test_when_finished "rm .git/hooks/reference-transaction actual" &&
+ test_when_finished "rm actual" &&
git reset --hard PRE &&
- write_script .git/hooks/reference-transaction <<-\EOF &&
+ test_hook reference-transaction <<-\EOF &&
if test "$1" = committed
then
while read -r line
@@ -86,9 +83,9 @@ test_expect_success 'hook gets all queued updates in committed state' '
'
test_expect_success 'hook gets all queued updates in aborted state' '
- test_when_finished "rm .git/hooks/reference-transaction actual" &&
+ test_when_finished "rm actual" &&
git reset --hard PRE &&
- write_script .git/hooks/reference-transaction <<-\EOF &&
+ test_hook reference-transaction <<-\EOF &&
if test "$1" = aborted
then
while read -r line
@@ -115,11 +112,11 @@ test_expect_success 'interleaving hook calls succeed' '
git init --bare target-repo.git &&
- write_script target-repo.git/hooks/reference-transaction <<-\EOF &&
+ test_hook -C target-repo.git reference-transaction <<-\EOF &&
echo $0 "$@" >>actual
EOF
- write_script target-repo.git/hooks/update <<-\EOF &&
+ test_hook -C target-repo.git update <<-\EOF &&
echo $0 "$@" >>actual
EOF
@@ -136,4 +133,54 @@ test_expect_success 'interleaving hook calls succeed' '
test_cmp expect target-repo.git/actual
'
+test_expect_success 'hook does not get called on packing refs' '
+ # Pack references first such that we are in a known state.
+ git pack-refs --all &&
+
+ test_hook reference-transaction <<-\EOF &&
+ echo "$@" >>actual
+ cat >>actual
+ EOF
+ rm -f actual &&
+
+ git update-ref refs/heads/unpacked-ref $POST_OID &&
+ git pack-refs --all &&
+
+ # We only expect a single hook invocation, which is the call to
+ # git-update-ref(1).
+ cat >expect <<-EOF &&
+ prepared
+ $ZERO_OID $POST_OID refs/heads/unpacked-ref
+ committed
+ $ZERO_OID $POST_OID refs/heads/unpacked-ref
+ EOF
+
+ test_cmp expect actual
+'
+
+test_expect_success 'deleting packed ref calls hook once' '
+ # Create a reference and pack it.
+ git update-ref refs/heads/to-be-deleted $POST_OID &&
+ git pack-refs --all &&
+
+ test_hook reference-transaction <<-\EOF &&
+ echo "$@" >>actual
+ cat >>actual
+ EOF
+ rm -f actual &&
+
+ git update-ref -d refs/heads/to-be-deleted $POST_OID &&
+
+ # We only expect a single hook invocation, which is the logical
+ # deletion.
+ cat >expect <<-EOF &&
+ prepared
+ $POST_OID $ZERO_OID refs/heads/to-be-deleted
+ committed
+ $POST_OID $ZERO_OID refs/heads/to-be-deleted
+ EOF
+
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t1418-reflog-exists.sh b/t/t1418-reflog-exists.sh
new file mode 100755
index 0000000..d51ecd5
--- /dev/null
+++ b/t/t1418-reflog-exists.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+test_description='Test reflog display routines'
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ test_commit A
+'
+
+test_expect_success 'usage' '
+ test_expect_code 129 git reflog exists &&
+ test_expect_code 129 git reflog exists -h
+'
+
+test_expect_success 'usage: unknown option' '
+ test_expect_code 129 git reflog exists --unknown-option
+'
+
+test_expect_success 'reflog exists works' '
+ git reflog exists refs/heads/main &&
+ test_must_fail git reflog exists refs/heads/nonexistent
+'
+
+test_expect_success 'reflog exists works with a "--" delimiter' '
+ git reflog exists -- refs/heads/main &&
+ test_must_fail git reflog exists -- refs/heads/nonexistent
+'
+
+test_expect_success 'reflog exists works with a "--end-of-options" delimiter' '
+ git reflog exists --end-of-options refs/heads/main &&
+ test_must_fail git reflog exists --end-of-options refs/heads/nonexistent
+'
+
+test_done
diff --git a/t/t1503-rev-parse-verify.sh b/t/t1503-rev-parse-verify.sh
index 94fe413..ba43168 100755
--- a/t/t1503-rev-parse-verify.sh
+++ b/t/t1503-rev-parse-verify.sh
@@ -132,8 +132,9 @@ test_expect_success 'use --default' '
test_must_fail git rev-parse --verify --default bar
'
-test_expect_success 'main@{n} for various n' '
- N=$(git reflog | wc -l) &&
+test_expect_success !SANITIZE_LEAK 'main@{n} for various n' '
+ git reflog >out &&
+ N=$(wc -l <out) &&
Nm1=$(($N-1)) &&
Np1=$(($N+1)) &&
git rev-parse --verify main@{0} &&
diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh
index b0119bf..98cefe3 100755
--- a/t/t1512-rev-parse-disambiguation.sh
+++ b/t/t1512-rev-parse-disambiguation.sh
@@ -25,6 +25,87 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
+test_cmp_failed_rev_parse () {
+ dir=$1
+ rev=$2
+
+ cat >expect &&
+ test_must_fail git -C "$dir" rev-parse "$rev" 2>actual.raw &&
+ sed "s/\($rev\)[0-9a-f]*/\1.../" <actual.raw >actual &&
+ test_cmp expect actual
+}
+
+test_expect_success 'ambiguous blob output' '
+ git init --bare blob.prefix &&
+ (
+ cd blob.prefix &&
+
+ # Both start with "dead..", under both SHA-1 and SHA-256
+ echo brocdnra | git hash-object -w --stdin &&
+ echo brigddsv | git hash-object -w --stdin &&
+
+ # Both start with "beef.."
+ echo 1agllotbh | git hash-object -w --stdin &&
+ echo 1bbfctrkc | git hash-object -w --stdin
+ ) &&
+
+ test_must_fail git -C blob.prefix rev-parse dead &&
+ test_cmp_failed_rev_parse blob.prefix beef <<-\EOF
+ error: short object ID beef... is ambiguous
+ hint: The candidates are:
+ hint: beef... blob
+ hint: beef... blob
+ fatal: ambiguous argument '\''beef...'\'': unknown revision or path not in the working tree.
+ Use '\''--'\'' to separate paths from revisions, like this:
+ '\''git <command> [<revision>...] -- [<file>...]'\''
+ EOF
+'
+
+test_expect_success 'ambiguous loose bad object parsed as OBJ_BAD' '
+ git init --bare blob.bad &&
+ (
+ cd blob.bad &&
+
+ # Both have the prefix "bad0"
+ echo xyzfaowcoh | git hash-object -t bad -w --stdin --literally &&
+ echo xyzhjpyvwl | git hash-object -t bad -w --stdin --literally
+ ) &&
+
+ test_cmp_failed_rev_parse blob.bad bad0 <<-\EOF
+ error: short object ID bad0... is ambiguous
+ fatal: invalid object type
+ EOF
+'
+
+test_expect_success POSIXPERM 'ambigous zlib corrupt loose blob' '
+ git init --bare blob.corrupt &&
+ (
+ cd blob.corrupt &&
+
+ # Both have the prefix "cafe"
+ echo bnkxmdwz | git hash-object -w --stdin &&
+ oid=$(echo bmwsjxzi | git hash-object -w --stdin) &&
+
+ oidf=objects/$(test_oid_to_path "$oid") &&
+ chmod 755 $oidf &&
+ echo broken >$oidf
+ ) &&
+
+ test_cmp_failed_rev_parse blob.corrupt cafe <<-\EOF
+ error: short object ID cafe... is ambiguous
+ error: inflate: data stream error (incorrect header check)
+ error: unable to unpack cafe... header
+ error: inflate: data stream error (incorrect header check)
+ error: unable to unpack cafe... header
+ hint: The candidates are:
+ hint: cafe... [bad object]
+ hint: cafe... blob
+ fatal: ambiguous argument '\''cafe...'\'': unknown revision or path not in the working tree.
+ Use '\''--'\'' to separate paths from revisions, like this:
+ '\''git <command> [<revision>...] -- [<file>...]'\''
+ EOF
+'
+
if ! test_have_prereq SHA1
then
skip_all='not using SHA-1 for objects'
diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh
new file mode 100755
index 0000000..26ed5e1
--- /dev/null
+++ b/t/t1800-hook.sh
@@ -0,0 +1,123 @@
+#!/bin/sh
+
+test_description='git-hook command'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+test_expect_success 'git hook usage' '
+ test_expect_code 129 git hook &&
+ test_expect_code 129 git hook run &&
+ test_expect_code 129 git hook run -h &&
+ test_expect_code 129 git hook run --unknown 2>err &&
+ grep "unknown option" err
+'
+
+test_expect_success 'git hook run: nonexistent hook' '
+ cat >stderr.expect <<-\EOF &&
+ error: cannot find a hook named test-hook
+ EOF
+ test_expect_code 1 git hook run test-hook 2>stderr.actual &&
+ test_cmp stderr.expect stderr.actual
+'
+
+test_expect_success 'git hook run: nonexistent hook with --ignore-missing' '
+ git hook run --ignore-missing does-not-exist 2>stderr.actual &&
+ test_must_be_empty stderr.actual
+'
+
+test_expect_success 'git hook run: basic' '
+ test_hook test-hook <<-EOF &&
+ echo Test hook
+ EOF
+
+ cat >expect <<-\EOF &&
+ Test hook
+ EOF
+ git hook run test-hook 2>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git hook run: stdout and stderr both write to our stderr' '
+ test_hook test-hook <<-EOF &&
+ echo >&1 Will end up on stderr
+ echo >&2 Will end up on stderr
+ EOF
+
+ cat >stderr.expect <<-\EOF &&
+ Will end up on stderr
+ Will end up on stderr
+ EOF
+ git hook run test-hook >stdout.actual 2>stderr.actual &&
+ test_cmp stderr.expect stderr.actual &&
+ test_must_be_empty stdout.actual
+'
+
+for code in 1 2 128 129
+do
+ test_expect_success "git hook run: exit code $code is passed along" '
+ test_hook test-hook <<-EOF &&
+ exit $code
+ EOF
+
+ test_expect_code $code git hook run test-hook
+ '
+done
+
+test_expect_success 'git hook run arg u ments without -- is not allowed' '
+ test_expect_code 129 git hook run test-hook arg u ments
+'
+
+test_expect_success 'git hook run -- pass arguments' '
+ test_hook test-hook <<-\EOF &&
+ echo $1
+ echo $2
+ EOF
+
+ cat >expect <<-EOF &&
+ arg
+ u ments
+ EOF
+
+ git hook run test-hook -- arg "u ments" 2>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git hook run -- out-of-repo runs excluded' '
+ test_hook test-hook <<-EOF &&
+ echo Test hook
+ EOF
+
+ nongit test_must_fail git hook run test-hook
+'
+
+test_expect_success 'git -c core.hooksPath=<PATH> hook run' '
+ mkdir my-hooks &&
+ write_script my-hooks/test-hook <<-\EOF &&
+ echo Hook ran $1 >>actual
+ EOF
+
+ cat >expect <<-\EOF &&
+ Test hook
+ Hook ran one
+ Hook ran two
+ Hook ran three
+ Hook ran four
+ EOF
+
+ test_hook test-hook <<-EOF &&
+ echo Test hook
+ EOF
+
+ # Test various ways of specifying the path. See also
+ # t1350-config-hooks-path.sh
+ >actual &&
+ git hook run test-hook -- ignored 2>>actual &&
+ git -c core.hooksPath=my-hooks hook run test-hook -- one 2>>actual &&
+ git -c core.hooksPath=my-hooks/ hook run test-hook -- two 2>>actual &&
+ git -c core.hooksPath="$PWD/my-hooks" hook run test-hook -- three 2>>actual &&
+ git -c core.hooksPath="$PWD/my-hooks/" hook run test-hook -- four 2>>actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t2012-checkout-last.sh b/t/t2012-checkout-last.sh
index 42601d5..1f6c4ed 100755
--- a/t/t2012-checkout-last.sh
+++ b/t/t2012-checkout-last.sh
@@ -21,14 +21,20 @@ test_expect_success 'first branch switch' '
git checkout other
'
+test_cmp_symbolic_HEAD_ref () {
+ echo refs/heads/"$1" >expect &&
+ git symbolic-ref HEAD >actual &&
+ test_cmp expect actual
+}
+
test_expect_success '"checkout -" switches back' '
git checkout - &&
- test "z$(git symbolic-ref HEAD)" = "zrefs/heads/main"
+ test_cmp_symbolic_HEAD_ref main
'
test_expect_success '"checkout -" switches forth' '
git checkout - &&
- test "z$(git symbolic-ref HEAD)" = "zrefs/heads/other"
+ test_cmp_symbolic_HEAD_ref other
'
test_expect_success 'detach HEAD' '
@@ -37,12 +43,16 @@ test_expect_success 'detach HEAD' '
test_expect_success '"checkout -" attaches again' '
git checkout - &&
- test "z$(git symbolic-ref HEAD)" = "zrefs/heads/other"
+ test_cmp_symbolic_HEAD_ref other
'
test_expect_success '"checkout -" detaches again' '
git checkout - &&
- test "z$(git rev-parse HEAD)" = "z$(git rev-parse other)" &&
+
+ git rev-parse other >expect &&
+ git rev-parse HEAD >actual &&
+ test_cmp expect actual &&
+
test_must_fail git symbolic-ref HEAD
'
@@ -63,31 +73,31 @@ more_switches () {
test_expect_success 'switch to the last' '
more_switches &&
git checkout @{-1} &&
- test "z$(git symbolic-ref HEAD)" = "zrefs/heads/branch2"
+ test_cmp_symbolic_HEAD_ref branch2
'
test_expect_success 'switch to second from the last' '
more_switches &&
git checkout @{-2} &&
- test "z$(git symbolic-ref HEAD)" = "zrefs/heads/branch3"
+ test_cmp_symbolic_HEAD_ref branch3
'
test_expect_success 'switch to third from the last' '
more_switches &&
git checkout @{-3} &&
- test "z$(git symbolic-ref HEAD)" = "zrefs/heads/branch4"
+ test_cmp_symbolic_HEAD_ref branch4
'
test_expect_success 'switch to fourth from the last' '
more_switches &&
git checkout @{-4} &&
- test "z$(git symbolic-ref HEAD)" = "zrefs/heads/branch5"
+ test_cmp_symbolic_HEAD_ref branch5
'
test_expect_success 'switch to twelfth from the last' '
more_switches &&
git checkout @{-12} &&
- test "z$(git symbolic-ref HEAD)" = "zrefs/heads/branch13"
+ test_cmp_symbolic_HEAD_ref branch13
'
test_expect_success 'merge base test setup' '
@@ -98,19 +108,28 @@ test_expect_success 'merge base test setup' '
test_expect_success 'another...main' '
git checkout another &&
git checkout another...main &&
- test "z$(git rev-parse --verify HEAD)" = "z$(git rev-parse --verify main^)"
+
+ git rev-parse --verify main^ >expect &&
+ git rev-parse --verify HEAD >actual &&
+ test_cmp expect actual
'
test_expect_success '...main' '
git checkout another &&
git checkout ...main &&
- test "z$(git rev-parse --verify HEAD)" = "z$(git rev-parse --verify main^)"
+
+ git rev-parse --verify main^ >expect &&
+ git rev-parse --verify HEAD >actual &&
+ test_cmp expect actual
'
test_expect_success 'main...' '
git checkout another &&
git checkout main... &&
- test "z$(git rev-parse --verify HEAD)" = "z$(git rev-parse --verify main^)"
+
+ git rev-parse --verify main^ >expect &&
+ git rev-parse --verify HEAD >actual &&
+ test_cmp expect actual
'
test_expect_success '"checkout -" works after a rebase A' '
@@ -118,7 +137,7 @@ test_expect_success '"checkout -" works after a rebase A' '
git checkout other &&
git rebase main &&
git checkout - &&
- test "z$(git symbolic-ref HEAD)" = "zrefs/heads/main"
+ test_cmp_symbolic_HEAD_ref main
'
test_expect_success '"checkout -" works after a rebase A B' '
@@ -127,7 +146,7 @@ test_expect_success '"checkout -" works after a rebase A B' '
git checkout other &&
git rebase main moodle &&
git checkout - &&
- test "z$(git symbolic-ref HEAD)" = "zrefs/heads/main"
+ test_cmp_symbolic_HEAD_ref main
'
test_expect_success '"checkout -" works after a rebase -i A' '
@@ -135,7 +154,7 @@ test_expect_success '"checkout -" works after a rebase -i A' '
git checkout other &&
git rebase -i main &&
git checkout - &&
- test "z$(git symbolic-ref HEAD)" = "zrefs/heads/main"
+ test_cmp_symbolic_HEAD_ref main
'
test_expect_success '"checkout -" works after a rebase -i A B' '
@@ -144,7 +163,7 @@ test_expect_success '"checkout -" works after a rebase -i A B' '
git checkout other &&
git rebase main foodle &&
git checkout - &&
- test "z$(git symbolic-ref HEAD)" = "zrefs/heads/main"
+ test_cmp_symbolic_HEAD_ref main
'
test_done
diff --git a/t/t2060-switch.sh b/t/t2060-switch.sh
index ebb961b..5a7caf9 100755
--- a/t/t2060-switch.sh
+++ b/t/t2060-switch.sh
@@ -32,6 +32,17 @@ test_expect_success 'switch and detach' '
test_must_fail git symbolic-ref HEAD
'
+test_expect_success 'suggestion to detach' '
+ test_must_fail git switch main^{commit} 2>stderr &&
+ grep "try again with the --detach option" stderr
+'
+
+test_expect_success 'suggestion to detach is suppressed with advice.suggestDetachingHead=false' '
+ test_config advice.suggestDetachingHead false &&
+ test_must_fail git switch main^{commit} 2>stderr &&
+ ! grep "try again with the --detach option" stderr
+'
+
test_expect_success 'switch and detach current branch' '
test_when_finished git switch main &&
git switch main &&
diff --git a/t/t2108-update-index-refresh-racy.sh b/t/t2108-update-index-refresh-racy.sh
new file mode 100755
index 0000000..bc5f288
--- /dev/null
+++ b/t/t2108-update-index-refresh-racy.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+test_description='update-index refresh tests related to racy timestamps'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+reset_files () {
+ echo content >file &&
+ echo content >other &&
+ test_set_magic_mtime file &&
+ test_set_magic_mtime other
+}
+
+update_assert_changed () {
+ test_set_magic_mtime .git/index &&
+ test_might_fail git update-index "$1" &&
+ ! test_is_magic_mtime .git/index
+}
+
+test_expect_success 'setup' '
+ reset_files &&
+ # we are calling reset_files() a couple of times during tests;
+ # test-tool chmtime does not change the ctime; to not weaken
+ # or even break our tests, disable ctime-checks entirely
+ git config core.trustctime false &&
+ git add file other &&
+ git commit -m "initial import"
+'
+
+test_expect_success '--refresh has no racy timestamps to fix' '
+ reset_files &&
+ # set the index time far enough to the future;
+ # it must be at least 3 seconds for VFAT
+ test_set_magic_mtime .git/index +60 &&
+ git update-index --refresh &&
+ test_is_magic_mtime .git/index +60
+'
+
+test_expect_success '--refresh should fix racy timestamp' '
+ reset_files &&
+ update_assert_changed --refresh
+'
+
+test_expect_success '--really-refresh should fix racy timestamp' '
+ reset_files &&
+ update_assert_changed --really-refresh
+'
+
+test_expect_success '--refresh should fix racy timestamp if other file needs update' '
+ reset_files &&
+ echo content2 >other &&
+ test_set_magic_mtime other &&
+ update_assert_changed --refresh
+'
+
+test_expect_success '--refresh should fix racy timestamp if racy file needs update' '
+ reset_files &&
+ echo content2 >file &&
+ test_set_magic_mtime file &&
+ update_assert_changed --refresh
+'
+
+test_done
diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh
index acd3650..0c38f8e 100755
--- a/t/t2200-add-update.sh
+++ b/t/t2200-add-update.sh
@@ -14,7 +14,6 @@ only the updates to dir/sub.
Also tested are "git add -u" without limiting, and "git add -u"
without contents changes, and other conditions'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
@@ -41,20 +40,28 @@ test_expect_success update '
'
test_expect_success 'update noticed a removal' '
- test "$(git ls-files dir1/sub1)" = ""
+ git ls-files dir1/sub1 >out &&
+ test_must_be_empty out
'
test_expect_success 'update touched correct path' '
- test "$(git diff-files --name-status dir2/sub3)" = ""
+ git diff-files --name-status dir2/sub3 >out &&
+ test_must_be_empty out
'
test_expect_success 'update did not touch other tracked files' '
- test "$(git diff-files --name-status check)" = "M check" &&
- test "$(git diff-files --name-status top)" = "M top"
+ echo "M check" >expect &&
+ git diff-files --name-status check >actual &&
+ test_cmp expect actual &&
+
+ echo "M top" >expect &&
+ git diff-files --name-status top >actual &&
+ test_cmp expect actual
'
test_expect_success 'update did not touch untracked files' '
- test "$(git ls-files dir2/other)" = ""
+ git ls-files dir2/other >out &&
+ test_must_be_empty out
'
test_expect_success 'cache tree has not been corrupted' '
@@ -76,9 +83,8 @@ test_expect_success 'update from a subdirectory' '
'
test_expect_success 'change gets noticed' '
-
- test "$(git diff-files --name-status dir1)" = ""
-
+ git diff-files --name-status dir1 >out &&
+ test_must_be_empty out
'
test_expect_success 'non-qualified update in subdir updates from the root' '
@@ -103,7 +109,8 @@ test_expect_success 'replace a file with a symlink' '
test_expect_success 'add everything changed' '
git add -u &&
- test -z "$(git diff-files)"
+ git diff-files >out &&
+ test_must_be_empty out
'
@@ -111,7 +118,8 @@ test_expect_success 'touch and then add -u' '
touch check &&
git add -u &&
- test -z "$(git diff-files)"
+ git diff-files >out &&
+ test_must_be_empty out
'
@@ -119,7 +127,8 @@ test_expect_success 'touch and then add explicitly' '
touch check &&
git add check &&
- test -z "$(git diff-files)"
+ git diff-files >out &&
+ test_must_be_empty out
'
diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh
index 37ad794..2f564d5 100755
--- a/t/t2400-worktree-add.sh
+++ b/t/t2400-worktree-add.sh
@@ -165,8 +165,62 @@ test_expect_success '"add" default branch of a bare repo' '
(
git clone --bare . bare2 &&
cd bare2 &&
- git worktree add ../there3 main
- )
+ git worktree add ../there3 main &&
+ cd ../there3 &&
+ # Simple check that a Git command does not
+ # immediately fail with the current setup
+ git status
+ ) &&
+ cat >expect <<-EOF &&
+ init.t
+ EOF
+ ls there3 >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '"add" to bare repo with worktree config' '
+ (
+ git clone --bare . bare3 &&
+ cd bare3 &&
+ git config extensions.worktreeconfig true &&
+
+ # Add config values that are erroneous to have in
+ # a config.worktree file outside of the main
+ # working tree, to check that Git filters them out
+ # when copying config during "git worktree add".
+ git config --worktree core.bare true &&
+ git config --worktree core.worktree "$(pwd)" &&
+
+ # We want to check that bogus.key is copied
+ git config --worktree bogus.key value &&
+ git config --unset core.bare &&
+ git worktree add ../there4 main &&
+ cd ../there4 &&
+
+ # Simple check that a Git command does not
+ # immediately fail with the current setup
+ git status &&
+ git worktree add --detach ../there5 &&
+ cd ../there5 &&
+ git status
+ ) &&
+
+ # the worktree has the arbitrary value copied.
+ test_cmp_config -C there4 value bogus.key &&
+ test_cmp_config -C there5 value bogus.key &&
+
+ # however, core.bare and core.worktree were removed.
+ test_must_fail git -C there4 config core.bare &&
+ test_must_fail git -C there4 config core.worktree &&
+
+ cat >expect <<-EOF &&
+ init.t
+ EOF
+
+ ls there4 >actual &&
+ test_cmp expect actual &&
+ ls there5 >actual &&
+ test_cmp expect actual
'
test_expect_success 'checkout with grafts' '
@@ -505,10 +559,7 @@ test_expect_success 'git worktree --no-guess-remote option overrides config' '
'
post_checkout_hook () {
- gitdir=${1:-.git}
- test_when_finished "rm -f $gitdir/hooks/post-checkout" &&
- mkdir -p $gitdir/hooks &&
- write_script $gitdir/hooks/post-checkout <<-\EOF
+ test_hook -C "$1" post-checkout <<-\EOF
{
echo $*
git rev-parse --git-dir --show-toplevel
diff --git a/t/t2402-worktree-list.sh b/t/t2402-worktree-list.sh
index c8a5a0a..79e0fce 100755
--- a/t/t2402-worktree-list.sh
+++ b/t/t2402-worktree-list.sh
@@ -64,6 +64,25 @@ test_expect_success '"list" all worktrees --porcelain' '
test_cmp expect actual
'
+test_expect_success '"list" all worktrees --porcelain -z' '
+ test_when_finished "rm -rf here _actual actual expect &&
+ git worktree prune" &&
+ printf "worktree %sQHEAD %sQbranch %sQQ" \
+ "$(git rev-parse --show-toplevel)" \
+ $(git rev-parse HEAD --symbolic-full-name HEAD) >expect &&
+ git worktree add --detach here main &&
+ printf "worktree %sQHEAD %sQdetachedQQ" \
+ "$(git -C here rev-parse --show-toplevel)" \
+ "$(git rev-parse HEAD)" >>expect &&
+ git worktree list --porcelain -z >_actual &&
+ nul_to_q <_actual >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '"list" -z fails without --porcelain' '
+ test_must_fail git worktree list -z
+'
+
test_expect_success '"list" all worktrees with locked annotation' '
test_when_finished "rm -rf locked unlocked out && git worktree prune" &&
git worktree add --detach locked main &&
diff --git a/t/t3007-ls-files-recurse-submodules.sh b/t/t3007-ls-files-recurse-submodules.sh
index 4a08000..dd7770e 100755
--- a/t/t3007-ls-files-recurse-submodules.sh
+++ b/t/t3007-ls-files-recurse-submodules.sh
@@ -34,6 +34,23 @@ test_expect_success 'ls-files correctly outputs files in submodule' '
test_cmp expect actual
'
+test_expect_success '--stage' '
+ GITMODULES_HASH=$(git rev-parse HEAD:.gitmodules) &&
+ A_HASH=$(git rev-parse HEAD:a) &&
+ B_HASH=$(git rev-parse HEAD:b/b) &&
+ C_HASH=$(git -C submodule rev-parse HEAD:c) &&
+
+ cat >expect <<-EOF &&
+ 100644 $GITMODULES_HASH 0 .gitmodules
+ 100644 $A_HASH 0 a
+ 100644 $B_HASH 0 b/b
+ 100644 $C_HASH 0 submodule/c
+ EOF
+
+ git ls-files --stage --recurse-submodules >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'ls-files correctly outputs files in submodule with -z' '
lf_to_nul >expect <<-\EOF &&
.gitmodules
@@ -292,7 +309,6 @@ test_incompatible_with_recurse_submodules () {
test_incompatible_with_recurse_submodules --deleted
test_incompatible_with_recurse_submodules --modified
test_incompatible_with_recurse_submodules --others
-test_incompatible_with_recurse_submodules --stage
test_incompatible_with_recurse_submodules --killed
test_incompatible_with_recurse_submodules --unmerged
diff --git a/t/t3101-ls-tree-dirname.sh b/t/t3101-ls-tree-dirname.sh
index 05fde64..217006d 100755
--- a/t/t3101-ls-tree-dirname.sh
+++ b/t/t3101-ls-tree-dirname.sh
@@ -201,31 +201,34 @@ EOF
test_cmp expected check
'
-test_expect_success 'ls-tree --name-only' '
- git ls-tree --name-only $tree >current &&
- cat >expected <<\EOF &&
-1.txt
-2.txt
-path0
-path1
-path2
-path3
-EOF
- test_output
-'
-
-test_expect_success 'ls-tree --name-only -r' '
- git ls-tree --name-only -r $tree >current &&
- cat >expected <<\EOF &&
-1.txt
-2.txt
-path0/a/b/c/1.txt
-path1/b/c/1.txt
-path2/1.txt
-path3/1.txt
-path3/2.txt
-EOF
- test_output
-'
+for opt in --name-only --name-status
+do
+ test_expect_success "ls-tree $opt" '
+ git ls-tree $opt $tree >current &&
+ cat >expected <<-\EOF &&
+ 1.txt
+ 2.txt
+ path0
+ path1
+ path2
+ path3
+ EOF
+ test_output
+ '
+
+ test_expect_success "ls-tree $opt -r" '
+ git ls-tree $opt -r $tree >current &&
+ cat >expected <<-\EOF &&
+ 1.txt
+ 2.txt
+ path0/a/b/c/1.txt
+ path1/b/c/1.txt
+ path2/1.txt
+ path3/1.txt
+ path3/2.txt
+ EOF
+ test_output
+ '
+done
test_done
diff --git a/t/t3103-ls-tree-misc.sh b/t/t3103-ls-tree-misc.sh
index d18ba1b..81c6343 100755
--- a/t/t3103-ls-tree-misc.sh
+++ b/t/t3103-ls-tree-misc.sh
@@ -23,4 +23,19 @@ test_expect_success 'ls-tree fails with non-zero exit code on broken tree' '
test_must_fail git ls-tree -r HEAD
'
+for opts in \
+ "--long --name-only" \
+ "--name-only --name-status" \
+ "--name-status --object-only" \
+ "--object-only --long"
+do
+ test_expect_success "usage: incompatible options: $opts" '
+ test_expect_code 129 git ls-tree $opts $tree
+ '
+
+ one_opt=$(echo "$opts" | cut -d' ' -f1)
+ test_expect_success "usage: incompatible options: $one_opt and --format" '
+ test_expect_code 129 git ls-tree $one_opt --format=fmt $tree
+ '
+done
test_done
diff --git a/t/t3104-ls-tree-format.sh b/t/t3104-ls-tree-format.sh
new file mode 100755
index 0000000..0769a93
--- /dev/null
+++ b/t/t3104-ls-tree-format.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+
+test_description='ls-tree --format'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+test_expect_success 'ls-tree --format usage' '
+ test_expect_code 129 git ls-tree --format=fmt -l HEAD &&
+ test_expect_code 129 git ls-tree --format=fmt --name-only HEAD &&
+ test_expect_code 129 git ls-tree --format=fmt --name-status HEAD
+'
+
+test_expect_success 'setup' '
+ mkdir dir &&
+ test_commit dir/sub-file &&
+ test_commit top-file
+'
+
+test_ls_tree_format () {
+ format=$1 &&
+ opts=$2 &&
+ fmtopts=$3 &&
+ shift 2 &&
+
+ test_expect_success "ls-tree '--format=<$format>' is like options '$opts $fmtopts'" '
+ git ls-tree $opts -r HEAD >expect &&
+ git ls-tree --format="$format" -r $fmtopts HEAD >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "ls-tree '--format=<$format>' on optimized v.s. non-optimized path" '
+ git ls-tree --format="$format" -r $fmtopts HEAD >expect &&
+ git ls-tree --format="> $format" -r $fmtopts HEAD >actual.raw &&
+ sed "s/^> //" >actual <actual.raw &&
+ test_cmp expect actual
+ '
+}
+
+test_ls_tree_format \
+ "%(objectmode) %(objecttype) %(objectname)%x09%(path)" \
+ ""
+
+test_ls_tree_format \
+ "%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)" \
+ "--long"
+
+test_ls_tree_format \
+ "%(path)" \
+ "--name-only"
+
+test_ls_tree_format \
+ "%(objectname)" \
+ "--object-only"
+
+test_ls_tree_format \
+ "%(objectname)" \
+ "--object-only --abbrev" \
+ "--abbrev"
+
+test_ls_tree_format \
+ "%(objectmode) %(objecttype) %(objectname)%x09%(path)" \
+ "-t" \
+ "-t"
+
+test_ls_tree_format \
+ "%(objectmode) %(objecttype) %(objectname)%x09%(path)" \
+ "--full-name" \
+ "--full-name"
+
+test_ls_tree_format \
+ "%(objectmode) %(objecttype) %(objectname)%x09%(path)" \
+ "--full-tree" \
+ "--full-tree"
+
+test_done
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 1bc3795..e12db59 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -42,6 +42,23 @@ test_expect_success 'git branch abc should create a branch' '
git branch abc && test_path_is_file .git/refs/heads/abc
'
+test_expect_success 'git branch abc should fail when abc exists' '
+ test_must_fail git branch abc
+'
+
+test_expect_success 'git branch --force abc should fail when abc is checked out' '
+ test_when_finished git switch main &&
+ git switch abc &&
+ test_must_fail git branch --force abc HEAD~1
+'
+
+test_expect_success 'git branch --force abc should succeed when abc exists' '
+ git rev-parse HEAD~1 >expect &&
+ git branch --force abc HEAD~1 &&
+ git rev-parse abc >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'git branch a/b/c should create a branch' '
git branch a/b/c && test_path_is_file .git/refs/heads/a/b/c
'
@@ -1022,13 +1039,27 @@ test_expect_success 'checkout -b with -l makes reflog when core.logAllRefUpdates
git rev-parse --verify gamma@{0}
'
-test_expect_success 'avoid ambiguous track' '
+test_expect_success 'avoid ambiguous track and advise' '
git config branch.autosetupmerge true &&
git config remote.ambi1.url lalala &&
git config remote.ambi1.fetch refs/heads/lalala:refs/heads/main &&
git config remote.ambi2.url lilili &&
git config remote.ambi2.fetch refs/heads/lilili:refs/heads/main &&
- test_must_fail git branch all1 main &&
+ cat <<-EOF >expected &&
+ fatal: not tracking: ambiguous information for ref '\''refs/heads/main'\''
+ hint: There are multiple remotes whose fetch refspecs map to the remote
+ hint: tracking ref '\''refs/heads/main'\'':
+ hint: ambi1
+ hint: ambi2
+ hint: ''
+ hint: This is typically a configuration error.
+ hint: ''
+ hint: To support setting up tracking branches, ensure that
+ hint: different remotes'\'' fetch refspecs map into different
+ hint: tracking namespaces.
+ EOF
+ test_must_fail git branch all1 main 2>actual &&
+ test_cmp expected actual &&
test -z "$(git config branch.all1.merge)"
'
diff --git a/t/t3207-branch-submodule.sh b/t/t3207-branch-submodule.sh
new file mode 100755
index 0000000..cfde6b2
--- /dev/null
+++ b/t/t3207-branch-submodule.sh
@@ -0,0 +1,328 @@
+#!/bin/sh
+
+test_description='git branch submodule tests'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-rebase.sh
+
+pwd=$(pwd)
+
+# Creates a clean test environment in "pwd" by copying the repo setup
+# from test_dirs.
+reset_test () {
+ rm -fr super &&
+ rm -fr sub-sub-upstream &&
+ rm -fr sub-upstream &&
+ cp -r test_dirs/* .
+}
+
+# Tests that the expected branch does not exist
+test_no_branch () {
+ DIR=$1 &&
+ BRANCH_NAME=$2 &&
+ test_must_fail git -C "$DIR" rev-parse "$BRANCH_NAME" 2>err &&
+ grep "ambiguous argument .$BRANCH_NAME." err
+}
+
+test_expect_success 'setup superproject and submodule' '
+ mkdir test_dirs &&
+ (
+ cd test_dirs &&
+ git init super &&
+ test_commit -C super foo &&
+ git init sub-sub-upstream &&
+ test_commit -C sub-sub-upstream foo &&
+ git init sub-upstream &&
+ # Submodule in a submodule
+ git -C sub-upstream submodule add "${pwd}/test_dirs/sub-sub-upstream" sub-sub &&
+ git -C sub-upstream commit -m "add submodule" &&
+ # Regular submodule
+ git -C super submodule add "${pwd}/test_dirs/sub-upstream" sub &&
+ # Submodule in a subdirectory
+ git -C super submodule add "${pwd}/test_dirs/sub-sub-upstream" second/sub &&
+ git -C super commit -m "add submodule" &&
+ git -C super config submodule.propagateBranches true &&
+ git -C super/sub submodule update --init
+ ) &&
+ reset_test
+'
+
+# Test the argument parsing
+test_expect_success '--recurse-submodules should create branches' '
+ test_when_finished "reset_test" &&
+ (
+ cd super &&
+ git branch --recurse-submodules branch-a &&
+ git rev-parse branch-a &&
+ git -C sub rev-parse branch-a &&
+ git -C sub/sub-sub rev-parse branch-a &&
+ git -C second/sub rev-parse branch-a
+ )
+'
+
+test_expect_success '--recurse-submodules should die if submodule.propagateBranches is false' '
+ test_when_finished "reset_test" &&
+ (
+ cd super &&
+ echo "fatal: branch with --recurse-submodules can only be used if submodule.propagateBranches is enabled" >expected &&
+ test_must_fail git -c submodule.propagateBranches=false branch --recurse-submodules branch-a 2>actual &&
+ test_cmp expected actual
+ )
+'
+
+test_expect_success '--recurse-submodules should fail when not creating branches' '
+ test_when_finished "reset_test" &&
+ (
+ cd super &&
+ git branch --recurse-submodules branch-a &&
+ echo "fatal: --recurse-submodules can only be used to create branches" >expected &&
+ test_must_fail git branch --recurse-submodules -D branch-a 2>actual &&
+ test_cmp expected actual &&
+ # Assert that the branches were not deleted
+ git rev-parse branch-a &&
+ git -C sub rev-parse branch-a
+ )
+'
+
+test_expect_success 'should respect submodule.recurse when creating branches' '
+ test_when_finished "reset_test" &&
+ (
+ cd super &&
+ git -c submodule.recurse=true branch branch-a &&
+ git rev-parse branch-a &&
+ git -C sub rev-parse branch-a
+ )
+'
+
+test_expect_success 'should ignore submodule.recurse when not creating branches' '
+ test_when_finished "reset_test" &&
+ (
+ cd super &&
+ git branch --recurse-submodules branch-a &&
+ git -c submodule.recurse=true branch -D branch-a &&
+ test_no_branch . branch-a &&
+ git -C sub rev-parse branch-a
+ )
+'
+
+# Test branch creation behavior
+test_expect_success 'should create branches based off commit id in superproject' '
+ test_when_finished "reset_test" &&
+ (
+ cd super &&
+ git branch --recurse-submodules branch-a &&
+ git checkout --recurse-submodules branch-a &&
+ git -C sub rev-parse HEAD >expected &&
+ # Move the tip of sub:branch-a so that it no longer matches the commit in super:branch-a
+ git -C sub checkout branch-a &&
+ test_commit -C sub bar &&
+ # Create a new branch-b branch with start-point=branch-a
+ git branch --recurse-submodules branch-b branch-a &&
+ git rev-parse branch-b &&
+ git -C sub rev-parse branch-b >actual &&
+ # Assert that the commit id of sub:second-branch matches super:branch-a and not sub:branch-a
+ test_cmp expected actual
+ )
+'
+
+test_expect_success 'should not create any branches if branch is not valid for all repos' '
+ test_when_finished "reset_test" &&
+ (
+ cd super &&
+ git -C sub branch branch-a &&
+ test_must_fail git branch --recurse-submodules branch-a 2>actual &&
+ test_no_branch . branch-a &&
+ grep "submodule .sub.: fatal: a branch named .branch-a. already exists" actual
+ )
+'
+
+test_expect_success 'should create branches if branch exists and --force is given' '
+ test_when_finished "reset_test" &&
+ (
+ cd super &&
+ git -C sub rev-parse HEAD >expected &&
+ test_commit -C sub baz &&
+ # branch-a in sub now points to a newer commit.
+ git -C sub branch branch-a HEAD &&
+ git -C sub rev-parse branch-a >actual-old-branch-a &&
+ git branch --recurse-submodules --force branch-a &&
+ git rev-parse branch-a &&
+ git -C sub rev-parse branch-a >actual-new-branch-a &&
+ test_cmp expected actual-new-branch-a &&
+ # assert that branch --force actually moved the sub
+ # branch
+ ! test_cmp expected actual-old-branch-a
+ )
+'
+
+test_expect_success 'should create branch when submodule is not in HEAD:.gitmodules' '
+ test_when_finished "reset_test" &&
+ (
+ cd super &&
+ git branch branch-a &&
+ git checkout -b branch-b &&
+ git submodule add ../sub-upstream sub2 &&
+ git -C sub2 submodule update --init &&
+ # branch-b now has a committed submodule not in branch-a
+ git commit -m "add second submodule" &&
+ git checkout branch-a &&
+ git branch --recurse-submodules branch-c branch-b &&
+ git checkout --recurse-submodules branch-c &&
+ git -C sub2 rev-parse branch-c &&
+ git -C sub2/sub-sub rev-parse branch-c
+ )
+'
+
+test_expect_success 'should not create branches in inactive submodules' '
+ test_when_finished "reset_test" &&
+ test_config -C super submodule.sub.active false &&
+ (
+ cd super &&
+ git branch --recurse-submodules branch-a &&
+ git rev-parse branch-a &&
+ test_no_branch sub branch-a
+ )
+'
+
+test_expect_success 'should set up tracking of local branches with track=always' '
+ test_when_finished "reset_test" &&
+ (
+ cd super &&
+ git -c branch.autoSetupMerge=always branch --recurse-submodules branch-a main &&
+ git -C sub rev-parse main &&
+ test_cmp_config -C sub . branch.branch-a.remote &&
+ test_cmp_config -C sub refs/heads/main branch.branch-a.merge
+ )
+'
+
+test_expect_success 'should set up tracking of local branches with explicit track' '
+ test_when_finished "reset_test" &&
+ (
+ cd super &&
+ git branch --track --recurse-submodules branch-a main &&
+ git -C sub rev-parse main &&
+ test_cmp_config -C sub . branch.branch-a.remote &&
+ test_cmp_config -C sub refs/heads/main branch.branch-a.merge
+ )
+'
+
+test_expect_success 'should not set up unnecessary tracking of local branches' '
+ test_when_finished "reset_test" &&
+ (
+ cd super &&
+ git branch --recurse-submodules branch-a main &&
+ git -C sub rev-parse main &&
+ test_cmp_config -C sub "" --default "" branch.branch-a.remote &&
+ test_cmp_config -C sub "" --default "" branch.branch-a.merge
+ )
+'
+
+reset_remote_test () {
+ rm -fr super-clone &&
+ reset_test
+}
+
+test_expect_success 'setup tests with remotes' '
+ (
+ cd test_dirs &&
+ (
+ cd super &&
+ git branch branch-a &&
+ git checkout -b branch-b &&
+ git submodule add ../sub-upstream sub2 &&
+ # branch-b now has a committed submodule not in branch-a
+ git commit -m "add second submodule"
+ ) &&
+ git clone --branch main --recurse-submodules super super-clone &&
+ git -C super-clone config submodule.propagateBranches true
+ ) &&
+ reset_remote_test
+'
+
+test_expect_success 'should get fatal error upon branch creation when submodule is not in .git/modules' '
+ test_when_finished "reset_remote_test" &&
+ (
+ cd super-clone &&
+ # This should succeed because super-clone has sub in .git/modules
+ git branch --recurse-submodules branch-a origin/branch-a &&
+ # This should fail because super-clone does not have sub2 .git/modules
+ test_must_fail git branch --recurse-submodules branch-b origin/branch-b 2>actual &&
+ grep "fatal: submodule .sub2.: unable to find submodule" actual &&
+ test_no_branch . branch-b &&
+ test_no_branch sub branch-b &&
+ # User can fix themselves by initializing the submodule
+ git checkout origin/branch-b &&
+ git submodule update --init --recursive &&
+ git branch --recurse-submodules branch-b origin/branch-b
+ )
+'
+
+test_expect_success 'should set up tracking of remote-tracking branches by default' '
+ test_when_finished "reset_remote_test" &&
+ (
+ cd super-clone &&
+ git branch --recurse-submodules branch-a origin/branch-a &&
+ test_cmp_config origin branch.branch-a.remote &&
+ test_cmp_config refs/heads/branch-a branch.branch-a.merge &&
+ # "origin/branch-a" does not exist for "sub", but it matches the refspec
+ # so tracking should be set up
+ test_cmp_config -C sub origin branch.branch-a.remote &&
+ test_cmp_config -C sub refs/heads/branch-a branch.branch-a.merge &&
+ test_cmp_config -C sub/sub-sub origin branch.branch-a.remote &&
+ test_cmp_config -C sub/sub-sub refs/heads/branch-a branch.branch-a.merge
+ )
+'
+
+test_expect_success 'should not fail when unable to set up tracking in submodule' '
+ test_when_finished "reset_remote_test" &&
+ (
+ cd super-clone &&
+ git remote rename origin ex-origin &&
+ git branch --recurse-submodules branch-a ex-origin/branch-a &&
+ test_cmp_config ex-origin branch.branch-a.remote &&
+ test_cmp_config refs/heads/branch-a branch.branch-a.merge &&
+ test_cmp_config -C sub "" --default "" branch.branch-a.remote &&
+ test_cmp_config -C sub "" --default "" branch.branch-a.merge
+ )
+'
+
+test_expect_success '--track=inherit should set up tracking correctly' '
+ test_when_finished "reset_remote_test" &&
+ (
+ cd super-clone &&
+ git branch --recurse-submodules branch-a origin/branch-a &&
+ # Set this manually instead of using branch --set-upstream-to
+ # to circumvent the "nonexistent upstream" check.
+ git -C sub config branch.branch-a.remote origin &&
+ git -C sub config branch.branch-a.merge refs/heads/sub-branch-a &&
+ git -C sub/sub-sub config branch.branch-a.remote other &&
+ git -C sub/sub-sub config branch.branch-a.merge refs/heads/sub-sub-branch-a &&
+
+ git branch --recurse-submodules --track=inherit branch-b branch-a &&
+ test_cmp_config origin branch.branch-b.remote &&
+ test_cmp_config refs/heads/branch-a branch.branch-b.merge &&
+ test_cmp_config -C sub origin branch.branch-b.remote &&
+ test_cmp_config -C sub refs/heads/sub-branch-a branch.branch-b.merge &&
+ test_cmp_config -C sub/sub-sub other branch.branch-b.remote &&
+ test_cmp_config -C sub/sub-sub refs/heads/sub-sub-branch-a branch.branch-b.merge
+ )
+'
+
+test_expect_success '--no-track should not set up tracking' '
+ test_when_finished "reset_remote_test" &&
+ (
+ cd super-clone &&
+ git branch --recurse-submodules --no-track branch-a origin/branch-a &&
+ test_cmp_config "" --default "" branch.branch-a.remote &&
+ test_cmp_config "" --default "" branch.branch-a.merge &&
+ test_cmp_config -C sub "" --default "" branch.branch-a.remote &&
+ test_cmp_config -C sub "" --default "" branch.branch-a.merge &&
+ test_cmp_config -C sub/sub-sub "" --default "" branch.branch-a.remote &&
+ test_cmp_config -C sub/sub-sub "" --default "" branch.branch-a.merge
+ )
+'
+
+test_done
diff --git a/t/t3302-notes-index-expensive.sh b/t/t3302-notes-index-expensive.sh
index bc9d8ee..bb5fea0 100755
--- a/t/t3302-notes-index-expensive.sh
+++ b/t/t3302-notes-index-expensive.sh
@@ -8,7 +8,6 @@ test_description='Test commit notes index (expensive!)'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
create_repo () {
@@ -65,7 +64,8 @@ create_repo () {
test_notes () {
count=$1 &&
git config core.notesRef refs/notes/commits &&
- git log | grep "^ " >output &&
+ git log >tmp &&
+ grep "^ " tmp >output &&
i=$count &&
while test $i -gt 0
do
@@ -90,7 +90,7 @@ write_script time_notes <<\EOF
unset GIT_NOTES_REF
;;
esac
- git log
+ git log || exit $?
i=$(($i+1))
done >/dev/null
EOF
diff --git a/t/t3303-notes-subtrees.sh b/t/t3303-notes-subtrees.sh
index 7e0a896..eac1937 100755
--- a/t/t3303-notes-subtrees.sh
+++ b/t/t3303-notes-subtrees.sh
@@ -5,7 +5,6 @@ test_description='Test commit notes organized in subtrees'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
number_of_commits=100
@@ -79,7 +78,7 @@ test_sha1_based () {
(
start_note_commit &&
nr=$number_of_commits &&
- git rev-list refs/heads/main |
+ git rev-list refs/heads/main >out &&
while read sha1; do
note_path=$(echo "$sha1" | sed "$1")
cat <<INPUT_END &&
@@ -91,9 +90,9 @@ EOF
INPUT_END
nr=$(($nr-1))
- done
- ) |
- git fast-import --quiet
+ done <out
+ ) >gfi &&
+ git fast-import --quiet <gfi
}
test_expect_success 'test notes in 2/38-fanout' 'test_sha1_based "s|^..|&/|"'
diff --git a/t/t3305-notes-fanout.sh b/t/t3305-notes-fanout.sh
index 1f59648..9976d78 100755
--- a/t/t3305-notes-fanout.sh
+++ b/t/t3305-notes-fanout.sh
@@ -2,7 +2,6 @@
test_description='Test that adding/removing many notes triggers automatic fanout restructuring'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
path_has_fanout() {
@@ -24,7 +23,7 @@ touched_one_note_with_fanout() {
all_notes_have_fanout() {
notes_commit=$1 &&
fanout=$2 &&
- git ls-tree -r --name-only $notes_commit 2>/dev/null |
+ git ls-tree -r --name-only $notes_commit |
while read path
do
path_has_fanout $path $fanout || return 1
@@ -51,8 +50,9 @@ test_expect_success 'creating many notes with git-notes' '
done
'
-test_expect_success 'many notes created correctly with git-notes' '
- git log | grep "^ " > output &&
+test_expect_success !SANITIZE_LEAK 'many notes created correctly with git-notes' '
+ git log >output.raw &&
+ grep "^ " output.raw >output &&
i=$num_notes &&
while test $i -gt 0
do
@@ -91,13 +91,13 @@ test_expect_success 'stable fanout 0 is followed by stable fanout 1' '
test_expect_success 'deleting most notes with git-notes' '
remove_notes=285 &&
i=0 &&
- git rev-list HEAD |
+ git rev-list HEAD >revs &&
while test $i -lt $remove_notes && read sha1
do
i=$(($i + 1)) &&
test_tick &&
- git notes remove "$sha1" 2>/dev/null || return 1
- done
+ git notes remove "$sha1" || return 1
+ done <revs
'
test_expect_success 'most notes deleted correctly with git-notes' '
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 23dbd3c..d5a8ee3 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -18,10 +18,7 @@ GIT_AUTHOR_EMAIL=bogus@email@address
export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
test_expect_success 'prepare repository with topic branches' '
- git config core.logAllRefUpdates true &&
- echo First >A &&
- git update-index --add A &&
- git commit -m "Add A." &&
+ test_commit "Add A." A First First &&
git checkout -b force-3way &&
echo Dummy >Y &&
git update-index --add Y &&
@@ -32,9 +29,7 @@ test_expect_success 'prepare repository with topic branches' '
git mv A D/A &&
git commit -m "Move A." &&
git checkout -b my-topic-branch main &&
- echo Second >B &&
- git update-index --add B &&
- git commit -m "Add B." &&
+ test_commit "Add B." B Second Second &&
git checkout -f main &&
echo Third >>A &&
git update-index A &&
@@ -399,6 +394,15 @@ test_expect_success 'switch to branch not checked out' '
git rebase main other
'
+test_expect_success 'switch to non-branch detaches HEAD' '
+ git checkout main &&
+ old_main=$(git rev-parse HEAD) &&
+ git rebase First Second^0 &&
+ test_cmp_rev HEAD Second &&
+ test_cmp_rev main $old_main &&
+ test_must_fail git symbolic-ref HEAD
+'
+
test_expect_success 'refuse to switch to branch checked out elsewhere' '
git checkout main &&
git worktree add wt &&
@@ -416,4 +420,25 @@ test_expect_success MINGW,SYMLINKS_WINDOWS 'rebase when .git/logs is a symlink'
mv actual_logs .git/logs
'
+test_expect_success 'rebase when inside worktree subdirectory' '
+ git init main-wt &&
+ (
+ cd main-wt &&
+ git commit --allow-empty -m "initial" &&
+ mkdir -p foo/bar &&
+ test_commit foo/bar/baz &&
+ mkdir -p a/b &&
+ test_commit a/b/c &&
+ # create another branch for our other worktree
+ git branch other &&
+ git worktree add ../other-wt other &&
+ cd ../other-wt &&
+ # create and cd into a subdirectory
+ mkdir -p random/dir &&
+ cd random/dir &&
+ # now do the rebase
+ git rebase --onto HEAD^^ HEAD^ # drops the HEAD^ commit
+ )
+'
+
test_done
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index a38f2da..f31afd4 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -619,9 +619,7 @@ test_expect_success 'rebase a detached HEAD' '
'
test_expect_success 'rebase a commit violating pre-commit' '
-
- mkdir -p .git/hooks &&
- write_script .git/hooks/pre-commit <<-\EOF &&
+ test_hook pre-commit <<-\EOF &&
test -z "$(git diff --cached --check)"
EOF
echo "monde! " >> file1 &&
@@ -636,8 +634,6 @@ test_expect_success 'rebase a commit violating pre-commit' '
'
test_expect_success 'rebase with a file named HEAD in worktree' '
-
- rm -fr .git/hooks &&
git reset --hard &&
git checkout -b branch3 A &&
@@ -1688,10 +1684,8 @@ test_expect_success 'valid author header when author contains single quote' '
'
test_expect_success 'post-commit hook is called' '
- test_when_finished "rm -f .git/hooks/post-commit" &&
>actual &&
- mkdir -p .git/hooks &&
- write_script .git/hooks/post-commit <<-\EOS &&
+ test_hook post-commit <<-\EOS &&
git rev-parse HEAD >>actual
EOS
(
diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh
index 77a313f..d17b450 100755
--- a/t/t3406-rebase-message.sh
+++ b/t/t3406-rebase-message.sh
@@ -105,6 +105,29 @@ test_expect_success 'GIT_REFLOG_ACTION' '
test_cmp expect actual
'
+test_expect_success 'rebase --apply reflog' '
+ git checkout -b reflog-apply start &&
+ old_head_reflog="$(git log -g --format=%gs -1 HEAD)" &&
+
+ git rebase --apply Y &&
+
+ git log -g --format=%gs -4 HEAD >actual &&
+ cat >expect <<-EOF &&
+ rebase finished: returning to refs/heads/reflog-apply
+ rebase: Z
+ rebase: checkout Y
+ $old_head_reflog
+ EOF
+ test_cmp expect actual &&
+
+ git log -g --format=%gs -2 reflog-apply >actual &&
+ cat >expect <<-EOF &&
+ rebase finished: refs/heads/reflog-apply onto $(git rev-parse Y)
+ branch: Created from start
+ EOF
+ test_cmp expect actual
+'
+
test_expect_success 'rebase -i onto unrelated history' '
git init unrelated &&
test_commit -C unrelated 1 &&
diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
index 19c6f4a..58371d8 100755
--- a/t/t3412-rebase-root.sh
+++ b/t/t3412-rebase-root.sh
@@ -11,7 +11,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
log_with_names () {
git rev-list --topo-order --parents --pretty="tformat:%s" HEAD |
- git name-rev --stdin --name-only --refs=refs/heads/$1
+ git name-rev --annotate-stdin --name-only --refs=refs/heads/$1
}
@@ -31,12 +31,9 @@ test_expect_success 'rebase --root fails with too many args' '
'
test_expect_success 'setup pre-rebase hook' '
- mkdir -p .git/hooks &&
- cat >.git/hooks/pre-rebase <<EOF &&
-#!$SHELL_PATH
-echo "\$1,\$2" >.git/PRE-REBASE-INPUT
-EOF
- chmod +x .git/hooks/pre-rebase
+ test_hook --setup pre-rebase <<-\EOF
+ echo "$1,$2" >.git/PRE-REBASE-INPUT
+ EOF
'
cat > expect <<EOF
4
@@ -141,12 +138,9 @@ commit work7~5
EOF
test_expect_success 'setup pre-rebase hook that fails' '
- mkdir -p .git/hooks &&
- cat >.git/hooks/pre-rebase <<EOF &&
-#!$SHELL_PATH
-false
-EOF
- chmod +x .git/hooks/pre-rebase
+ test_hook --setup --clobber pre-rebase <<-\EOF
+ false
+ EOF
'
test_expect_success 'pre-rebase hook stops rebase' '
diff --git a/t/t3413-rebase-hook.sh b/t/t3413-rebase-hook.sh
index b4acb3b..9fab0d7 100755
--- a/t/t3413-rebase-hook.sh
+++ b/t/t3413-rebase-hook.sh
@@ -41,12 +41,9 @@ test_expect_success 'rebase -i' '
'
test_expect_success 'setup pre-rebase hook' '
- mkdir -p .git/hooks &&
- cat >.git/hooks/pre-rebase <<EOF &&
-#!$SHELL_PATH
-echo "\$1,\$2" >.git/PRE-REBASE-INPUT
-EOF
- chmod +x .git/hooks/pre-rebase
+ test_hook --setup pre-rebase <<-\EOF
+ echo "$1,$2" >.git/PRE-REBASE-INPUT
+ EOF
'
test_expect_success 'pre-rebase hook gets correct input (1)' '
@@ -102,12 +99,9 @@ test_expect_success 'pre-rebase hook gets correct input (6)' '
'
test_expect_success 'setup pre-rebase hook that fails' '
- mkdir -p .git/hooks &&
- cat >.git/hooks/pre-rebase <<EOF &&
-#!$SHELL_PATH
-false
-EOF
- chmod +x .git/hooks/pre-rebase
+ test_hook --setup --clobber pre-rebase <<-\EOF
+ false
+ EOF
'
test_expect_success 'pre-rebase hook stops rebase (1)' '
diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh
index 22eca73..130e2f9 100755
--- a/t/t3418-rebase-continue.sh
+++ b/t/t3418-rebase-continue.sh
@@ -308,4 +308,30 @@ test_expect_success 'there is no --no-reschedule-failed-exec in an ongoing rebas
test_expect_code 129 git rebase --edit-todo --no-reschedule-failed-exec
'
+test_orig_head_helper () {
+ test_when_finished 'git rebase --abort &&
+ git checkout topic &&
+ git reset --hard commit-new-file-F2-on-topic-branch' &&
+ git update-ref -d ORIG_HEAD &&
+ test_must_fail git rebase "$@" &&
+ test_cmp_rev ORIG_HEAD commit-new-file-F2-on-topic-branch
+}
+
+test_orig_head () {
+ type=$1
+ test_expect_success "rebase $type sets ORIG_HEAD correctly" '
+ git checkout topic &&
+ git reset --hard commit-new-file-F2-on-topic-branch &&
+ test_orig_head_helper $type main
+ '
+
+ test_expect_success "rebase $type <upstream> <branch> sets ORIG_HEAD correctly" '
+ git checkout main &&
+ test_orig_head_helper $type main topic
+ '
+}
+
+test_orig_head --apply
+test_orig_head --merge
+
test_done
diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh
index 43c82d9..f351701 100755
--- a/t/t3430-rebase-merges.sh
+++ b/t/t3430-rebase-merges.sh
@@ -292,9 +292,9 @@ test_expect_success 'post-rewrite hook and fixups work for merges' '
git commit --fixup HEAD same2.t &&
fixup="$(git rev-parse HEAD)" &&
- mkdir -p .git/hooks &&
- test_when_finished "rm .git/hooks/post-rewrite" &&
- echo "cat >actual" | write_script .git/hooks/post-rewrite &&
+ test_hook post-rewrite <<-\EOF &&
+ cat >actual
+ EOF
test_tick &&
git rebase -i --autosquash -r HEAD^^^ &&
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index 2077146..94537a6 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -326,7 +326,9 @@ test_expect_success 'correct message when there is nothing to do' '
test_expect_success 'setup again' '
git reset --hard &&
test_chmod +x file &&
- echo content >>file
+ echo content >>file &&
+ test_write_lines A B C D>file2 &&
+ git add file2
'
# Write the patch file with a new line at the top and bottom
@@ -341,13 +343,27 @@ test_expect_success 'setup patch' '
content
+lastline
\ No newline at end of file
+ diff --git a/file2 b/file2
+ index 8422d40..35b930a 100644
+ --- a/file2
+ +++ b/file2
+ @@ -1,4 +1,5 @@
+ -A
+ +Z
+ B
+ +Y
+ C
+ -D
+ +X
EOF
'
# Expected output, diff is similar to the patch but w/ diff at the top
test_expect_success 'setup expected' '
echo diff --git a/file b/file >expected &&
- cat patch |sed "/^index/s/ 100644/ 100755/" >>expected &&
+ sed -e "/^index 180b47c/s/ 100644/ 100755/" \
+ -e /1,5/s//1,4/ \
+ -e /Y/d patch >>expected &&
cat >expected-output <<-\EOF
--- a/file
+++ b/file
@@ -366,6 +382,28 @@ test_expect_success 'setup expected' '
content
+lastline
\ No newline at end of file
+ --- a/file2
+ +++ b/file2
+ @@ -1,4 +1,5 @@
+ -A
+ +Z
+ B
+ +Y
+ C
+ -D
+ +X
+ @@ -1,2 +1,2 @@
+ -A
+ +Z
+ B
+ @@ -2,2 +2,3 @@
+ B
+ +Y
+ C
+ @@ -3,2 +4,2 @@
+ C
+ -D
+ +X
EOF
'
@@ -373,9 +411,9 @@ test_expect_success 'setup expected' '
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 |
- sed -n -e "s/^([1-2]\/[1-2]) Stage this hunk[^@]*\(@@ .*\)/\1/" \
- -e "/^[-+@ \\\\]"/p >output &&
+ test_write_lines s y y s y n y | git add -p 2>error >raw-output &&
+ sed -n -e "s/^([1-9]\/[1-9]) Stage this hunk[^@]*\(@@ .*\)/\1/" \
+ -e "/^[-+@ \\\\]"/p raw-output >output &&
test_must_be_empty error &&
git diff --cached >diff &&
diff_cmp expected diff &&
diff --git a/t/t3705-add-sparse-checkout.sh b/t/t3705-add-sparse-checkout.sh
index 81f3384..9560904 100755
--- a/t/t3705-add-sparse-checkout.sh
+++ b/t/t3705-add-sparse-checkout.sh
@@ -19,6 +19,7 @@ setup_sparse_entry () {
fi &&
git add sparse_entry &&
git update-index --skip-worktree sparse_entry &&
+ git config core.sparseCheckout false &&
git commit --allow-empty -m "ensure sparse_entry exists at HEAD" &&
SPARSE_ENTRY_BLOB=$(git rev-parse :sparse_entry)
}
@@ -126,6 +127,7 @@ test_expect_success 'git add --chmod does not update sparse entries' '
'
test_expect_success 'git add --renormalize does not update sparse entries' '
+ test_when_finished rm .gitattributes &&
test_config core.autocrlf false &&
setup_sparse_entry "LINEONE\r\nLINETWO\r\n" &&
echo "sparse_entry text=auto" >.gitattributes &&
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 686747e..4abbc8f 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -41,7 +41,7 @@ diff_cmp () {
rm -f "$1.compare" "$2.compare"
}
-test_expect_success 'stash some dirty working directory' '
+setup_stash() {
echo 1 >file &&
git add file &&
echo unrelated >other-file &&
@@ -55,6 +55,10 @@ test_expect_success 'stash some dirty working directory' '
git stash &&
git diff-files --quiet &&
git diff-index --cached --quiet HEAD
+}
+
+test_expect_success 'stash some dirty working directory' '
+ setup_stash
'
cat >expect <<EOF
@@ -185,6 +189,43 @@ test_expect_success 'drop middle stash by index' '
test 1 = $(git show HEAD:file)
'
+test_expect_success 'drop stash reflog updates refs/stash' '
+ git reset --hard &&
+ git rev-parse refs/stash >expect &&
+ echo 9 >file &&
+ git stash &&
+ git stash drop stash@{0} &&
+ git rev-parse refs/stash >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success REFFILES 'drop stash reflog updates refs/stash with rewrite' '
+ git init repo &&
+ (
+ cd repo &&
+ setup_stash
+ ) &&
+ echo 9 >repo/file &&
+
+ old_oid="$(git -C repo rev-parse stash@{0})" &&
+ git -C repo stash &&
+ new_oid="$(git -C repo rev-parse stash@{0})" &&
+
+ cat >expect <<-EOF &&
+ $(test_oid zero) $old_oid
+ $old_oid $new_oid
+ EOF
+ cut -d" " -f1-2 repo/.git/logs/refs/stash >actual &&
+ test_cmp expect actual &&
+
+ git -C repo stash drop stash@{1} &&
+ cut -d" " -f1-2 repo/.git/logs/refs/stash >actual &&
+ cat >expect <<-EOF &&
+ $(test_oid zero) $new_oid
+ EOF
+ test_cmp expect actual
+'
+
test_expect_success 'stash pop' '
git reset --hard &&
git stash pop &&
@@ -261,6 +302,18 @@ test_expect_success 'apply -q is quiet' '
test_must_be_empty output.out
'
+test_expect_success 'apply --index -q is quiet' '
+ # Added file, deleted file, modified file all staged for commit
+ echo foo >new-file &&
+ echo test >file &&
+ git add new-file file &&
+ git rm other-file &&
+
+ git stash &&
+ git stash apply --index -q >output.out 2>&1 &&
+ test_must_be_empty output.out
+'
+
test_expect_success 'save -q is quiet' '
git stash save --quiet >output.out 2>&1 &&
test_must_be_empty output.out
@@ -291,6 +344,27 @@ test_expect_success 'drop -q is quiet' '
test_must_be_empty output.out
'
+test_expect_success 'stash push -q --staged refreshes the index' '
+ git reset --hard &&
+ echo test >file &&
+ git add file &&
+ git stash push -q --staged &&
+ git diff-files >output.out &&
+ test_must_be_empty output.out
+'
+
+test_expect_success 'stash apply -q --index refreshes the index' '
+ echo test >other-file &&
+ git add other-file &&
+ echo another-change >other-file &&
+ git diff-files >expect &&
+ git stash &&
+
+ git stash apply -q --index &&
+ git diff-files >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'stash -k' '
echo bar3 >file &&
echo bar4 >file2 &&
@@ -390,10 +464,11 @@ test_expect_success SYMLINKS 'stash file to symlink' '
rm file &&
ln -s file2 file &&
git stash save "file to symlink" &&
- test -f file &&
+ test_path_is_file_not_symlink file &&
test bar = "$(cat file)" &&
git stash apply &&
- case "$(ls -l file)" in *" file -> file2") :;; *) false;; esac
+ test_path_is_symlink file &&
+ test "$(test_readlink file)" = file2
'
test_expect_success SYMLINKS 'stash file to symlink (stage rm)' '
@@ -401,10 +476,11 @@ test_expect_success SYMLINKS 'stash file to symlink (stage rm)' '
git rm file &&
ln -s file2 file &&
git stash save "file to symlink (stage rm)" &&
- test -f file &&
+ test_path_is_file_not_symlink file &&
test bar = "$(cat file)" &&
git stash apply &&
- case "$(ls -l file)" in *" file -> file2") :;; *) false;; esac
+ test_path_is_symlink file &&
+ test "$(test_readlink file)" = file2
'
test_expect_success SYMLINKS 'stash file to symlink (full stage)' '
@@ -413,10 +489,11 @@ test_expect_success SYMLINKS 'stash file to symlink (full stage)' '
ln -s file2 file &&
git add file &&
git stash save "file to symlink (full stage)" &&
- test -f file &&
+ test_path_is_file_not_symlink file &&
test bar = "$(cat file)" &&
git stash apply &&
- case "$(ls -l file)" in *" file -> file2") :;; *) false;; esac
+ test_path_is_symlink file &&
+ test "$(test_readlink file)" = file2
'
# This test creates a commit with a symlink used for the following tests
@@ -487,7 +564,7 @@ test_expect_failure 'stash directory to file' '
rm -fr dir &&
echo bar >dir &&
git stash save "directory to file" &&
- test -d dir &&
+ test_path_is_dir dir &&
test foo = "$(cat dir/file)" &&
test_must_fail git stash apply &&
test bar = "$(cat dir)" &&
@@ -500,10 +577,10 @@ test_expect_failure 'stash file to directory' '
mkdir file &&
echo foo >file/file &&
git stash save "file to directory" &&
- test -f file &&
+ test_path_is_file file &&
test bar = "$(cat file)" &&
git stash apply &&
- test -f file/file &&
+ test_path_is_file file/file &&
test foo = "$(cat file/file)"
'
@@ -1042,6 +1119,17 @@ test_expect_success 'create stores correct message' '
test_cmp expect actual
'
+test_expect_success 'create when branch name has /' '
+ test_when_finished "git checkout main" &&
+ git checkout -b some/topic &&
+ >foo &&
+ git add foo &&
+ STASH_ID=$(git stash create "create test message") &&
+ echo "On some/topic: create test message" >expect &&
+ git show --pretty=%s -s ${STASH_ID} >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'create with multiple arguments for the message' '
>foo &&
git add foo &&
@@ -1272,7 +1360,6 @@ test_expect_success 'stash works when user.name and user.email are not set' '
>2 &&
git add 2 &&
test_config user.useconfigonly true &&
- test_config stash.usebuiltin true &&
(
sane_unset GIT_AUTHOR_NAME &&
sane_unset GIT_AUTHOR_EMAIL &&
@@ -1323,20 +1410,6 @@ test_expect_success 'stash handles skip-worktree entries nicely' '
git rev-parse --verify refs/stash:A.t
'
-test_expect_success 'stash -c stash.useBuiltin=false warning ' '
- expected="stash.useBuiltin support has been removed" &&
-
- git -c stash.useBuiltin=false stash 2>err &&
- test_i18ngrep "$expected" err &&
- env GIT_TEST_STASH_USE_BUILTIN=false git stash 2>err &&
- test_i18ngrep "$expected" err &&
-
- git -c stash.useBuiltin=true stash 2>err &&
- test_must_be_empty err &&
- env GIT_TEST_STASH_USE_BUILTIN=true git stash 2>err &&
- test_must_be_empty err
-'
-
test_expect_success 'git stash succeeds despite directory/file change' '
test_create_repo directory_file_switch_v1 &&
(
diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh
index 9babf13..f3e20dd 100755
--- a/t/t4015-diff-whitespace.sh
+++ b/t/t4015-diff-whitespace.sh
@@ -6,6 +6,8 @@
test_description='Test special whitespace in diff engine.
'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff.sh
@@ -1622,7 +1624,7 @@ test_expect_success 'cmd option assumes configured colored-moved' '
test_cmp expected actual
'
-test_expect_success 'no effect from --color-moved with --word-diff' '
+test_expect_success 'no effect on diff from --color-moved with --word-diff' '
cat <<-\EOF >text.txt &&
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
EOF
@@ -1636,6 +1638,12 @@ test_expect_success 'no effect from --color-moved with --word-diff' '
test_cmp expect actual
'
+test_expect_success !SANITIZE_LEAK 'no effect on show from --color-moved with --word-diff' '
+ git show --color-moved --word-diff >actual &&
+ git show --word-diff >expect &&
+ test_cmp expect actual
+'
+
test_expect_success 'set up whitespace tests' '
git reset --hard &&
# Note that these lines have no leading or trailing whitespace.
@@ -2016,7 +2024,7 @@ test_expect_success '--color-moved rewinds for MIN_ALNUM_COUNT' '
test_cmp expected actual
'
-test_expect_success 'move detection with submodules' '
+test_expect_success !SANITIZE_LEAK 'move detection with submodules' '
test_create_repo bananas &&
echo ripe >bananas/recipe &&
git -C bananas add recipe &&
diff --git a/t/t4018/kotlin-class b/t/t4018/kotlin-class
new file mode 100644
index 0000000..bb864f2
--- /dev/null
+++ b/t/t4018/kotlin-class
@@ -0,0 +1,5 @@
+class RIGHT {
+ //comment
+ //comment
+ return ChangeMe
+}
diff --git a/t/t4018/kotlin-enum-class b/t/t4018/kotlin-enum-class
new file mode 100644
index 0000000..8885f90
--- /dev/null
+++ b/t/t4018/kotlin-enum-class
@@ -0,0 +1,5 @@
+enum class RIGHT{
+ // Left
+ // a comment
+ ChangeMe
+}
diff --git a/t/t4018/kotlin-fun b/t/t4018/kotlin-fun
new file mode 100644
index 0000000..2a60280
--- /dev/null
+++ b/t/t4018/kotlin-fun
@@ -0,0 +1,5 @@
+fun RIGHT(){
+ //a comment
+ //b comment
+ return ChangeMe()
+}
diff --git a/t/t4018/kotlin-inheritace-class b/t/t4018/kotlin-inheritace-class
new file mode 100644
index 0000000..77376c1
--- /dev/null
+++ b/t/t4018/kotlin-inheritace-class
@@ -0,0 +1,5 @@
+open class RIGHT{
+ // a comment
+ // b comment
+ // ChangeMe
+}
diff --git a/t/t4018/kotlin-inline-class b/t/t4018/kotlin-inline-class
new file mode 100644
index 0000000..7bf46dd
--- /dev/null
+++ b/t/t4018/kotlin-inline-class
@@ -0,0 +1,5 @@
+value class RIGHT(Args){
+ // a comment
+ // b comment
+ ChangeMe
+}
diff --git a/t/t4018/kotlin-interface b/t/t4018/kotlin-interface
new file mode 100644
index 0000000..f686ba7
--- /dev/null
+++ b/t/t4018/kotlin-interface
@@ -0,0 +1,5 @@
+interface RIGHT{
+ //another comment
+ //another comment
+ //ChangeMe
+}
diff --git a/t/t4018/kotlin-nested-fun b/t/t4018/kotlin-nested-fun
new file mode 100644
index 0000000..1218685
--- /dev/null
+++ b/t/t4018/kotlin-nested-fun
@@ -0,0 +1,9 @@
+class LEFT{
+ class CENTER{
+ fun RIGHT( a:Int){
+ //comment
+ //comment
+ ChangeMe
+ }
+ }
+}
diff --git a/t/t4018/kotlin-public-class b/t/t4018/kotlin-public-class
new file mode 100644
index 0000000..9433fcc
--- /dev/null
+++ b/t/t4018/kotlin-public-class
@@ -0,0 +1,5 @@
+public class RIGHT{
+ //comment1
+ //comment2
+ ChangeMe
+}
diff --git a/t/t4018/kotlin-sealed-class b/t/t4018/kotlin-sealed-class
new file mode 100644
index 0000000..0efa4a4
--- /dev/null
+++ b/t/t4018/kotlin-sealed-class
@@ -0,0 +1,5 @@
+sealed class RIGHT {
+ // a comment
+ // b comment
+ ChangeMe
+}
diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh
index 54bb8ef..1219f8b 100755
--- a/t/t4020-diff-external.sh
+++ b/t/t4020-diff-external.sh
@@ -24,45 +24,38 @@ test_expect_success setup '
'
test_expect_success 'GIT_EXTERNAL_DIFF environment' '
-
- GIT_EXTERNAL_DIFF=echo git diff | {
- read path oldfile oldhex oldmode newfile newhex newmode &&
- test "z$path" = zfile &&
- test "z$oldmode" = z100644 &&
- test "z$newhex" = "z$ZERO_OID" &&
- test "z$newmode" = z100644 &&
- oh=$(git rev-parse --verify HEAD:file) &&
- test "z$oh" = "z$oldhex"
- }
+ cat >expect <<-EOF &&
+ file $(git rev-parse --verify HEAD:file) 100644 file $(test_oid zero) 100644
+ EOF
+ GIT_EXTERNAL_DIFF=echo git diff >out &&
+ cut -d" " -f1,3- <out >actual &&
+ test_cmp expect actual
'
-test_expect_success 'GIT_EXTERNAL_DIFF environment should apply only to diff' '
-
- GIT_EXTERNAL_DIFF=echo git log -p -1 HEAD |
- grep "^diff --git a/file b/file"
+test_expect_success !SANITIZE_LEAK 'GIT_EXTERNAL_DIFF environment should apply only to diff' '
+ GIT_EXTERNAL_DIFF=echo git log -p -1 HEAD >out &&
+ grep "^diff --git a/file b/file" out
'
test_expect_success 'GIT_EXTERNAL_DIFF environment and --no-ext-diff' '
-
- GIT_EXTERNAL_DIFF=echo git diff --no-ext-diff |
- grep "^diff --git a/file b/file"
+ GIT_EXTERNAL_DIFF=echo git diff --no-ext-diff >out &&
+ grep "^diff --git a/file b/file" out
'
test_expect_success SYMLINKS 'typechange diff' '
rm -f file &&
ln -s elif file &&
- GIT_EXTERNAL_DIFF=echo git diff | {
- read path oldfile oldhex oldmode newfile newhex newmode &&
- test "z$path" = zfile &&
- test "z$oldmode" = z100644 &&
- test "z$newhex" = "z$ZERO_OID" &&
- test "z$newmode" = z120000 &&
- oh=$(git rev-parse --verify HEAD:file) &&
- test "z$oh" = "z$oldhex"
- } &&
+
+ cat >expect <<-EOF &&
+ file $(git rev-parse --verify HEAD:file) 100644 $(test_oid zero) 120000
+ EOF
+ GIT_EXTERNAL_DIFF=echo git diff >out &&
+ cut -d" " -f1,3-4,6- <out >actual &&
+ test_cmp expect actual &&
+
GIT_EXTERNAL_DIFF=echo git diff --no-ext-diff >actual &&
git diff >expect &&
test_cmp expect actual
@@ -72,27 +65,25 @@ test_expect_success 'diff.external' '
git reset --hard &&
echo third >file &&
test_config diff.external echo &&
- git diff | {
- read path oldfile oldhex oldmode newfile newhex newmode &&
- test "z$path" = zfile &&
- test "z$oldmode" = z100644 &&
- test "z$newhex" = "z$ZERO_OID" &&
- test "z$newmode" = z100644 &&
- oh=$(git rev-parse --verify HEAD:file) &&
- test "z$oh" = "z$oldhex"
- }
+
+ cat >expect <<-EOF &&
+ file $(git rev-parse --verify HEAD:file) 100644 $(test_oid zero) 100644
+ EOF
+ git diff >out &&
+ cut -d" " -f1,3-4,6- <out >actual &&
+ test_cmp expect actual
'
-test_expect_success 'diff.external should apply only to diff' '
+test_expect_success !SANITIZE_LEAK 'diff.external should apply only to diff' '
test_config diff.external echo &&
- git log -p -1 HEAD |
- grep "^diff --git a/file b/file"
+ git log -p -1 HEAD >out &&
+ grep "^diff --git a/file b/file" out
'
test_expect_success 'diff.external and --no-ext-diff' '
test_config diff.external echo &&
- git diff --no-ext-diff |
- grep "^diff --git a/file b/file"
+ git diff --no-ext-diff >out &&
+ grep "^diff --git a/file b/file" out
'
test_expect_success 'diff attribute' '
@@ -103,29 +94,23 @@ test_expect_success 'diff attribute' '
echo >.gitattributes "file diff=parrot" &&
- git diff | {
- read path oldfile oldhex oldmode newfile newhex newmode &&
- test "z$path" = zfile &&
- test "z$oldmode" = z100644 &&
- test "z$newhex" = "z$ZERO_OID" &&
- test "z$newmode" = z100644 &&
- oh=$(git rev-parse --verify HEAD:file) &&
- test "z$oh" = "z$oldhex"
- }
-
+ cat >expect <<-EOF &&
+ file $(git rev-parse --verify HEAD:file) 100644 $(test_oid zero) 100644
+ EOF
+ git diff >out &&
+ cut -d" " -f1,3-4,6- <out >actual &&
+ test_cmp expect actual
'
-test_expect_success 'diff attribute should apply only to diff' '
-
- git log -p -1 HEAD |
- grep "^diff --git a/file b/file"
+test_expect_success !SANITIZE_LEAK 'diff attribute should apply only to diff' '
+ git log -p -1 HEAD >out &&
+ grep "^diff --git a/file b/file" out
'
test_expect_success 'diff attribute and --no-ext-diff' '
-
- git diff --no-ext-diff |
- grep "^diff --git a/file b/file"
+ git diff --no-ext-diff >out &&
+ grep "^diff --git a/file b/file" out
'
@@ -136,48 +121,55 @@ test_expect_success 'diff attribute' '
echo >.gitattributes "file diff=color" &&
- git diff | {
- read path oldfile oldhex oldmode newfile newhex newmode &&
- test "z$path" = zfile &&
- test "z$oldmode" = z100644 &&
- test "z$newhex" = "z$ZERO_OID" &&
- test "z$newmode" = z100644 &&
- oh=$(git rev-parse --verify HEAD:file) &&
- test "z$oh" = "z$oldhex"
- }
-
+ cat >expect <<-EOF &&
+ file $(git rev-parse --verify HEAD:file) 100644 $(test_oid zero) 100644
+ EOF
+ git diff >out &&
+ cut -d" " -f1,3-4,6- <out >actual &&
+ test_cmp expect actual
'
-test_expect_success 'diff attribute should apply only to diff' '
-
- git log -p -1 HEAD |
- grep "^diff --git a/file b/file"
+test_expect_success !SANITIZE_LEAK 'diff attribute should apply only to diff' '
+ git log -p -1 HEAD >out &&
+ grep "^diff --git a/file b/file" out
'
test_expect_success 'diff attribute and --no-ext-diff' '
-
- git diff --no-ext-diff |
- grep "^diff --git a/file b/file"
+ git diff --no-ext-diff >out &&
+ grep "^diff --git a/file b/file" out
'
test_expect_success 'GIT_EXTERNAL_DIFF trumps diff.external' '
>.gitattributes &&
test_config diff.external "echo ext-global" &&
- GIT_EXTERNAL_DIFF="echo ext-env" git diff | grep ext-env
+
+ cat >expect <<-EOF &&
+ ext-env file $(git rev-parse --verify HEAD:file) 100644 file $(test_oid zero) 100644
+ EOF
+ GIT_EXTERNAL_DIFF="echo ext-env" git diff >out &&
+ cut -d" " -f1-2,4- <out >actual &&
+ test_cmp expect actual
'
test_expect_success 'attributes trump GIT_EXTERNAL_DIFF and diff.external' '
test_config diff.foo.command "echo ext-attribute" &&
test_config diff.external "echo ext-global" &&
echo "file diff=foo" >.gitattributes &&
- GIT_EXTERNAL_DIFF="echo ext-env" git diff | grep ext-attribute
+
+ cat >expect <<-EOF &&
+ ext-attribute file $(git rev-parse --verify HEAD:file) 100644 file $(test_oid zero) 100644
+ EOF
+ GIT_EXTERNAL_DIFF="echo ext-env" git diff >out &&
+ cut -d" " -f1-2,4- <out >actual &&
+ test_cmp expect actual
'
test_expect_success 'no diff with -diff' '
echo >.gitattributes "file -diff" &&
- git diff | grep Binary
+ git diff >out &&
+ grep Binary out
'
echo NULZbetweenZwords | perl -pe 'y/Z/\000/' > file
@@ -217,7 +209,12 @@ test_expect_success 'GIT_EXTERNAL_DIFF generates pretty paths' '
touch file.ext &&
git add file.ext &&
echo with extension > file.ext &&
- GIT_EXTERNAL_DIFF=echo git diff file.ext | grep ......_file\.ext &&
+
+ cat >expect <<-EOF &&
+ file.ext file $(git rev-parse --verify HEAD:file) 100644 file.ext $(test_oid zero) 100644
+ EOF
+ GIT_EXTERNAL_DIFF=echo git diff file.ext >out &&
+ cut -d" " -f1,3- <out >actual &&
git update-index --force-remove file.ext &&
rm file.ext
'
diff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh
index 6cef0da..295da98 100755
--- a/t/t4027-diff-submodule.sh
+++ b/t/t4027-diff-submodule.sh
@@ -2,7 +2,6 @@
test_description='difference in submodules'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff.sh
@@ -28,10 +27,8 @@ test_expect_success setup '
git commit -m "submodule #2"
) &&
- set x $(
- cd sub &&
- git rev-list HEAD
- ) &&
+ git -C sub rev-list HEAD >revs &&
+ set x $(cat revs) &&
echo ":160000 160000 $3 $ZERO_OID M sub" >expect &&
subtip=$3 subprev=$2
'
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index d5abcf4..15764ee 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -324,6 +324,7 @@ test_language_driver dts
test_language_driver fortran
test_language_driver html
test_language_driver java
+test_language_driver kotlin
test_language_driver matlab
test_language_driver objc
test_language_driver pascal
diff --git a/t/t4034/kotlin/expect b/t/t4034/kotlin/expect
new file mode 100644
index 0000000..7f76f75
--- /dev/null
+++ b/t/t4034/kotlin/expect
@@ -0,0 +1,43 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 11ea3de..2e1df4c 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,30 +1,30 @@<RESET>
+println("Hello World<RED>!\n<RESET><GREEN>?<RESET>")
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a a<RESET><GREEN>x x<RESET>.inv() <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET><GREEN>y<RESET>
+a <RED>shr<RESET><GREEN>shl<RESET> b
+<RED>a<RESET><GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b a<RESET><GREEN>y x<RESET>===<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> and <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> or <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b a<RESET><GREEN>y x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET><GREEN>y<RESET>
+a<RED>=<RESET><GREEN>+=<RESET>b c<RED>+=<RESET><GREEN>=<RESET>d e<RED>-=<RESET><GREEN><=<RESET>f g<RED>*=<RESET><GREEN>>=<RESET>h i<RED>/=<RESET><GREEN>/<RESET>j k<RED>%=<RESET><GREEN>%<RESET>l m<RED><<=<RESET><GREEN><<<RESET>n o<RED>>>=<RESET><GREEN>>><RESET>p q<RED>&=<RESET><GREEN>&<RESET>r s<RED>^=<RESET><GREEN>^<RESET>t u<RED>|=<RESET><GREEN>|<RESET>v
+a<RED><<=<RESET><GREEN><=<RESET>b
+a<RED>||<RESET><GREEN>|<RESET>b a<RED>&&<RESET><GREEN>&<RESET>b
+<RED>a<RESET><GREEN>x<RESET>,y
+--a<RED>==<RESET><GREEN>!=<RESET>--b
+a++<RED>==<RESET><GREEN>!=<RESET>++b
+<RED>0xFF_EC_DE_5E 0b100_000 100_000<RESET><GREEN>0xFF_E1_DE_5E 0b100_100 200_000<RESET>
+a<RED>==<RESET><GREEN>===<RESET>b
+a<RED>!!<RESET><GREEN>!=<RESET>b
+<RED>_32<RESET><GREEN>_33<RESET>.find(arr)
+X.<RED>fill<RESET><GREEN>find<RESET>()
+X.<RED>u<RESET><GREEN>f<RESET>+1
+X.u<RED>-<RESET><GREEN>+<RESET>2
+a<RED>.<RESET><GREEN>..<RESET>b
+a<RED>?.<RESET><GREEN>?:<RESET>b
+<RED>.32_00_456<RESET><GREEN>.32_00_446<RESET>
diff --git a/t/t4034/kotlin/post b/t/t4034/kotlin/post
new file mode 100644
index 0000000..2e1df4c
--- /dev/null
+++ b/t/t4034/kotlin/post
@@ -0,0 +1,30 @@
+println("Hello World?")
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x x.inv() x*y x&y
+x*y x/y x%y
+x+y x-y
+a shl b
+x<y x<=y x>y x>=y
+x==y x!=y x===y
+x and y
+x^y
+x or y
+x&&y x||y
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+a+=b c=d e<=f g>=h i/j k%l m<<n o>>p q&r s^t u|v
+a<=b
+a|b a&b
+x,y
+--a!=--b
+a++!=++b
+0xFF_E1_DE_5E 0b100_100 200_000
+a===b
+a!=b
+_33.find(arr)
+X.find()
+X.f+1
+X.u+2
+a..b
+a?:b
+.32_00_446
diff --git a/t/t4034/kotlin/pre b/t/t4034/kotlin/pre
new file mode 100644
index 0000000..11ea3de
--- /dev/null
+++ b/t/t4034/kotlin/pre
@@ -0,0 +1,30 @@
+println("Hello World!\n")
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a a.inv() a*b a&b
+a*b a/b a%b
+a+b a-b
+a shr b
+a<b a<=b a>b a>=b
+a==b a!=b a===b
+a and b
+a^b
+a or b
+a&&b a||b
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a=b c+=d e-=f g*=h i/=j k%=l m<<=n o>>=p q&=r s^=t u|=v
+a<<=b
+a||b a&&b
+a,y
+--a==--b
+a++==++b
+0xFF_EC_DE_5E 0b100_000 100_000
+a==b
+a!!b
+_32.find(arr)
+X.fill()
+X.u+1
+X.u-2
+a.b
+a?.b
+.32_00_456
diff --git a/t/t4069-remerge-diff.sh b/t/t4069-remerge-diff.sh
new file mode 100755
index 0000000..35f9495
--- /dev/null
+++ b/t/t4069-remerge-diff.sh
@@ -0,0 +1,291 @@
+#!/bin/sh
+
+test_description='remerge-diff handling'
+
+. ./test-lib.sh
+
+# This test is ort-specific
+if test "${GIT_TEST_MERGE_ALGORITHM}" != ort
+then
+ skip_all="GIT_TEST_MERGE_ALGORITHM != ort"
+ test_done
+fi
+
+test_expect_success 'setup basic merges' '
+ test_write_lines 1 2 3 4 5 6 7 8 9 >numbers &&
+ git add numbers &&
+ git commit -m base &&
+
+ git branch feature_a &&
+ git branch feature_b &&
+ git branch feature_c &&
+
+ git branch ab_resolution &&
+ git branch bc_resolution &&
+
+ git checkout feature_a &&
+ test_write_lines 1 2 three 4 5 6 7 eight 9 >numbers &&
+ git commit -a -m change_a &&
+
+ git checkout feature_b &&
+ test_write_lines 1 2 tres 4 5 6 7 8 9 >numbers &&
+ git commit -a -m change_b &&
+
+ git checkout feature_c &&
+ test_write_lines 1 2 3 4 5 6 7 8 9 10 >numbers &&
+ git commit -a -m change_c &&
+
+ git checkout bc_resolution &&
+ git merge --ff-only feature_b &&
+ # no conflict
+ git merge feature_c &&
+
+ git checkout ab_resolution &&
+ git merge --ff-only feature_a &&
+ # conflicts!
+ test_must_fail git merge feature_b &&
+ # Resolve conflict...and make another change elsewhere
+ test_write_lines 1 2 drei 4 5 6 7 acht 9 >numbers &&
+ git add numbers &&
+ git merge --continue
+'
+
+test_expect_success 'remerge-diff on a clean merge' '
+ git log -1 --oneline bc_resolution >expect &&
+ git show --oneline --remerge-diff bc_resolution >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'remerge-diff with both a resolved conflict and an unrelated change' '
+ git log -1 --oneline ab_resolution >tmp &&
+ cat <<-EOF >>tmp &&
+ diff --git a/numbers b/numbers
+ remerge CONFLICT (content): Merge conflict in numbers
+ index a1fb731..6875544 100644
+ --- a/numbers
+ +++ b/numbers
+ @@ -1,13 +1,9 @@
+ 1
+ 2
+ -<<<<<<< b0ed5cb (change_a)
+ -three
+ -=======
+ -tres
+ ->>>>>>> 6cd3f82 (change_b)
+ +drei
+ 4
+ 5
+ 6
+ 7
+ -eight
+ +acht
+ 9
+ EOF
+ # Hashes above are sha1; rip them out so test works with sha256
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect &&
+
+ git show --oneline --remerge-diff ab_resolution >tmp &&
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'setup non-content conflicts' '
+ git switch --orphan base &&
+
+ test_write_lines 1 2 3 4 5 6 7 8 9 >numbers &&
+ test_write_lines a b c d e f g h i >letters &&
+ test_write_lines in the way >content &&
+ git add numbers letters content &&
+ git commit -m base &&
+
+ git branch side1 &&
+ git branch side2 &&
+
+ git checkout side1 &&
+ test_write_lines 1 2 three 4 5 6 7 8 9 >numbers &&
+ git mv letters letters_side1 &&
+ git mv content file_or_directory &&
+ git add numbers &&
+ git commit -m side1 &&
+
+ git checkout side2 &&
+ git rm numbers &&
+ git mv letters letters_side2 &&
+ mkdir file_or_directory &&
+ echo hello >file_or_directory/world &&
+ git add file_or_directory/world &&
+ git commit -m side2 &&
+
+ git checkout -b resolution side1 &&
+ test_must_fail git merge side2 &&
+ test_write_lines 1 2 three 4 5 6 7 8 9 >numbers &&
+ git add numbers &&
+ git add letters_side1 &&
+ git rm letters &&
+ git rm letters_side2 &&
+ git add file_or_directory~HEAD &&
+ git mv file_or_directory~HEAD wanted_content &&
+ git commit -m resolved
+'
+
+test_expect_success 'remerge-diff with non-content conflicts' '
+ git log -1 --oneline resolution >tmp &&
+ cat <<-EOF >>tmp &&
+ diff --git a/file_or_directory~HASH (side1) b/wanted_content
+ similarity index 100%
+ rename from file_or_directory~HASH (side1)
+ rename to wanted_content
+ remerge CONFLICT (file/directory): directory in the way of file_or_directory from HASH (side1); moving it to file_or_directory~HASH (side1) instead.
+ diff --git a/letters b/letters
+ remerge CONFLICT (rename/rename): letters renamed to letters_side1 in HASH (side1) and to letters_side2 in HASH (side2).
+ diff --git a/letters_side2 b/letters_side2
+ deleted file mode 100644
+ index b236ae5..0000000
+ --- a/letters_side2
+ +++ /dev/null
+ @@ -1,9 +0,0 @@
+ -a
+ -b
+ -c
+ -d
+ -e
+ -f
+ -g
+ -h
+ -i
+ diff --git a/numbers b/numbers
+ remerge CONFLICT (modify/delete): numbers deleted in HASH (side2) and modified in HASH (side1). Version HASH (side1) of numbers left in tree.
+ EOF
+ # We still have some sha1 hashes above; rip them out so test works
+ # with sha256
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect &&
+
+ git show --oneline --remerge-diff resolution >tmp &&
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'remerge-diff w/ diff-filter=U: all conflict headers, no diff content' '
+ git log -1 --oneline resolution >tmp &&
+ cat <<-EOF >>tmp &&
+ diff --git a/file_or_directory~HASH (side1) b/file_or_directory~HASH (side1)
+ remerge CONFLICT (file/directory): directory in the way of file_or_directory from HASH (side1); moving it to file_or_directory~HASH (side1) instead.
+ diff --git a/letters b/letters
+ remerge CONFLICT (rename/rename): letters renamed to letters_side1 in HASH (side1) and to letters_side2 in HASH (side2).
+ diff --git a/numbers b/numbers
+ remerge CONFLICT (modify/delete): numbers deleted in HASH (side2) and modified in HASH (side1). Version HASH (side1) of numbers left in tree.
+ EOF
+ # We still have some sha1 hashes above; rip them out so test works
+ # with sha256
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect &&
+
+ git show --oneline --remerge-diff --diff-filter=U resolution >tmp &&
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'remerge-diff w/ diff-filter=R: relevant file + conflict header' '
+ git log -1 --oneline resolution >tmp &&
+ cat <<-EOF >>tmp &&
+ diff --git a/file_or_directory~HASH (side1) b/wanted_content
+ similarity index 100%
+ rename from file_or_directory~HASH (side1)
+ rename to wanted_content
+ remerge CONFLICT (file/directory): directory in the way of file_or_directory from HASH (side1); moving it to file_or_directory~HASH (side1) instead.
+ EOF
+ # We still have some sha1 hashes above; rip them out so test works
+ # with sha256
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect &&
+
+ git show --oneline --remerge-diff --diff-filter=R resolution >tmp &&
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'remerge-diff w/ pathspec: limits to relevant file including conflict header' '
+ git log -1 --oneline resolution >tmp &&
+ cat <<-EOF >>tmp &&
+ diff --git a/letters b/letters
+ remerge CONFLICT (rename/rename): letters renamed to letters_side1 in HASH (side1) and to letters_side2 in HASH (side2).
+ diff --git a/letters_side2 b/letters_side2
+ deleted file mode 100644
+ index b236ae5..0000000
+ --- a/letters_side2
+ +++ /dev/null
+ @@ -1,9 +0,0 @@
+ -a
+ -b
+ -c
+ -d
+ -e
+ -f
+ -g
+ -h
+ -i
+ EOF
+ # We still have some sha1 hashes above; rip them out so test works
+ # with sha256
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect &&
+
+ git show --oneline --remerge-diff resolution -- "letters*" >tmp &&
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'setup non-content conflicts' '
+ git switch --orphan newbase &&
+
+ test_write_lines 1 2 3 4 5 6 7 8 9 >numbers &&
+ git add numbers &&
+ git commit -m base &&
+
+ git branch newside1 &&
+ git branch newside2 &&
+
+ git checkout newside1 &&
+ test_write_lines 1 2 three 4 5 6 7 8 9 >numbers &&
+ git add numbers &&
+ git commit -m side1 &&
+
+ git checkout newside2 &&
+ test_write_lines 1 2 drei 4 5 6 7 8 9 >numbers &&
+ git add numbers &&
+ git commit -m side2 &&
+
+ git checkout -b newresolution newside1 &&
+ test_must_fail git merge newside2 &&
+ git checkout --theirs numbers &&
+ git add -u numbers &&
+ git commit -m resolved
+'
+
+test_expect_success 'remerge-diff turns off history simplification' '
+ git log -1 --oneline newresolution >tmp &&
+ cat <<-EOF >>tmp &&
+ diff --git a/numbers b/numbers
+ remerge CONFLICT (content): Merge conflict in numbers
+ index 070e9e7..5335e78 100644
+ --- a/numbers
+ +++ b/numbers
+ @@ -1,10 +1,6 @@
+ 1
+ 2
+ -<<<<<<< 96f1e45 (side1)
+ -three
+ -=======
+ drei
+ ->>>>>>> 4fd522f (side2)
+ 4
+ 5
+ 6
+ EOF
+ # We still have some sha1 hashes above; rip them out so test works
+ # with sha256
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect &&
+
+ git show --oneline --remerge-diff newresolution -- numbers >tmp &&
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t4123-apply-shrink.sh b/t/t4123-apply-shrink.sh
index dfa053f..3ef8461 100755
--- a/t/t4123-apply-shrink.sh
+++ b/t/t4123-apply-shrink.sh
@@ -2,8 +2,6 @@
test_description='apply a patch that is larger than the preimage'
-
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
cat >F <<\EOF
@@ -41,20 +39,8 @@ test_expect_success setup '
'
test_expect_success 'apply should fail gracefully' '
-
- if git apply --index patch
- then
- echo Oops, should not have succeeded
- false
- else
- status=$? &&
- echo "Status was $status" &&
- if test -f .git/index.lock
- then
- echo Oops, should not have crashed
- false
- fi
- fi
+ test_must_fail git apply --index patch &&
+ test_path_is_missing .git/index.lock
'
test_done
diff --git a/t/t4128-apply-root.sh b/t/t4128-apply-root.sh
index cb3181e..f6db5a7 100755
--- a/t/t4128-apply-root.sh
+++ b/t/t4128-apply-root.sh
@@ -2,8 +2,6 @@
test_description='apply same filename'
-
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -26,10 +24,11 @@ diff a/bla/blub/dir/file b/bla/blub/dir/file
EOF
test_expect_success 'apply --directory -p (1)' '
-
git apply --directory=some/sub -p3 --index patch &&
- test Bello = $(git show :some/sub/dir/file) &&
- test Bello = $(cat some/sub/dir/file)
+ echo Bello >expect &&
+ git show :some/sub/dir/file >actual &&
+ test_cmp expect actual &&
+ test_cmp expect some/sub/dir/file
'
@@ -37,8 +36,10 @@ test_expect_success 'apply --directory -p (2) ' '
git reset --hard initial &&
git apply --directory=some/sub/ -p3 --index patch &&
- test Bello = $(git show :some/sub/dir/file) &&
- test Bello = $(cat some/sub/dir/file)
+ echo Bello >expect &&
+ git show :some/sub/dir/file >actual &&
+ test_cmp expect actual &&
+ test_cmp expect some/sub/dir/file
'
@@ -55,8 +56,10 @@ EOF
test_expect_success 'apply --directory (new file)' '
git reset --hard initial &&
git apply --directory=some/sub/dir/ --index patch &&
- test content = $(git show :some/sub/dir/newfile) &&
- test content = $(cat some/sub/dir/newfile)
+ echo content >expect &&
+ git show :some/sub/dir/newfile >actual &&
+ test_cmp expect actual &&
+ test_cmp expect some/sub/dir/newfile
'
cat > patch << EOF
@@ -72,8 +75,10 @@ EOF
test_expect_success 'apply --directory -p (new file)' '
git reset --hard initial &&
git apply -p2 --directory=some/sub/dir/ --index patch &&
- test content = $(git show :some/sub/dir/newfile2) &&
- test content = $(cat some/sub/dir/newfile2)
+ echo content >expect &&
+ git show :some/sub/dir/newfile2 >actual &&
+ test_cmp expect actual &&
+ test_cmp expect some/sub/dir/newfile2
'
cat > patch << EOF
@@ -91,7 +96,8 @@ test_expect_success 'apply --directory (delete file)' '
echo content >some/sub/dir/delfile &&
git add some/sub/dir/delfile &&
git apply --directory=some/sub/dir/ --index patch &&
- ! (git ls-files | grep delfile)
+ git ls-files >out &&
+ ! grep delfile out
'
cat > patch << 'EOF'
@@ -107,8 +113,10 @@ EOF
test_expect_success 'apply --directory (quoted filename)' '
git reset --hard initial &&
git apply --directory=some/sub/dir/ --index patch &&
- test content = $(git show :some/sub/dir/quotefile) &&
- test content = $(cat some/sub/dir/quotefile)
+ echo content >expect &&
+ git show :some/sub/dir/quotefile >actual &&
+ test_cmp expect actual &&
+ test_cmp expect some/sub/dir/quotefile
'
test_done
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 6caff0c..cdad4b6 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -315,12 +315,10 @@ test_expect_success 'am --patch-format=hg applies hg patch' '
'
test_expect_success 'am with applypatch-msg hook' '
- test_when_finished "rm -f .git/hooks/applypatch-msg" &&
rm -fr .git/rebase-apply &&
git reset --hard &&
git checkout first &&
- mkdir -p .git/hooks &&
- write_script .git/hooks/applypatch-msg <<-\EOF &&
+ test_hook applypatch-msg <<-\EOF &&
cat "$1" >actual-msg &&
echo hook-message >"$1"
EOF
@@ -335,12 +333,10 @@ test_expect_success 'am with applypatch-msg hook' '
'
test_expect_success 'am with failing applypatch-msg hook' '
- test_when_finished "rm -f .git/hooks/applypatch-msg" &&
rm -fr .git/rebase-apply &&
git reset --hard &&
git checkout first &&
- mkdir -p .git/hooks &&
- write_script .git/hooks/applypatch-msg <<-\EOF &&
+ test_hook applypatch-msg <<-\EOF &&
exit 1
EOF
test_must_fail git am patch1 &&
@@ -350,12 +346,10 @@ test_expect_success 'am with failing applypatch-msg hook' '
'
test_expect_success 'am with pre-applypatch hook' '
- test_when_finished "rm -f .git/hooks/pre-applypatch" &&
rm -fr .git/rebase-apply &&
git reset --hard &&
git checkout first &&
- mkdir -p .git/hooks &&
- write_script .git/hooks/pre-applypatch <<-\EOF &&
+ test_hook pre-applypatch <<-\EOF &&
git diff first >diff.actual
exit 0
EOF
@@ -368,12 +362,10 @@ test_expect_success 'am with pre-applypatch hook' '
'
test_expect_success 'am with failing pre-applypatch hook' '
- test_when_finished "rm -f .git/hooks/pre-applypatch" &&
rm -fr .git/rebase-apply &&
git reset --hard &&
git checkout first &&
- mkdir -p .git/hooks &&
- write_script .git/hooks/pre-applypatch <<-\EOF &&
+ test_hook pre-applypatch <<-\EOF &&
exit 1
EOF
test_must_fail git am patch1 &&
@@ -383,12 +375,10 @@ test_expect_success 'am with failing pre-applypatch hook' '
'
test_expect_success 'am with post-applypatch hook' '
- test_when_finished "rm -f .git/hooks/post-applypatch" &&
rm -fr .git/rebase-apply &&
git reset --hard &&
git checkout first &&
- mkdir -p .git/hooks &&
- write_script .git/hooks/post-applypatch <<-\EOF &&
+ test_hook post-applypatch <<-\EOF &&
git rev-parse HEAD >head.actual
git diff second >diff.actual
exit 0
@@ -403,12 +393,10 @@ test_expect_success 'am with post-applypatch hook' '
'
test_expect_success 'am with failing post-applypatch hook' '
- test_when_finished "rm -f .git/hooks/post-applypatch" &&
rm -fr .git/rebase-apply &&
git reset --hard &&
git checkout first &&
- mkdir -p .git/hooks &&
- write_script .git/hooks/post-applypatch <<-\EOF &&
+ test_hook post-applypatch <<-\EOF &&
git rev-parse HEAD >head.actual
exit 1
EOF
@@ -1169,7 +1157,7 @@ test_expect_success 'invalid when passing the --empty option alone' '
test_when_finished "git am --abort || :" &&
git checkout empty-commit^ &&
test_must_fail git am --empty empty-commit.patch 2>err &&
- echo "error: Invalid value for --empty: empty-commit.patch" >expected &&
+ echo "error: invalid value for '\''--empty'\'': '\''empty-commit.patch'\''" >expected &&
test_cmp expected err
'
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index 5049559..be07407 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -142,6 +142,19 @@ test_expect_success 'diff-filter=R' '
'
+test_expect_success 'multiple --diff-filter bits' '
+
+ git log -M --pretty="format:%s" --diff-filter=R HEAD >expect &&
+ git log -M --pretty="format:%s" --diff-filter=Ra HEAD >actual &&
+ test_cmp expect actual &&
+ git log -M --pretty="format:%s" --diff-filter=aR HEAD >actual &&
+ test_cmp expect actual &&
+ git log -M --pretty="format:%s" \
+ --diff-filter=a --diff-filter=R HEAD >actual &&
+ test_cmp expect actual
+
+'
+
test_expect_success 'diff-filter=C' '
git log -C -C --pretty="format:%s" --diff-filter=C HEAD >actual &&
@@ -449,6 +462,29 @@ test_expect_success !FAIL_PREREQS 'log with various grep.patternType configurati
)
'
+for cmd in show whatchanged reflog format-patch
+do
+ case "$cmd" in
+ format-patch) myarg="HEAD~.." ;;
+ *) myarg= ;;
+ esac
+
+ test_expect_success "$cmd: understands grep.patternType, like 'log'" '
+ git init "pattern-type-$cmd" &&
+ (
+ cd "pattern-type-$cmd" &&
+ test_commit 1 file A &&
+ test_commit "(1|2)" file B 2 &&
+
+ git -c grep.patternType=fixed $cmd --grep="..." $myarg >actual &&
+ test_must_be_empty actual &&
+
+ git -c grep.patternType=basic $cmd --grep="..." $myarg >actual &&
+ test_file_not_empty actual
+ )
+ '
+done
+
test_expect_success 'log --author' '
cat >expect <<-\EOF &&
Author: <BOLD;RED>A U<RESET> Thor <author@example.com>
@@ -659,7 +695,7 @@ EOF
test_expect_success 'log --graph with full output' '
git log --graph --date-order --pretty=short |
- git name-rev --name-only --stdin |
+ git name-rev --name-only --annotate-stdin |
sed "s/Merge:.*/Merge: A B/;s/ *\$//" >actual &&
test_cmp expect actual
'
@@ -1671,6 +1707,75 @@ test_expect_success 'log --graph with --name-only' '
test_cmp_graph --name-only tangle..reach
'
+test_expect_success '--no-graph countermands --graph' '
+ git log >expect &&
+ git log --graph --no-graph >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--graph countermands --no-graph' '
+ git log --graph >expect &&
+ git log --no-graph --graph >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--no-graph does not unset --topo-order' '
+ git log --topo-order >expect &&
+ git log --topo-order --no-graph >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--no-graph does not unset --parents' '
+ git log --parents >expect &&
+ git log --parents --no-graph >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--reverse and --graph conflict' '
+ test_must_fail git log --reverse --graph 2>stderr &&
+ test_i18ngrep "cannot be used together" stderr
+'
+
+test_expect_success '--reverse --graph --no-graph works' '
+ git log --reverse >expect &&
+ git log --reverse --graph --no-graph >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--show-linear-break and --graph conflict' '
+ test_must_fail git log --show-linear-break --graph 2>stderr &&
+ test_i18ngrep "cannot be used together" stderr
+'
+
+test_expect_success '--show-linear-break --graph --no-graph works' '
+ git log --show-linear-break >expect &&
+ git log --show-linear-break --graph --no-graph >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--no-walk and --graph conflict' '
+ test_must_fail git log --no-walk --graph 2>stderr &&
+ test_i18ngrep "cannot be used together" stderr
+'
+
+test_expect_success '--no-walk --graph --no-graph works' '
+ git log --no-walk >expect &&
+ git log --no-walk --graph --no-graph >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--walk-reflogs and --graph conflict' '
+ test_must_fail git log --walk-reflogs --graph 2>stderr &&
+ (test_i18ngrep "cannot combine" stderr ||
+ test_i18ngrep "cannot be used together" stderr)
+'
+
+test_expect_success '--walk-reflogs --graph --no-graph works' '
+ git log --walk-reflogs >expect &&
+ git log --walk-reflogs --graph --no-graph >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'dotdot is a parent directory' '
mkdir -p a/b &&
( echo sixth && echo fifth ) >expect &&
@@ -1931,7 +2036,8 @@ test_expect_success GPGSM 'log --graph --show-signature for merged tag x509 miss
git merge --no-ff -m msg signed_tag_x509_nokey &&
GNUPGHOME=. git log --graph --show-signature -n1 plain-x509-nokey >actual &&
grep "^|\\\ merged tag" actual &&
- grep "^| | gpgsm: certificate not found" actual
+ grep -e "^| | gpgsm: certificate not found" \
+ -e "^| | gpgsm: failed to find the certificate: Not found" actual
'
test_expect_success GPGSM 'log --graph --show-signature for merged tag x509 bad signature' '
diff --git a/t/t4204-patch-id.sh b/t/t4204-patch-id.sh
index 80f4a65..a730c0d 100755
--- a/t/t4204-patch-id.sh
+++ b/t/t4204-patch-id.sh
@@ -38,7 +38,7 @@ calc_patch_id () {
shift
git patch-id "$@" >patch-id.output &&
sed "s/ .*//" patch-id.output >patch-id_"$patch_name" &&
- test_line_count -gt 0 patch-id_"$patch_name"
+ test_line_count -eq 1 patch-id_"$patch_name"
}
get_top_diff () {
@@ -166,40 +166,67 @@ test_expect_success 'patch-id respects config from subdir' '
)
'
-cat >nonl <<\EOF
-diff --git i/a w/a
-index e69de29..2e65efe 100644
---- i/a
-+++ w/a
-@@ -0,0 +1 @@
-+a
-\ No newline at end of file
-diff --git i/b w/b
-index e69de29..6178079 100644
---- i/b
-+++ w/b
-@@ -0,0 +1 @@
-+b
-EOF
-
-cat >withnl <<\EOF
-diff --git i/a w/a
-index e69de29..7898192 100644
---- i/a
-+++ w/a
-@@ -0,0 +1 @@
-+a
-diff --git i/b w/b
-index e69de29..6178079 100644
---- i/b
-+++ w/b
-@@ -0,0 +1 @@
-+b
-EOF
-
test_expect_success 'patch-id handles no-nl-at-eof markers' '
- cat nonl | calc_patch_id nonl &&
- cat withnl | calc_patch_id withnl &&
+ cat >nonl <<-\EOF &&
+ diff --git i/a w/a
+ index e69de29..2e65efe 100644
+ --- i/a
+ +++ w/a
+ @@ -0,0 +1 @@
+ +a
+ \ No newline at end of file
+ diff --git i/b w/b
+ index e69de29..6178079 100644
+ --- i/b
+ +++ w/b
+ @@ -0,0 +1 @@
+ +b
+ EOF
+ cat >withnl <<-\EOF &&
+ diff --git i/a w/a
+ index e69de29..7898192 100644
+ --- i/a
+ +++ w/a
+ @@ -0,0 +1 @@
+ +a
+ diff --git i/b w/b
+ index e69de29..6178079 100644
+ --- i/b
+ +++ w/b
+ @@ -0,0 +1 @@
+ +b
+ EOF
+ calc_patch_id nonl <nonl &&
+ calc_patch_id withnl <withnl &&
test_cmp patch-id_nonl patch-id_withnl
'
+
+test_expect_success 'patch-id handles diffs with one line of before/after' '
+ cat >diffu1 <<-\EOF &&
+ diff --git a/bar b/bar
+ index bdaf90f..31051f6 100644
+ --- a/bar
+ +++ b/bar
+ @@ -2 +2,2 @@
+ b
+ +c
+ diff --git a/car b/car
+ index 00750ed..2ae5e34 100644
+ --- a/car
+ +++ b/car
+ @@ -1 +1,2 @@
+ 3
+ +d
+ diff --git a/foo b/foo
+ index e439850..7146eb8 100644
+ --- a/foo
+ +++ b/foo
+ @@ -2 +2,2 @@
+ a
+ +e
+ EOF
+ calc_patch_id diffu1 <diffu1 &&
+ test_config patchid.stable true &&
+ calc_patch_id diffu1stable <diffu1
+'
test_done
diff --git a/t/t4216-log-bloom.sh b/t/t4216-log-bloom.sh
index cc3cebf..fa9d32f 100755
--- a/t/t4216-log-bloom.sh
+++ b/t/t4216-log-bloom.sh
@@ -48,6 +48,7 @@ graph_read_expect () {
header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0
num_commits: $1
chunks: oid_fanout oid_lookup commit_metadata generation_data bloom_indexes bloom_data
+ options: bloom(1,10,7) read_generation_data
EOF
test-tool read-graph >actual &&
test_cmp expect actual
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 2fd8451..a11d612 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -315,8 +315,10 @@ test_expect_success \
git index-pack -o tmp.idx test-3.pack &&
cmp tmp.idx test-1-${packname_1}.idx &&
- git index-pack test-3.pack &&
+ git index-pack --promisor=message test-3.pack &&
cmp test-3.idx test-1-${packname_1}.idx &&
+ echo message >expect &&
+ test_cmp expect test-3.promisor &&
cat test-2-${packname_2}.pack >test-3.pack &&
git index-pack -o tmp.idx test-2-${packname_2}.pack &&
diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh
index 8ee67df..b0095ab 100755
--- a/t/t5302-pack-index.sh
+++ b/t/t5302-pack-index.sh
@@ -284,4 +284,12 @@ test_expect_success 'index-pack -v --stdin produces progress for both phases' '
test_i18ngrep "Resolving deltas" err
'
+test_expect_success 'too-large packs report the breach' '
+ pack=$(git pack-objects --all pack </dev/null) &&
+ sz="$(test_file_size pack-$pack.pack)" &&
+ test "$sz" -gt 20 &&
+ test_must_fail git index-pack --max-input-size=20 pack-$pack.pack 2>err &&
+ grep "maximum allowed size (20 bytes)" err
+'
+
test_done
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index d05ab71..f775fc1 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -397,4 +397,32 @@ test_expect_success 'pack.preferBitmapTips' '
)
'
+test_expect_success 'complains about multiple pack bitmaps' '
+ rm -fr repo &&
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit base &&
+
+ git repack -adb &&
+ bitmap="$(ls .git/objects/pack/pack-*.bitmap)" &&
+ mv "$bitmap" "$bitmap.bak" &&
+
+ test_commit other &&
+ git repack -ab &&
+
+ mv "$bitmap.bak" "$bitmap" &&
+
+ find .git/objects/pack -type f -name "*.pack" >packs &&
+ find .git/objects/pack -type f -name "*.bitmap" >bitmaps &&
+ test_line_count = 2 packs &&
+ test_line_count = 2 bitmaps &&
+
+ git rev-list --use-bitmap-index HEAD 2>err &&
+ grep "ignoring extra bitmap file" err
+ )
+'
+
test_done
diff --git a/t/t5312-prune-corruption.sh b/t/t5312-prune-corruption.sh
index ea889c0..9d8e249 100755
--- a/t/t5312-prune-corruption.sh
+++ b/t/t5312-prune-corruption.sh
@@ -22,8 +22,8 @@ test_expect_success 'disable reflogs' '
'
create_bogus_ref () {
- test_when_finished 'rm -f .git/refs/heads/bogus..name' &&
- echo $bogus >.git/refs/heads/bogus..name
+ test-tool ref-store main update-ref msg "refs/heads/bogus..name" $bogus $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
+ test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/bogus..name"
}
test_expect_success 'create history reachable only from a bogus-named ref' '
@@ -113,7 +113,7 @@ test_expect_success 'pack-refs does not silently delete broken loose ref' '
# we do not want to count on running pack-refs to
# actually pack it, as it is perfectly reasonable to
# skip processing a broken ref
-test_expect_success 'create packed-refs file with broken ref' '
+test_expect_success REFFILES 'create packed-refs file with broken ref' '
rm -f .git/refs/heads/main &&
cat >.git/packed-refs <<-EOF &&
$missing refs/heads/main
@@ -124,13 +124,13 @@ test_expect_success 'create packed-refs file with broken ref' '
test_cmp expect actual
'
-test_expect_success 'pack-refs does not silently delete broken packed ref' '
+test_expect_success REFFILES 'pack-refs does not silently delete broken packed ref' '
git pack-refs --all --prune &&
git rev-parse refs/heads/main >actual &&
test_cmp expect actual
'
-test_expect_success 'pack-refs does not drop broken refs during deletion' '
+test_expect_success REFFILES 'pack-refs does not drop broken refs during deletion' '
git update-ref -d refs/heads/other &&
git rev-parse refs/heads/main >actual &&
test_cmp expect actual
diff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh
index df524f7..e904500 100755
--- a/t/t5316-pack-delta-depth.sh
+++ b/t/t5316-pack-delta-depth.sh
@@ -64,7 +64,11 @@ test_expect_success 'create series of packs' '
echo $cur &&
echo "$(git rev-parse :file) file"
} | git pack-objects --stdout >tmp &&
- git index-pack --stdin --fix-thin <tmp || return 1
+ GIT_TRACE2_EVENT=$PWD/trace \
+ git index-pack -v --stdin --fix-thin <tmp || return 1 &&
+ grep -c region_enter.*progress trace >enter &&
+ grep -c region_leave.*progress trace >leave &&
+ test_cmp enter leave &&
prev=$cur
done
'
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index edb728f..fbf0d64 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -29,12 +29,7 @@ test_expect_success 'setup full repo' '
cd "$TRASH_DIRECTORY/full" &&
git init &&
git config core.commitGraph true &&
- objdir=".git/objects" &&
-
- test_oid_cache <<-EOF
- oid_version sha1:1
- oid_version sha256:2
- EOF
+ objdir=".git/objects"
'
test_expect_success POSIXPERM 'tweak umask for modebit tests' '
@@ -69,46 +64,10 @@ test_expect_success 'create commits and repack' '
git repack
'
-graph_git_two_modes() {
- git -c core.commitGraph=true $1 >output &&
- git -c core.commitGraph=false $1 >expect &&
- test_cmp expect output
-}
-
-graph_git_behavior() {
- MSG=$1
- DIR=$2
- BRANCH=$3
- COMPARE=$4
- test_expect_success "check normal git operations: $MSG" '
- cd "$TRASH_DIRECTORY/$DIR" &&
- graph_git_two_modes "log --oneline $BRANCH" &&
- graph_git_two_modes "log --topo-order $BRANCH" &&
- graph_git_two_modes "log --graph $COMPARE..$BRANCH" &&
- graph_git_two_modes "branch -vv" &&
- graph_git_two_modes "merge-base -a $BRANCH $COMPARE"
- '
-}
+. "$TEST_DIRECTORY"/lib-commit-graph.sh
graph_git_behavior 'no graph' full commits/3 commits/1
-graph_read_expect() {
- OPTIONAL=""
- NUM_CHUNKS=3
- if test ! -z "$2"
- then
- OPTIONAL=" $2"
- NUM_CHUNKS=$((3 + $(echo "$2" | wc -w)))
- fi
- cat >expect <<- EOF
- header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0
- num_commits: $1
- chunks: oid_fanout oid_lookup commit_metadata$OPTIONAL
- EOF
- test-tool read-graph >output &&
- test_cmp expect output
-}
-
test_expect_success 'exit with correct error on bad input to --stdin-commits' '
cd "$TRASH_DIRECTORY/full" &&
# invalid, non-hex OID
@@ -466,10 +425,10 @@ test_expect_success 'warn on improper hash version' '
)
'
-test_expect_success 'lower layers have overflow chunk' '
+test_expect_success TIME_IS_64BIT,TIME_T_IS_64BIT 'lower layers have overflow chunk' '
cd "$TRASH_DIRECTORY/full" &&
UNIX_EPOCH_ZERO="@0 +0000" &&
- FUTURE_DATE="@2147483646 +0000" &&
+ FUTURE_DATE="@4147483646 +0000" &&
rm -f .git/objects/info/commit-graph &&
test_commit --date "$FUTURE_DATE" future-1 &&
test_commit --date "$UNIX_EPOCH_ZERO" old-1 &&
@@ -497,7 +456,7 @@ test_expect_success 'git commit-graph verify' '
cd "$TRASH_DIRECTORY/full" &&
git rev-parse commits/8 | git -c commitGraph.generationVersion=1 commit-graph write --stdin-commits &&
git commit-graph verify >output &&
- graph_read_expect 9 extra_edges
+ graph_read_expect 9 extra_edges 1
'
NUM_COMMITS=9
@@ -825,10 +784,6 @@ test_expect_success 'set up and verify repo with generation data overflow chunk'
objdir=".git/objects" &&
UNIX_EPOCH_ZERO="@0 +0000" &&
FUTURE_DATE="@2147483646 +0000" &&
- test_oid_cache <<-EOF &&
- oid_version sha1:1
- oid_version sha256:2
- EOF
cd "$TRASH_DIRECTORY" &&
mkdir repo &&
cd repo &&
diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh
index 847b809..669ddc6 100755
--- a/t/t5324-split-commit-graph.sh
+++ b/t/t5324-split-commit-graph.sh
@@ -30,10 +30,16 @@ graph_read_expect() {
then
NUM_BASE=$2
fi
+ OPTIONS=
+ if test -z "$3"
+ then
+ OPTIONS=" read_generation_data"
+ fi
cat >expect <<- EOF
header: 43475048 1 $(test_oid oid_version) 4 $NUM_BASE
num_commits: $1
chunks: oid_fanout oid_lookup commit_metadata generation_data
+ options:$OPTIONS
EOF
test-tool read-graph >output &&
test_cmp expect output
@@ -508,6 +514,7 @@ test_expect_success 'setup repo for mixed generation commit-graph-chain' '
header: 43475048 1 $(test_oid oid_version) 4 1
num_commits: $NUM_SECOND_LAYER_COMMITS
chunks: oid_fanout oid_lookup commit_metadata
+ options:
EOF
test_cmp expect output &&
git commit-graph verify &&
@@ -540,6 +547,7 @@ test_expect_success 'do not write generation data chunk if not present on existi
header: 43475048 1 $(test_oid oid_version) 4 2
num_commits: $NUM_THIRD_LAYER_COMMITS
chunks: oid_fanout oid_lookup commit_metadata
+ options:
EOF
test_cmp expect output &&
git commit-graph verify
@@ -581,6 +589,7 @@ test_expect_success 'do not write generation data chunk if the topmost remaining
header: 43475048 1 $(test_oid oid_version) 4 2
num_commits: $(($NUM_THIRD_LAYER_COMMITS + $NUM_FOURTH_LAYER_COMMITS))
chunks: oid_fanout oid_lookup commit_metadata
+ options:
EOF
test_cmp expect output &&
git commit-graph verify
@@ -620,6 +629,7 @@ test_expect_success 'write generation data chunk if topmost remaining layer has
header: 43475048 1 $(test_oid oid_version) 5 1
num_commits: $(($NUM_SECOND_LAYER_COMMITS + $NUM_THIRD_LAYER_COMMITS + $NUM_FOURTH_LAYER_COMMITS + $NUM_FIFTH_LAYER_COMMITS))
chunks: oid_fanout oid_lookup commit_metadata generation_data
+ options: read_generation_data
EOF
test_cmp expect output
)
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index e187f90..4fe5741 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -9,125 +9,13 @@ test_description='exercise basic multi-pack bitmap functionality'
GIT_TEST_MULTI_PACK_INDEX=0
GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
-objdir=.git/objects
-midx=$objdir/pack/multi-pack-index
+# This test exercise multi-pack bitmap functionality where the object order is
+# stored and read from a special chunk within the MIDX, so use the default
+# behavior here.
+sane_unset GIT_TEST_MIDX_WRITE_REV
+sane_unset GIT_TEST_MIDX_READ_RIDX
-# midx_pack_source <obj>
-midx_pack_source () {
- test-tool read-midx --show-objects .git/objects | grep "^$1 " | cut -f2
-}
-
-setup_bitmap_history
-
-test_expect_success 'enable core.multiPackIndex' '
- git config core.multiPackIndex true
-'
-
-test_expect_success 'create single-pack midx with bitmaps' '
- git repack -ad &&
- git multi-pack-index write --bitmap &&
- test_path_is_file $midx &&
- test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
- test_path_is_file $midx-$(midx_checksum $objdir).rev
-'
-
-basic_bitmap_tests
-
-test_expect_success 'create new additional packs' '
- for i in $(test_seq 1 16)
- do
- test_commit "$i" &&
- git repack -d || return 1
- done &&
-
- git checkout -b other2 HEAD~8 &&
- for i in $(test_seq 1 8)
- do
- test_commit "side-$i" &&
- git repack -d || return 1
- done &&
- git checkout second
-'
-
-test_expect_success 'create multi-pack midx with bitmaps' '
- git multi-pack-index write --bitmap &&
-
- ls $objdir/pack/pack-*.pack >packs &&
- test_line_count = 25 packs &&
-
- test_path_is_file $midx &&
- test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
- test_path_is_file $midx-$(midx_checksum $objdir).rev
-'
-
-basic_bitmap_tests
-
-test_expect_success '--no-bitmap is respected when bitmaps exist' '
- git multi-pack-index write --bitmap &&
-
- test_commit respect--no-bitmap &&
- git repack -d &&
-
- test_path_is_file $midx &&
- test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
- test_path_is_file $midx-$(midx_checksum $objdir).rev &&
-
- git multi-pack-index write --no-bitmap &&
-
- test_path_is_file $midx &&
- test_path_is_missing $midx-$(midx_checksum $objdir).bitmap &&
- test_path_is_missing $midx-$(midx_checksum $objdir).rev
-'
-
-test_expect_success 'setup midx with base from later pack' '
- # Write a and b so that "a" is a delta on top of base "b", since Git
- # prefers to delete contents out of a base rather than add to a shorter
- # object.
- test_seq 1 128 >a &&
- test_seq 1 130 >b &&
-
- git add a b &&
- git commit -m "initial commit" &&
-
- a=$(git rev-parse HEAD:a) &&
- b=$(git rev-parse HEAD:b) &&
-
- # In the first pack, "a" is stored as a delta to "b".
- p1=$(git pack-objects .git/objects/pack/pack <<-EOF
- $a
- $b
- EOF
- ) &&
-
- # In the second pack, "a" is missing, and "b" is not a delta nor base to
- # any other object.
- p2=$(git pack-objects .git/objects/pack/pack <<-EOF
- $b
- $(git rev-parse HEAD)
- $(git rev-parse HEAD^{tree})
- EOF
- ) &&
-
- git prune-packed &&
- # Use the second pack as the preferred source, so that "b" occurs
- # earlier in the MIDX object order, rendering "a" unusable for pack
- # reuse.
- git multi-pack-index write --bitmap --preferred-pack=pack-$p2.idx &&
-
- have_delta $a $b &&
- test $(midx_pack_source $a) != $(midx_pack_source $b)
-'
-
-rev_list_tests 'full bitmap with backwards delta'
-
-test_expect_success 'clone with bitmaps enabled' '
- git clone --no-local --bare . clone-reverse-delta.git &&
- test_when_finished "rm -fr clone-reverse-delta.git" &&
-
- git rev-parse HEAD >expect &&
- git --git-dir=clone-reverse-delta.git rev-parse HEAD >actual &&
- test_cmp expect actual
-'
+midx_bitmap_core
bitmap_reuse_tests() {
from=$1
@@ -204,17 +92,7 @@ test_expect_success 'missing object closure fails gracefully' '
)
'
-test_expect_success 'setup partial bitmaps' '
- test_commit packed &&
- git repack &&
- test_commit loose &&
- git multi-pack-index write --bitmap 2>err &&
- test_path_is_file $midx &&
- test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
- test_path_is_file $midx-$(midx_checksum $objdir).rev
-'
-
-basic_bitmap_tests HEAD~
+midx_bitmap_partial_tests
test_expect_success 'removing a MIDX clears stale bitmaps' '
rm -fr repo &&
@@ -228,7 +106,6 @@ test_expect_success 'removing a MIDX clears stale bitmaps' '
# Write a MIDX and bitmap; remove the MIDX but leave the bitmap.
stale_bitmap=$midx-$(midx_checksum $objdir).bitmap &&
- stale_rev=$midx-$(midx_checksum $objdir).rev &&
rm $midx &&
# Then write a new MIDX.
@@ -238,9 +115,7 @@ test_expect_success 'removing a MIDX clears stale bitmaps' '
test_path_is_file $midx &&
test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
- test_path_is_file $midx-$(midx_checksum $objdir).rev &&
- test_path_is_missing $stale_bitmap &&
- test_path_is_missing $stale_rev
+ test_path_is_missing $stale_bitmap
)
'
@@ -261,7 +136,6 @@ test_expect_success 'pack.preferBitmapTips' '
git multi-pack-index write --bitmap &&
test_path_is_file $midx &&
test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
- test_path_is_file $midx-$(midx_checksum $objdir).rev &&
test-tool bitmap list-commits | sort >bitmaps &&
comm -13 bitmaps commits >before &&
@@ -271,7 +145,6 @@ test_expect_success 'pack.preferBitmapTips' '
<before | git update-ref --stdin &&
rm -fr $midx-$(midx_checksum $objdir).bitmap &&
- rm -fr $midx-$(midx_checksum $objdir).rev &&
rm -fr $midx &&
git -c pack.preferBitmapTips=refs/tags/include \
@@ -309,7 +182,6 @@ test_expect_success 'writing a bitmap with --refs-snapshot' '
grep "$(git rev-parse two)" bitmaps &&
rm -fr $midx-$(midx_checksum $objdir).bitmap &&
- rm -fr $midx-$(midx_checksum $objdir).rev &&
rm -fr $midx &&
# Then again, but with a refs snapshot which only sees
@@ -354,7 +226,6 @@ test_expect_success 'write a bitmap with --refs-snapshot (preferred tips)' '
) >snapshot &&
rm -fr $midx-$(midx_checksum $objdir).bitmap &&
- rm -fr $midx-$(midx_checksum $objdir).rev &&
rm -fr $midx &&
git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
@@ -395,4 +266,45 @@ test_expect_success 'hash-cache values are propagated from pack bitmaps' '
)
'
+test_expect_success 'no .bitmap is written without any objects' '
+ rm -fr repo &&
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ empty="$(git pack-objects $objdir/pack/pack </dev/null)" &&
+ cat >packs <<-EOF &&
+ pack-$empty.idx
+ EOF
+
+ git multi-pack-index write --bitmap --stdin-packs \
+ <packs 2>err &&
+
+ grep "bitmap without any objects" err &&
+
+ test_path_is_file $midx &&
+ test_path_is_missing $midx-$(midx_checksum $objdir).bitmap
+ )
+'
+
+test_expect_success 'graceful fallback when missing reverse index' '
+ rm -fr repo &&
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit base &&
+
+ # write a pack and MIDX bitmap containing base
+ git repack -adb &&
+ git multi-pack-index write --bitmap &&
+
+ GIT_TEST_MIDX_READ_RIDX=0 \
+ git rev-list --use-bitmap-index HEAD 2>err &&
+ ! grep "ignoring extra bitmap file" err
+ )
+'
+
test_done
diff --git a/t/t5327-multi-pack-bitmaps-rev.sh b/t/t5327-multi-pack-bitmaps-rev.sh
new file mode 100755
index 0000000..d30ba63
--- /dev/null
+++ b/t/t5327-multi-pack-bitmaps-rev.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+test_description='exercise basic multi-pack bitmap functionality (.rev files)'
+
+. ./test-lib.sh
+. "${TEST_DIRECTORY}/lib-bitmap.sh"
+
+# We'll be writing our own midx and bitmaps, so avoid getting confused by the
+# automatic ones.
+GIT_TEST_MULTI_PACK_INDEX=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
+
+# Unlike t5326, this test exercise multi-pack bitmap functionality where the
+# object order is stored in a separate .rev file.
+GIT_TEST_MIDX_WRITE_REV=1
+GIT_TEST_MIDX_READ_RIDX=0
+export GIT_TEST_MIDX_WRITE_REV
+export GIT_TEST_MIDX_READ_RIDX
+
+midx_bitmap_core rev
+midx_bitmap_partial_tests rev
+
+test_done
diff --git a/t/t5328-commit-graph-64bit-time.sh b/t/t5328-commit-graph-64bit-time.sh
new file mode 100755
index 0000000..093f0c0
--- /dev/null
+++ b/t/t5328-commit-graph-64bit-time.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+test_description='commit graph with 64-bit timestamps'
+. ./test-lib.sh
+
+if ! test_have_prereq TIME_IS_64BIT || ! test_have_prereq TIME_T_IS_64BIT
+then
+ skip_all='skipping 64-bit timestamp tests'
+ test_done
+fi
+
+. "$TEST_DIRECTORY"/lib-commit-graph.sh
+
+UNIX_EPOCH_ZERO="@0 +0000"
+FUTURE_DATE="@4147483646 +0000"
+
+GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=0
+
+test_expect_success 'lower layers have overflow chunk' '
+ rm -f .git/objects/info/commit-graph &&
+ test_commit --date "$FUTURE_DATE" future-1 &&
+ test_commit --date "$UNIX_EPOCH_ZERO" old-1 &&
+ git commit-graph write --reachable &&
+ test_commit --date "$FUTURE_DATE" future-2 &&
+ test_commit --date "$UNIX_EPOCH_ZERO" old-2 &&
+ git commit-graph write --reachable --split=no-merge &&
+ test_commit extra &&
+ git commit-graph write --reachable --split=no-merge &&
+ git commit-graph write --reachable &&
+ graph_read_expect 5 "generation_data generation_data_overflow" &&
+ mv .git/objects/info/commit-graph commit-graph-upgraded &&
+ git commit-graph write --reachable &&
+ graph_read_expect 5 "generation_data generation_data_overflow" &&
+ test_cmp .git/objects/info/commit-graph commit-graph-upgraded
+'
+
+graph_git_behavior 'overflow' '' HEAD~2 HEAD
+
+test_expect_success 'set up and verify repo with generation data overflow chunk' '
+ mkdir repo &&
+ cd repo &&
+ git init &&
+ test_commit --date "$UNIX_EPOCH_ZERO" 1 &&
+ test_commit 2 &&
+ test_commit --date "$UNIX_EPOCH_ZERO" 3 &&
+ git commit-graph write --reachable &&
+ graph_read_expect 3 generation_data &&
+ test_commit --date "$FUTURE_DATE" 4 &&
+ test_commit 5 &&
+ test_commit --date "$UNIX_EPOCH_ZERO" 6 &&
+ git branch left &&
+ git reset --hard 3 &&
+ test_commit 7 &&
+ test_commit --date "$FUTURE_DATE" 8 &&
+ test_commit 9 &&
+ git branch right &&
+ git reset --hard 3 &&
+ test_merge M left right &&
+ git commit-graph write --reachable &&
+ graph_read_expect 10 "generation_data generation_data_overflow" &&
+ git commit-graph verify
+'
+
+graph_git_behavior 'overflow 2' repo left right
+
+test_done
diff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh
index 6012cc8..001b7a1 100755
--- a/t/t5401-update-hooks.sh
+++ b/t/t5401-update-hooks.sh
@@ -20,45 +20,37 @@ test_expect_success setup '
git clone --bare ./. victim.git &&
GIT_DIR=victim.git git update-ref refs/heads/tofail $commit1 &&
git update-ref refs/heads/main $commit1 &&
- git update-ref refs/heads/tofail $commit0
-'
+ git update-ref refs/heads/tofail $commit0 &&
-cat >victim.git/hooks/pre-receive <<'EOF'
-#!/bin/sh
-printf %s "$@" >>$GIT_DIR/pre-receive.args
-cat - >$GIT_DIR/pre-receive.stdin
-echo STDOUT pre-receive
-echo STDERR pre-receive >&2
-EOF
-chmod u+x victim.git/hooks/pre-receive
+ test_hook --setup -C victim.git pre-receive <<-\EOF &&
+ printf %s "$@" >>$GIT_DIR/pre-receive.args
+ cat - >$GIT_DIR/pre-receive.stdin
+ echo STDOUT pre-receive
+ echo STDERR pre-receive >&2
+ EOF
-cat >victim.git/hooks/update <<'EOF'
-#!/bin/sh
-echo "$@" >>$GIT_DIR/update.args
-read x; printf %s "$x" >$GIT_DIR/update.stdin
-echo STDOUT update $1
-echo STDERR update $1 >&2
-test "$1" = refs/heads/main || exit
-EOF
-chmod u+x victim.git/hooks/update
+ test_hook --setup -C victim.git update <<-\EOF &&
+ echo "$@" >>$GIT_DIR/update.args
+ read x; printf %s "$x" >$GIT_DIR/update.stdin
+ echo STDOUT update $1
+ echo STDERR update $1 >&2
+ test "$1" = refs/heads/main || exit
+ EOF
-cat >victim.git/hooks/post-receive <<'EOF'
-#!/bin/sh
-printf %s "$@" >>$GIT_DIR/post-receive.args
-cat - >$GIT_DIR/post-receive.stdin
-echo STDOUT post-receive
-echo STDERR post-receive >&2
-EOF
-chmod u+x victim.git/hooks/post-receive
+ test_hook --setup -C victim.git post-receive <<-\EOF &&
+ printf %s "$@" >>$GIT_DIR/post-receive.args
+ cat - >$GIT_DIR/post-receive.stdin
+ echo STDOUT post-receive
+ echo STDERR post-receive >&2
+ EOF
-cat >victim.git/hooks/post-update <<'EOF'
-#!/bin/sh
-echo "$@" >>$GIT_DIR/post-update.args
-read x; printf %s "$x" >$GIT_DIR/post-update.stdin
-echo STDOUT post-update
-echo STDERR post-update >&2
-EOF
-chmod u+x victim.git/hooks/post-update
+ test_hook --setup -C victim.git post-update <<-\EOF
+ echo "$@" >>$GIT_DIR/post-update.args
+ read x; printf %s "$x" >$GIT_DIR/post-update.stdin
+ echo STDOUT post-update
+ echo STDERR post-update >&2
+ EOF
+'
test_expect_success push '
test_must_fail git send-pack --force ./victim.git \
@@ -136,7 +128,7 @@ test_expect_success 'send-pack stderr contains hook messages' '
'
test_expect_success 'pre-receive hook that forgets to read its input' '
- write_script victim.git/hooks/pre-receive <<-\EOF &&
+ test_hook --clobber -C victim.git pre-receive <<-\EOF &&
exit 0
EOF
rm -f victim.git/hooks/update victim.git/hooks/post-update &&
diff --git a/t/t5402-post-merge-hook.sh b/t/t5402-post-merge-hook.sh
index 3e5e19c..915af2d 100755
--- a/t/t5402-post-merge-hook.sh
+++ b/t/t5402-post-merge-hook.sh
@@ -25,13 +25,15 @@ test_expect_success setup '
GIT_DIR=clone2/.git git update-index --add a
'
-for clone in 1 2; do
- cat >clone${clone}/.git/hooks/post-merge <<'EOF'
-#!/bin/sh
-echo $@ >> $GIT_DIR/post-merge.args
-EOF
- chmod u+x clone${clone}/.git/hooks/post-merge
-done
+test_expect_success 'setup clone hooks' '
+ test_when_finished "rm -f hook" &&
+ cat >hook <<-\EOF &&
+ echo $@ >>$GIT_DIR/post-merge.args
+ EOF
+
+ test_hook --setup -C clone1 post-merge <hook &&
+ test_hook --setup -C clone2 post-merge <hook
+'
test_expect_success 'post-merge does not run for up-to-date ' '
GIT_DIR=clone1/.git git merge $commit0 &&
diff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh
index 1ec9e23..978f240 100755
--- a/t/t5403-post-checkout-hook.sh
+++ b/t/t5403-post-checkout-hook.sh
@@ -10,8 +10,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
test_expect_success setup '
- mkdir -p .git/hooks &&
- write_script .git/hooks/post-checkout <<-\EOF &&
+ test_hook --setup post-checkout <<-\EOF &&
echo "$@" >.git/post-checkout.args
EOF
test_commit one &&
@@ -49,23 +48,60 @@ test_expect_success 'post-checkout receives the right args when not switching br
test $old = $new && test $flag = 0
'
-test_expect_success 'post-checkout is triggered on rebase' '
- test_when_finished "rm -f .git/post-checkout.args" &&
- git checkout -b rebase-test main &&
- rm -f .git/post-checkout.args &&
- git rebase rebase-on-me &&
- read old new flag <.git/post-checkout.args &&
- test $old != $new && test $flag = 1
-'
+test_rebase () {
+ args="$*" &&
+ test_expect_success "post-checkout is triggered on rebase $args" '
+ test_when_finished "rm -f .git/post-checkout.args" &&
+ git checkout -B rebase-test main &&
+ rm -f .git/post-checkout.args &&
+ git rebase $args rebase-on-me &&
+ read old new flag <.git/post-checkout.args &&
+ test_cmp_rev main $old &&
+ test_cmp_rev rebase-on-me $new &&
+ test $flag = 1
+ '
+
+ test_expect_success "post-checkout is triggered on rebase $args with fast-forward" '
+ test_when_finished "rm -f .git/post-checkout.args" &&
+ git checkout -B ff-rebase-test rebase-on-me^ &&
+ rm -f .git/post-checkout.args &&
+ git rebase $args rebase-on-me &&
+ read old new flag <.git/post-checkout.args &&
+ test_cmp_rev rebase-on-me^ $old &&
+ test_cmp_rev rebase-on-me $new &&
+ test $flag = 1
+ '
+
+ test_expect_success "rebase $args fast-forward branch checkout runs post-checkout hook" '
+ test_when_finished "test_might_fail git rebase --abort" &&
+ test_when_finished "rm -f .git/post-checkout.args" &&
+ git update-ref refs/heads/rebase-fast-forward three &&
+ git checkout two &&
+ rm -f .git/post-checkout.args &&
+ git rebase $args HEAD rebase-fast-forward &&
+ read old new flag <.git/post-checkout.args &&
+ test_cmp_rev two $old &&
+ test_cmp_rev three $new &&
+ test $flag = 1
+ '
+
+ test_expect_success "rebase $args checkout does not remove untracked files" '
+ test_when_finished "test_might_fail git rebase --abort" &&
+ test_when_finished "rm -f .git/post-checkout.args" &&
+ git update-ref refs/heads/rebase-fast-forward three &&
+ git checkout two &&
+ rm -f .git/post-checkout.args &&
+ echo untracked >three.t &&
+ test_when_finished "rm three.t" &&
+ test_must_fail git rebase $args HEAD rebase-fast-forward 2>err &&
+ grep "untracked working tree files would be overwritten by checkout" err &&
+ test_path_is_missing .git/post-checkout.args
-test_expect_success 'post-checkout is triggered on rebase with fast-forward' '
- test_when_finished "rm -f .git/post-checkout.args" &&
- git checkout -b ff-rebase-test rebase-on-me^ &&
- rm -f .git/post-checkout.args &&
- git rebase rebase-on-me &&
- read old new flag <.git/post-checkout.args &&
- test $old != $new && test $flag = 1
'
+}
+
+test_rebase --apply &&
+test_rebase --merge
test_expect_success 'post-checkout hook is triggered by clone' '
mkdir -p templates/hooks &&
diff --git a/t/t5406-remote-rejects.sh b/t/t5406-remote-rejects.sh
index 5c509db..dcbeb42 100755
--- a/t/t5406-remote-rejects.sh
+++ b/t/t5406-remote-rejects.sh
@@ -5,7 +5,7 @@ test_description='remote push rejects are reported by client'
. ./test-lib.sh
test_expect_success 'setup' '
- write_script .git/hooks/update <<-\EOF &&
+ test_hook update <<-\EOF &&
exit 1
EOF
echo 1 >file &&
diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index 6da8d76..5f3ff05 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -17,15 +17,13 @@ test_expect_success 'setup' '
git checkout A^0 &&
test_commit E bar E &&
test_commit F foo F &&
- git checkout main
-'
+ git checkout main &&
-cat >.git/hooks/post-rewrite <<EOF
-#!/bin/sh
-echo \$@ > "$TRASH_DIRECTORY"/post-rewrite.args
-cat > "$TRASH_DIRECTORY"/post-rewrite.data
-EOF
-chmod u+x .git/hooks/post-rewrite
+ test_hook --setup post-rewrite <<-EOF
+ echo \$@ > "$TRASH_DIRECTORY"/post-rewrite.args
+ cat > "$TRASH_DIRECTORY"/post-rewrite.data
+ EOF
+'
clear_hook_input () {
rm -f post-rewrite.args post-rewrite.data
diff --git a/t/t5409-colorize-remote-messages.sh b/t/t5409-colorize-remote-messages.sh
index 9f1a483..fa5de45 100755
--- a/t/t5409-colorize-remote-messages.sh
+++ b/t/t5409-colorize-remote-messages.sh
@@ -5,7 +5,7 @@ test_description='remote messages are colorized on the client'
. ./test-lib.sh
test_expect_success 'setup' '
- write_script .git/hooks/update <<-\EOF &&
+ test_hook --setup update <<-\EOF &&
echo error: error
echo ERROR: also highlighted
echo hint: hint
diff --git a/t/t5411-proc-receive-hook.sh b/t/t5411-proc-receive-hook.sh
index 98b0e81..92cf52c 100755
--- a/t/t5411-proc-receive-hook.sh
+++ b/t/t5411-proc-receive-hook.sh
@@ -36,7 +36,7 @@ setup_upstream_and_workbench () {
TAG=$(git -C workbench rev-parse v123) &&
# setup pre-receive hook
- write_script upstream.git/hooks/pre-receive <<-\EOF &&
+ test_hook --setup -C upstream.git pre-receive <<-\EOF &&
exec >&2
echo "# pre-receive hook"
while read old new ref
@@ -46,7 +46,7 @@ setup_upstream_and_workbench () {
EOF
# setup post-receive hook
- write_script upstream.git/hooks/post-receive <<-\EOF &&
+ test_hook --setup -C upstream.git post-receive <<-\EOF &&
exec >&2
echo "# post-receive hook"
while read old new ref
diff --git a/t/t5411/once-0010-report-status-v1.sh b/t/t5411/once-0010-report-status-v1.sh
index 297b109..f9ffb01 100644
--- a/t/t5411/once-0010-report-status-v1.sh
+++ b/t/t5411/once-0010-report-status-v1.sh
@@ -3,7 +3,7 @@ test_expect_success "setup receive.procReceiveRefs" '
'
test_expect_success "setup proc-receive hook" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic1" \
diff --git a/t/t5411/test-0002-pre-receive-declined.sh b/t/t5411/test-0002-pre-receive-declined.sh
index 0c3490c..98a9d13 100644
--- a/t/t5411/test-0002-pre-receive-declined.sh
+++ b/t/t5411/test-0002-pre-receive-declined.sh
@@ -1,6 +1,6 @@
test_expect_success "setup pre-receive hook ($PROTOCOL)" '
mv "$upstream/hooks/pre-receive" "$upstream/hooks/pre-receive.ok" &&
- write_script "$upstream/hooks/pre-receive" <<-EOF
+ test_hook -C "$upstream" --clobber pre-receive <<-\EOF
exit 1
EOF
'
@@ -21,7 +21,7 @@ test_expect_success "git-push is declined ($PROTOCOL)" '
EOF
test_cmp expect actual &&
- test_cmp_refs -C "$upstream" <<-EOF
+ test_cmp_refs -C "$upstream" <<-\EOF
<COMMIT-A> refs/heads/main
EOF
'
diff --git a/t/t5411/test-0003-pre-receive-declined--porcelain.sh b/t/t5411/test-0003-pre-receive-declined--porcelain.sh
index 2393b04..67ca6dc 100644
--- a/t/t5411/test-0003-pre-receive-declined--porcelain.sh
+++ b/t/t5411/test-0003-pre-receive-declined--porcelain.sh
@@ -1,6 +1,6 @@
test_expect_success "setup pre-receive hook ($PROTOCOL/porcelain)" '
mv "$upstream/hooks/pre-receive" "$upstream/hooks/pre-receive.ok" &&
- write_script "$upstream/hooks/pre-receive" <<-EOF
+ test_hook -C "$upstream" --clobber pre-receive <<-\EOF
exit 1
EOF
'
diff --git a/t/t5411/test-0013-bad-protocol.sh b/t/t5411/test-0013-bad-protocol.sh
index c08a00d..8d22e17 100644
--- a/t/t5411/test-0013-bad-protocol.sh
+++ b/t/t5411/test-0013-bad-protocol.sh
@@ -1,5 +1,5 @@
test_expect_success "setup proc-receive hook (unknown version, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v --version 2
EOF
@@ -40,7 +40,7 @@ test_expect_success "proc-receive: bad protocol (unknown version, $PROTOCOL)" '
'
test_expect_success "setup proc-receive hook (hook --die-read-version, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v --die-read-version
EOF
@@ -65,13 +65,13 @@ test_expect_success "proc-receive: bad protocol (hook --die-read-version, $PROTO
grep "remote: fatal: die with the --die-read-version option" out-$test_count &&
grep "remote: error: fail to negotiate version with proc-receive hook" out-$test_count &&
- test_cmp_refs -C "$upstream" <<-EOF
+ test_cmp_refs -C "$upstream" <<-\EOF
<COMMIT-A> refs/heads/main
EOF
'
test_expect_success "setup proc-receive hook (hook --die-write-version, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v --die-write-version
EOF
@@ -102,7 +102,7 @@ test_expect_success "proc-receive: bad protocol (hook --die-write-version, $PROT
'
test_expect_success "setup proc-receive hook (hook --die-read-commands, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v --die-read-commands
EOF
@@ -132,7 +132,7 @@ test_expect_success "proc-receive: bad protocol (hook --die-read-commands, $PROT
'
test_expect_success "setup proc-receive hook (hook --die-read-push-options, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v --die-read-push-options
EOF
@@ -164,7 +164,7 @@ test_expect_success "proc-receive: bad protocol (hook --die-read-push-options, $
'
test_expect_success "setup proc-receive hook (hook --die-write-report, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v --die-write-report
EOF
@@ -194,7 +194,7 @@ test_expect_success "proc-receive: bad protocol (hook --die-write-report, $PROTO
'
test_expect_success "setup proc-receive hook (no report, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v
EOF
@@ -236,7 +236,7 @@ test_expect_success "cleanup ($PROTOCOL)" '
'
test_expect_success "setup proc-receive hook (no ref, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok"
@@ -269,7 +269,7 @@ test_expect_success "proc-receive: bad protocol (no ref, $PROTOCOL)" '
'
test_expect_success "setup proc-receive hook (unknown status, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "xx refs/for/main/topic"
diff --git a/t/t5411/test-0014-bad-protocol--porcelain.sh b/t/t5411/test-0014-bad-protocol--porcelain.sh
index 3eaa597..298a3d1 100644
--- a/t/t5411/test-0014-bad-protocol--porcelain.sh
+++ b/t/t5411/test-0014-bad-protocol--porcelain.sh
@@ -1,5 +1,5 @@
test_expect_success "setup proc-receive hook (unknown version, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v --version 2
EOF
@@ -40,7 +40,7 @@ test_expect_success "proc-receive: bad protocol (unknown version, $PROTOCOL/porc
'
test_expect_success "setup proc-receive hook (hook --die-read-version, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v --die-read-version
EOF
@@ -71,7 +71,7 @@ test_expect_success "proc-receive: bad protocol (hook --die-read-version, $PROTO
'
test_expect_success "setup proc-receive hook (hook --die-write-version, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v --die-write-version
EOF
@@ -102,7 +102,7 @@ test_expect_success "proc-receive: bad protocol (hook --die-write-version, $PROT
'
test_expect_success "setup proc-receive hook (hook --die-read-commands, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v --die-read-commands
EOF
@@ -132,7 +132,7 @@ test_expect_success "proc-receive: bad protocol (hook --die-read-commands, $PROT
'
test_expect_success "setup proc-receive hook (hook --die-read-push-options, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v --die-read-push-options
EOF
@@ -164,7 +164,7 @@ test_expect_success "proc-receive: bad protocol (hook --die-read-push-options, $
'
test_expect_success "setup proc-receive hook (hook --die-write-report, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v --die-write-report
EOF
@@ -194,7 +194,7 @@ test_expect_success "proc-receive: bad protocol (hook --die-write-report, $PROTO
'
test_expect_success "setup proc-receive hook (no report, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v
EOF
@@ -236,7 +236,7 @@ test_expect_success "cleanup ($PROTOCOL/porcelain)" '
'
test_expect_success "setup proc-receive hook (no ref, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok"
@@ -270,7 +270,7 @@ test_expect_success "proc-receive: bad protocol (no ref, $PROTOCOL/porcelain)" '
'
test_expect_success "setup proc-receive hook (unknown status, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "xx refs/for/main/topic"
diff --git a/t/t5411/test-0020-report-ng.sh b/t/t5411/test-0020-report-ng.sh
index e915dbc..6347c96 100644
--- a/t/t5411/test-0020-report-ng.sh
+++ b/t/t5411/test-0020-report-ng.sh
@@ -1,5 +1,5 @@
test_expect_success "setup proc-receive hook (ng, no message, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ng refs/for/main/topic"
@@ -31,7 +31,7 @@ test_expect_success "proc-receive: fail to update (ng, no message, $PROTOCOL)" '
'
test_expect_success "setup proc-receive hook (ng message, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ng refs/for/main/topic error msg"
diff --git a/t/t5411/test-0021-report-ng--porcelain.sh b/t/t5411/test-0021-report-ng--porcelain.sh
index 2a392e0..502b34f 100644
--- a/t/t5411/test-0021-report-ng--porcelain.sh
+++ b/t/t5411/test-0021-report-ng--porcelain.sh
@@ -1,5 +1,5 @@
test_expect_success "setup proc-receive hook (ng, no message, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ng refs/for/main/topic"
@@ -32,7 +32,7 @@ test_expect_success "proc-receive: fail to update (ng, no message, $PROTOCOL/por
'
test_expect_success "setup proc-receive hook (ng message, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ng refs/for/main/topic error msg"
diff --git a/t/t5411/test-0022-report-unexpect-ref.sh b/t/t5411/test-0022-report-unexpect-ref.sh
index f7a494b..7744392 100644
--- a/t/t5411/test-0022-report-unexpect-ref.sh
+++ b/t/t5411/test-0022-report-unexpect-ref.sh
@@ -1,5 +1,5 @@
test_expect_success "setup proc-receive hook (unexpected ref, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/heads/main"
diff --git a/t/t5411/test-0023-report-unexpect-ref--porcelain.sh b/t/t5411/test-0023-report-unexpect-ref--porcelain.sh
index 63c479e..6d116ef 100644
--- a/t/t5411/test-0023-report-unexpect-ref--porcelain.sh
+++ b/t/t5411/test-0023-report-unexpect-ref--porcelain.sh
@@ -1,5 +1,5 @@
test_expect_success "setup proc-receive hook (unexpected ref, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/heads/main"
diff --git a/t/t5411/test-0024-report-unknown-ref.sh b/t/t5411/test-0024-report-unknown-ref.sh
index af055aa..619ca2f 100644
--- a/t/t5411/test-0024-report-unknown-ref.sh
+++ b/t/t5411/test-0024-report-unknown-ref.sh
@@ -1,5 +1,5 @@
test_expect_success "setup proc-receive hook (unexpected ref, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic"
diff --git a/t/t5411/test-0025-report-unknown-ref--porcelain.sh b/t/t5411/test-0025-report-unknown-ref--porcelain.sh
index 99601ca..8b3f5d0 100644
--- a/t/t5411/test-0025-report-unknown-ref--porcelain.sh
+++ b/t/t5411/test-0025-report-unknown-ref--porcelain.sh
@@ -1,5 +1,5 @@
test_expect_success "setup proc-receive hook (unexpected ref, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic"
diff --git a/t/t5411/test-0026-push-options.sh b/t/t5411/test-0026-push-options.sh
index fec5f95..6dfc7b1 100644
--- a/t/t5411/test-0026-push-options.sh
+++ b/t/t5411/test-0026-push-options.sh
@@ -1,6 +1,6 @@
test_expect_success "setup proc-receive hook and disable push-options ($PROTOCOL)" '
git -C "$upstream" config receive.advertisePushOptions false &&
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic"
@@ -31,7 +31,7 @@ test_expect_success "enable push options ($PROTOCOL)" '
'
test_expect_success "setup version=0 for proc-receive hook ($PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
--version 0 \
@@ -75,7 +75,7 @@ test_expect_success "proc-receive: ignore push-options for version 0 ($PROTOCOL)
'
test_expect_success "restore proc-receive hook ($PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic"
diff --git a/t/t5411/test-0027-push-options--porcelain.sh b/t/t5411/test-0027-push-options--porcelain.sh
index 8fb75a8..768880b 100644
--- a/t/t5411/test-0027-push-options--porcelain.sh
+++ b/t/t5411/test-0027-push-options--porcelain.sh
@@ -1,6 +1,6 @@
test_expect_success "setup proc-receive hook and disable push-options ($PROTOCOL/porcelain)" '
git -C "$upstream" config receive.advertisePushOptions false &&
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic"
@@ -32,7 +32,7 @@ test_expect_success "enable push options ($PROTOCOL/porcelain)" '
'
test_expect_success "setup version=0 for proc-receive hook ($PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
--version 0 \
@@ -78,7 +78,7 @@ test_expect_success "proc-receive: ignore push-options for version 0 ($PROTOCOL/
'
test_expect_success "restore proc-receive hook ($PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic"
diff --git a/t/t5411/test-0030-report-ok.sh b/t/t5411/test-0030-report-ok.sh
index a3a6278..0f190a6 100644
--- a/t/t5411/test-0030-report-ok.sh
+++ b/t/t5411/test-0030-report-ok.sh
@@ -1,5 +1,5 @@
test_expect_success "setup proc-receive hook (ok, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic"
diff --git a/t/t5411/test-0031-report-ok--porcelain.sh b/t/t5411/test-0031-report-ok--porcelain.sh
index 0e17538..7ec3981 100644
--- a/t/t5411/test-0031-report-ok--porcelain.sh
+++ b/t/t5411/test-0031-report-ok--porcelain.sh
@@ -1,5 +1,5 @@
test_expect_success "setup proc-receive hook (ok, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic"
diff --git a/t/t5411/test-0032-report-with-options.sh b/t/t5411/test-0032-report-with-options.sh
index 988a430..07733b9 100644
--- a/t/t5411/test-0032-report-with-options.sh
+++ b/t/t5411/test-0032-report-with-options.sh
@@ -1,5 +1,5 @@
test_expect_success "setup proc-receive hook (option without matching ok, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "option refname refs/pull/123/head" \
@@ -30,7 +30,7 @@ test_expect_success "proc-receive: report option without matching ok ($PROTOCOL)
'
test_expect_success "setup proc-receive hook (option refname, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
@@ -62,7 +62,7 @@ test_expect_success "proc-receive: report option refname ($PROTOCOL)" '
'
test_expect_success "setup proc-receive hook (option refname and forced-update, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
@@ -95,7 +95,7 @@ test_expect_success "proc-receive: report option refname and forced-update ($PRO
'
test_expect_success "setup proc-receive hook (option refname and old-oid, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
@@ -129,7 +129,7 @@ test_expect_success "proc-receive: report option refname and old-oid ($PROTOCOL)
'
test_expect_success "setup proc-receive hook (option old-oid, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
@@ -161,7 +161,7 @@ test_expect_success "proc-receive: report option old-oid ($PROTOCOL)" '
'
test_expect_success "setup proc-receive hook (option old-oid and new-oid, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
@@ -195,7 +195,7 @@ test_expect_success "proc-receive: report option old-oid and new-oid ($PROTOCOL)
'
test_expect_success "setup proc-receive hook (report with multiple rewrites, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/a/b/c/topic" \
diff --git a/t/t5411/test-0033-report-with-options--porcelain.sh b/t/t5411/test-0033-report-with-options--porcelain.sh
index daacb3d..2e1831b 100644
--- a/t/t5411/test-0033-report-with-options--porcelain.sh
+++ b/t/t5411/test-0033-report-with-options--porcelain.sh
@@ -1,5 +1,5 @@
test_expect_success "setup proc-receive hook (option without matching ok, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "option refname refs/pull/123/head" \
@@ -31,7 +31,7 @@ test_expect_success "proc-receive: report option without matching ok ($PROTOCOL/
'
test_expect_success "setup proc-receive hook (option refname, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
@@ -64,7 +64,7 @@ test_expect_success "proc-receive: report option refname ($PROTOCOL/porcelain)"
'
test_expect_success "setup proc-receive hook (option refname and forced-update, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
@@ -99,7 +99,7 @@ test_expect_success "proc-receive: report option refname and forced-update ($PRO
'
test_expect_success "setup proc-receive hook (option refname and old-oid, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
@@ -134,7 +134,7 @@ test_expect_success "proc-receive: report option refname and old-oid ($PROTOCOL/
'
test_expect_success "setup proc-receive hook (option old-oid, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
@@ -167,7 +167,7 @@ test_expect_success "proc-receive: report option old-oid ($PROTOCOL/porcelain)"
'
test_expect_success "setup proc-receive hook (option old-oid and new-oid, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
@@ -202,7 +202,7 @@ test_expect_success "proc-receive: report option old-oid and new-oid ($PROTOCOL/
'
test_expect_success "setup proc-receive hook (report with multiple rewrites, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/a/b/c/topic" \
diff --git a/t/t5411/test-0034-report-ft.sh b/t/t5411/test-0034-report-ft.sh
index 73a47d1..0e37535 100644
--- a/t/t5411/test-0034-report-ft.sh
+++ b/t/t5411/test-0034-report-ft.sh
@@ -1,5 +1,5 @@
test_expect_success "setup proc-receive hook (ft, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
diff --git a/t/t5411/test-0035-report-ft--porcelain.sh b/t/t5411/test-0035-report-ft--porcelain.sh
index c350201..b9a0518 100644
--- a/t/t5411/test-0035-report-ft--porcelain.sh
+++ b/t/t5411/test-0035-report-ft--porcelain.sh
@@ -1,5 +1,5 @@
test_expect_success "setup proc-receive hook (fall-through, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-\EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
diff --git a/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh b/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh
index 8c8a6c1..889e970 100644
--- a/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh
+++ b/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh
@@ -14,7 +14,7 @@ test_expect_success "setup git config for remote-tracking of special refs" '
'
test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 1st rewrite, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
@@ -87,7 +87,7 @@ test_expect_success "proc-receive: check remote-tracking #1 ($PROTOCOL)" '
'
test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 2nd rewrite, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
@@ -162,7 +162,7 @@ test_expect_success "proc-receive: check remote-tracking #2 ($PROTOCOL)" '
'
test_expect_success "setup proc-receive hook (multiple rewrites for one ref, $PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
diff --git a/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh b/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh
index bc44810..1e523b1 100644
--- a/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh
+++ b/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh
@@ -1,5 +1,5 @@
test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 1st rewrite, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
@@ -58,7 +58,7 @@ test_expect_success "proc-receive: multiple rewrite for one ref, no refname for
'
test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 2nd rewrite, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
@@ -119,7 +119,7 @@ test_expect_success "proc-receive: multiple rewrites for one ref, no refname for
'
test_expect_success "setup proc-receive hook (multiple rewrites for one ref, $PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
diff --git a/t/t5411/test-0038-report-mixed-refs.sh b/t/t5411/test-0038-report-mixed-refs.sh
index e63fe7b..4c70e84 100644
--- a/t/t5411/test-0038-report-mixed-refs.sh
+++ b/t/t5411/test-0038-report-mixed-refs.sh
@@ -1,5 +1,5 @@
test_expect_success "setup proc-receive hook ($PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/next/topic2" \
diff --git a/t/t5411/test-0039-report-mixed-refs--porcelain.sh b/t/t5411/test-0039-report-mixed-refs--porcelain.sh
index 99d17b7..40f4c5b 100644
--- a/t/t5411/test-0039-report-mixed-refs--porcelain.sh
+++ b/t/t5411/test-0039-report-mixed-refs--porcelain.sh
@@ -1,5 +1,5 @@
test_expect_success "setup proc-receive hook ($PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/next/topic2" \
diff --git a/t/t5411/test-0040-process-all-refs.sh b/t/t5411/test-0040-process-all-refs.sh
index 2f405ad..7ae3851 100644
--- a/t/t5411/test-0040-process-all-refs.sh
+++ b/t/t5411/test-0040-process-all-refs.sh
@@ -17,7 +17,7 @@ test_expect_success "setup upstream branches ($PROTOCOL)" '
'
test_expect_success "setup proc-receive hook ($PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/heads/main" \
diff --git a/t/t5411/test-0041-process-all-refs--porcelain.sh b/t/t5411/test-0041-process-all-refs--porcelain.sh
index c884057..02e1e08 100644
--- a/t/t5411/test-0041-process-all-refs--porcelain.sh
+++ b/t/t5411/test-0041-process-all-refs--porcelain.sh
@@ -17,7 +17,7 @@ test_expect_success "setup upstream branches ($PROTOCOL/porcelain)" '
'
test_expect_success "setup proc-receive hook ($PROTOCOL/porcelain)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/heads/main" \
diff --git a/t/t5411/test-0050-proc-receive-refs-with-modifiers.sh b/t/t5411/test-0050-proc-receive-refs-with-modifiers.sh
index 31989f0..7efdfe5 100644
--- a/t/t5411/test-0050-proc-receive-refs-with-modifiers.sh
+++ b/t/t5411/test-0050-proc-receive-refs-with-modifiers.sh
@@ -9,7 +9,7 @@ test_expect_success "config receive.procReceiveRefs with modifiers ($PROTOCOL)"
'
test_expect_success "setup proc-receive hook ($PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/heads/main" \
@@ -70,7 +70,7 @@ test_expect_success "setup upstream: create tags/v123 ($PROTOCOL)" '
'
test_expect_success "setup proc-receive hook ($PROTOCOL)" '
- write_script "$upstream/hooks/proc-receive" <<-EOF
+ test_hook -C "$upstream" --clobber proc-receive <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/heads/main" \
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index f0dc4e6..ee6d2dd 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -927,7 +927,8 @@ test_expect_success 'fetching deepen' '
)
'
-test_expect_success 'use ref advertisement to prune "have" lines sent' '
+test_negotiation_algorithm_default () {
+ test_when_finished rm -rf clientv0 clientv2 &&
rm -rf server client &&
git init server &&
test_commit -C server both_have_1 &&
@@ -946,7 +947,7 @@ test_expect_success 'use ref advertisement to prune "have" lines sent' '
rm -f trace &&
cp -r client clientv0 &&
GIT_TRACE_PACKET="$(pwd)/trace" git -C clientv0 \
- fetch origin server_has both_have_2 &&
+ "$@" fetch origin server_has both_have_2 &&
grep "have $(git -C client rev-parse client_has)" trace &&
grep "have $(git -C client rev-parse both_have_2)" trace &&
! grep "have $(git -C client rev-parse both_have_2^)" trace &&
@@ -954,10 +955,27 @@ test_expect_success 'use ref advertisement to prune "have" lines sent' '
rm -f trace &&
cp -r client clientv2 &&
GIT_TRACE_PACKET="$(pwd)/trace" git -C clientv2 -c protocol.version=2 \
- fetch origin server_has both_have_2 &&
+ "$@" fetch origin server_has both_have_2 &&
grep "have $(git -C client rev-parse client_has)" trace &&
grep "have $(git -C client rev-parse both_have_2)" trace &&
! grep "have $(git -C client rev-parse both_have_2^)" trace
+}
+
+test_expect_success 'use ref advertisement to prune "have" lines sent' '
+ test_negotiation_algorithm_default
+'
+
+test_expect_success 'same as last but with config overrides' '
+ test_negotiation_algorithm_default \
+ -c feature.experimental=true \
+ -c fetch.negotiationAlgorithm=consecutive
+'
+
+test_expect_success 'ensure bogus fetch.negotiationAlgorithm yields error' '
+ test_when_finished rm -rf clientv0 &&
+ cp -r client clientv0 &&
+ test_must_fail git -C clientv0 --fetch.negotiationAlgorithm=bogus \
+ fetch origin server_has both_have_2
'
test_expect_success 'filtering by size' '
diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh
index 195fc64..acdb731 100755
--- a/t/t5503-tagfollow.sh
+++ b/t/t5503-tagfollow.sh
@@ -160,4 +160,68 @@ test_expect_success 'new clone fetch main and tags' '
test_cmp expect actual
'
+test_expect_success 'atomic fetch with failing backfill' '
+ git init clone3 &&
+
+ # We want to test whether a failure when backfilling tags correctly
+ # aborts the complete transaction when `--atomic` is passed: we should
+ # neither create the branch nor should we create the tag when either
+ # one of both fails to update correctly.
+ #
+ # To trigger failure we simply abort when backfilling a tag.
+ test_hook -C clone3 reference-transaction <<-\EOF &&
+ while read oldrev newrev reference
+ do
+ if test "$reference" = refs/tags/tag1
+ then
+ exit 1
+ fi
+ done
+ EOF
+
+ test_must_fail git -C clone3 fetch --atomic .. $B:refs/heads/something &&
+ test_must_fail git -C clone3 rev-parse --verify refs/heads/something &&
+ test_must_fail git -C clone3 rev-parse --verify refs/tags/tag2
+'
+
+test_expect_success 'atomic fetch with backfill should use single transaction' '
+ git init clone4 &&
+
+ # Fetching with the `--atomic` flag should update all references in a
+ # single transaction, including backfilled tags. We thus expect to see
+ # a single reference transaction for the created branch and tags.
+ cat >expected <<-EOF &&
+ prepared
+ $ZERO_OID $B refs/heads/something
+ $ZERO_OID $S refs/tags/tag2
+ $ZERO_OID $T refs/tags/tag1
+ committed
+ $ZERO_OID $B refs/heads/something
+ $ZERO_OID $S refs/tags/tag2
+ $ZERO_OID $T refs/tags/tag1
+ EOF
+
+ test_hook -C clone4 reference-transaction <<-\EOF &&
+ ( echo "$*" && cat ) >>actual
+ EOF
+
+ git -C clone4 fetch --atomic .. $B:refs/heads/something &&
+ test_cmp expected clone4/actual
+'
+
+test_expect_success 'backfill failure causes command to fail' '
+ git init clone5 &&
+
+ # Create a tag that is nested below the tag we are about to fetch via
+ # the backfill mechanism. This causes a D/F conflict when backfilling
+ # and should thus cause the command to fail.
+ empty_blob=$(git -C clone5 hash-object -w --stdin </dev/null) &&
+ git -C clone5 update-ref refs/tags/tag1/nested $empty_blob &&
+
+ test_must_fail git -C clone5 fetch .. $B:refs/heads/something &&
+ test $B = $(git -C clone5 rev-parse --verify refs/heads/something) &&
+ test $S = $(git -C clone5 rev-parse --verify tag2) &&
+ test_must_fail git -C clone5 rev-parse --verify tag1
+'
+
test_done
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 9ab3154..c90cf47 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -753,7 +753,9 @@ test_expect_success 'rename a remote' '
(
cd four &&
git config branch.main.pushRemote origin &&
- git remote rename origin upstream &&
+ GIT_TRACE2_EVENT=$(pwd)/trace \
+ git remote rename --progress origin upstream &&
+ test_region progress "Renaming remote references" trace &&
grep "pushRemote" .git/config &&
test -z "$(git for-each-ref refs/remotes/origin)" &&
test "$(git symbolic-ref refs/remotes/upstream/HEAD)" = "refs/remotes/upstream/main" &&
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 20f7110..6f38a69 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -164,6 +164,17 @@ test_expect_success 'fetch --prune --tags with refspec prunes based on refspec'
git rev-parse sometag
'
+test_expect_success REFFILES 'fetch --prune fails to delete branches' '
+ cd "$D" &&
+ git clone . prune-fail &&
+ cd prune-fail &&
+ git update-ref refs/remotes/origin/extrabranch main &&
+ : this will prevent --prune from locking packed-refs for deleting refs, but adding loose refs still succeeds &&
+ >.git/packed-refs.new &&
+
+ test_must_fail git fetch --prune origin
+'
+
test_expect_success 'fetch --atomic works with a single branch' '
test_when_finished "rm -rf \"$D\"/atomic" &&
@@ -262,7 +273,7 @@ test_expect_success 'fetch --atomic executes a single reference transaction only
EOF
rm -f atomic/actual &&
- write_script atomic/.git/hooks/reference-transaction <<-\EOF &&
+ test_hook -C atomic reference-transaction <<-\EOF &&
( echo "$*" && cat ) >>actual
EOF
@@ -295,7 +306,7 @@ test_expect_success 'fetch --atomic aborts all reference updates if hook aborts'
EOF
rm -f atomic/actual &&
- write_script atomic/.git/hooks/reference-transaction <<-\EOF &&
+ test_hook -C atomic/.git reference-transaction <<-\EOF &&
( echo "$*" && cat ) >>actual
exit 1
EOF
@@ -323,7 +334,7 @@ test_expect_success 'fetch --atomic --append appends to FETCH_HEAD' '
test_line_count = 2 atomic/.git/FETCH_HEAD &&
cp atomic/.git/FETCH_HEAD expected &&
- write_script atomic/.git/hooks/reference-transaction <<-\EOF &&
+ test_hook -C atomic reference-transaction <<-\EOF &&
exit 1
EOF
@@ -332,6 +343,35 @@ test_expect_success 'fetch --atomic --append appends to FETCH_HEAD' '
test_cmp expected atomic/.git/FETCH_HEAD
'
+test_expect_success 'fetch --atomic --prune executes a single reference transaction only' '
+ test_when_finished "rm -rf \"$D\"/atomic" &&
+
+ cd "$D" &&
+ git branch scheduled-for-deletion &&
+ git clone . atomic &&
+ git branch -D scheduled-for-deletion &&
+ git branch new-branch &&
+ head_oid=$(git rev-parse HEAD) &&
+
+ # Fetching with the `--atomic` flag should update all references in a
+ # single transaction.
+ cat >expected <<-EOF &&
+ prepared
+ $ZERO_OID $ZERO_OID refs/remotes/origin/scheduled-for-deletion
+ $ZERO_OID $head_oid refs/remotes/origin/new-branch
+ committed
+ $ZERO_OID $ZERO_OID refs/remotes/origin/scheduled-for-deletion
+ $ZERO_OID $head_oid refs/remotes/origin/new-branch
+ EOF
+
+ test_hook -C atomic reference-transaction <<-\EOF &&
+ ( echo "$*" && cat ) >>actual
+ EOF
+
+ git -C atomic fetch --atomic --prune origin &&
+ test_cmp expected atomic/actual
+'
+
test_expect_success '--refmap="" ignores configured refspec' '
cd "$TRASH_DIRECTORY" &&
git clone "$D" remote-refs &&
diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh
index be025b9..fc55681 100755
--- a/t/t5511-refspec.sh
+++ b/t/t5511-refspec.sh
@@ -2,6 +2,7 @@
test_description='refspec parsing'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_refspec () {
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 2f04cf9..4dfb080 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -23,14 +23,10 @@ D=$(pwd)
mk_empty () {
repo_name="$1"
- rm -fr "$repo_name" &&
- mkdir "$repo_name" &&
- (
- cd "$repo_name" &&
- git init &&
- git config receive.denyCurrentBranch warn &&
- mv .git/hooks .git/hooks-disabled
- )
+ test_when_finished "rm -rf \"$repo_name\"" &&
+ test_path_is_missing "$repo_name" &&
+ git init "$repo_name" &&
+ git -C "$repo_name" config receive.denyCurrentBranch warn
}
mk_test () {
@@ -59,40 +55,28 @@ mk_test () {
mk_test_with_hooks() {
repo_name=$1
mk_test "$@" &&
- (
- cd "$repo_name" &&
- mkdir .git/hooks &&
- cd .git/hooks &&
-
- cat >pre-receive <<-'EOF' &&
- #!/bin/sh
- cat - >>pre-receive.actual
- EOF
-
- cat >update <<-'EOF' &&
- #!/bin/sh
- printf "%s %s %s\n" "$@" >>update.actual
- EOF
-
- cat >post-receive <<-'EOF' &&
- #!/bin/sh
- cat - >>post-receive.actual
- EOF
-
- cat >post-update <<-'EOF' &&
- #!/bin/sh
- for ref in "$@"
- do
- printf "%s\n" "$ref" >>post-update.actual
- done
- EOF
-
- chmod +x pre-receive update post-receive post-update
- )
+ test_hook -C "$repo_name" pre-receive <<-'EOF' &&
+ cat - >>pre-receive.actual
+ EOF
+
+ test_hook -C "$repo_name" update <<-'EOF' &&
+ printf "%s %s %s\n" "$@" >>update.actual
+ EOF
+
+ test_hook -C "$repo_name" post-receive <<-'EOF' &&
+ cat - >>post-receive.actual
+ EOF
+
+ test_hook -C "$repo_name" post-update <<-'EOF'
+ for ref in "$@"
+ do
+ printf "%s\n" "$ref" >>post-update.actual
+ done
+ EOF
}
mk_child() {
- rm -rf "$2" &&
+ test_when_finished "rm -rf \"$2\"" &&
git clone "$1" "$2"
}
@@ -197,38 +181,50 @@ grep_wrote () {
grep 'write_pack_file/wrote.*"value":"'$1'"' $2
}
-test_expect_success 'push with negotiation' '
- # Without negotiation
+test_expect_success 'push without negotiation' '
mk_empty testrepo &&
git push testrepo $the_first_commit:refs/remotes/origin/first_commit &&
test_commit -C testrepo unrelated_commit &&
git -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&
- echo now pushing without negotiation &&
+ test_when_finished "rm event" &&
GIT_TRACE2_EVENT="$(pwd)/event" git -c protocol.version=2 push testrepo refs/heads/main:refs/remotes/origin/main &&
- grep_wrote 5 event && # 2 commits, 2 trees, 1 blob
+ grep_wrote 5 event # 2 commits, 2 trees, 1 blob
+'
- # Same commands, but with negotiation
- rm event &&
+test_expect_success 'push with negotiation' '
mk_empty testrepo &&
git push testrepo $the_first_commit:refs/remotes/origin/first_commit &&
test_commit -C testrepo unrelated_commit &&
git -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&
+ test_when_finished "rm event" &&
GIT_TRACE2_EVENT="$(pwd)/event" git -c protocol.version=2 -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main &&
grep_wrote 2 event # 1 commit, 1 tree
'
test_expect_success 'push with negotiation proceeds anyway even if negotiation fails' '
- rm event &&
mk_empty testrepo &&
git push testrepo $the_first_commit:refs/remotes/origin/first_commit &&
test_commit -C testrepo unrelated_commit &&
git -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&
+ test_when_finished "rm event" &&
GIT_TEST_PROTOCOL_VERSION=0 GIT_TRACE2_EVENT="$(pwd)/event" \
git -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main 2>err &&
grep_wrote 5 event && # 2 commits, 2 trees, 1 blob
test_i18ngrep "push negotiation failed" err
'
+test_expect_success 'push with negotiation does not attempt to fetch submodules' '
+ mk_empty submodule_upstream &&
+ test_commit -C submodule_upstream submodule_commit &&
+ git submodule add ./submodule_upstream submodule &&
+ mk_empty testrepo &&
+ git push testrepo $the_first_commit:refs/remotes/origin/first_commit &&
+ test_commit -C testrepo unrelated_commit &&
+ git -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&
+ git -c submodule.recurse=true -c protocol.version=2 -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main 2>err &&
+ ! grep "Fetching submodule" err
+'
+
test_expect_success 'push without wildcard' '
mk_empty testrepo &&
@@ -656,7 +652,6 @@ test_expect_success 'push does not update local refs on failure' '
mk_test testrepo heads/main &&
mk_child testrepo child &&
- mkdir testrepo/.git/hooks &&
echo "#!/no/frobnication/today" >testrepo/.git/hooks/pre-receive &&
chmod +x testrepo/.git/hooks/pre-receive &&
(
@@ -1318,7 +1313,7 @@ done
test_expect_success 'fetch follows tags by default' '
mk_test testrepo heads/main &&
- rm -fr src dst &&
+ test_when_finished "rm -rf src" &&
git init src &&
(
cd src &&
@@ -1328,6 +1323,7 @@ test_expect_success 'fetch follows tags by default' '
sed -n "p; s|refs/heads/main$|refs/remotes/origin/main|p" tmp1 |
sort -k 3 >../expect
) &&
+ test_when_finished "rm -rf dst" &&
git init dst &&
(
cd dst &&
@@ -1353,8 +1349,9 @@ test_expect_success 'peeled advertisements are not considered ref tips' '
test_expect_success 'pushing a specific ref applies remote.$name.push as refmap' '
mk_test testrepo heads/main &&
- rm -fr src dst &&
+ test_when_finished "rm -rf src" &&
git init src &&
+ test_when_finished "rm -rf dst" &&
git init --bare dst &&
(
cd src &&
@@ -1377,8 +1374,9 @@ test_expect_success 'pushing a specific ref applies remote.$name.push as refmap'
test_expect_success 'with no remote.$name.push, it is not used as refmap' '
mk_test testrepo heads/main &&
- rm -fr src dst &&
+ test_when_finished "rm -rf src" &&
git init src &&
+ test_when_finished "rm -rf dst" &&
git init --bare dst &&
(
cd src &&
@@ -1399,8 +1397,9 @@ test_expect_success 'with no remote.$name.push, it is not used as refmap' '
test_expect_success 'with no remote.$name.push, upstream mapping is used' '
mk_test testrepo heads/main &&
- rm -fr src dst &&
+ test_when_finished "rm -rf src" &&
git init src &&
+ test_when_finished "rm -rf dst" &&
git init --bare dst &&
(
cd src &&
@@ -1428,8 +1427,9 @@ test_expect_success 'with no remote.$name.push, upstream mapping is used' '
test_expect_success 'push does not follow tags by default' '
mk_test testrepo heads/main &&
- rm -fr src dst &&
+ test_when_finished "rm -rf src" &&
git init src &&
+ test_when_finished "rm -rf dst" &&
git init --bare dst &&
(
cd src &&
@@ -1451,8 +1451,9 @@ test_expect_success 'push does not follow tags by default' '
test_expect_success 'push --follow-tags only pushes relevant tags' '
mk_test testrepo heads/main &&
- rm -fr src dst &&
+ test_when_finished "rm -rf src" &&
git init src &&
+ test_when_finished "rm -rf dst" &&
git init --bare dst &&
(
cd src &&
@@ -1490,9 +1491,9 @@ EOF
'
test_expect_success 'pushing a tag pushes the tagged object' '
- rm -rf dst.git &&
blob=$(echo unreferenced | git hash-object -w --stdin) &&
git tag -m foo tag-of-blob $blob &&
+ test_when_finished "rm -rf dst.git" &&
git init --bare dst.git &&
git push dst.git tag-of-blob &&
# the receiving index-pack should have noticed
@@ -1503,7 +1504,7 @@ test_expect_success 'pushing a tag pushes the tagged object' '
'
test_expect_success 'push into bare respects core.logallrefupdates' '
- rm -rf dst.git &&
+ test_when_finished "rm -rf dst.git" &&
git init --bare dst.git &&
git -C dst.git config core.logallrefupdates true &&
@@ -1521,7 +1522,7 @@ test_expect_success 'push into bare respects core.logallrefupdates' '
'
test_expect_success 'fetch into bare respects core.logallrefupdates' '
- rm -rf dst.git &&
+ test_when_finished "rm -rf dst.git" &&
git init --bare dst.git &&
(
cd dst.git &&
@@ -1542,6 +1543,7 @@ test_expect_success 'fetch into bare respects core.logallrefupdates' '
'
test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+ mk_empty testrepo &&
git push testrepo main &&
(
cd testrepo &&
@@ -1644,7 +1646,7 @@ test_expect_success 'receive.denyCurrentBranch = updateInstead' '
) &&
# (5) push into void
- rm -fr void &&
+ test_when_finished "rm -rf void" &&
git init void &&
(
cd void &&
@@ -1666,26 +1668,23 @@ test_expect_success 'receive.denyCurrentBranch = updateInstead' '
'
test_expect_success 'updateInstead with push-to-checkout hook' '
- rm -fr testrepo &&
+ test_when_finished "rm -rf testrepo" &&
git init testrepo &&
- (
- cd testrepo &&
- git pull .. main &&
- git reset --hard HEAD^^ &&
- git tag initial &&
- git config receive.denyCurrentBranch updateInstead &&
- write_script .git/hooks/push-to-checkout <<-\EOF
- echo >&2 updating from $(git rev-parse HEAD)
- echo >&2 updating to "$1"
-
- git update-index -q --refresh &&
- git read-tree -u -m HEAD "$1" || {
- status=$?
- echo >&2 read-tree failed
- exit $status
- }
- EOF
- ) &&
+ git -C testrepo pull .. main &&
+ git -C testrepo reset --hard HEAD^^ &&
+ git -C testrepo tag initial &&
+ git -C testrepo config receive.denyCurrentBranch updateInstead &&
+ test_hook -C testrepo push-to-checkout <<-\EOF &&
+ echo >&2 updating from $(git rev-parse HEAD)
+ echo >&2 updating to "$1"
+
+ git update-index -q --refresh &&
+ git read-tree -u -m HEAD "$1" || {
+ status=$?
+ echo >&2 read-tree failed
+ exit $status
+ }
+ EOF
# Try pushing into a pristine
git push testrepo main &&
@@ -1728,35 +1727,32 @@ test_expect_success 'updateInstead with push-to-checkout hook' '
) &&
# push into void
- rm -fr void &&
+ test_when_finished "rm -rf void" &&
git init void &&
- (
- cd void &&
- git config receive.denyCurrentBranch updateInstead &&
- write_script .git/hooks/push-to-checkout <<-\EOF
- if git rev-parse --quiet --verify HEAD
- then
- has_head=yes
- echo >&2 updating from $(git rev-parse HEAD)
- else
- has_head=no
- echo >&2 pushing into void
- fi
- echo >&2 updating to "$1"
-
- git update-index -q --refresh &&
- case "$has_head" in
- yes)
- git read-tree -u -m HEAD "$1" ;;
- no)
- git read-tree -u -m "$1" ;;
- esac || {
- status=$?
- echo >&2 read-tree failed
- exit $status
- }
- EOF
- ) &&
+ git -C void config receive.denyCurrentBranch updateInstead &&
+ test_hook -C void push-to-checkout <<-\EOF &&
+ if git rev-parse --quiet --verify HEAD
+ then
+ has_head=yes
+ echo >&2 updating from $(git rev-parse HEAD)
+ else
+ has_head=no
+ echo >&2 pushing into void
+ fi
+ echo >&2 updating to "$1"
+
+ git update-index -q --refresh &&
+ case "$has_head" in
+ yes)
+ git read-tree -u -m HEAD "$1" ;;
+ no)
+ git read-tree -u -m "$1" ;;
+ esac || {
+ status=$?
+ echo >&2 read-tree failed
+ exit $status
+ }
+ EOF
git push void main &&
(
@@ -1809,4 +1805,12 @@ test_expect_success 'refuse fetch to current branch of bare repository worktree'
git -C bare.git fetch -u .. HEAD:wt
'
+test_expect_success 'refuse to push a hidden ref, and make sure do not pollute the repository' '
+ mk_empty testrepo &&
+ git -C testrepo config receive.hiderefs refs/hidden &&
+ git -C testrepo config receive.unpackLimit 1 &&
+ test_must_fail git push testrepo HEAD:refs/hidden/foo &&
+ test_dir_is_empty testrepo/.git/objects/pack
+'
+
test_done
diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh
index 93ecfcd..0818080 100755
--- a/t/t5520-pull.sh
+++ b/t/t5520-pull.sh
@@ -330,6 +330,19 @@ test_expect_success '--rebase --autostash fast forward' '
test_cmp_rev HEAD to-rebase-ff
'
+test_expect_success '--rebase with rebase.autostash succeeds on ff' '
+ test_when_finished "rm -fr src dst actual" &&
+ git init src &&
+ test_commit -C src "initial" file "content" &&
+ git clone src dst &&
+ test_commit -C src --printf "more_content" file "more content\ncontent\n" &&
+ echo "dirty" >>dst/file &&
+ test_config -C dst rebase.autostash true &&
+ git -C dst pull --rebase >actual 2>&1 &&
+ grep -q "Fast-forward" actual &&
+ grep -q "Applied autostash." actual
+'
+
test_expect_success '--rebase with conflicts shows advice' '
test_when_finished "git rebase --abort; git checkout -f to-rebase" &&
git checkout -b seq &&
diff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh
index 66cfcb0..264de29 100755
--- a/t/t5521-pull-options.sh
+++ b/t/t5521-pull-options.sh
@@ -233,7 +233,7 @@ test_expect_success 'git pull --no-verify flag passed to merge' '
git init src &&
test_commit -C src one &&
git clone src dst &&
- write_script dst/.git/hooks/commit-msg <<-\EOF &&
+ test_hook -C dst commit-msg <<-\EOF &&
false
EOF
test_commit -C src two &&
@@ -245,7 +245,7 @@ test_expect_success 'git pull --no-verify --verify passed to merge' '
git init src &&
test_commit -C src one &&
git clone src dst &&
- write_script dst/.git/hooks/commit-msg <<-\EOF &&
+ test_hook -C dst commit-msg <<-\EOF &&
false
EOF
test_commit -C src two &&
diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh
index 840c89c..43dada8 100755
--- a/t/t5526-fetch-submodules.sh
+++ b/t/t5526-fetch-submodules.sh
@@ -10,33 +10,122 @@ export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB
pwd=$(pwd)
-add_upstream_commit() {
+write_expected_sub () {
+ NEW_HEAD=$1 &&
+ SUPER_HEAD=$2 &&
+ cat >"$pwd/expect.err.sub" <<-EOF
+ Fetching submodule submodule${SUPER_HEAD:+ at commit $SUPER_HEAD}
+ From $pwd/submodule
+ OLD_HEAD..$NEW_HEAD sub -> origin/sub
+ EOF
+}
+
+write_expected_sub2 () {
+ NEW_HEAD=$1 &&
+ SUPER_HEAD=$2 &&
+ cat >"$pwd/expect.err.sub2" <<-EOF
+ Fetching submodule submodule2${SUPER_HEAD:+ at commit $SUPER_HEAD}
+ From $pwd/submodule2
+ OLD_HEAD..$NEW_HEAD sub2 -> origin/sub2
+ EOF
+}
+
+write_expected_deep () {
+ NEW_HEAD=$1 &&
+ SUB_HEAD=$2 &&
+ cat >"$pwd/expect.err.deep" <<-EOF
+ Fetching submodule submodule/subdir/deepsubmodule${SUB_HEAD:+ at commit $SUB_HEAD}
+ From $pwd/deepsubmodule
+ OLD_HEAD..$NEW_HEAD deep -> origin/deep
+ EOF
+}
+
+write_expected_super () {
+ NEW_HEAD=$1 &&
+ cat >"$pwd/expect.err.super" <<-EOF
+ From $pwd/.
+ OLD_HEAD..$NEW_HEAD super -> origin/super
+ EOF
+}
+
+# For each submodule in the test setup, this creates a commit and writes
+# a file that contains the expected err if that new commit were fetched.
+# These output files get concatenated in the right order by
+# verify_fetch_result().
+add_submodule_commits () {
(
cd submodule &&
- head1=$(git rev-parse --short HEAD) &&
echo new >> subfile &&
test_tick &&
git add subfile &&
git commit -m new subfile &&
- head2=$(git rev-parse --short HEAD) &&
- echo "Fetching submodule submodule" > ../expect.err &&
- echo "From $pwd/submodule" >> ../expect.err &&
- echo " $head1..$head2 sub -> origin/sub" >> ../expect.err
+ new_head=$(git rev-parse --short HEAD) &&
+ write_expected_sub $new_head
) &&
(
cd deepsubmodule &&
- head1=$(git rev-parse --short HEAD) &&
echo new >> deepsubfile &&
test_tick &&
git add deepsubfile &&
git commit -m new deepsubfile &&
- head2=$(git rev-parse --short HEAD) &&
- echo "Fetching submodule submodule/subdir/deepsubmodule" >> ../expect.err
- echo "From $pwd/deepsubmodule" >> ../expect.err &&
- echo " $head1..$head2 deep -> origin/deep" >> ../expect.err
+ new_head=$(git rev-parse --short HEAD) &&
+ write_expected_deep $new_head
)
}
+# For each superproject in the test setup, update its submodule, add the
+# submodule and create a new commit with the submodule change.
+#
+# This requires add_submodule_commits() to be called first, otherwise
+# the submodules will not have changed and cannot be "git add"-ed.
+add_superproject_commits () {
+ (
+ cd submodule &&
+ (
+ cd subdir/deepsubmodule &&
+ git fetch &&
+ git checkout -q FETCH_HEAD
+ ) &&
+ git add subdir/deepsubmodule &&
+ git commit -m "new deep submodule"
+ ) &&
+ git add submodule &&
+ git commit -m "new submodule" &&
+ super_head=$(git rev-parse --short HEAD) &&
+ sub_head=$(git -C submodule rev-parse --short HEAD) &&
+ write_expected_super $super_head &&
+ write_expected_sub $sub_head
+}
+
+# Verifies that the expected repositories were fetched. This is done by
+# concatenating the files expect.err.[super|sub|deep] in the correct
+# order and comparing it to the actual stderr.
+#
+# If a repo should not be fetched in the test, its corresponding
+# expect.err file should be rm-ed.
+verify_fetch_result () {
+ ACTUAL_ERR=$1 &&
+ rm -f expect.err.combined &&
+ if test -f expect.err.super
+ then
+ cat expect.err.super >>expect.err.combined
+ fi &&
+ if test -f expect.err.sub
+ then
+ cat expect.err.sub >>expect.err.combined
+ fi &&
+ if test -f expect.err.deep
+ then
+ cat expect.err.deep >>expect.err.combined
+ fi &&
+ if test -f expect.err.sub2
+ then
+ cat expect.err.sub2 >>expect.err.combined
+ fi &&
+ sed -e 's/[0-9a-f][0-9a-f]*\.\./OLD_HEAD\.\./' "$ACTUAL_ERR" >actual.err.cmp &&
+ test_cmp expect.err.combined actual.err.cmp
+}
+
test_expect_success setup '
mkdir deepsubmodule &&
(
@@ -68,38 +157,38 @@ test_expect_success setup '
'
test_expect_success "fetch --recurse-submodules recurses into submodules" '
- add_upstream_commit &&
+ add_submodule_commits &&
(
cd downstream &&
git fetch --recurse-submodules >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_cmp expect.err actual.err
+ verify_fetch_result actual.err
'
test_expect_success "submodule.recurse option triggers recursive fetch" '
- add_upstream_commit &&
+ add_submodule_commits &&
(
cd downstream &&
git -c submodule.recurse fetch >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_cmp expect.err actual.err
+ verify_fetch_result actual.err
'
test_expect_success "fetch --recurse-submodules -j2 has the same output behaviour" '
- add_upstream_commit &&
+ add_submodule_commits &&
(
cd downstream &&
GIT_TRACE="$TRASH_DIRECTORY/trace.out" git fetch --recurse-submodules -j2 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_cmp expect.err actual.err &&
+ verify_fetch_result actual.err &&
grep "2 tasks" trace.out
'
test_expect_success "fetch alone only fetches superproject" '
- add_upstream_commit &&
+ add_submodule_commits &&
(
cd downstream &&
git fetch >../actual.out 2>../actual.err
@@ -124,11 +213,11 @@ test_expect_success "using fetchRecurseSubmodules=true in .gitmodules recurses i
git fetch >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_cmp expect.err actual.err
+ verify_fetch_result actual.err
'
test_expect_success "--no-recurse-submodules overrides .gitmodules config" '
- add_upstream_commit &&
+ add_submodule_commits &&
(
cd downstream &&
git fetch --no-recurse-submodules >../actual.out 2>../actual.err
@@ -155,7 +244,7 @@ test_expect_success "--recurse-submodules overrides fetchRecurseSubmodules setti
git config --unset submodule.submodule.fetchRecurseSubmodules
) &&
test_must_be_empty actual.out &&
- test_cmp expect.err actual.err
+ verify_fetch_result actual.err
'
test_expect_success "--quiet propagates to submodules" '
@@ -177,13 +266,13 @@ test_expect_success "--quiet propagates to parallel submodules" '
'
test_expect_success "--dry-run propagates to submodules" '
- add_upstream_commit &&
+ add_submodule_commits &&
(
cd downstream &&
git fetch --recurse-submodules --dry-run >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_cmp expect.err actual.err
+ verify_fetch_result actual.err
'
test_expect_success "Without --dry-run propagates to submodules" '
@@ -192,22 +281,22 @@ test_expect_success "Without --dry-run propagates to submodules" '
git fetch --recurse-submodules >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_cmp expect.err actual.err
+ verify_fetch_result actual.err
'
test_expect_success "recurseSubmodules=true propagates into submodules" '
- add_upstream_commit &&
+ add_submodule_commits &&
(
cd downstream &&
git config fetch.recurseSubmodules true &&
git fetch >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_cmp expect.err actual.err
+ verify_fetch_result actual.err
'
test_expect_success "--recurse-submodules overrides config in submodule" '
- add_upstream_commit &&
+ add_submodule_commits &&
(
cd downstream &&
(
@@ -217,11 +306,11 @@ test_expect_success "--recurse-submodules overrides config in submodule" '
git fetch --recurse-submodules >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_cmp expect.err actual.err
+ verify_fetch_result actual.err
'
test_expect_success "--no-recurse-submodules overrides config setting" '
- add_upstream_commit &&
+ add_submodule_commits &&
(
cd downstream &&
git config fetch.recurseSubmodules true &&
@@ -246,36 +335,34 @@ test_expect_success "Recursion doesn't happen when no new commits are fetched in
'
test_expect_success "Recursion stops when no new submodule commits are fetched" '
- head1=$(git rev-parse --short HEAD) &&
git add submodule &&
git commit -m "new submodule" &&
- head2=$(git rev-parse --short HEAD) &&
- echo "From $pwd/." > expect.err.sub &&
- echo " $head1..$head2 super -> origin/super" >>expect.err.sub &&
- head -3 expect.err >> expect.err.sub &&
+ new_head=$(git rev-parse --short HEAD) &&
+ write_expected_super $new_head &&
+ rm expect.err.deep &&
(
cd downstream &&
git fetch >../actual.out 2>../actual.err
) &&
- test_cmp expect.err.sub actual.err &&
+ verify_fetch_result actual.err &&
test_must_be_empty actual.out
'
test_expect_success "Recursion doesn't happen when new superproject commits don't change any submodules" '
- add_upstream_commit &&
- head1=$(git rev-parse --short HEAD) &&
+ add_submodule_commits &&
echo a > file &&
git add file &&
git commit -m "new file" &&
- head2=$(git rev-parse --short HEAD) &&
- echo "From $pwd/." > expect.err.file &&
- echo " $head1..$head2 super -> origin/super" >> expect.err.file &&
+ new_head=$(git rev-parse --short HEAD) &&
+ write_expected_super $new_head &&
+ rm expect.err.sub &&
+ rm expect.err.deep &&
(
cd downstream &&
git fetch >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_cmp expect.err.file actual.err
+ verify_fetch_result actual.err
'
test_expect_success "Recursion picks up config in submodule" '
@@ -287,14 +374,11 @@ test_expect_success "Recursion picks up config in submodule" '
git config fetch.recurseSubmodules true
)
) &&
- add_upstream_commit &&
- head1=$(git rev-parse --short HEAD) &&
+ add_submodule_commits &&
git add submodule &&
git commit -m "new submodule" &&
- head2=$(git rev-parse --short HEAD) &&
- echo "From $pwd/." > expect.err.sub &&
- echo " $head1..$head2 super -> origin/super" >> expect.err.sub &&
- cat expect.err >> expect.err.sub &&
+ new_head=$(git rev-parse --short HEAD) &&
+ write_expected_super $new_head &&
(
cd downstream &&
git fetch >../actual.out 2>../actual.err &&
@@ -303,60 +387,23 @@ test_expect_success "Recursion picks up config in submodule" '
git config --unset fetch.recurseSubmodules
)
) &&
- test_cmp expect.err.sub actual.err &&
+ verify_fetch_result actual.err &&
test_must_be_empty actual.out
'
test_expect_success "Recursion picks up all submodules when necessary" '
- add_upstream_commit &&
- (
- cd submodule &&
- (
- cd subdir/deepsubmodule &&
- git fetch &&
- git checkout -q FETCH_HEAD
- ) &&
- head1=$(git rev-parse --short HEAD^) &&
- git add subdir/deepsubmodule &&
- git commit -m "new deepsubmodule" &&
- head2=$(git rev-parse --short HEAD) &&
- echo "Fetching submodule submodule" > ../expect.err.sub &&
- echo "From $pwd/submodule" >> ../expect.err.sub &&
- echo " $head1..$head2 sub -> origin/sub" >> ../expect.err.sub
- ) &&
- head1=$(git rev-parse --short HEAD) &&
- git add submodule &&
- git commit -m "new submodule" &&
- head2=$(git rev-parse --short HEAD) &&
- echo "From $pwd/." > expect.err.2 &&
- echo " $head1..$head2 super -> origin/super" >> expect.err.2 &&
- cat expect.err.sub >> expect.err.2 &&
- tail -3 expect.err >> expect.err.2 &&
+ add_submodule_commits &&
+ add_superproject_commits &&
(
cd downstream &&
git fetch >../actual.out 2>../actual.err
) &&
- test_cmp expect.err.2 actual.err &&
+ verify_fetch_result actual.err &&
test_must_be_empty actual.out
'
test_expect_success "'--recurse-submodules=on-demand' doesn't recurse when no new commits are fetched in the superproject (and ignores config)" '
- add_upstream_commit &&
- (
- cd submodule &&
- (
- cd subdir/deepsubmodule &&
- git fetch &&
- git checkout -q FETCH_HEAD
- ) &&
- head1=$(git rev-parse --short HEAD^) &&
- git add subdir/deepsubmodule &&
- git commit -m "new deepsubmodule" &&
- head2=$(git rev-parse --short HEAD) &&
- echo Fetching submodule submodule > ../expect.err.sub &&
- echo "From $pwd/submodule" >> ../expect.err.sub &&
- echo " $head1..$head2 sub -> origin/sub" >> ../expect.err.sub
- ) &&
+ add_submodule_commits &&
(
cd downstream &&
git config fetch.recurseSubmodules true &&
@@ -368,15 +415,8 @@ test_expect_success "'--recurse-submodules=on-demand' doesn't recurse when no ne
'
test_expect_success "'--recurse-submodules=on-demand' recurses as deep as necessary (and ignores config)" '
- head1=$(git rev-parse --short HEAD) &&
- git add submodule &&
- git commit -m "new submodule" &&
- head2=$(git rev-parse --short HEAD) &&
- tail -3 expect.err > expect.err.deepsub &&
- echo "From $pwd/." > expect.err &&
- echo " $head1..$head2 super -> origin/super" >>expect.err &&
- cat expect.err.sub >> expect.err &&
- cat expect.err.deepsub >> expect.err &&
+ add_submodule_commits &&
+ add_superproject_commits &&
(
cd downstream &&
git config fetch.recurseSubmodules false &&
@@ -392,24 +432,165 @@ test_expect_success "'--recurse-submodules=on-demand' recurses as deep as necess
)
) &&
test_must_be_empty actual.out &&
- test_cmp expect.err actual.err
+ verify_fetch_result actual.err
+'
+
+# These tests verify that we can fetch submodules that aren't in the
+# index.
+#
+# First, test the simple case where the index is empty and we only fetch
+# submodules that are not in the index.
+test_expect_success 'setup downstream branch without submodules' '
+ (
+ cd downstream &&
+ git checkout --recurse-submodules -b no-submodules &&
+ git rm .gitmodules &&
+ git rm submodule &&
+ git commit -m "no submodules" &&
+ git checkout --recurse-submodules super
+ )
+'
+
+test_expect_success "'--recurse-submodules=on-demand' should fetch submodule commits if the submodule is changed but the index has no submodules" '
+ add_submodule_commits &&
+ add_superproject_commits &&
+ # Fetch the new superproject commit
+ (
+ cd downstream &&
+ git switch --recurse-submodules no-submodules &&
+ git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err
+ ) &&
+ super_head=$(git rev-parse --short HEAD) &&
+ sub_head=$(git -C submodule rev-parse --short HEAD) &&
+ deep_head=$(git -C submodule/subdir/deepsubmodule rev-parse --short HEAD) &&
+
+ # assert that these are fetched from commits, not the index
+ write_expected_sub $sub_head $super_head &&
+ write_expected_deep $deep_head $sub_head &&
+
+ test_must_be_empty actual.out &&
+ verify_fetch_result actual.err
+'
+
+test_expect_success "'--recurse-submodules' should fetch submodule commits if the submodule is changed but the index has no submodules" '
+ add_submodule_commits &&
+ add_superproject_commits &&
+ # Fetch the new superproject commit
+ (
+ cd downstream &&
+ git switch --recurse-submodules no-submodules &&
+ git fetch --recurse-submodules >../actual.out 2>../actual.err
+ ) &&
+ super_head=$(git rev-parse --short HEAD) &&
+ sub_head=$(git -C submodule rev-parse --short HEAD) &&
+ deep_head=$(git -C submodule/subdir/deepsubmodule rev-parse --short HEAD) &&
+
+ # assert that these are fetched from commits, not the index
+ write_expected_sub $sub_head $super_head &&
+ write_expected_deep $deep_head $sub_head &&
+
+ test_must_be_empty actual.out &&
+ verify_fetch_result actual.err
+'
+
+test_expect_success "'--recurse-submodules' should ignore changed, inactive submodules" '
+ add_submodule_commits &&
+ add_superproject_commits &&
+
+ # Fetch the new superproject commit
+ (
+ cd downstream &&
+ git switch --recurse-submodules no-submodules &&
+ git -c submodule.submodule.active=false fetch --recurse-submodules >../actual.out 2>../actual.err
+ ) &&
+ test_must_be_empty actual.out &&
+ super_head=$(git rev-parse --short HEAD) &&
+ write_expected_super $super_head &&
+ # Neither should be fetched because the submodule is inactive
+ rm expect.err.sub &&
+ rm expect.err.deep &&
+ verify_fetch_result actual.err
+'
+
+# Now that we know we can fetch submodules that are not in the index,
+# test that we can fetch index and non-index submodules in the same
+# operation.
+test_expect_success 'setup downstream branch with other submodule' '
+ mkdir submodule2 &&
+ (
+ cd submodule2 &&
+ git init &&
+ echo sub2content >sub2file &&
+ git add sub2file &&
+ git commit -a -m new &&
+ git branch -M sub2
+ ) &&
+ git checkout -b super-sub2-only &&
+ git submodule add "$pwd/submodule2" submodule2 &&
+ git commit -m "add sub2" &&
+ git checkout super &&
+ (
+ cd downstream &&
+ git fetch --recurse-submodules origin &&
+ git checkout super-sub2-only &&
+ # Explicitly run "git submodule update" because sub2 is new
+ # and has not been cloned.
+ git submodule update --init &&
+ git checkout --recurse-submodules super
+ )
+'
+
+test_expect_success "'--recurse-submodules' should fetch submodule commits in changed submodules and the index" '
+ test_when_finished "rm expect.err.sub2" &&
+ # Create new commit in origin/super
+ add_submodule_commits &&
+ add_superproject_commits &&
+
+ # Create new commit in origin/super-sub2-only
+ git checkout super-sub2-only &&
+ (
+ cd submodule2 &&
+ test_commit --no-tag foo
+ ) &&
+ git add submodule2 &&
+ git commit -m "new submodule2" &&
+
+ git checkout super &&
+ (
+ cd downstream &&
+ git fetch --recurse-submodules >../actual.out 2>../actual.err
+ ) &&
+ test_must_be_empty actual.out &&
+ sub2_head=$(git -C submodule2 rev-parse --short HEAD) &&
+ super_head=$(git rev-parse --short super) &&
+ super_sub2_only_head=$(git rev-parse --short super-sub2-only) &&
+ write_expected_sub2 $sub2_head $super_sub2_only_head &&
+
+ # write_expected_super cannot handle >1 branch. Since this is a
+ # one-off, construct expect.err.super manually.
+ cat >"$pwd/expect.err.super" <<-EOF &&
+ From $pwd/.
+ OLD_HEAD..$super_head super -> origin/super
+ OLD_HEAD..$super_sub2_only_head super-sub2-only -> origin/super-sub2-only
+ EOF
+ verify_fetch_result actual.err
'
test_expect_success "'--recurse-submodules=on-demand' stops when no new submodule commits are found in the superproject (and ignores config)" '
- add_upstream_commit &&
- head1=$(git rev-parse --short HEAD) &&
+ add_submodule_commits &&
echo a >> file &&
git add file &&
git commit -m "new file" &&
- head2=$(git rev-parse --short HEAD) &&
- echo "From $pwd/." > expect.err.file &&
- echo " $head1..$head2 super -> origin/super" >> expect.err.file &&
+ new_head=$(git rev-parse --short HEAD) &&
+ write_expected_super $new_head &&
+ rm expect.err.sub &&
+ rm expect.err.deep &&
(
cd downstream &&
git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_cmp expect.err.file actual.err
+ verify_fetch_result actual.err
'
test_expect_success "'fetch.recurseSubmodules=on-demand' overrides global config" '
@@ -417,15 +598,13 @@ test_expect_success "'fetch.recurseSubmodules=on-demand' overrides global config
cd downstream &&
git fetch --recurse-submodules
) &&
- add_upstream_commit &&
+ add_submodule_commits &&
git config --global fetch.recurseSubmodules false &&
- head1=$(git rev-parse --short HEAD) &&
git add submodule &&
git commit -m "new submodule" &&
- head2=$(git rev-parse --short HEAD) &&
- echo "From $pwd/." > expect.err.2 &&
- echo " $head1..$head2 super -> origin/super" >>expect.err.2 &&
- head -3 expect.err >> expect.err.2 &&
+ new_head=$(git rev-parse --short HEAD) &&
+ write_expected_super $new_head &&
+ rm expect.err.deep &&
(
cd downstream &&
git config fetch.recurseSubmodules on-demand &&
@@ -437,7 +616,7 @@ test_expect_success "'fetch.recurseSubmodules=on-demand' overrides global config
git config --unset fetch.recurseSubmodules
) &&
test_must_be_empty actual.out &&
- test_cmp expect.err.2 actual.err
+ verify_fetch_result actual.err
'
test_expect_success "'submodule.<sub>.fetchRecurseSubmodules=on-demand' overrides fetch.recurseSubmodules" '
@@ -445,15 +624,13 @@ test_expect_success "'submodule.<sub>.fetchRecurseSubmodules=on-demand' override
cd downstream &&
git fetch --recurse-submodules
) &&
- add_upstream_commit &&
+ add_submodule_commits &&
git config fetch.recurseSubmodules false &&
- head1=$(git rev-parse --short HEAD) &&
git add submodule &&
git commit -m "new submodule" &&
- head2=$(git rev-parse --short HEAD) &&
- echo "From $pwd/." > expect.err.2 &&
- echo " $head1..$head2 super -> origin/super" >>expect.err.2 &&
- head -3 expect.err >> expect.err.2 &&
+ new_head=$(git rev-parse --short HEAD) &&
+ write_expected_super $new_head &&
+ rm expect.err.deep &&
(
cd downstream &&
git config submodule.submodule.fetchRecurseSubmodules on-demand &&
@@ -465,7 +642,7 @@ test_expect_success "'submodule.<sub>.fetchRecurseSubmodules=on-demand' override
git config --unset submodule.submodule.fetchRecurseSubmodules
) &&
test_must_be_empty actual.out &&
- test_cmp expect.err.2 actual.err
+ verify_fetch_result actual.err
'
test_expect_success "don't fetch submodule when newly recorded commits are already present" '
@@ -473,18 +650,19 @@ test_expect_success "don't fetch submodule when newly recorded commits are alrea
cd submodule &&
git checkout -q HEAD^^
) &&
- head1=$(git rev-parse --short HEAD) &&
git add submodule &&
git commit -m "submodule rewound" &&
- head2=$(git rev-parse --short HEAD) &&
- echo "From $pwd/." > expect.err &&
- echo " $head1..$head2 super -> origin/super" >> expect.err &&
+ new_head=$(git rev-parse --short HEAD) &&
+ write_expected_super $new_head &&
+ rm expect.err.sub &&
+ # This file does not exist, but rm -f for readability
+ rm -f expect.err.deep &&
(
cd downstream &&
git fetch >../actual.out 2>../actual.err
) &&
test_must_be_empty actual.out &&
- test_cmp expect.err actual.err &&
+ verify_fetch_result actual.err &&
(
cd submodule &&
git checkout -q sub
@@ -496,15 +674,13 @@ test_expect_success "'fetch.recurseSubmodules=on-demand' works also without .git
cd downstream &&
git fetch --recurse-submodules
) &&
- add_upstream_commit &&
- head1=$(git rev-parse --short HEAD) &&
+ add_submodule_commits &&
git add submodule &&
git rm .gitmodules &&
git commit -m "new submodule without .gitmodules" &&
- head2=$(git rev-parse --short HEAD) &&
- echo "From $pwd/." >expect.err.2 &&
- echo " $head1..$head2 super -> origin/super" >>expect.err.2 &&
- head -3 expect.err >>expect.err.2 &&
+ new_head=$(git rev-parse --short HEAD) &&
+ write_expected_super $new_head &&
+ rm expect.err.deep &&
(
cd downstream &&
rm .gitmodules &&
@@ -520,7 +696,7 @@ test_expect_success "'fetch.recurseSubmodules=on-demand' works also without .git
git reset --hard
) &&
test_must_be_empty actual.out &&
- test_cmp expect.err.2 actual.err &&
+ verify_fetch_result actual.err &&
git checkout HEAD^ -- .gitmodules &&
git add .gitmodules &&
git commit -m "new submodule restored .gitmodules"
@@ -842,4 +1018,111 @@ test_expect_success 'recursive fetch after deinit a submodule' '
test_cmp expect actual
'
+test_expect_success 'setup repo with upstreams that share a submodule name' '
+ mkdir same-name-1 &&
+ (
+ cd same-name-1 &&
+ git init -b main &&
+ test_commit --no-tag a
+ ) &&
+ git clone same-name-1 same-name-2 &&
+ # same-name-1 and same-name-2 both add a submodule with the
+ # name "submodule"
+ (
+ cd same-name-1 &&
+ mkdir submodule &&
+ git -C submodule init -b main &&
+ test_commit -C submodule --no-tag a1 &&
+ git submodule add "$pwd/same-name-1/submodule" &&
+ git add submodule &&
+ git commit -m "super-a1"
+ ) &&
+ (
+ cd same-name-2 &&
+ mkdir submodule &&
+ git -C submodule init -b main &&
+ test_commit -C submodule --no-tag a2 &&
+ git submodule add "$pwd/same-name-2/submodule" &&
+ git add submodule &&
+ git commit -m "super-a2"
+ ) &&
+ git clone same-name-1 -o same-name-1 same-name-downstream &&
+ (
+ cd same-name-downstream &&
+ git remote add same-name-2 ../same-name-2 &&
+ git fetch --all &&
+ # init downstream with same-name-1
+ git submodule update --init
+ )
+'
+
+test_expect_success 'fetch --recurse-submodules updates name-conflicted, populated submodule' '
+ test_when_finished "git -C same-name-downstream checkout main" &&
+ (
+ cd same-name-1 &&
+ test_commit -C submodule --no-tag b1 &&
+ git add submodule &&
+ git commit -m "super-b1"
+ ) &&
+ (
+ cd same-name-2 &&
+ test_commit -C submodule --no-tag b2 &&
+ git add submodule &&
+ git commit -m "super-b2"
+ ) &&
+ (
+ cd same-name-downstream &&
+ # even though the .gitmodules is correct, we cannot
+ # fetch from same-name-2
+ git checkout same-name-2/main &&
+ git fetch --recurse-submodules same-name-1 &&
+ test_must_fail git fetch --recurse-submodules same-name-2
+ ) &&
+ super_head1=$(git -C same-name-1 rev-parse HEAD) &&
+ git -C same-name-downstream cat-file -e $super_head1 &&
+
+ super_head2=$(git -C same-name-2 rev-parse HEAD) &&
+ git -C same-name-downstream cat-file -e $super_head2 &&
+
+ sub_head1=$(git -C same-name-1/submodule rev-parse HEAD) &&
+ git -C same-name-downstream/submodule cat-file -e $sub_head1 &&
+
+ sub_head2=$(git -C same-name-2/submodule rev-parse HEAD) &&
+ test_must_fail git -C same-name-downstream/submodule cat-file -e $sub_head2
+'
+
+test_expect_success 'fetch --recurse-submodules updates name-conflicted, unpopulated submodule' '
+ (
+ cd same-name-1 &&
+ test_commit -C submodule --no-tag c1 &&
+ git add submodule &&
+ git commit -m "super-c1"
+ ) &&
+ (
+ cd same-name-2 &&
+ test_commit -C submodule --no-tag c2 &&
+ git add submodule &&
+ git commit -m "super-c2"
+ ) &&
+ (
+ cd same-name-downstream &&
+ git checkout main &&
+ git rm .gitmodules &&
+ git rm submodule &&
+ git commit -m "no submodules" &&
+ git fetch --recurse-submodules same-name-1
+ ) &&
+ head1=$(git -C same-name-1/submodule rev-parse HEAD) &&
+ head2=$(git -C same-name-2/submodule rev-parse HEAD) &&
+ (
+ cd same-name-downstream/.git/modules/submodule &&
+ # The submodule has core.worktree pointing to the "git
+ # rm"-ed directory, overwrite the invalid value. See
+ # comment in get_fetch_task_from_changed() for more
+ # information.
+ git --work-tree=. cat-file -e $head1 &&
+ test_must_fail git --work-tree=. cat-file -e $head2
+ )
+'
+
test_done
diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh
index 24d374a..7c0a148 100755
--- a/t/t5534-push-signed.sh
+++ b/t/t5534-push-signed.sh
@@ -35,8 +35,7 @@ test_expect_success setup '
test_expect_success 'unsigned push does not send push certificate' '
prepare_dst &&
- mkdir -p dst/.git/hooks &&
- write_script dst/.git/hooks/post-receive <<-\EOF &&
+ test_hook -C dst post-receive <<-\EOF &&
# discard the update list
cat >/dev/null
# record the push certificate
@@ -52,8 +51,7 @@ test_expect_success 'unsigned push does not send push certificate' '
test_expect_success 'talking with a receiver without push certificate support' '
prepare_dst &&
- mkdir -p dst/.git/hooks &&
- write_script dst/.git/hooks/post-receive <<-\EOF &&
+ test_hook -C dst post-receive <<-\EOF &&
# discard the update list
cat >/dev/null
# record the push certificate
@@ -69,22 +67,19 @@ test_expect_success 'talking with a receiver without push certificate support' '
test_expect_success 'push --signed fails with a receiver without push certificate support' '
prepare_dst &&
- mkdir -p dst/.git/hooks &&
test_must_fail git push --signed dst noop ff +noff 2>err &&
test_i18ngrep "the receiving end does not support" err
'
test_expect_success 'push --signed=1 is accepted' '
prepare_dst &&
- mkdir -p dst/.git/hooks &&
test_must_fail git push --signed=1 dst noop ff +noff 2>err &&
test_i18ngrep "the receiving end does not support" err
'
test_expect_success GPG 'no certificate for a signed push with no update' '
prepare_dst &&
- mkdir -p dst/.git/hooks &&
- write_script dst/.git/hooks/post-receive <<-\EOF &&
+ test_hook -C dst post-receive <<-\EOF &&
if test -n "${GIT_PUSH_CERT-}"
then
git cat-file blob $GIT_PUSH_CERT >../push-cert
@@ -96,9 +91,8 @@ test_expect_success GPG 'no certificate for a signed push with no update' '
test_expect_success GPG 'signed push sends push certificate' '
prepare_dst &&
- mkdir -p dst/.git/hooks &&
git -C dst config receive.certnonceseed sekrit &&
- write_script dst/.git/hooks/post-receive <<-\EOF &&
+ test_hook -C dst post-receive <<-\EOF &&
# discard the update list
cat >/dev/null
# record the push certificate
@@ -139,10 +133,9 @@ test_expect_success GPG 'signed push sends push certificate' '
test_expect_success GPGSSH 'ssh signed push sends push certificate' '
prepare_dst &&
- mkdir -p dst/.git/hooks &&
git -C dst config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
git -C dst config receive.certnonceseed sekrit &&
- write_script dst/.git/hooks/post-receive <<-\EOF &&
+ test_hook -C dst post-receive <<-\EOF &&
# discard the update list
cat >/dev/null
# record the push certificate
@@ -223,9 +216,8 @@ test_expect_success GPG 'inconsistent push options in signed push not allowed' '
test_expect_success GPG 'fail without key and heed user.signingkey' '
prepare_dst &&
- mkdir -p dst/.git/hooks &&
git -C dst config receive.certnonceseed sekrit &&
- write_script dst/.git/hooks/post-receive <<-\EOF &&
+ test_hook -C dst post-receive <<-\EOF &&
# discard the update list
cat >/dev/null
# record the push certificate
@@ -273,9 +265,8 @@ test_expect_success GPG 'fail without key and heed user.signingkey' '
test_expect_success GPGSM 'fail without key and heed user.signingkey x509' '
test_config gpg.format x509 &&
prepare_dst &&
- mkdir -p dst/.git/hooks &&
git -C dst config receive.certnonceseed sekrit &&
- write_script dst/.git/hooks/post-receive <<-\EOF &&
+ test_hook -C dst post-receive <<-\EOF &&
# discard the update list
cat >/dev/null
# record the push certificate
@@ -326,10 +317,9 @@ test_expect_success GPGSM 'fail without key and heed user.signingkey x509' '
test_expect_success GPGSSH 'fail without key and heed user.signingkey ssh' '
test_config gpg.format ssh &&
prepare_dst &&
- mkdir -p dst/.git/hooks &&
git -C dst config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
git -C dst config receive.certnonceseed sekrit &&
- write_script dst/.git/hooks/post-receive <<-\EOF &&
+ test_hook -C dst post-receive <<-\EOF &&
# discard the update list
cat >/dev/null
# record the push certificate
diff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh
index 11d5ea5..92948de 100755
--- a/t/t5537-fetch-shallow.sh
+++ b/t/t5537-fetch-shallow.sh
@@ -161,6 +161,15 @@ test_expect_success 'fetch --update-shallow' '
)
'
+test_expect_success 'fetch --update-shallow into a repo with submodules' '
+ git init a-submodule &&
+ test_commit -C a-submodule foo &&
+ git init repo-with-sub &&
+ git -C repo-with-sub submodule add ../a-submodule a-submodule &&
+ git -C repo-with-sub commit -m "added submodule" &&
+ git -C repo-with-sub fetch --update-shallow ../shallow/.git refs/heads/*:refs/remotes/shallow/*
+'
+
test_expect_success 'fetch --update-shallow (with fetch.writeCommitGraph)' '
(
cd shallow &&
diff --git a/t/t5540-http-push-webdav.sh b/t/t5540-http-push-webdav.sh
index b0dbacf..37db3de 100755
--- a/t/t5540-http-push-webdav.sh
+++ b/t/t5540-http-push-webdav.sh
@@ -42,7 +42,9 @@ test_expect_success 'setup remote repository' '
git clone --bare test_repo test_repo.git &&
cd test_repo.git &&
git --bare update-server-info &&
- mv hooks/post-update.sample hooks/post-update &&
+ test_hook --setup post-update <<-\EOF &&
+ exec git update-server-info
+ EOF
ORIG_HEAD=$(git rev-parse --verify HEAD) &&
cd - &&
mv test_repo.git "$HTTPD_DOCUMENT_ROOT_PATH"
diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh
index 8ca50f8..2f09ff4 100755
--- a/t/t5541-http-push-smart.sh
+++ b/t/t5541-http-push-smart.sh
@@ -96,18 +96,18 @@ test_expect_success 'create and delete remote branch' '
test_must_fail git show-ref --verify refs/remotes/origin/dev
'
-cat >"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update" <<EOF
-#!/bin/sh
-exit 1
-EOF
-chmod a+x "$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update"
+test_expect_success 'setup rejected update hook' '
+ test_hook --setup -C "$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" update <<-\EOF &&
+ exit 1
+ EOF
-cat >exp <<EOF
-remote: error: hook declined to update refs/heads/dev2
-To http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git
- ! [remote rejected] dev2 -> dev2 (hook declined)
-error: failed to push some refs to 'http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git'
-EOF
+ cat >exp <<-EOF
+ remote: error: hook declined to update refs/heads/dev2
+ To http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git
+ ! [remote rejected] dev2 -> dev2 (hook declined)
+ error: failed to push some refs to '\''http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git'\''
+ EOF
+'
test_expect_success 'rejected update prints status' '
cd "$ROOT_PATH"/test_repo_clone &&
@@ -419,10 +419,7 @@ test_expect_success CMDLINE_LIMIT 'push 2000 tags over http' '
'
test_expect_success GPG 'push with post-receive to inspect certificate' '
- (
- cd "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git &&
- mkdir -p hooks &&
- write_script hooks/post-receive <<-\EOF &&
+ test_hook -C "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git post-receive <<-\EOF &&
# discard the update list
cat >/dev/null
# record the push certificate
@@ -437,8 +434,9 @@ test_expect_success GPG 'push with post-receive to inspect certificate' '
NONCE_STATUS=${GIT_PUSH_CERT_NONCE_STATUS-nononcestatus}
NONCE=${GIT_PUSH_CERT_NONCE-nononce}
E_O_F
- EOF
-
+ EOF
+ (
+ cd "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git &&
git config receive.certnonceseed sekrit &&
git config receive.certnonceslop 30
) &&
diff --git a/t/t5543-atomic-push.sh b/t/t5543-atomic-push.sh
index bfee461..7043112 100755
--- a/t/t5543-atomic-push.sh
+++ b/t/t5543-atomic-push.sh
@@ -162,16 +162,10 @@ test_expect_success 'atomic push obeys update hook preventing a branch to be pus
test_commit two &&
git push --mirror up
) &&
- (
- cd upstream &&
- HOOKDIR="$(git rev-parse --git-dir)/hooks" &&
- HOOK="$HOOKDIR/update" &&
- mkdir -p "$HOOKDIR" &&
- write_script "$HOOK" <<-\EOF
- # only allow update to main from now on
- test "$1" = "refs/heads/main"
- EOF
- ) &&
+ test_hook -C upstream update <<-\EOF &&
+ # only allow update to main from now on
+ test "$1" = "refs/heads/main"
+ EOF
(
cd workbench &&
git checkout main &&
diff --git a/t/t5547-push-quarantine.sh b/t/t5547-push-quarantine.sh
index faaa51c..1876fb3 100755
--- a/t/t5547-push-quarantine.sh
+++ b/t/t5547-push-quarantine.sh
@@ -5,7 +5,7 @@ test_description='check quarantine of objects during push'
test_expect_success 'create picky dest repo' '
git init --bare dest.git &&
- write_script dest.git/hooks/pre-receive <<-\EOF
+ test_hook --setup -C dest.git pre-receive <<-\EOF
while read old new ref; do
test "$(git log -1 --format=%s $new)" = reject && exit 1
done
@@ -60,7 +60,7 @@ test_expect_success 'push to repo path with path separator (colon)' '
test_expect_success 'updating a ref from quarantine is forbidden' '
git init --bare update.git &&
- write_script update.git/hooks/pre-receive <<-\EOF &&
+ test_hook -C update.git pre-receive <<-\EOF &&
read old new refname
git update-ref refs/heads/unrelated $new
exit 1
diff --git a/t/t5548-push-porcelain.sh b/t/t5548-push-porcelain.sh
index f11ff57..6282728 100755
--- a/t/t5548-push-porcelain.sh
+++ b/t/t5548-push-porcelain.sh
@@ -168,7 +168,7 @@ run_git_push_porcelain_output_test() {
'
test_expect_success "prepare pre-receive hook ($PROTOCOL)" '
- write_script "$upstream/hooks/pre-receive" <<-EOF
+ test_hook --setup -C "$upstream" pre-receive <<-EOF
exit 1
EOF
'
diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh
index 2592039..f0d9cd5 100755
--- a/t/t5550-http-fetch-dumb.sh
+++ b/t/t5550-http-fetch-dumb.sh
@@ -25,16 +25,17 @@ test_expect_success 'setup repository' '
git commit -m two
'
+setup_post_update_server_info_hook () {
+ test_hook --setup -C "$1" post-update <<-\EOF &&
+ exec git update-server-info
+ EOF
+ git -C "$1" update-server-info
+}
+
test_expect_success 'create http-accessible bare repository with loose objects' '
cp -R .git "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
- (cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
- git config core.bare true &&
- mkdir -p hooks &&
- write_script "hooks/post-update" <<-\EOF &&
- exec git update-server-info
- EOF
- hooks/post-update
- ) &&
+ git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" config core.bare true &&
+ setup_post_update_server_info_hook "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
git remote add public "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
git push public main:main
'
@@ -62,13 +63,7 @@ test_expect_success 'create password-protected repository' '
test_expect_success 'create empty remote repository' '
git init --bare "$HTTPD_DOCUMENT_ROOT_PATH/empty.git" &&
- (cd "$HTTPD_DOCUMENT_ROOT_PATH/empty.git" &&
- mkdir -p hooks &&
- write_script "hooks/post-update" <<-\EOF &&
- exec git update-server-info
- EOF
- hooks/post-update
- )
+ setup_post_update_server_info_hook "$HTTPD_DOCUMENT_ROOT_PATH/empty.git"
'
test_expect_success 'empty dumb HTTP repository has default hash algorithm' '
diff --git a/t/t5571-pre-push-hook.sh b/t/t5571-pre-push-hook.sh
index 660f876..a11b20e 100755
--- a/t/t5571-pre-push-hook.sh
+++ b/t/t5571-pre-push-hook.sh
@@ -6,57 +6,66 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
-# Setup hook that always succeeds
-HOOKDIR="$(git rev-parse --git-dir)/hooks"
-HOOK="$HOOKDIR/pre-push"
-mkdir -p "$HOOKDIR"
-write_script "$HOOK" <<EOF
-cat >/dev/null
-exit 0
-EOF
-
test_expect_success 'setup' '
+ test_hook pre-push <<-\EOF &&
+ cat >actual
+ EOF
+
git config push.default upstream &&
git init --bare repo1 &&
git remote add parent1 repo1 &&
test_commit one &&
- git push parent1 HEAD:foreign
+ cat >expect <<-EOF &&
+ HEAD $(git rev-parse HEAD) refs/heads/foreign $(test_oid zero)
+ EOF
+
+ test_when_finished "rm actual" &&
+ git push parent1 HEAD:foreign &&
+ test_cmp expect actual
'
-write_script "$HOOK" <<EOF
-cat >/dev/null
-exit 1
-EOF
COMMIT1="$(git rev-parse HEAD)"
export COMMIT1
test_expect_success 'push with failing hook' '
+ test_hook pre-push <<-\EOF &&
+ cat >actual &&
+ exit 1
+ EOF
+
test_commit two &&
- test_must_fail git push parent1 HEAD
+ cat >expect <<-EOF &&
+ HEAD $(git rev-parse HEAD) refs/heads/main $(test_oid zero)
+ EOF
+
+ test_when_finished "rm actual" &&
+ test_must_fail git push parent1 HEAD &&
+ test_cmp expect actual
'
test_expect_success '--no-verify bypasses hook' '
- git push --no-verify parent1 HEAD
+ git push --no-verify parent1 HEAD &&
+ test_path_is_missing actual
'
COMMIT2="$(git rev-parse HEAD)"
export COMMIT2
-write_script "$HOOK" <<'EOF'
-echo "$1" >actual
-echo "$2" >>actual
-cat >>actual
-EOF
-
-cat >expected <<EOF
-parent1
-repo1
-refs/heads/main $COMMIT2 refs/heads/foreign $COMMIT1
-EOF
-
test_expect_success 'push with hook' '
+ test_hook --setup pre-push <<-\EOF &&
+ echo "$1" >actual
+ echo "$2" >>actual
+ cat >>actual
+ EOF
+
+ cat >expect <<-EOF &&
+ parent1
+ repo1
+ refs/heads/main $COMMIT2 refs/heads/foreign $COMMIT1
+ EOF
+
git push parent1 main:foreign &&
- diff expected actual
+ test_cmp expect actual
'
test_expect_success 'add a branch' '
@@ -67,49 +76,48 @@ test_expect_success 'add a branch' '
COMMIT3="$(git rev-parse HEAD)"
export COMMIT3
-cat >expected <<EOF
-parent1
-repo1
-refs/heads/other $COMMIT3 refs/heads/foreign $COMMIT2
-EOF
-
test_expect_success 'push to default' '
+ cat >expect <<-EOF &&
+ parent1
+ repo1
+ refs/heads/other $COMMIT3 refs/heads/foreign $COMMIT2
+ EOF
git push &&
- diff expected actual
+ test_cmp expect actual
'
-cat >expected <<EOF
-parent1
-repo1
-refs/tags/one $COMMIT1 refs/tags/tag1 $ZERO_OID
-HEAD~ $COMMIT2 refs/heads/prev $ZERO_OID
-EOF
-
test_expect_success 'push non-branches' '
+ cat >expect <<-EOF &&
+ parent1
+ repo1
+ refs/tags/one $COMMIT1 refs/tags/tag1 $ZERO_OID
+ HEAD~ $COMMIT2 refs/heads/prev $ZERO_OID
+ EOF
+
git push parent1 one:tag1 HEAD~:refs/heads/prev &&
- diff expected actual
+ test_cmp expect actual
'
-cat >expected <<EOF
-parent1
-repo1
-(delete) $ZERO_OID refs/heads/prev $COMMIT2
-EOF
-
test_expect_success 'push delete' '
+ cat >expect <<-EOF &&
+ parent1
+ repo1
+ (delete) $ZERO_OID refs/heads/prev $COMMIT2
+ EOF
+
git push parent1 :prev &&
- diff expected actual
+ test_cmp expect actual
'
-cat >expected <<EOF
-repo1
-repo1
-HEAD $COMMIT3 refs/heads/other $ZERO_OID
-EOF
-
test_expect_success 'push to URL' '
+ cat >expect <<-EOF &&
+ repo1
+ repo1
+ HEAD $COMMIT3 refs/heads/other $ZERO_OID
+ EOF
+
git push repo1 HEAD &&
- diff expected actual
+ test_cmp expect actual
'
test_expect_success 'set up many-ref tests' '
@@ -124,7 +132,9 @@ test_expect_success 'set up many-ref tests' '
'
test_expect_success 'sigpipe does not cause pre-push hook failure' '
- echo "exit 0" | write_script "$HOOK" &&
+ test_hook --clobber pre-push <<-\EOF &&
+ exit 0
+ EOF
git push parent1 "refs/heads/b/*:refs/heads/b/*"
'
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 83c24fc..4a61f2c 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -79,12 +79,10 @@ test_expect_success 'clone from hooks' '
cd .. &&
git init r1 &&
cd r1 &&
- cat >.git/hooks/pre-commit <<-\EOF &&
- #!/bin/sh
+ test_hook pre-commit <<-\EOF &&
git clone ../r0 ../r2
exit 1
EOF
- chmod u+x .git/hooks/pre-commit &&
: >file &&
git add file &&
test_must_fail git commit -m invoke-hook &&
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index 34469b6..4a3778d 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -166,6 +166,85 @@ test_expect_success 'manual prefetch of missing objects' '
test_line_count = 0 observed.oids
'
+# create new commits in "src" repo to establish a history on file.4.txt
+# and push to "srv.bare".
+test_expect_success 'push new commits to server for file.4.txt' '
+ for x in a b c d e f
+ do
+ echo "Mod file.4.txt $x" >src/file.4.txt &&
+ if list_contains "a,b" "$x"; then
+ printf "%10000s" X >>src/file.4.txt
+ fi &&
+ if list_contains "c,d" "$x"; then
+ printf "%20000s" X >>src/file.4.txt
+ fi &&
+ git -C src add file.4.txt &&
+ git -C src commit -m "mod $x" || return 1
+ done &&
+ git -C src push -u srv main
+'
+
+# Do partial fetch to fetch smaller files; then verify that without --refetch
+# applying a new filter does not refetch missing large objects. Then use
+# --refetch to apply the new filter on existing commits. Test it under both
+# protocol v2 & v0.
+test_expect_success 'apply a different filter using --refetch' '
+ git -C pc1 fetch --filter=blob:limit=999 origin &&
+ git -C pc1 rev-list --quiet --objects --missing=print \
+ main..origin/main >observed &&
+ test_line_count = 4 observed &&
+
+ git -C pc1 fetch --filter=blob:limit=19999 --refetch origin &&
+ git -C pc1 rev-list --quiet --objects --missing=print \
+ main..origin/main >observed &&
+ test_line_count = 2 observed &&
+
+ git -c protocol.version=0 -C pc1 fetch --filter=blob:limit=29999 \
+ --refetch origin &&
+ git -C pc1 rev-list --quiet --objects --missing=print \
+ main..origin/main >observed &&
+ test_line_count = 0 observed
+'
+
+test_expect_success 'fetch --refetch works with a shallow clone' '
+ git clone --no-checkout --depth=1 --filter=blob:none "file://$(pwd)/srv.bare" pc1s &&
+ git -C pc1s rev-list --objects --missing=print HEAD >observed &&
+ test_line_count = 6 observed &&
+
+ GIT_TRACE=1 git -C pc1s fetch --filter=blob:limit=999 --refetch origin &&
+ git -C pc1s rev-list --objects --missing=print HEAD >observed &&
+ test_line_count = 6 observed
+'
+
+test_expect_success 'fetch --refetch triggers repacking' '
+ GIT_TRACE2_CONFIG_PARAMS=gc.autoPackLimit,maintenance.incremental-repack.auto &&
+ export GIT_TRACE2_CONFIG_PARAMS &&
+
+ GIT_TRACE2_EVENT="$PWD/trace1.event" \
+ git -C pc1 fetch --refetch origin &&
+ test_subcommand git maintenance run --auto --no-quiet <trace1.event &&
+ grep \"param\":\"gc.autopacklimit\",\"value\":\"1\" trace1.event &&
+ grep \"param\":\"maintenance.incremental-repack.auto\",\"value\":\"-1\" trace1.event &&
+
+ GIT_TRACE2_EVENT="$PWD/trace2.event" \
+ git -c protocol.version=0 \
+ -c gc.autoPackLimit=0 \
+ -c maintenance.incremental-repack.auto=1234 \
+ -C pc1 fetch --refetch origin &&
+ test_subcommand git maintenance run --auto --no-quiet <trace2.event &&
+ grep \"param\":\"gc.autopacklimit\",\"value\":\"0\" trace2.event &&
+ grep \"param\":\"maintenance.incremental-repack.auto\",\"value\":\"-1\" trace2.event &&
+
+ GIT_TRACE2_EVENT="$PWD/trace3.event" \
+ git -c protocol.version=0 \
+ -c gc.autoPackLimit=1234 \
+ -c maintenance.incremental-repack.auto=0 \
+ -C pc1 fetch --refetch origin &&
+ test_subcommand git maintenance run --auto --no-quiet <trace3.event &&
+ grep \"param\":\"gc.autopacklimit\",\"value\":\"1\" trace3.event &&
+ grep \"param\":\"maintenance.incremental-repack.auto\",\"value\":\"0\" trace3.event
+'
+
test_expect_success 'partial clone with transfer.fsckobjects=1 works with submodules' '
test_create_repo submodule &&
test_commit -C submodule mycommit &&
@@ -225,7 +304,7 @@ test_expect_success 'use fsck before and after manually fetching a missing subtr
# Auto-fetch all remaining trees and blobs with --missing=error
git -C dst rev-list --missing=error --objects main >fetched_objects &&
- test_line_count = 70 fetched_objects &&
+ test_line_count = 88 fetched_objects &&
awk -f print_1.awk fetched_objects |
xargs -n1 git -C dst cat-file -t >fetched_types &&
diff --git a/t/t5617-clone-submodules-remote.sh b/t/t5617-clone-submodules-remote.sh
index e2dbb4e..ca8f800 100755
--- a/t/t5617-clone-submodules-remote.sh
+++ b/t/t5617-clone-submodules-remote.sh
@@ -28,6 +28,13 @@ test_expect_success 'setup' '
)
'
+# bare clone giving "srv.bare" for use as our server.
+test_expect_success 'setup bare clone for server' '
+ git clone --bare "file://$(pwd)/." srv.bare &&
+ git -C srv.bare config --local uploadpack.allowfilter 1 &&
+ git -C srv.bare config --local uploadpack.allowanysha1inwant 1
+'
+
test_expect_success 'clone with --no-remote-submodules' '
test_when_finished "rm -rf super_clone" &&
git clone --recurse-submodules --no-remote-submodules "file://$pwd/." super_clone &&
@@ -65,4 +72,38 @@ test_expect_success 'clone with --single-branch' '
)
'
+# do basic partial clone from "srv.bare"
+# confirm partial clone was registered in the local config for super and sub.
+test_expect_success 'clone with --filter' '
+ git clone --recurse-submodules \
+ --filter blob:none --also-filter-submodules \
+ "file://$pwd/srv.bare" super_clone &&
+ test_cmp_config -C super_clone true remote.origin.promisor &&
+ test_cmp_config -C super_clone blob:none remote.origin.partialclonefilter &&
+ test_cmp_config -C super_clone/sub true remote.origin.promisor &&
+ test_cmp_config -C super_clone/sub blob:none remote.origin.partialclonefilter
+'
+
+# check that clone.filterSubmodules works (--also-filter-submodules can be
+# omitted)
+test_expect_success 'filters applied with clone.filterSubmodules' '
+ test_config_global clone.filterSubmodules true &&
+ git clone --recurse-submodules --filter blob:none \
+ "file://$pwd/srv.bare" super_clone2 &&
+ test_cmp_config -C super_clone2 true remote.origin.promisor &&
+ test_cmp_config -C super_clone2 blob:none remote.origin.partialclonefilter &&
+ test_cmp_config -C super_clone2/sub true remote.origin.promisor &&
+ test_cmp_config -C super_clone2/sub blob:none remote.origin.partialclonefilter
+'
+
+test_expect_success '--no-also-filter-submodules overrides clone.filterSubmodules=true' '
+ test_config_global clone.filterSubmodules true &&
+ git clone --recurse-submodules --filter blob:none \
+ --no-also-filter-submodules \
+ "file://$pwd/srv.bare" super_clone3 &&
+ test_cmp_config -C super_clone3 true remote.origin.promisor &&
+ test_cmp_config -C super_clone3 blob:none remote.origin.partialclonefilter &&
+ test_cmp_config -C super_clone3/sub false --default false remote.origin.promisor
+'
+
test_done
diff --git a/t/t5700-protocol-v1.sh b/t/t5700-protocol-v1.sh
index 468bd3e..6c8d4c6 100755
--- a/t/t5700-protocol-v1.sh
+++ b/t/t5700-protocol-v1.sh
@@ -149,6 +149,21 @@ test_expect_success 'push with file:// using protocol v1' '
grep "push< version 1" log
'
+test_expect_success 'cloning branchless tagless but not refless remote' '
+ rm -rf server client &&
+
+ git -c init.defaultbranch=main init server &&
+ echo foo >server/foo.txt &&
+ git -C server add foo.txt &&
+ git -C server commit -m "message" &&
+ git -C server update-ref refs/notbranch/alsonottag HEAD &&
+ git -C server checkout --detach &&
+ git -C server branch -D main &&
+ git -C server symbolic-ref HEAD refs/heads/nonexistentbranch &&
+
+ git -c protocol.version=1 clone "file://$(pwd)/server" client
+'
+
# Test protocol v1 with 'ssh://' transport
#
test_expect_success 'setup ssh wrapper' '
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index 710f33e..00ce9ae 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -619,7 +619,7 @@ test_expect_success 'usage: --negotiate-only without --negotiation-tip' '
setup_negotiate_only "$SERVER" "$URI" &&
cat >err.expect <<-\EOF &&
- fatal: --negotiate-only needs one or more --negotiate-tip=*
+ fatal: --negotiate-only needs one or more --negotiation-tip=*
EOF
test_must_fail git -c protocol.version=2 -C client fetch \
@@ -628,6 +628,18 @@ test_expect_success 'usage: --negotiate-only without --negotiation-tip' '
test_cmp err.expect err.actual
'
+test_expect_success 'usage: --negotiate-only with --recurse-submodules' '
+ cat >err.expect <<-\EOF &&
+ fatal: options '\''--negotiate-only'\'' and '\''--recurse-submodules'\'' cannot be used together
+ EOF
+
+ test_must_fail git -c protocol.version=2 -C client fetch \
+ --negotiate-only \
+ --recurse-submodules \
+ origin 2>err.actual &&
+ test_cmp err.expect err.actual
+'
+
test_expect_success 'file:// --negotiate-only' '
SERVER="server" &&
URI="file://$(pwd)/server" &&
diff --git a/t/t6005-rev-list-count.sh b/t/t6005-rev-list-count.sh
index 86542c6..e960049 100755
--- a/t/t6005-rev-list-count.sh
+++ b/t/t6005-rev-list-count.sh
@@ -2,7 +2,6 @@
test_description='git rev-list --max-count and --skip test'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -14,39 +13,39 @@ test_expect_success 'setup' '
'
test_expect_success 'no options' '
- test $(git rev-list HEAD | wc -l) = 5
+ test_stdout_line_count = 5 git rev-list HEAD
'
test_expect_success '--max-count' '
- test $(git rev-list HEAD --max-count=0 | wc -l) = 0 &&
- test $(git rev-list HEAD --max-count=3 | wc -l) = 3 &&
- test $(git rev-list HEAD --max-count=5 | wc -l) = 5 &&
- test $(git rev-list HEAD --max-count=10 | wc -l) = 5
+ test_stdout_line_count = 0 git rev-list HEAD --max-count=0 &&
+ test_stdout_line_count = 3 git rev-list HEAD --max-count=3 &&
+ test_stdout_line_count = 5 git rev-list HEAD --max-count=5 &&
+ test_stdout_line_count = 5 git rev-list HEAD --max-count=10
'
test_expect_success '--max-count all forms' '
- test $(git rev-list HEAD --max-count=1 | wc -l) = 1 &&
- test $(git rev-list HEAD -1 | wc -l) = 1 &&
- test $(git rev-list HEAD -n1 | wc -l) = 1 &&
- test $(git rev-list HEAD -n 1 | wc -l) = 1
+ test_stdout_line_count = 1 git rev-list HEAD --max-count=1 &&
+ test_stdout_line_count = 1 git rev-list HEAD -1 &&
+ test_stdout_line_count = 1 git rev-list HEAD -n1 &&
+ test_stdout_line_count = 1 git rev-list HEAD -n 1
'
test_expect_success '--skip' '
- test $(git rev-list HEAD --skip=0 | wc -l) = 5 &&
- test $(git rev-list HEAD --skip=3 | wc -l) = 2 &&
- test $(git rev-list HEAD --skip=5 | wc -l) = 0 &&
- test $(git rev-list HEAD --skip=10 | wc -l) = 0
+ test_stdout_line_count = 5 git rev-list HEAD --skip=0 &&
+ test_stdout_line_count = 2 git rev-list HEAD --skip=3 &&
+ test_stdout_line_count = 0 git rev-list HEAD --skip=5 &&
+ test_stdout_line_count = 0 git rev-list HEAD --skip=10
'
test_expect_success '--skip --max-count' '
- test $(git rev-list HEAD --skip=0 --max-count=0 | wc -l) = 0 &&
- test $(git rev-list HEAD --skip=0 --max-count=10 | wc -l) = 5 &&
- test $(git rev-list HEAD --skip=3 --max-count=0 | wc -l) = 0 &&
- test $(git rev-list HEAD --skip=3 --max-count=1 | wc -l) = 1 &&
- test $(git rev-list HEAD --skip=3 --max-count=2 | wc -l) = 2 &&
- test $(git rev-list HEAD --skip=3 --max-count=10 | wc -l) = 2 &&
- test $(git rev-list HEAD --skip=5 --max-count=10 | wc -l) = 0 &&
- test $(git rev-list HEAD --skip=10 --max-count=10 | wc -l) = 0
+ test_stdout_line_count = 0 git rev-list HEAD --skip=0 --max-count=0 &&
+ test_stdout_line_count = 5 git rev-list HEAD --skip=0 --max-count=10 &&
+ test_stdout_line_count = 0 git rev-list HEAD --skip=3 --max-count=0 &&
+ test_stdout_line_count = 1 git rev-list HEAD --skip=3 --max-count=1 &&
+ test_stdout_line_count = 2 git rev-list HEAD --skip=3 --max-count=2 &&
+ test_stdout_line_count = 2 git rev-list HEAD --skip=3 --max-count=10 &&
+ test_stdout_line_count = 0 git rev-list HEAD --skip=5 --max-count=10 &&
+ test_stdout_line_count = 0 git rev-list HEAD --skip=10 --max-count=10
'
test_done
diff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh
index aebe4b6..6f3e543 100755
--- a/t/t6007-rev-list-cherry-pick-file.sh
+++ b/t/t6007-rev-list-cherry-pick-file.sh
@@ -58,7 +58,7 @@ EOF
test_expect_success '--left-right' '
git rev-list --left-right B...C > actual &&
- git name-rev --stdin --name-only --refs="*tags/*" \
+ git name-rev --annotate-stdin --name-only --refs="*tags/*" \
< actual > actual.named &&
test_cmp expect actual.named
'
@@ -78,14 +78,14 @@ EOF
test_expect_success '--cherry-pick bar does not come up empty' '
git rev-list --left-right --cherry-pick B...C -- bar > actual &&
- git name-rev --stdin --name-only --refs="*tags/*" \
+ git name-rev --annotate-stdin --name-only --refs="*tags/*" \
< actual > actual.named &&
test_cmp expect actual.named
'
test_expect_success 'bar does not come up empty' '
git rev-list --left-right B...C -- bar > actual &&
- git name-rev --stdin --name-only --refs="*tags/*" \
+ git name-rev --annotate-stdin --name-only --refs="*tags/*" \
< actual > actual.named &&
test_cmp expect actual.named
'
@@ -97,14 +97,14 @@ EOF
test_expect_success '--cherry-pick bar does not come up empty (II)' '
git rev-list --left-right --cherry-pick F...E -- bar > actual &&
- git name-rev --stdin --name-only --refs="*tags/*" \
+ git name-rev --annotate-stdin --name-only --refs="*tags/*" \
< actual > actual.named &&
test_cmp expect actual.named
'
test_expect_success 'name-rev multiple --refs combine inclusive' '
git rev-list --left-right --cherry-pick F...E -- bar >actual &&
- git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" \
+ git name-rev --annotate-stdin --name-only --refs="*tags/F" --refs="*tags/E" \
<actual >actual.named &&
test_cmp expect actual.named
'
@@ -116,7 +116,7 @@ EOF
test_expect_success 'name-rev --refs excludes non-matched patterns' '
git rev-list --left-right --right-only --cherry-pick F...E -- bar >>expect &&
git rev-list --left-right --cherry-pick F...E -- bar >actual &&
- git name-rev --stdin --name-only --refs="*tags/F" \
+ git name-rev --annotate-stdin --name-only --refs="*tags/F" \
<actual >actual.named &&
test_cmp expect actual.named
'
@@ -128,14 +128,14 @@ EOF
test_expect_success 'name-rev --exclude excludes matched patterns' '
git rev-list --left-right --right-only --cherry-pick F...E -- bar >>expect &&
git rev-list --left-right --cherry-pick F...E -- bar >actual &&
- git name-rev --stdin --name-only --refs="*tags/*" --exclude="*E" \
+ git name-rev --annotate-stdin --name-only --refs="*tags/*" --exclude="*E" \
<actual >actual.named &&
test_cmp expect actual.named
'
test_expect_success 'name-rev --no-refs clears the refs list' '
git rev-list --left-right --cherry-pick F...E -- bar >expect &&
- git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" --no-refs --refs="*tags/G" \
+ git name-rev --annotate-stdin --name-only --refs="*tags/F" --refs="*tags/E" --no-refs --refs="*tags/G" \
<expect >actual &&
test_cmp expect actual
'
@@ -149,7 +149,7 @@ EOF
test_expect_success '--cherry-mark' '
git rev-list --cherry-mark F...E -- bar > actual &&
- git name-rev --stdin --name-only --refs="*tags/*" \
+ git name-rev --annotate-stdin --name-only --refs="*tags/*" \
< actual > actual.named &&
test_cmp expect actual.named
'
@@ -163,7 +163,7 @@ EOF
test_expect_success '--cherry-mark --left-right' '
git rev-list --cherry-mark --left-right F...E -- bar > actual &&
- git name-rev --stdin --name-only --refs="*tags/*" \
+ git name-rev --annotate-stdin --name-only --refs="*tags/*" \
< actual > actual.named &&
test_cmp expect actual.named
'
@@ -174,14 +174,14 @@ EOF
test_expect_success '--cherry-pick --right-only' '
git rev-list --cherry-pick --right-only F...E -- bar > actual &&
- git name-rev --stdin --name-only --refs="*tags/*" \
+ git name-rev --annotate-stdin --name-only --refs="*tags/*" \
< actual > actual.named &&
test_cmp expect actual.named
'
test_expect_success '--cherry-pick --left-only' '
git rev-list --cherry-pick --left-only E...F -- bar > actual &&
- git name-rev --stdin --name-only --refs="*tags/*" \
+ git name-rev --annotate-stdin --name-only --refs="*tags/*" \
< actual > actual.named &&
test_cmp expect actual.named
'
@@ -193,7 +193,7 @@ EOF
test_expect_success '--cherry' '
git rev-list --cherry F...E -- bar > actual &&
- git name-rev --stdin --name-only --refs="*tags/*" \
+ git name-rev --annotate-stdin --name-only --refs="*tags/*" \
< actual > actual.named &&
test_cmp expect actual.named
'
diff --git a/t/t6012-rev-list-simplify.sh b/t/t6012-rev-list-simplify.sh
index 4f7fa8b..de1e87f 100755
--- a/t/t6012-rev-list-simplify.sh
+++ b/t/t6012-rev-list-simplify.sh
@@ -12,17 +12,18 @@ note () {
}
unnote () {
- git name-rev --tags --stdin | sed -e "s|$OID_REGEX (tags/\([^)]*\)) |\1 |g"
+ test_when_finished "rm -f tmp" &&
+ git name-rev --tags --annotate-stdin >tmp &&
+ sed -e "s|$OID_REGEX (tags/\([^)]*\)) |\1 |g" <tmp
}
#
-# Create a test repo with interesting commit graph:
+# Create a test repo with an interesting commit graph:
#
-# A--B----------G--H--I--K--L
-# \ \ / /
-# \ \ / /
-# C------E---F J
-# \_/
+# A-----B-----G--H--I--K--L
+# \ \ / /
+# \ \ / /
+# C--D--E--F J
#
# The commits are laid out from left-to-right starting with
# the root commit A and terminating at the tip commit L.
@@ -112,8 +113,8 @@ check_outcome () {
shift &&
param="$*" &&
test_expect_$outcome "log $param" '
- git log --pretty="$FMT" --parents $param |
- unnote >actual &&
+ git log --pretty="$FMT" --parents $param >out &&
+ unnote >actual <out &&
sed -e "s/^.* \([^ ]*\) .*/\1/" >check <actual &&
test_cmp expect check
'
@@ -142,11 +143,18 @@ check_result 'I B A' --author-date-order -- file
check_result 'H' --first-parent -- another-file
check_result 'H' --first-parent --topo-order -- another-file
+check_result 'L K I H G B A' --first-parent L
+check_result 'F E D C' --exclude-first-parent-only F ^L
+check_result '' F ^L
+check_result 'L K I H G J' L ^F
+check_result 'L K I H G B J' --exclude-first-parent-only L ^F
+check_result 'L K I H G B' --exclude-first-parent-only --first-parent L ^F
+
check_result 'E C B A' --full-history E -- lost
test_expect_success 'full history simplification without parent' '
printf "%s\n" E C B A >expect &&
- git log --pretty="$FMT" --full-history E -- lost |
- unnote >actual &&
+ git log --pretty="$FMT" --full-history E -- lost >out &&
+ unnote >actual <out &&
sed -e "s/^.* \([^ ]*\) .*/\1/" >check <actual &&
test_cmp expect check
'
diff --git a/t/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh
index b13e8a5..8332051 100755
--- a/t/t6020-bundle-misc.sh
+++ b/t/t6020-bundle-misc.sh
@@ -122,6 +122,8 @@ format_and_save_expect () {
sed -e 's/Z$//' >expect
}
+HASH_MESSAGE="The bundle uses this hash algorithm: $GIT_DEFAULT_HASH"
+
# (C) (D, pull/1/head, topic/1)
# o --- o
# / \ (L)
@@ -194,11 +196,12 @@ test_expect_success 'create bundle from special rev: main^!' '
git bundle verify special-rev.bdl |
make_user_friendly_and_stable_output >actual &&
- format_and_save_expect <<-\EOF &&
+ format_and_save_expect <<-EOF &&
The bundle contains this ref:
<COMMIT-P> refs/heads/main
The bundle requires this ref:
<COMMIT-O> Z
+ $HASH_MESSAGE
EOF
test_cmp expect actual &&
@@ -215,12 +218,13 @@ test_expect_success 'create bundle with --max-count option' '
git bundle verify max-count.bdl |
make_user_friendly_and_stable_output >actual &&
- format_and_save_expect <<-\EOF &&
+ format_and_save_expect <<-EOF &&
The bundle contains these 2 refs:
<COMMIT-P> refs/heads/main
<TAG-1> refs/tags/v1
The bundle requires this ref:
<COMMIT-O> Z
+ $HASH_MESSAGE
EOF
test_cmp expect actual &&
@@ -240,7 +244,7 @@ test_expect_success 'create bundle with --since option' '
git bundle verify since.bdl |
make_user_friendly_and_stable_output >actual &&
- format_and_save_expect <<-\EOF &&
+ format_and_save_expect <<-EOF &&
The bundle contains these 5 refs:
<COMMIT-P> refs/heads/main
<COMMIT-N> refs/heads/release
@@ -250,6 +254,7 @@ test_expect_success 'create bundle with --since option' '
The bundle requires these 2 refs:
<COMMIT-M> Z
<COMMIT-K> Z
+ $HASH_MESSAGE
EOF
test_cmp expect actual &&
@@ -267,11 +272,12 @@ test_expect_success 'create bundle 1 - no prerequisites' '
EOF
git bundle create stdin-1.bdl --stdin <input &&
- cat >expect <<-\EOF &&
+ format_and_save_expect <<-EOF &&
The bundle contains these 2 refs:
<COMMIT-D> refs/heads/topic/1
<COMMIT-H> refs/heads/topic/2
The bundle records a complete history.
+ $HASH_MESSAGE
EOF
# verify bundle, which has no prerequisites
@@ -308,13 +314,14 @@ test_expect_success 'create bundle 2 - has prerequisites' '
--stdin \
release <input &&
- format_and_save_expect <<-\EOF &&
+ format_and_save_expect <<-EOF &&
The bundle contains this ref:
<COMMIT-N> refs/heads/release
The bundle requires these 3 refs:
<COMMIT-D> Z
<COMMIT-E> Z
<COMMIT-G> Z
+ $HASH_MESSAGE
EOF
git bundle verify 2.bdl |
@@ -367,13 +374,14 @@ test_expect_success 'create bundle 3 - two refs, same object' '
--stdin \
main HEAD <input &&
- format_and_save_expect <<-\EOF &&
+ format_and_save_expect <<-EOF &&
The bundle contains these 2 refs:
<COMMIT-P> refs/heads/main
<COMMIT-P> HEAD
The bundle requires these 2 refs:
<COMMIT-M> Z
<COMMIT-K> Z
+ $HASH_MESSAGE
EOF
git bundle verify 3.bdl |
@@ -409,12 +417,13 @@ test_expect_success 'create bundle 4 - with tags' '
--stdin \
--all <input &&
- cat >expect <<-\EOF &&
+ cat >expect <<-EOF &&
The bundle contains these 3 refs:
<TAG-1> refs/tags/v1
<TAG-2> refs/tags/v2
<TAG-3> refs/tags/v3
The bundle records a complete history.
+ $HASH_MESSAGE
EOF
git bundle verify 4.bdl |
@@ -475,4 +484,79 @@ test_expect_success 'clone from bundle' '
test_cmp expect actual
'
+test_expect_success 'unfiltered bundle with --objects' '
+ git bundle create all-objects.bdl \
+ --all --objects &&
+ git bundle create all.bdl \
+ --all &&
+
+ # Compare the headers of these files.
+ sed -n -e "/^$/q" -e "p" all.bdl >expect &&
+ sed -n -e "/^$/q" -e "p" all-objects.bdl >actual &&
+ test_cmp expect actual
+'
+
+for filter in "blob:none" "tree:0" "tree:1" "blob:limit=100"
+do
+ test_expect_success "filtered bundle: $filter" '
+ test_when_finished rm -rf .git/objects/pack cloned unbundled &&
+ git bundle create partial.bdl \
+ --all \
+ --filter=$filter &&
+
+ git bundle verify partial.bdl >unfiltered &&
+ make_user_friendly_and_stable_output <unfiltered >actual &&
+
+ cat >expect <<-EOF &&
+ The bundle contains these 10 refs:
+ <COMMIT-P> refs/heads/main
+ <COMMIT-N> refs/heads/release
+ <COMMIT-D> refs/heads/topic/1
+ <COMMIT-H> refs/heads/topic/2
+ <COMMIT-D> refs/pull/1/head
+ <COMMIT-G> refs/pull/2/head
+ <TAG-1> refs/tags/v1
+ <TAG-2> refs/tags/v2
+ <TAG-3> refs/tags/v3
+ <COMMIT-P> HEAD
+ The bundle records a complete history.
+ $HASH_MESSAGE
+ The bundle uses this filter: $filter
+ EOF
+ test_cmp expect actual &&
+
+ test_config uploadpack.allowfilter 1 &&
+ test_config uploadpack.allowanysha1inwant 1 &&
+ git clone --no-local --filter=$filter --bare "file://$(pwd)" cloned &&
+
+ git init unbundled &&
+ git -C unbundled bundle unbundle ../partial.bdl >ref-list.txt &&
+ ls unbundled/.git/objects/pack/pack-*.promisor >promisor &&
+ test_line_count = 1 promisor &&
+
+ # Count the same number of reachable objects.
+ reflist=$(git for-each-ref --format="%(objectname)") &&
+ git rev-list --objects --filter=$filter --missing=allow-any \
+ $reflist >expect &&
+ for repo in cloned unbundled
+ do
+ git -C $repo rev-list --objects --missing=allow-any \
+ $reflist >actual &&
+ test_cmp expect actual || return 1
+ done
+ '
+done
+
+# NEEDSWORK: 'git clone --bare' should be able to clone from a filtered
+# bundle, but that requires a change to promisor/filter config options.
+# For now, we fail gracefully with a helpful error. This behavior can be
+# changed in the future to succeed as much as possible.
+test_expect_success 'cloning from filtered bundle has useful error' '
+ git bundle create partial.bdl \
+ --all \
+ --filter=blob:none &&
+ test_must_fail git clone --bare partial.bdl partial 2>err &&
+ grep "cannot clone from filtered bundle" err
+'
+
test_done
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 1be85d0..5382e5d 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -278,6 +278,51 @@ test_expect_success '"git bisect run" with more complex "git bisect start"' '
git bisect reset
'
+test_expect_success 'bisect run accepts exit code 126 as bad' '
+ test_when_finished "git bisect reset" &&
+ write_script test_script.sh <<-\EOF &&
+ ! grep Another hello || exit 126 >/dev/null
+ EOF
+ git bisect start &&
+ git bisect good $HASH1 &&
+ git bisect bad $HASH4 &&
+ git bisect run ./test_script.sh >my_bisect_log.txt &&
+ grep "$HASH3 is the first bad commit" my_bisect_log.txt
+'
+
+test_expect_success POSIXPERM 'bisect run fails with non-executable test script' '
+ test_when_finished "git bisect reset" &&
+ >not-executable.sh &&
+ chmod -x not-executable.sh &&
+ git bisect start &&
+ git bisect good $HASH1 &&
+ git bisect bad $HASH4 &&
+ test_must_fail git bisect run ./not-executable.sh >my_bisect_log.txt &&
+ ! grep "is the first bad commit" my_bisect_log.txt
+'
+
+test_expect_success 'bisect run accepts exit code 127 as bad' '
+ test_when_finished "git bisect reset" &&
+ write_script test_script.sh <<-\EOF &&
+ ! grep Another hello || exit 127 >/dev/null
+ EOF
+ git bisect start &&
+ git bisect good $HASH1 &&
+ git bisect bad $HASH4 &&
+ git bisect run ./test_script.sh >my_bisect_log.txt &&
+ grep "$HASH3 is the first bad commit" my_bisect_log.txt
+'
+
+test_expect_success 'bisect run fails with missing test script' '
+ test_when_finished "git bisect reset" &&
+ rm -f does-not-exist.sh &&
+ git bisect start &&
+ git bisect good $HASH1 &&
+ git bisect bad $HASH4 &&
+ test_must_fail git bisect run ./does-not-exist.sh >my_bisect_log.txt &&
+ ! grep "is the first bad commit" my_bisect_log.txt
+'
+
# $HASH1 is good, $HASH5 is bad, we skip $HASH3
# but $HASH4 is good,
# so we should find $HASH5 as the first bad commit
diff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh
index 6f0902b..cf0195e 100755
--- a/t/t6102-rev-list-unexpected-objects.sh
+++ b/t/t6102-rev-list-unexpected-objects.sh
@@ -17,8 +17,13 @@ test_expect_success 'setup unexpected non-blob entry' '
broken_tree="$(git hash-object -w --literally -t tree broken-tree)"
'
-test_expect_failure 'traverse unexpected non-blob entry (lone)' '
- test_must_fail git rev-list --objects $broken_tree
+test_expect_success !SANITIZE_LEAK 'TODO (should fail!): traverse unexpected non-blob entry (lone)' '
+ sed "s/Z$//" >expect <<-EOF &&
+ $broken_tree Z
+ $tree foo
+ EOF
+ git rev-list --objects $broken_tree >actual &&
+ test_cmp expect actual
'
test_expect_success 'traverse unexpected non-blob entry (seen)' '
@@ -116,8 +121,8 @@ test_expect_success 'setup unexpected non-blob tag' '
tag=$(git hash-object -w --literally -t tag broken-tag)
'
-test_expect_failure 'traverse unexpected non-blob tag (lone)' '
- test_must_fail git rev-list --objects $tag
+test_expect_success !SANITIZE_LEAK 'TODO (should fail!): traverse unexpected non-blob tag (lone)' '
+ git rev-list --objects $tag
'
test_expect_success 'traverse unexpected non-blob tag (seen)' '
diff --git a/t/t6111-rev-list-treesame.sh b/t/t6111-rev-list-treesame.sh
index e07b607..90ff141 100755
--- a/t/t6111-rev-list-treesame.sh
+++ b/t/t6111-rev-list-treesame.sh
@@ -23,7 +23,8 @@ note () {
}
unnote () {
- git name-rev --tags --stdin | sed -e "s|$OID_REGEX (tags/\([^)]*\))\([ ]\)|\1\2|g"
+ git name-rev --tags --annotate-stdin | \
+ sed -e "s|$OID_REGEX (tags/\([^)]*\))\([ ]\)|\1\2|g"
}
test_expect_success setup '
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index d8af2bb..9a35e78 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -270,7 +270,7 @@ test_expect_success 'name-rev --all' '
test_cmp expect actual
'
-test_expect_success 'name-rev --stdin' '
+test_expect_success 'name-rev --annotate-stdin' '
>expect.unsorted &&
for rev in $(git rev-list --all)
do
@@ -278,11 +278,16 @@ test_expect_success 'name-rev --stdin' '
echo "$rev ($name)" >>expect.unsorted || return 1
done &&
sort <expect.unsorted >expect &&
- git rev-list --all | git name-rev --stdin >actual.unsorted &&
+ git rev-list --all | git name-rev --annotate-stdin >actual.unsorted &&
sort <actual.unsorted >actual &&
test_cmp expect actual
'
+test_expect_success 'name-rev --stdin deprecated' "
+ git rev-list --all | git name-rev --stdin 2>actual &&
+ grep -E 'warning: --stdin is deprecated' actual
+"
+
test_expect_success 'describe --contains with the exact tags' '
echo "A^0" >expect &&
tag_object=$(git rev-parse refs/tags/A) &&
@@ -483,6 +488,124 @@ test_expect_success 'name-rev covers all conditions while looking at parents' '
)
'
+# A-B-C-D-E-main
+#
+# Where C has a non-monotonically increasing commit timestamp w.r.t. other
+# commits
+test_expect_success 'non-monotonic commit dates setup' '
+ UNIX_EPOCH_ZERO="@0 +0000" &&
+ git init non-monotonic &&
+ test_commit -C non-monotonic A &&
+ test_commit -C non-monotonic --no-tag B &&
+ test_commit -C non-monotonic --no-tag --date "$UNIX_EPOCH_ZERO" C &&
+ test_commit -C non-monotonic D &&
+ test_commit -C non-monotonic E
+'
+
+test_expect_success 'name-rev with commitGraph handles non-monotonic timestamps' '
+ test_config -C non-monotonic core.commitGraph true &&
+ (
+ cd non-monotonic &&
+
+ git commit-graph write --reachable &&
+
+ echo "main~3 tags/D~2" >expect &&
+ git name-rev --tags main~3 >actual &&
+
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'name-rev --all works with non-monotonic timestamps' '
+ test_config -C non-monotonic core.commitGraph false &&
+ (
+ cd non-monotonic &&
+
+ rm -rf .git/info/commit-graph* &&
+
+ cat >tags <<-\EOF &&
+ tags/E
+ tags/D
+ tags/D~1
+ tags/D~2
+ tags/A
+ EOF
+
+ git log --pretty=%H >revs &&
+
+ paste -d" " revs tags | sort >expect &&
+
+ git name-rev --tags --all | sort >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'name-rev --annotate-stdin works with non-monotonic timestamps' '
+ test_config -C non-monotonic core.commitGraph false &&
+ (
+ cd non-monotonic &&
+
+ rm -rf .git/info/commit-graph* &&
+
+ cat >expect <<-\EOF &&
+ E
+ D
+ D~1
+ D~2
+ A
+ EOF
+
+ git log --pretty=%H >revs &&
+ git name-rev --tags --annotate-stdin --name-only <revs >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'name-rev --all works with commitGraph' '
+ test_config -C non-monotonic core.commitGraph true &&
+ (
+ cd non-monotonic &&
+
+ git commit-graph write --reachable &&
+
+ cat >tags <<-\EOF &&
+ tags/E
+ tags/D
+ tags/D~1
+ tags/D~2
+ tags/A
+ EOF
+
+ git log --pretty=%H >revs &&
+
+ paste -d" " revs tags | sort >expect &&
+
+ git name-rev --tags --all | sort >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'name-rev --annotate-stdin works with commitGraph' '
+ test_config -C non-monotonic core.commitGraph true &&
+ (
+ cd non-monotonic &&
+
+ git commit-graph write --reachable &&
+
+ cat >expect <<-\EOF &&
+ E
+ D
+ D~1
+ D~2
+ A
+ EOF
+
+ git log --pretty=%H >revs &&
+ git name-rev --tags --annotate-stdin --name-only <revs >actual &&
+ test_cmp expect actual
+ )
+'
+
# B
# o
# \
diff --git a/t/t6404-recursive-merge.sh b/t/t6404-recursive-merge.sh
index eaf48e9..b8735c6 100755
--- a/t/t6404-recursive-merge.sh
+++ b/t/t6404-recursive-merge.sh
@@ -108,8 +108,13 @@ test_expect_success 'refuse to merge binary files' '
printf "\0\0" >binary-file &&
git add binary-file &&
git commit -m binary2 &&
- test_must_fail git merge F >merge.out 2>merge.err &&
- grep "Cannot merge binary files: binary-file (HEAD vs. F)" merge.err
+ if test "$GIT_TEST_MERGE_ALGORITHM" = ort
+ then
+ test_must_fail git merge F >merge_output
+ else
+ test_must_fail git merge F 2>merge_output
+ fi &&
+ grep "Cannot merge binary files: binary-file (HEAD vs. F)" merge_output
'
test_expect_success 'mark rename/delete as unmerged' '
diff --git a/t/t6406-merge-attr.sh b/t/t6406-merge-attr.sh
index 57e6af5..99abefd 100755
--- a/t/t6406-merge-attr.sh
+++ b/t/t6406-merge-attr.sh
@@ -221,8 +221,13 @@ test_expect_success 'binary files with union attribute' '
printf "two\0" >bin.txt &&
git commit -am two &&
- test_must_fail git merge bin-main 2>stderr &&
- grep -i "warning.*cannot merge.*HEAD vs. bin-main" stderr
+ if test "$GIT_TEST_MERGE_ALGORITHM" = ort
+ then
+ test_must_fail git merge bin-main >output
+ else
+ test_must_fail git merge bin-main 2>output
+ fi &&
+ grep -i "warning.*cannot merge.*HEAD vs. bin-main" output
'
test_done
diff --git a/t/t6407-merge-binary.sh b/t/t6407-merge-binary.sh
index 8e6241f..0753fc9 100755
--- a/t/t6407-merge-binary.sh
+++ b/t/t6407-merge-binary.sh
@@ -43,14 +43,9 @@ test_expect_success resolve '
rm -f a* m* &&
git reset --hard anchor &&
- if git merge -s resolve main
- then
- echo Oops, should not have succeeded
- false
- else
- git ls-files -s >current &&
- test_cmp expect current
- fi
+ test_must_fail git merge -s resolve main &&
+ git ls-files -s >current &&
+ test_cmp expect current
'
test_expect_success recursive '
@@ -58,14 +53,9 @@ test_expect_success recursive '
rm -f a* m* &&
git reset --hard anchor &&
- if git merge -s recursive main
- then
- echo Oops, should not have succeeded
- false
- else
- git ls-files -s >current &&
- test_cmp expect current
- fi
+ test_must_fail git merge -s recursive main &&
+ git ls-files -s >current &&
+ test_cmp expect current
'
test_done
diff --git a/t/t6423-merge-rename-directories.sh b/t/t6423-merge-rename-directories.sh
index 5b81a13..479db32 100755
--- a/t/t6423-merge-rename-directories.sh
+++ b/t/t6423-merge-rename-directories.sh
@@ -4421,14 +4421,14 @@ test_setup_12c1 () {
git checkout A &&
git mv node2/ node1/ &&
- for i in `git ls-files`; do echo side A >>$i; done &&
+ for i in $(git ls-files); do echo side A >>$i; done &&
git add -u &&
test_tick &&
git commit -m "A" &&
git checkout B &&
git mv node1/ node2/ &&
- for i in `git ls-files`; do echo side B >>$i; done &&
+ for i in $(git ls-files); do echo side B >>$i; done &&
git add -u &&
test_tick &&
git commit -m "B"
@@ -4511,7 +4511,7 @@ test_setup_12c2 () {
git checkout A &&
git mv node2/ node1/ &&
- for i in `git ls-files`; do echo side A >>$i; done &&
+ for i in $(git ls-files); do echo side A >>$i; done &&
git add -u &&
echo leaf5 >node1/leaf5 &&
git add node1/leaf5 &&
@@ -4520,7 +4520,7 @@ test_setup_12c2 () {
git checkout B &&
git mv node1/ node2/ &&
- for i in `git ls-files`; do echo side B >>$i; done &&
+ for i in $(git ls-files); do echo side B >>$i; done &&
git add -u &&
echo leaf6 >node2/leaf6 &&
git add node2/leaf6 &&
@@ -4759,7 +4759,7 @@ test_setup_12f () {
echo g >dir/subdir/tweaked/g &&
echo h >dir/subdir/tweaked/h &&
test_seq 20 30 >dir/subdir/tweaked/Makefile &&
- for i in `test_seq 1 88`; do
+ for i in $(test_seq 1 88); do
echo content $i >dir/unchanged/file_$i
done &&
git add . &&
diff --git a/t/t6428-merge-conflicts-sparse.sh b/t/t6428-merge-conflicts-sparse.sh
index 7e8bf49..142c9aa 100755
--- a/t/t6428-merge-conflicts-sparse.sh
+++ b/t/t6428-merge-conflicts-sparse.sh
@@ -112,7 +112,7 @@ test_expect_success 'conflicting entries written to worktree even if sparse' '
)
'
-test_expect_merge_algorithm failure success 'present-despite-SKIP_WORKTREE handled reasonably' '
+test_expect_success 'present-despite-SKIP_WORKTREE handled reasonably' '
test_setup_numerals in_the_way &&
(
cd numerals_in_the_way &&
@@ -132,26 +132,13 @@ test_expect_merge_algorithm failure success 'present-despite-SKIP_WORKTREE handl
test_must_fail git merge -s recursive B^0 &&
- git ls-files -t >index_files &&
- test_cmp expected-index index_files &&
+ test_path_is_missing .git/MERGE_HEAD &&
- test_path_is_file README &&
test_path_is_file numerals &&
- test_cmp expected-merge numerals &&
-
- # There should still be a file with "foobar" in it
- grep foobar * &&
-
- # 5 other files:
- # * expected-merge
- # * expected-index
- # * index_files
- # * others
- # * whatever name was given to the numerals file that had
- # "foobar" in it
- git ls-files -o >others &&
- test_line_count = 5 others
+ # numerals should still have "foobar" in it
+ echo foobar >expect &&
+ test_cmp expect numerals
)
'
diff --git a/t/t6429-merge-sequence-rename-caching.sh b/t/t6429-merge-sequence-rename-caching.sh
index 035edc4..f2bc8a7 100755
--- a/t/t6429-merge-sequence-rename-caching.sh
+++ b/t/t6429-merge-sequence-rename-caching.sh
@@ -697,4 +697,71 @@ test_expect_success 'caching renames only on upstream side, part 2' '
)
'
+#
+# The following testcase just creates two simple renames (slightly modified
+# on both sides but without conflicting changes), and a directory full of
+# files that are otherwise uninteresting. The setup is as follows:
+#
+# base: unrelated/<BUNCH OF FILES>
+# numbers
+# values
+# upstream: modify: numbers
+# modify: values
+# topic: add: unrelated/foo
+# modify: numbers
+# modify: values
+# rename: numbers -> sequence
+# rename: values -> progression
+#
+# This is a trivial rename case, but we're curious what happens with a very
+# low renameLimit interacting with the restart optimization trying to notice
+# that unrelated/ looks like a trivial merge candidate.
+#
+test_expect_success 'avoid assuming we detected renames' '
+ git init redo-weirdness &&
+ (
+ cd redo-weirdness &&
+
+ mkdir unrelated &&
+ for i in $(test_seq 1 10)
+ do
+ >unrelated/$i
+ done &&
+ test_seq 2 10 >numbers &&
+ test_seq 12 20 >values &&
+ git add numbers values unrelated/ &&
+ git commit -m orig &&
+
+ git branch upstream &&
+ git branch topic &&
+
+ git switch upstream &&
+ test_seq 1 10 >numbers &&
+ test_seq 11 20 >values &&
+ git add numbers &&
+ git commit -m "Some tweaks" &&
+
+ git switch topic &&
+
+ >unrelated/foo &&
+ test_seq 2 12 >numbers &&
+ test_seq 12 22 >values &&
+ git add numbers values unrelated/ &&
+ git mv numbers sequence &&
+ git mv values progression &&
+ git commit -m A &&
+
+ #
+ # Actual testing
+ #
+
+ git switch --detach topic^0 &&
+
+ test_must_fail git -c merge.renameLimit=1 rebase upstream &&
+
+ git ls-files -u >actual &&
+ ! test_file_is_empty actual
+ )
+'
+
test_done
diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh
index c202126..cd6c533 100755
--- a/t/t6500-gc.sh
+++ b/t/t6500-gc.sh
@@ -101,12 +101,12 @@ test_expect_success 'pre-auto-gc hook can stop auto gc' '
EOF
git init pre-auto-gc-hook &&
+ test_hook -C pre-auto-gc-hook pre-auto-gc <<-\EOF &&
+ echo >&2 no gc for you &&
+ exit 1
+ EOF
(
cd pre-auto-gc-hook &&
- write_script ".git/hooks/pre-auto-gc" <<-\EOF &&
- echo >&2 no gc for you &&
- exit 1
- EOF
git config gc.auto 3 &&
git config gc.autoDetach false &&
@@ -128,14 +128,12 @@ test_expect_success 'pre-auto-gc hook can stop auto gc' '
See "git help gc" for manual housekeeping.
EOF
- (
- cd pre-auto-gc-hook &&
- write_script ".git/hooks/pre-auto-gc" <<-\EOF &&
- echo >&2 will gc for you &&
- exit 0
- EOF
- git gc --auto >../out.actual 2>../err.actual
- ) &&
+ test_hook -C pre-auto-gc-hook --clobber pre-auto-gc <<-\EOF &&
+ echo >&2 will gc for you &&
+ exit 0
+ EOF
+
+ git -C pre-auto-gc-hook gc --auto >out.actual 2>err.actual &&
test_must_be_empty out.actual &&
test_cmp err.expect err.actual
diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh
index 963356b..a402908 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -4,6 +4,25 @@ test_description='git mv in subdirs'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff-data.sh
+test_expect_success 'mv -f refreshes updated index entry' '
+ echo test >bar &&
+ git add bar &&
+ git commit -m test &&
+
+ echo foo >foo &&
+ git add foo &&
+
+ # Wait one second to ensure ctime of rename will differ from original
+ # file creation ctime.
+ sleep 1 &&
+ git mv -f foo bar &&
+ git reset --merge HEAD &&
+
+ # Verify the index has been reset
+ git diff-files >out &&
+ test_must_be_empty out
+'
+
test_expect_success 'prepare reference tree' '
mkdir path0 path1 &&
COPYING_test_data >path0/COPYING &&
diff --git a/t/t7012-skip-worktree-writing.sh b/t/t7012-skip-worktree-writing.sh
index a1080b9..cb9f1a6 100755
--- a/t/t7012-skip-worktree-writing.sh
+++ b/t/t7012-skip-worktree-writing.sh
@@ -171,50 +171,20 @@ test_expect_success 'stash restore in sparse checkout' '
# Put a file in the working directory in the way
echo in the way >modified &&
- git stash apply &&
+ test_must_fail git stash apply 2>error&&
- # Ensure stash vivifies modifies paths...
- cat >expect <<-EOF &&
- H addme
- H modified
- H removeme
- H subdir/A
- S untouched
- EOF
- git ls-files -t >actual &&
- test_cmp expect actual &&
+ grep "changes.*would be overwritten by merge" error &&
- # ...and that the paths show up in status as changed...
- cat >expect <<-EOF &&
- A addme
- M modified
- D removeme
- M subdir/A
- ?? actual
- ?? expect
- ?? modified.stash.XXXXXX
- EOF
- git status --porcelain | \
- sed -e s/stash......./stash.XXXXXX/ >actual &&
- test_cmp expect actual &&
+ echo in the way >expect &&
+ test_cmp expect modified &&
+ git diff --quiet HEAD ":!modified" &&
# ...and that working directory reflects the files correctly
- test_path_is_file addme &&
+ test_path_is_missing addme &&
test_path_is_file modified &&
test_path_is_missing removeme &&
test_path_is_file subdir/A &&
- test_path_is_missing untouched &&
-
- # ...including that we have the expected "modified" file...
- cat >expect <<-EOF &&
- modified
- tweaked
- EOF
- test_cmp expect modified &&
-
- # ...and that the other "modified" file is still present...
- echo in the way >expect &&
- test_cmp expect modified.stash.*
+ test_path_is_missing untouched
)
'
diff --git a/t/t7063-status-untracked-cache.sh b/t/t7063-status-untracked-cache.sh
index a0c123b..ca90ee8 100755
--- a/t/t7063-status-untracked-cache.sh
+++ b/t/t7063-status-untracked-cache.sh
@@ -90,6 +90,9 @@ test_expect_success 'setup' '
cd worktree &&
mkdir done dtwo dthree &&
touch one two three done/one dtwo/two dthree/three &&
+ test-tool chmtime =-300 one two three done/one dtwo/two dthree/three &&
+ test-tool chmtime =-300 done dtwo dthree &&
+ test-tool chmtime =-300 . &&
git add one two done/one &&
: >.git/info/exclude &&
git update-index --untracked-cache &&
@@ -142,7 +145,6 @@ two
EOF
test_expect_success 'status first time (empty cache)' '
- avoid_racy &&
: >../trace.output &&
GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../actual &&
@@ -166,7 +168,6 @@ test_expect_success 'untracked cache after first status' '
'
test_expect_success 'status second time (fully populated cache)' '
- avoid_racy &&
: >../trace.output &&
GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../actual &&
@@ -190,8 +191,8 @@ test_expect_success 'untracked cache after second status' '
'
test_expect_success 'modify in root directory, one dir invalidation' '
- avoid_racy &&
: >four &&
+ test-tool chmtime =-240 four &&
: >../trace.output &&
GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../actual &&
@@ -241,7 +242,6 @@ EOF
'
test_expect_success 'new .gitignore invalidates recursively' '
- avoid_racy &&
echo four >.gitignore &&
: >../trace.output &&
GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
@@ -292,7 +292,6 @@ EOF
'
test_expect_success 'new info/exclude invalidates everything' '
- avoid_racy &&
echo three >>.git/info/exclude &&
: >../trace.output &&
GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
@@ -520,14 +519,14 @@ test_expect_success 'create/modify files, some of which are gitignored' '
echo three >done/three && # three is gitignored
echo four >done/four && # four is gitignored at a higher level
echo five >done/five && # five is not gitignored
- echo test >base && #we need to ensure that the root dir is touched
- rm base &&
+ test-tool chmtime =-180 done/two done/three done/four done/five done &&
+ # we need to ensure that the root dir is touched (in the past);
+ test-tool chmtime =-180 . &&
sync_mtime
'
test_expect_success 'test sparse status with untracked cache' '
: >../trace.output &&
- avoid_racy &&
GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../status.actual &&
iuc status --porcelain >../status.iuc &&
@@ -570,7 +569,6 @@ EOF
'
test_expect_success 'test sparse status again with untracked cache' '
- avoid_racy &&
: >../trace.output &&
GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../status.actual &&
@@ -597,11 +595,11 @@ EOF
test_expect_success 'set up for test of subdir and sparse checkouts' '
mkdir done/sub &&
mkdir done/sub/sub &&
- echo "sub" > done/sub/sub/file
+ echo "sub" > done/sub/sub/file &&
+ test-tool chmtime =-120 done/sub/sub/file done/sub/sub done/sub done
'
test_expect_success 'test sparse status with untracked cache and subdir' '
- avoid_racy &&
: >../trace.output &&
GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../status.actual &&
@@ -651,7 +649,6 @@ EOF
'
test_expect_success 'test sparse status again with untracked cache and subdir' '
- avoid_racy &&
: >../trace.output &&
GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
git status --porcelain >../status.actual &&
diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh
index d054260..22477f3 100755
--- a/t/t7102-reset.sh
+++ b/t/t7102-reset.sh
@@ -462,14 +462,40 @@ test_expect_success 'resetting an unmodified path is a no-op' '
git diff-index --cached --exit-code HEAD
'
+test_reset_refreshes_index () {
+
+ # To test whether the index is refreshed in `git reset --mixed` with
+ # the given options, create a scenario where we clearly see different
+ # results depending on whether the refresh occurred or not.
+
+ # Step 0: start with a clean index
+ git reset --hard HEAD &&
+
+ # Step 1: remove file2, but only in the index (no change to worktree)
+ git rm --cached file2 &&
+
+ # Step 2: reset index & leave worktree unchanged from HEAD
+ git $1 reset $2 --mixed HEAD &&
+
+ # Step 3: verify whether the index is refreshed by checking whether
+ # file2 still has staged changes in the index differing from HEAD (if
+ # the refresh occurred, there should be no such changes)
+ git diff-files >output.log &&
+ test_must_be_empty output.log
+}
+
test_expect_success '--mixed refreshes the index' '
- cat >expect <<-\EOF &&
- Unstaged changes after reset:
- M file2
- EOF
- echo 123 >>file2 &&
- git reset --mixed HEAD >output &&
- test_cmp expect output
+ # Verify default behavior (without --[no-]refresh or reset.refresh)
+ test_reset_refreshes_index &&
+
+ # With --quiet
+ test_reset_refreshes_index "" --quiet
+'
+
+test_expect_success '--mixed --[no-]refresh sets refresh behavior' '
+ # Verify that --[no-]refresh controls index refresh
+ test_reset_refreshes_index "" --refresh &&
+ ! test_reset_refreshes_index "" --no-refresh
'
test_expect_success '--mixed preserves skip-worktree' '
diff --git a/t/t7103-reset-bare.sh b/t/t7103-reset-bare.sh
index 0de83e3..a60153f 100755
--- a/t/t7103-reset-bare.sh
+++ b/t/t7103-reset-bare.sh
@@ -63,9 +63,12 @@ test_expect_success '"mixed" reset is not allowed in bare' '
test_must_fail git reset --mixed HEAD^
'
-test_expect_success '"soft" reset is allowed in bare' '
+test_expect_success !SANITIZE_LEAK '"soft" reset is allowed in bare' '
git reset --soft HEAD^ &&
- test "$(git show --pretty=format:%s | head -n 1)" = "one"
+ git show --pretty=format:%s >out &&
+ echo one >expect &&
+ head -n 1 out >actual &&
+ test_cmp expect actual
'
test_done
diff --git a/t/t7113-post-index-change-hook.sh b/t/t7113-post-index-change-hook.sh
index a21781d..58e55a7 100755
--- a/t/t7113-post-index-change-hook.sh
+++ b/t/t7113-post-index-change-hook.sh
@@ -17,8 +17,7 @@ test_expect_success 'setup' '
'
test_expect_success 'test status, add, commit, others trigger hook without flags set' '
- mkdir -p .git/hooks &&
- write_script .git/hooks/post-index-change <<-\EOF &&
+ test_hook post-index-change <<-\EOF &&
if test "$1" -eq 1; then
echo "Invalid combination of flags passed to hook; updated_workdir is set." >testfailure
exit 1
@@ -63,7 +62,7 @@ test_expect_success 'test status, add, commit, others trigger hook without flags
'
test_expect_success 'test checkout and reset trigger the hook' '
- write_script .git/hooks/post-index-change <<-\EOF &&
+ test_hook post-index-change <<-\EOF &&
if test "$1" -eq 1 && test "$2" -eq 1; then
echo "Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set." >testfailure
exit 1
@@ -106,7 +105,7 @@ test_expect_success 'test checkout and reset trigger the hook' '
'
test_expect_success 'test reset --mixed and update-index triggers the hook' '
- write_script .git/hooks/post-index-change <<-\EOF &&
+ test_hook post-index-change <<-\EOF &&
if test "$1" -eq 1 && test "$2" -eq 1; then
echo "Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set." >testfailure
exit 1
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 11cccbb..000e055 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -205,8 +205,18 @@ test_expect_success 'submodule update should fail due to local changes' '
(cd submodule &&
compare_head
) &&
- test_must_fail git submodule update submodule
- )
+ test_must_fail git submodule update submodule 2>../actual.raw
+ ) &&
+ sed "s/^> //" >expect <<-\EOF &&
+ > error: Your local changes to the following files would be overwritten by checkout:
+ > file
+ > Please commit your changes or stash them before you switch branches.
+ > Aborting
+ > fatal: Unable to checkout OID in submodule path '\''submodule'\''
+ EOF
+ sed -e "s/checkout $SQ[^$SQ]*$SQ/checkout OID/" <actual.raw >actual &&
+ test_cmp expect actual
+
'
test_expect_success 'submodule update should throw away changes with --force ' '
(cd super &&
@@ -1061,4 +1071,16 @@ test_expect_success 'submodule update --quiet passes quietness to fetch with a s
)
'
+test_expect_success 'submodule update --filter requires --init' '
+ test_expect_code 129 git -C super submodule update --filter blob:none
+'
+
+test_expect_success 'submodule update --filter sets partial clone settings' '
+ test_when_finished "rm -rf super-filter" &&
+ git clone cloned super-filter &&
+ git -C super-filter submodule update --init --filter blob:none &&
+ test_cmp_config -C super-filter/submodule true remote.origin.promisor &&
+ test_cmp_config -C super-filter/submodule blob:none remote.origin.partialclonefilter
+'
+
test_done
diff --git a/t/t7408-submodule-reference.sh b/t/t7408-submodule-reference.sh
index a3892f4..c3a4545 100755
--- a/t/t7408-submodule-reference.sh
+++ b/t/t7408-submodule-reference.sh
@@ -193,7 +193,19 @@ test_expect_success 'missing nested submodule alternate fails clone and submodul
cd supersuper-clone &&
check_that_two_of_three_alternates_are_used &&
# update of the submodule fails
- test_must_fail git submodule update --init --recursive
+ cat >expect <<-\EOF &&
+ fatal: submodule '\''sub'\'' cannot add alternate: path ... does not exist
+ Failed to clone '\''sub'\''. Retry scheduled
+ fatal: submodule '\''sub-dissociate'\'' cannot add alternate: path ... does not exist
+ Failed to clone '\''sub-dissociate'\''. Retry scheduled
+ fatal: submodule '\''sub'\'' cannot add alternate: path ... does not exist
+ Failed to clone '\''sub'\'' a second time, aborting
+ fatal: Failed to recurse into submodule path ...
+ EOF
+ test_must_fail git submodule update --init --recursive 2>err &&
+ grep -e fatal: -e ^Failed err >actual.raw &&
+ sed -e "s/path $SQ[^$SQ]*$SQ/path .../" <actual.raw >actual &&
+ test_cmp expect actual
)
'
diff --git a/t/t7500-commit-template-squash-signoff.sh b/t/t7500-commit-template-squash-signoff.sh
index 9196465..5fcaa0b 100755
--- a/t/t7500-commit-template-squash-signoff.sh
+++ b/t/t7500-commit-template-squash-signoff.sh
@@ -442,7 +442,7 @@ test_expect_success '--fixup=reword: give error with pathsec' '
'
test_expect_success '--fixup=reword: -F give error message' '
- echo "fatal: Only one of -c/-C/-F/--fixup can be used." >expect &&
+ echo "fatal: options '\''-F'\'' and '\''--fixup'\'' cannot be used together" >expect &&
test_must_fail git commit --fixup=reword:HEAD~ -F msg 2>actual &&
test_cmp expect actual
'
diff --git a/t/t7503-pre-commit-and-pre-merge-commit-hooks.sh b/t/t7503-pre-commit-and-pre-merge-commit-hooks.sh
index 606d8d0..ad1eb64 100755
--- a/t/t7503-pre-commit-and-pre-merge-commit-hooks.sh
+++ b/t/t7503-pre-commit-and-pre-merge-commit-hooks.sh
@@ -7,37 +7,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
-HOOKDIR="$(git rev-parse --git-dir)/hooks"
-PRECOMMIT="$HOOKDIR/pre-commit"
-PREMERGE="$HOOKDIR/pre-merge-commit"
-
-# Prepare sample scripts that write their $0 to actual_hooks
-test_expect_success 'sample script setup' '
- mkdir -p "$HOOKDIR" &&
- write_script "$HOOKDIR/success.sample" <<-\EOF &&
- echo $0 >>actual_hooks
- exit 0
- EOF
- write_script "$HOOKDIR/fail.sample" <<-\EOF &&
- echo $0 >>actual_hooks
- exit 1
- EOF
- write_script "$HOOKDIR/non-exec.sample" <<-\EOF &&
- echo $0 >>actual_hooks
- exit 1
- EOF
- chmod -x "$HOOKDIR/non-exec.sample" &&
- write_script "$HOOKDIR/require-prefix.sample" <<-\EOF &&
- echo $0 >>actual_hooks
- test $GIT_PREFIX = "success/"
- EOF
- write_script "$HOOKDIR/check-author.sample" <<-\EOF
- echo $0 >>actual_hooks
- test "$GIT_AUTHOR_NAME" = "New Author" &&
- test "$GIT_AUTHOR_EMAIL" = "newauthor@example.com"
- EOF
-'
-
test_expect_success 'root commit' '
echo "root" >file &&
git add file &&
@@ -96,10 +65,16 @@ test_expect_success '--no-verify with no hook (merge)' '
test_path_is_missing actual_hooks
'
+setup_success_hook () {
+ test_when_finished "rm -f actual_hooks expected_hooks" &&
+ echo "$1" >expected_hooks &&
+ test_hook "$1" <<-EOF
+ echo $1 >>actual_hooks
+ EOF
+}
+
test_expect_success 'with succeeding hook' '
- test_when_finished "rm -f \"$PRECOMMIT\" expected_hooks actual_hooks" &&
- cp "$HOOKDIR/success.sample" "$PRECOMMIT" &&
- echo "$PRECOMMIT" >expected_hooks &&
+ setup_success_hook "pre-commit" &&
echo "more" >>file &&
git add file &&
git commit -m "more" &&
@@ -107,9 +82,7 @@ test_expect_success 'with succeeding hook' '
'
test_expect_success 'with succeeding hook (merge)' '
- test_when_finished "rm -f \"$PREMERGE\" expected_hooks actual_hooks" &&
- cp "$HOOKDIR/success.sample" "$PREMERGE" &&
- echo "$PREMERGE" >expected_hooks &&
+ setup_success_hook "pre-merge-commit" &&
git checkout side &&
git merge -m "merge main" main &&
git checkout main &&
@@ -117,17 +90,14 @@ test_expect_success 'with succeeding hook (merge)' '
'
test_expect_success 'automatic merge fails; both hooks are available' '
- test_when_finished "rm -f \"$PREMERGE\" \"$PRECOMMIT\"" &&
- test_when_finished "rm -f expected_hooks actual_hooks" &&
- test_when_finished "git checkout main" &&
- cp "$HOOKDIR/success.sample" "$PREMERGE" &&
- cp "$HOOKDIR/success.sample" "$PRECOMMIT" &&
+ setup_success_hook "pre-commit" &&
+ setup_success_hook "pre-merge-commit" &&
git checkout conflicting-a &&
test_must_fail git merge -m "merge conflicting-b" conflicting-b &&
test_path_is_missing actual_hooks &&
- echo "$PRECOMMIT" >expected_hooks &&
+ echo "pre-commit" >expected_hooks &&
echo a+b >conflicting &&
git add conflicting &&
git commit -m "resolve conflict" &&
@@ -135,8 +105,7 @@ test_expect_success 'automatic merge fails; both hooks are available' '
'
test_expect_success '--no-verify with succeeding hook' '
- test_when_finished "rm -f \"$PRECOMMIT\" actual_hooks" &&
- cp "$HOOKDIR/success.sample" "$PRECOMMIT" &&
+ setup_success_hook "pre-commit" &&
echo "even more" >>file &&
git add file &&
git commit --no-verify -m "even more" &&
@@ -144,8 +113,7 @@ test_expect_success '--no-verify with succeeding hook' '
'
test_expect_success '--no-verify with succeeding hook (merge)' '
- test_when_finished "rm -f \"$PREMERGE\" actual_hooks" &&
- cp "$HOOKDIR/success.sample" "$PREMERGE" &&
+ setup_success_hook "pre-merge-commit" &&
git branch -f side side-orig &&
git checkout side &&
git merge --no-verify -m "merge main" main &&
@@ -153,10 +121,19 @@ test_expect_success '--no-verify with succeeding hook (merge)' '
test_path_is_missing actual_hooks
'
+setup_failing_hook () {
+ test_when_finished "rm -f actual_hooks" &&
+ test_hook "$1" <<-EOF
+ echo $1-failing-hook >>actual_hooks
+ exit 1
+ EOF
+}
+
test_expect_success 'with failing hook' '
- test_when_finished "rm -f \"$PRECOMMIT\" expected_hooks actual_hooks" &&
- cp "$HOOKDIR/fail.sample" "$PRECOMMIT" &&
- echo "$PRECOMMIT" >expected_hooks &&
+ setup_failing_hook "pre-commit" &&
+ test_when_finished "rm -f expected_hooks" &&
+ echo "pre-commit-failing-hook" >expected_hooks &&
+
echo "another" >>file &&
git add file &&
test_must_fail git commit -m "another" &&
@@ -164,8 +141,7 @@ test_expect_success 'with failing hook' '
'
test_expect_success '--no-verify with failing hook' '
- test_when_finished "rm -f \"$PRECOMMIT\" actual_hooks" &&
- cp "$HOOKDIR/fail.sample" "$PRECOMMIT" &&
+ setup_failing_hook "pre-commit" &&
echo "stuff" >>file &&
git add file &&
git commit --no-verify -m "stuff" &&
@@ -173,9 +149,8 @@ test_expect_success '--no-verify with failing hook' '
'
test_expect_success 'with failing hook (merge)' '
- test_when_finished "rm -f \"$PREMERGE\" expected_hooks actual_hooks" &&
- cp "$HOOKDIR/fail.sample" "$PREMERGE" &&
- echo "$PREMERGE" >expected_hooks &&
+ setup_failing_hook "pre-merge-commit" &&
+ echo "pre-merge-commit-failing-hook" >expected_hooks &&
git checkout side &&
test_must_fail git merge -m "merge main" main &&
git checkout main &&
@@ -183,8 +158,8 @@ test_expect_success 'with failing hook (merge)' '
'
test_expect_success '--no-verify with failing hook (merge)' '
- test_when_finished "rm -f \"$PREMERGE\" actual_hooks" &&
- cp "$HOOKDIR/fail.sample" "$PREMERGE" &&
+ setup_failing_hook "pre-merge-commit" &&
+
git branch -f side side-orig &&
git checkout side &&
git merge --no-verify -m "merge main" main &&
@@ -192,9 +167,18 @@ test_expect_success '--no-verify with failing hook (merge)' '
test_path_is_missing actual_hooks
'
+setup_non_exec_hook () {
+ test_when_finished "rm -f actual_hooks" &&
+ test_hook "$1" <<-\EOF &&
+ echo non-exec >>actual_hooks
+ exit 1
+ EOF
+ test_hook --disable "$1"
+}
+
+
test_expect_success POSIXPERM 'with non-executable hook' '
- test_when_finished "rm -f \"$PRECOMMIT\" actual_hooks" &&
- cp "$HOOKDIR/non-exec.sample" "$PRECOMMIT" &&
+ setup_non_exec_hook "pre-commit" &&
echo "content" >>file &&
git add file &&
git commit -m "content" &&
@@ -202,8 +186,7 @@ test_expect_success POSIXPERM 'with non-executable hook' '
'
test_expect_success POSIXPERM '--no-verify with non-executable hook' '
- test_when_finished "rm -f \"$PRECOMMIT\" actual_hooks" &&
- cp "$HOOKDIR/non-exec.sample" "$PRECOMMIT" &&
+ setup_non_exec_hook "pre-commit" &&
echo "more content" >>file &&
git add file &&
git commit --no-verify -m "more content" &&
@@ -211,8 +194,7 @@ test_expect_success POSIXPERM '--no-verify with non-executable hook' '
'
test_expect_success POSIXPERM 'with non-executable hook (merge)' '
- test_when_finished "rm -f \"$PREMERGE\" actual_hooks" &&
- cp "$HOOKDIR/non-exec.sample" "$PREMERGE" &&
+ setup_non_exec_hook "pre-merge" &&
git branch -f side side-orig &&
git checkout side &&
git merge -m "merge main" main &&
@@ -221,8 +203,7 @@ test_expect_success POSIXPERM 'with non-executable hook (merge)' '
'
test_expect_success POSIXPERM '--no-verify with non-executable hook (merge)' '
- test_when_finished "rm -f \"$PREMERGE\" actual_hooks" &&
- cp "$HOOKDIR/non-exec.sample" "$PREMERGE" &&
+ setup_non_exec_hook "pre-merge" &&
git branch -f side side-orig &&
git checkout side &&
git merge --no-verify -m "merge main" main &&
@@ -230,10 +211,18 @@ test_expect_success POSIXPERM '--no-verify with non-executable hook (merge)' '
test_path_is_missing actual_hooks
'
+setup_require_prefix_hook () {
+ test_when_finished "rm -f expected_hooks" &&
+ echo require-prefix >expected_hooks &&
+ test_hook pre-commit <<-\EOF
+ echo require-prefix >>actual_hooks
+ test $GIT_PREFIX = "success/"
+ EOF
+}
+
test_expect_success 'with hook requiring GIT_PREFIX' '
- test_when_finished "rm -rf \"$PRECOMMIT\" expected_hooks actual_hooks success" &&
- cp "$HOOKDIR/require-prefix.sample" "$PRECOMMIT" &&
- echo "$PRECOMMIT" >expected_hooks &&
+ test_when_finished "rm -rf actual_hooks success" &&
+ setup_require_prefix_hook &&
echo "more content" >>file &&
git add file &&
mkdir success &&
@@ -245,9 +234,8 @@ test_expect_success 'with hook requiring GIT_PREFIX' '
'
test_expect_success 'with failing hook requiring GIT_PREFIX' '
- test_when_finished "rm -rf \"$PRECOMMIT\" expected_hooks actual_hooks fail" &&
- cp "$HOOKDIR/require-prefix.sample" "$PRECOMMIT" &&
- echo "$PRECOMMIT" >expected_hooks &&
+ test_when_finished "rm -rf actual_hooks fail" &&
+ setup_require_prefix_hook &&
echo "more content" >>file &&
git add file &&
mkdir fail &&
@@ -259,13 +247,23 @@ test_expect_success 'with failing hook requiring GIT_PREFIX' '
test_cmp expected_hooks actual_hooks
'
+setup_require_author_hook () {
+ test_when_finished "rm -f expected_hooks actual_hooks" &&
+ echo check-author >expected_hooks &&
+ test_hook pre-commit <<-\EOF
+ echo check-author >>actual_hooks
+ test "$GIT_AUTHOR_NAME" = "New Author" &&
+ test "$GIT_AUTHOR_EMAIL" = "newauthor@example.com"
+ EOF
+}
+
+
test_expect_success 'check the author in hook' '
- test_when_finished "rm -f \"$PRECOMMIT\" expected_hooks actual_hooks" &&
- cp "$HOOKDIR/check-author.sample" "$PRECOMMIT" &&
+ setup_require_author_hook &&
cat >expected_hooks <<-EOF &&
- $PRECOMMIT
- $PRECOMMIT
- $PRECOMMIT
+ check-author
+ check-author
+ check-author
EOF
test_must_fail git commit --allow-empty -m "by a.u.thor" &&
(
diff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh
index bba58f0..a39de8c 100755
--- a/t/t7504-commit-msg-hook.sh
+++ b/t/t7504-commit-msg-hook.sh
@@ -54,15 +54,11 @@ test_expect_success '--no-verify with no hook (editor)' '
'
-# now install hook that always succeeds
-HOOKDIR="$(git rev-parse --git-dir)/hooks"
-HOOK="$HOOKDIR/commit-msg"
-mkdir -p "$HOOKDIR"
-cat > "$HOOK" <<EOF
-#!/bin/sh
-exit 0
-EOF
-chmod +x "$HOOK"
+test_expect_success 'setup: commit-msg hook that always succeeds' '
+ test_hook --setup commit-msg <<-\EOF
+ exit 0
+ EOF
+'
test_expect_success 'with succeeding hook' '
@@ -98,11 +94,11 @@ test_expect_success '--no-verify with succeeding hook (editor)' '
'
-# now a hook that fails
-cat > "$HOOK" <<EOF
-#!/bin/sh
-exit 1
-EOF
+test_expect_success 'setup: commit-msg hook that always fails' '
+ test_hook --clobber commit-msg <<-\EOF
+ exit 1
+ EOF
+'
commit_msg_is () {
test "$(git log --pretty=format:%s%b -1)" = "$1"
@@ -176,8 +172,12 @@ test_expect_success 'merge bypasses failing hook with --no-verify' '
commit_msg_is "Merge branch '\''main'\'' into newbranch"
'
+test_expect_success 'setup: commit-msg hook made non-executable' '
+ git_dir="$(git rev-parse --git-dir)" &&
+ chmod -x "$git_dir/hooks/commit-msg"
+'
+
-chmod -x "$HOOK"
test_expect_success POSIXPERM 'with non-executable hook' '
echo "content" >file &&
@@ -212,13 +212,12 @@ test_expect_success POSIXPERM '--no-verify with non-executable hook (editor)' '
'
-# now a hook that edits the commit message
-cat > "$HOOK" <<'EOF'
-#!/bin/sh
-echo "new message" > "$1"
-exit 0
-EOF
-chmod +x "$HOOK"
+test_expect_success 'setup: commit-msg hook that edits the commit message' '
+ test_hook --clobber commit-msg <<-\EOF
+ echo "new message" >"$1"
+ exit 0
+ EOF
+'
test_expect_success 'hook edits commit message' '
diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh
index e39c809..2128142 100755
--- a/t/t7505-prepare-commit-msg-hook.sh
+++ b/t/t7505-prepare-commit-msg-hook.sh
@@ -47,25 +47,19 @@ test_expect_success 'with no hook' '
'
-# set up fake editor for interactive editing
-cat > fake-editor <<'EOF'
-#!/bin/sh
-exit 0
-EOF
-chmod +x fake-editor
-
-## Not using test_set_editor here so we can easily ensure the editor variable
-## is only set for the editor tests
-FAKE_EDITOR="$(pwd)/fake-editor"
-export FAKE_EDITOR
+test_expect_success 'setup fake editor for interactive editing' '
+ write_script fake-editor <<-\EOF &&
+ exit 0
+ EOF
-# now install hook that always succeeds and adds a message
-HOOKDIR="$(git rev-parse --git-dir)/hooks"
-HOOK="$HOOKDIR/prepare-commit-msg"
-mkdir -p "$HOOKDIR"
-echo "#!$SHELL_PATH" > "$HOOK"
-cat >> "$HOOK" <<'EOF'
+ ## Not using test_set_editor here so we can easily ensure the editor variable
+ ## is only set for the editor tests
+ FAKE_EDITOR="$(pwd)/fake-editor" &&
+ export FAKE_EDITOR
+'
+test_expect_success 'setup prepare-commit-msg hook' '
+ test_hook --setup prepare-commit-msg <<\EOF
GIT_DIR=$(git rev-parse --git-dir)
if test -d "$GIT_DIR/rebase-merge"
then
@@ -103,7 +97,7 @@ else
fi
exit 0
EOF
-chmod +x "$HOOK"
+'
echo dummy template > "$(git rev-parse --git-dir)/template"
@@ -265,10 +259,11 @@ test_expect_success 'with hook and editor (cherry-pick)' '
test "$(git log -1 --pretty=format:%s)" = merge
'
-cat > "$HOOK" <<'EOF'
-#!/bin/sh
-exit 1
-EOF
+test_expect_success 'setup: commit-msg hook that always fails' '
+ test_hook --setup --clobber prepare-commit-msg <<-\EOF
+ exit 1
+ EOF
+'
test_expect_success 'with failing hook' '
@@ -296,9 +291,9 @@ test_expect_success 'with failing hook (merge)' '
git checkout -B other HEAD@{1} &&
echo "more" >> file &&
git add file &&
- rm -f "$HOOK" &&
+ test_hook --remove prepare-commit-msg &&
git commit -m other &&
- write_script "$HOOK" <<-EOF &&
+ test_hook --setup prepare-commit-msg <<-\EOF &&
exit 1
EOF
git checkout - &&
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index 05c6c02..2b7ef6c 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1647,13 +1647,33 @@ test_expect_success '"Initial commit" should not be noted in commit template' '
'
test_expect_success '--no-optional-locks prevents index update' '
- test-tool chmtime =1234567890 .git/index &&
+ test_set_magic_mtime .git/index &&
git --no-optional-locks status &&
- test-tool chmtime --get .git/index >out &&
- grep ^1234567890 out &&
+ test_is_magic_mtime .git/index &&
git status &&
- test-tool chmtime --get .git/index >out &&
- ! grep ^1234567890 out
+ ! test_is_magic_mtime .git/index
+'
+
+test_expect_success 'racy timestamps will be fixed for clean worktree' '
+ echo content >racy-dirty &&
+ echo content >racy-racy &&
+ git add racy* &&
+ git commit -m "racy test files" &&
+ # let status rewrite the index, if necessary; after that we expect
+ # no more index writes unless caused by racy timestamps; note that
+ # timestamps may already be racy now (depending on previous tests)
+ git status &&
+ test_set_magic_mtime .git/index &&
+ git status &&
+ ! test_is_magic_mtime .git/index
+'
+
+test_expect_success 'racy timestamps will be fixed for dirty worktree' '
+ echo content2 >racy-dirty &&
+ git status &&
+ test_set_magic_mtime .git/index &&
+ git status &&
+ ! test_is_magic_mtime .git/index
'
test_done
diff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh
index a6308ac..d4f9c6a 100755
--- a/t/t7519-status-fsmonitor.sh
+++ b/t/t7519-status-fsmonitor.sh
@@ -26,7 +26,7 @@ dirty_repo () {
}
write_integration_script () {
- write_script .git/hooks/fsmonitor-test<<-\EOF
+ test_hook --setup --clobber fsmonitor-test<<-\EOF
if test "$#" -ne 2
then
echo "$0: exactly 2 arguments expected"
@@ -56,7 +56,6 @@ test_lazy_prereq UNTRACKED_CACHE '
'
test_expect_success 'setup' '
- mkdir -p .git/hooks &&
: >tracked &&
: >modified &&
mkdir dir1 &&
@@ -108,7 +107,7 @@ EOF
# test that "update-index --fsmonitor-valid" sets the fsmonitor valid bit
test_expect_success 'update-index --fsmonitor-valid" sets the fsmonitor valid bit' '
- write_script .git/hooks/fsmonitor-test<<-\EOF &&
+ test_hook fsmonitor-test<<-\EOF &&
printf "last_update_token\0"
EOF
git update-index --fsmonitor &&
@@ -169,7 +168,7 @@ EOF
# test that newly added files are marked valid
test_expect_success 'newly added files are marked valid' '
- write_script .git/hooks/fsmonitor-test<<-\EOF &&
+ test_hook --setup --clobber fsmonitor-test<<-\EOF &&
printf "last_update_token\0"
EOF
git add new &&
@@ -210,7 +209,7 @@ EOF
# test that *only* files returned by the integration script get flagged as invalid
test_expect_success '*only* files returned by the integration script get flagged as invalid' '
- write_script .git/hooks/fsmonitor-test<<-\EOF &&
+ test_hook --clobber fsmonitor-test<<-\EOF &&
printf "last_update_token\0"
printf "dir1/modified\0"
EOF
@@ -231,7 +230,7 @@ test_expect_success 'refresh_index() invalidates fsmonitor cache' '
dirty_repo &&
write_integration_script &&
git add . &&
- write_script .git/hooks/fsmonitor-test<<-\EOF &&
+ test_hook --clobber fsmonitor-test<<-\EOF &&
EOF
git commit -m "to reset" &&
git reset HEAD~1 &&
@@ -280,7 +279,7 @@ do
# Make sure it's actually skipping the check for modified and untracked
# (if enabled) files unless it is told about them.
test_expect_success "status doesn't detect unreported modifications" '
- write_script .git/hooks/fsmonitor-test<<-\EOF &&
+ test_hook --clobber fsmonitor-test<<-\EOF &&
printf "last_update_token\0"
:>marker
EOF
@@ -322,19 +321,25 @@ test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR'
test_create_repo dot-git &&
(
cd dot-git &&
- mkdir -p .git/hooks &&
: >tracked &&
+ test-tool chmtime =-60 tracked &&
: >modified &&
+ test-tool chmtime =-60 modified &&
mkdir dir1 &&
: >dir1/tracked &&
+ test-tool chmtime =-60 dir1/tracked &&
: >dir1/modified &&
+ test-tool chmtime =-60 dir1/modified &&
mkdir dir2 &&
: >dir2/tracked &&
+ test-tool chmtime =-60 dir2/tracked &&
: >dir2/modified &&
+ test-tool chmtime =-60 dir2/modified &&
write_integration_script &&
git config core.fsmonitor .git/hooks/fsmonitor-test &&
git update-index --untracked-cache &&
git update-index --fsmonitor &&
+ git status &&
GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace-before" \
git status &&
test-tool dump-untracked-cache >../before
@@ -407,14 +412,14 @@ test_expect_success 'status succeeds with sparse index' '
git -C sparse sparse-checkout init --cone --sparse-index &&
git -C sparse sparse-checkout set dir1 dir2 &&
- write_script .git/hooks/fsmonitor-test <<-\EOF &&
+ test_hook --clobber fsmonitor-test <<-\EOF &&
printf "last_update_token\0"
EOF
git -C full config core.fsmonitor ../.git/hooks/fsmonitor-test &&
git -C sparse config core.fsmonitor ../.git/hooks/fsmonitor-test &&
check_sparse_index_behavior ! &&
- write_script .git/hooks/fsmonitor-test <<-\EOF &&
+ test_hook --clobber fsmonitor-test <<-\EOF &&
printf "last_update_token\0"
printf "dir1/modified\0"
EOF
@@ -432,7 +437,7 @@ test_expect_success 'status succeeds with sparse index' '
# This one modifies outside the sparse-checkout definition
# and hence we expect to expand the sparse-index.
- write_script .git/hooks/fsmonitor-test <<-\EOF &&
+ test_hook --clobber fsmonitor-test <<-\EOF &&
printf "last_update_token\0"
printf "dir1a/modified\0"
EOF
diff --git a/t/t7520-ignored-hook-warning.sh b/t/t7520-ignored-hook-warning.sh
index 634fb7f..dc57526 100755
--- a/t/t7520-ignored-hook-warning.sh
+++ b/t/t7520-ignored-hook-warning.sh
@@ -5,10 +5,7 @@ test_description='ignored hook warning'
. ./test-lib.sh
test_expect_success setup '
- hookdir="$(git rev-parse --git-dir)/hooks" &&
- hook="$hookdir/pre-commit" &&
- mkdir -p "$hookdir" &&
- write_script "$hook" <<-\EOF
+ test_hook --setup pre-commit <<-\EOF
exit 0
EOF
'
@@ -19,20 +16,20 @@ test_expect_success 'no warning if hook is not ignored' '
'
test_expect_success POSIXPERM 'warning if hook is ignored' '
- chmod -x "$hook" &&
+ test_hook --disable pre-commit &&
git commit --allow-empty -m "even more" 2>message &&
test_i18ngrep -e "hook was ignored" message
'
test_expect_success POSIXPERM 'no warning if advice.ignoredHook set to false' '
test_config advice.ignoredHook false &&
- chmod -x "$hook" &&
+ test_hook --disable pre-commit &&
git commit --allow-empty -m "even more" 2>message &&
test_i18ngrep ! -e "hook was ignored" message
'
test_expect_success 'no warning if unset advice.ignoredHook and hook removed' '
- rm -f "$hook" &&
+ test_hook --remove pre-commit &&
test_unconfig advice.ignoredHook &&
git commit --allow-empty -m "even more" 2>message &&
test_i18ngrep ! -e "hook was ignored" message
diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh
new file mode 100755
index 0000000..bd0c952
--- /dev/null
+++ b/t/t7527-builtin-fsmonitor.sh
@@ -0,0 +1,609 @@
+#!/bin/sh
+
+test_description='built-in file system watcher'
+
+. ./test-lib.sh
+
+if ! test_have_prereq FSMONITOR_DAEMON
+then
+ skip_all="fsmonitor--daemon is not supported on this platform"
+ test_done
+fi
+
+stop_daemon_delete_repo () {
+ r=$1 &&
+ test_might_fail git -C $r fsmonitor--daemon stop &&
+ rm -rf $1
+}
+
+start_daemon () {
+ r= tf= t2= tk= &&
+
+ while test "$#" -ne 0
+ do
+ case "$1" in
+ -C)
+ r="-C ${2?}"
+ shift
+ ;;
+ --tf)
+ tf="${2?}"
+ shift
+ ;;
+ --t2)
+ t2="${2?}"
+ shift
+ ;;
+ --tk)
+ tk="${2?}"
+ shift
+ ;;
+ -*)
+ BUG "error: unknown option: '$1'"
+ ;;
+ *)
+ BUG "error: unbound argument: '$1'"
+ ;;
+ esac
+ shift
+ done &&
+
+ (
+ if test -n "$tf"
+ then
+ GIT_TRACE_FSMONITOR="$tf"
+ export GIT_TRACE_FSMONITOR
+ fi &&
+
+ if test -n "$t2"
+ then
+ GIT_TRACE2_PERF="$t2"
+ export GIT_TRACE2_PERF
+ fi &&
+
+ if test -n "$tk"
+ then
+ GIT_TEST_FSMONITOR_TOKEN="$tk"
+ export GIT_TEST_FSMONITOR_TOKEN
+ fi &&
+
+ git $r fsmonitor--daemon start &&
+ git $r fsmonitor--daemon status
+ )
+}
+
+# Is a Trace2 data event present with the given catetory and key?
+# We do not care what the value is.
+#
+have_t2_data_event () {
+ c=$1 &&
+ k=$2 &&
+
+ grep -e '"event":"data".*"category":"'"$c"'".*"key":"'"$k"'"'
+}
+
+test_expect_success 'explicit daemon start and stop' '
+ test_when_finished "stop_daemon_delete_repo test_explicit" &&
+
+ git init test_explicit &&
+ start_daemon -C test_explicit &&
+
+ git -C test_explicit fsmonitor--daemon stop &&
+ test_must_fail git -C test_explicit fsmonitor--daemon status
+'
+
+test_expect_success 'implicit daemon start' '
+ test_when_finished "stop_daemon_delete_repo test_implicit" &&
+
+ git init test_implicit &&
+ test_must_fail git -C test_implicit fsmonitor--daemon status &&
+
+ # query will implicitly start the daemon.
+ #
+ # for test-script simplicity, we send a V1 timestamp rather than
+ # a V2 token. either way, the daemon response to any query contains
+ # a new V2 token. (the daemon may complain that we sent a V1 request,
+ # but this test case is only concerned with whether the daemon was
+ # implicitly started.)
+
+ GIT_TRACE2_EVENT="$PWD/.git/trace" \
+ test-tool -C test_implicit fsmonitor-client query --token 0 >actual &&
+ nul_to_q <actual >actual.filtered &&
+ grep "builtin:" actual.filtered &&
+
+ # confirm that a daemon was started in the background.
+ #
+ # since the mechanism for starting the background daemon is platform
+ # dependent, just confirm that the foreground command received a
+ # response from the daemon.
+
+ have_t2_data_event fsm_client query/response-length <.git/trace &&
+
+ git -C test_implicit fsmonitor--daemon status &&
+ git -C test_implicit fsmonitor--daemon stop &&
+ test_must_fail git -C test_implicit fsmonitor--daemon status
+'
+
+test_expect_success 'implicit daemon stop (delete .git)' '
+ test_when_finished "stop_daemon_delete_repo test_implicit_1" &&
+
+ git init test_implicit_1 &&
+
+ start_daemon -C test_implicit_1 &&
+
+ # deleting the .git directory will implicitly stop the daemon.
+ rm -rf test_implicit_1/.git &&
+
+ # [1] Create an empty .git directory so that the following Git
+ # command will stay relative to the `-C` directory.
+ #
+ # Without this, the Git command will override the requested
+ # -C argument and crawl out to the containing Git source tree.
+ # This would make the test result dependent upon whether we
+ # were using fsmonitor on our development worktree.
+ #
+ sleep 1 &&
+ mkdir test_implicit_1/.git &&
+
+ test_must_fail git -C test_implicit_1 fsmonitor--daemon status
+'
+
+test_expect_success 'implicit daemon stop (rename .git)' '
+ test_when_finished "stop_daemon_delete_repo test_implicit_2" &&
+
+ git init test_implicit_2 &&
+
+ start_daemon -C test_implicit_2 &&
+
+ # renaming the .git directory will implicitly stop the daemon.
+ mv test_implicit_2/.git test_implicit_2/.xxx &&
+
+ # See [1] above.
+ #
+ sleep 1 &&
+ mkdir test_implicit_2/.git &&
+
+ test_must_fail git -C test_implicit_2 fsmonitor--daemon status
+'
+
+test_expect_success 'cannot start multiple daemons' '
+ test_when_finished "stop_daemon_delete_repo test_multiple" &&
+
+ git init test_multiple &&
+
+ start_daemon -C test_multiple &&
+
+ test_must_fail git -C test_multiple fsmonitor--daemon start 2>actual &&
+ grep "fsmonitor--daemon is already running" actual &&
+
+ git -C test_multiple fsmonitor--daemon stop &&
+ test_must_fail git -C test_multiple fsmonitor--daemon status
+'
+
+# These tests use the main repo in the trash directory
+
+test_expect_success 'setup' '
+ >tracked &&
+ >modified &&
+ >delete &&
+ >rename &&
+ mkdir dir1 &&
+ >dir1/tracked &&
+ >dir1/modified &&
+ >dir1/delete &&
+ >dir1/rename &&
+ mkdir dir2 &&
+ >dir2/tracked &&
+ >dir2/modified &&
+ >dir2/delete &&
+ >dir2/rename &&
+ mkdir dirtorename &&
+ >dirtorename/a &&
+ >dirtorename/b &&
+
+ cat >.gitignore <<-\EOF &&
+ .gitignore
+ expect*
+ actual*
+ flush*
+ trace*
+ EOF
+
+ git -c core.fsmonitor=false add . &&
+ test_tick &&
+ git -c core.fsmonitor=false commit -m initial &&
+
+ git config core.fsmonitor true
+'
+
+# The test already explicitly stopped (or tried to stop) the daemon.
+# This is here in case something else fails first.
+#
+redundant_stop_daemon () {
+ test_might_fail git fsmonitor--daemon stop
+}
+
+test_expect_success 'update-index implicitly starts daemon' '
+ test_when_finished redundant_stop_daemon &&
+
+ test_must_fail git fsmonitor--daemon status &&
+
+ GIT_TRACE2_EVENT="$PWD/.git/trace_implicit_1" \
+ git update-index --fsmonitor &&
+
+ git fsmonitor--daemon status &&
+ test_might_fail git fsmonitor--daemon stop &&
+
+ # Confirm that the trace2 log contains a record of the
+ # daemon starting.
+ test_subcommand git fsmonitor--daemon start <.git/trace_implicit_1
+'
+
+test_expect_success 'status implicitly starts daemon' '
+ test_when_finished redundant_stop_daemon &&
+
+ test_must_fail git fsmonitor--daemon status &&
+
+ GIT_TRACE2_EVENT="$PWD/.git/trace_implicit_2" \
+ git status >actual &&
+
+ git fsmonitor--daemon status &&
+ test_might_fail git fsmonitor--daemon stop &&
+
+ # Confirm that the trace2 log contains a record of the
+ # daemon starting.
+ test_subcommand git fsmonitor--daemon start <.git/trace_implicit_2
+'
+
+edit_files () {
+ echo 1 >modified &&
+ echo 2 >dir1/modified &&
+ echo 3 >dir2/modified &&
+ >dir1/untracked
+}
+
+delete_files () {
+ rm -f delete &&
+ rm -f dir1/delete &&
+ rm -f dir2/delete
+}
+
+create_files () {
+ echo 1 >new &&
+ echo 2 >dir1/new &&
+ echo 3 >dir2/new
+}
+
+rename_files () {
+ mv rename renamed &&
+ mv dir1/rename dir1/renamed &&
+ mv dir2/rename dir2/renamed
+}
+
+file_to_directory () {
+ rm -f delete &&
+ mkdir delete &&
+ echo 1 >delete/new
+}
+
+directory_to_file () {
+ rm -rf dir1 &&
+ echo 1 >dir1
+}
+
+# The next few test cases confirm that our fsmonitor daemon sees each type
+# of OS filesystem notification that we care about. At this layer we just
+# ensure we are getting the OS notifications and do not try to confirm what
+# is reported by `git status`.
+#
+# We run a simple query after modifying the filesystem just to introduce
+# a bit of a delay so that the trace logging from the daemon has time to
+# get flushed to disk.
+#
+# We `reset` and `clean` at the bottom of each test (and before stopping the
+# daemon) because these commands might implicitly restart the daemon.
+
+clean_up_repo_and_stop_daemon () {
+ git reset --hard HEAD &&
+ git clean -fd &&
+ test_might_fail git fsmonitor--daemon stop &&
+ rm -f .git/trace
+}
+
+test_expect_success 'edit some files' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
+ start_daemon --tf "$PWD/.git/trace" &&
+
+ edit_files &&
+
+ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: dir1/modified$" .git/trace &&
+ grep "^event: dir2/modified$" .git/trace &&
+ grep "^event: modified$" .git/trace &&
+ grep "^event: dir1/untracked$" .git/trace
+'
+
+test_expect_success 'create some files' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
+ start_daemon --tf "$PWD/.git/trace" &&
+
+ create_files &&
+
+ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: dir1/new$" .git/trace &&
+ grep "^event: dir2/new$" .git/trace &&
+ grep "^event: new$" .git/trace
+'
+
+test_expect_success 'delete some files' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
+ start_daemon --tf "$PWD/.git/trace" &&
+
+ delete_files &&
+
+ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: dir1/delete$" .git/trace &&
+ grep "^event: dir2/delete$" .git/trace &&
+ grep "^event: delete$" .git/trace
+'
+
+test_expect_success 'rename some files' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
+ start_daemon --tf "$PWD/.git/trace" &&
+
+ rename_files &&
+
+ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: dir1/rename$" .git/trace &&
+ grep "^event: dir2/rename$" .git/trace &&
+ grep "^event: rename$" .git/trace &&
+ grep "^event: dir1/renamed$" .git/trace &&
+ grep "^event: dir2/renamed$" .git/trace &&
+ grep "^event: renamed$" .git/trace
+'
+
+test_expect_success 'rename directory' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
+ start_daemon --tf "$PWD/.git/trace" &&
+
+ mv dirtorename dirrenamed &&
+
+ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: dirtorename/*$" .git/trace &&
+ grep "^event: dirrenamed/*$" .git/trace
+'
+
+test_expect_success 'file changes to directory' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
+ start_daemon --tf "$PWD/.git/trace" &&
+
+ file_to_directory &&
+
+ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: delete$" .git/trace &&
+ grep "^event: delete/new$" .git/trace
+'
+
+test_expect_success 'directory changes to a file' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
+ start_daemon --tf "$PWD/.git/trace" &&
+
+ directory_to_file &&
+
+ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: dir1$" .git/trace
+'
+
+# The next few test cases exercise the token-resync code. When filesystem
+# drops events (because of filesystem velocity or because the daemon isn't
+# polling fast enough), we need to discard the cached data (relative to the
+# current token) and start collecting events under a new token.
+#
+# the 'test-tool fsmonitor-client flush' command can be used to send a
+# "flush" message to a running daemon and ask it to do a flush/resync.
+
+test_expect_success 'flush cached data' '
+ test_when_finished "stop_daemon_delete_repo test_flush" &&
+
+ git init test_flush &&
+
+ start_daemon -C test_flush --tf "$PWD/.git/trace_daemon" --tk true &&
+
+ # The daemon should have an initial token with no events in _0 and
+ # then a few (probably platform-specific number of) events in _1.
+ # These should both have the same <token_id>.
+
+ test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000001:0" >actual_0 &&
+ nul_to_q <actual_0 >actual_q0 &&
+
+ >test_flush/file_1 &&
+ >test_flush/file_2 &&
+
+ test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000001:0" >actual_1 &&
+ nul_to_q <actual_1 >actual_q1 &&
+
+ grep "file_1" actual_q1 &&
+
+ # Force a flush. This will change the <token_id>, reset the <seq_nr>, and
+ # flush the file data. Then create some events and ensure that the file
+ # again appears in the cache. It should have the new <token_id>.
+
+ test-tool -C test_flush fsmonitor-client flush >flush_0 &&
+ nul_to_q <flush_0 >flush_q0 &&
+ grep "^builtin:test_00000002:0Q/Q$" flush_q0 &&
+
+ test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000002:0" >actual_2 &&
+ nul_to_q <actual_2 >actual_q2 &&
+
+ grep "^builtin:test_00000002:0Q$" actual_q2 &&
+
+ >test_flush/file_3 &&
+
+ test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000002:0" >actual_3 &&
+ nul_to_q <actual_3 >actual_q3 &&
+
+ grep "file_3" actual_q3
+'
+
+# The next few test cases create repos where the .git directory is NOT
+# inside the one of the working directory. That is, where .git is a file
+# that points to a directory elsewhere. This happens for submodules and
+# non-primary worktrees.
+
+test_expect_success 'setup worktree base' '
+ git init wt-base &&
+ echo 1 >wt-base/file1 &&
+ git -C wt-base add file1 &&
+ git -C wt-base commit -m "c1"
+'
+
+test_expect_success 'worktree with .git file' '
+ git -C wt-base worktree add ../wt-secondary &&
+
+ start_daemon -C wt-secondary \
+ --tf "$PWD/trace_wt_secondary" \
+ --t2 "$PWD/trace2_wt_secondary" &&
+
+ git -C wt-secondary fsmonitor--daemon stop &&
+ test_must_fail git -C wt-secondary fsmonitor--daemon status
+'
+
+# NEEDSWORK: Repeat one of the "edit" tests on wt-secondary and
+# confirm that we get the same events and behavior -- that is, that
+# fsmonitor--daemon correctly watches BOTH the working directory and
+# the external GITDIR directory and behaves the same as when ".git"
+# is a directory inside the working directory.
+
+test_expect_success 'cleanup worktrees' '
+ stop_daemon_delete_repo wt-secondary &&
+ stop_daemon_delete_repo wt-base
+'
+
+# The next few tests perform arbitrary/contrived file operations and
+# confirm that status is correct. That is, that the data (or lack of
+# data) from fsmonitor doesn't cause incorrect results. And doesn't
+# cause incorrect results when the untracked-cache is enabled.
+
+test_lazy_prereq UNTRACKED_CACHE '
+ git update-index --test-untracked-cache
+'
+
+test_expect_success 'Matrix: setup for untracked-cache,fsmonitor matrix' '
+ test_unconfig core.fsmonitor &&
+ git update-index --no-fsmonitor &&
+ test_might_fail git fsmonitor--daemon stop
+'
+
+matrix_clean_up_repo () {
+ git reset --hard HEAD &&
+ git clean -fd
+}
+
+matrix_try () {
+ uc=$1 &&
+ fsm=$2 &&
+ fn=$3 &&
+
+ if test $uc = true && test $fsm = false
+ then
+ # The untracked-cache is buggy when FSMonitor is
+ # DISABLED, so skip the tests for this matrix
+ # combination.
+ #
+ # We've observed random, occasional test failures on
+ # Windows and MacOS when the UC is turned on and FSM
+ # is turned off. These are rare, but they do happen
+ # indicating that it is probably a race condition within
+ # the untracked cache itself.
+ #
+ # It usually happens when a test does F/D trickery and
+ # then the NEXT test fails because of extra status
+ # output from stale UC data from the previous test.
+ #
+ # Since FSMonitor is not involved in the error, skip
+ # the tests for this matrix combination.
+ #
+ return 0
+ fi &&
+
+ test_expect_success "Matrix[uc:$uc][fsm:$fsm] $fn" '
+ matrix_clean_up_repo &&
+ $fn &&
+ if test $uc = false && test $fsm = false
+ then
+ git status --porcelain=v1 >.git/expect.$fn
+ else
+ git status --porcelain=v1 >.git/actual.$fn &&
+ test_cmp .git/expect.$fn .git/actual.$fn
+ fi
+ '
+}
+
+uc_values="false"
+test_have_prereq UNTRACKED_CACHE && uc_values="false true"
+for uc_val in $uc_values
+do
+ if test $uc_val = false
+ then
+ test_expect_success "Matrix[uc:$uc_val] disable untracked cache" '
+ git config core.untrackedcache false &&
+ git update-index --no-untracked-cache
+ '
+ else
+ test_expect_success "Matrix[uc:$uc_val] enable untracked cache" '
+ git config core.untrackedcache true &&
+ git update-index --untracked-cache
+ '
+ fi
+
+ fsm_values="false true"
+ for fsm_val in $fsm_values
+ do
+ if test $fsm_val = false
+ then
+ test_expect_success "Matrix[uc:$uc_val][fsm:$fsm_val] disable fsmonitor" '
+ test_unconfig core.fsmonitor &&
+ git update-index --no-fsmonitor &&
+ test_might_fail git fsmonitor--daemon stop
+ '
+ else
+ test_expect_success "Matrix[uc:$uc_val][fsm:$fsm_val] enable fsmonitor" '
+ git config core.fsmonitor true &&
+ git fsmonitor--daemon start &&
+ git update-index --fsmonitor
+ '
+ fi
+
+ matrix_try $uc_val $fsm_val edit_files
+ matrix_try $uc_val $fsm_val delete_files
+ matrix_try $uc_val $fsm_val create_files
+ matrix_try $uc_val $fsm_val rename_files
+ matrix_try $uc_val $fsm_val file_to_directory
+ matrix_try $uc_val $fsm_val directory_to_file
+
+ if test $fsm_val = true
+ then
+ test_expect_success "Matrix[uc:$uc_val][fsm:$fsm_val] disable fsmonitor at end" '
+ test_unconfig core.fsmonitor &&
+ git update-index --no-fsmonitor &&
+ test_might_fail git fsmonitor--daemon stop
+ '
+ fi
+ done
+done
+
+test_done
diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh
index e489869..ca45c4c 100755
--- a/t/t7700-repack.sh
+++ b/t/t7700-repack.sh
@@ -312,16 +312,13 @@ test_expect_success 'cleans up MIDX when appropriate' '
checksum=$(midx_checksum $objdir) &&
test_path_is_file $midx &&
test_path_is_file $midx-$checksum.bitmap &&
- test_path_is_file $midx-$checksum.rev &&
test_commit repack-3 &&
GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adb --write-midx &&
test_path_is_file $midx &&
test_path_is_missing $midx-$checksum.bitmap &&
- test_path_is_missing $midx-$checksum.rev &&
test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
- test_path_is_file $midx-$(midx_checksum $objdir).rev &&
test_commit repack-4 &&
GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adb &&
@@ -354,7 +351,6 @@ test_expect_success '--write-midx with preferred bitmap tips' '
test_line_count = 1 before &&
rm -fr $midx-$(midx_checksum $objdir).bitmap &&
- rm -fr $midx-$(midx_checksum $objdir).rev &&
rm -fr $midx &&
# instead of constructing the snapshot ourselves (c.f., the test
@@ -373,10 +369,61 @@ test_expect_success '--write-midx with preferred bitmap tips' '
)
'
+# The first argument is expected to be a filename
+# and that file should contain the name of a .idx
+# file. Send the list of objects in that .idx file
+# into stdout.
+get_sorted_objects_from_pack () {
+ git show-index <$(cat "$1") >raw &&
+ cut -d" " -f2 raw
+}
+
test_expect_success '--write-midx -b packs non-kept objects' '
- GIT_TRACE2_EVENT="$(pwd)/trace.txt" \
- git repack --write-midx -a -b &&
- test_subcommand_inexact git pack-objects --honor-pack-keep <trace.txt
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ # Create a kept pack-file
+ test_commit base &&
+ git repack -ad &&
+ find $objdir/pack -name "*.idx" >before &&
+ test_line_count = 1 before &&
+ before_name=$(cat before) &&
+ >${before_name%.idx}.keep &&
+
+ # Create a non-kept pack-file
+ test_commit other &&
+ git repack &&
+
+ # Create loose objects
+ test_commit loose &&
+
+ # Repack everything
+ git repack --write-midx -a -b -d &&
+
+ # There should be two pack-files now, the
+ # old, kept pack and the new, non-kept pack.
+ find $objdir/pack -name "*.idx" | sort >after &&
+ test_line_count = 2 after &&
+ find $objdir/pack -name "*.keep" >kept &&
+ kept_name=$(cat kept) &&
+ echo ${kept_name%.keep}.idx >kept-idx &&
+ test_cmp before kept-idx &&
+
+ # Get object list from the kept pack.
+ get_sorted_objects_from_pack before >old.objects &&
+
+ # Get object list from the one non-kept pack-file
+ comm -13 before after >new-pack &&
+ test_line_count = 1 new-pack &&
+ get_sorted_objects_from_pack new-pack >new.objects &&
+
+ # None of the objects in the new pack should
+ # exist within the kept pack.
+ comm -12 old.objects new.objects >shared.objects &&
+ test_must_be_empty shared.objects
+ )
'
test_expect_success TTY '--quiet disables progress' '
@@ -385,4 +432,54 @@ test_expect_success TTY '--quiet disables progress' '
test_must_be_empty stderr
'
+test_expect_success 'setup for update-server-info' '
+ git init update-server-info &&
+ test_commit -C update-server-info message
+'
+
+test_server_info_present () {
+ test_path_is_file update-server-info/.git/objects/info/packs &&
+ test_path_is_file update-server-info/.git/info/refs
+}
+
+test_server_info_missing () {
+ test_path_is_missing update-server-info/.git/objects/info/packs &&
+ test_path_is_missing update-server-info/.git/info/refs
+}
+
+test_server_info_cleanup () {
+ rm -f update-server-info/.git/objects/info/packs update-server-info/.git/info/refs &&
+ test_server_info_missing
+}
+
+test_expect_success 'updates server info by default' '
+ test_server_info_cleanup &&
+ git -C update-server-info repack &&
+ test_server_info_present
+'
+
+test_expect_success '-n skips updating server info' '
+ test_server_info_cleanup &&
+ git -C update-server-info repack -n &&
+ test_server_info_missing
+'
+
+test_expect_success 'repack.updateServerInfo=true updates server info' '
+ test_server_info_cleanup &&
+ git -C update-server-info -c repack.updateServerInfo=true repack &&
+ test_server_info_present
+'
+
+test_expect_success 'repack.updateServerInfo=false skips updating server info' '
+ test_server_info_cleanup &&
+ git -C update-server-info -c repack.updateServerInfo=false repack &&
+ test_server_info_missing
+'
+
+test_expect_success '-n overrides repack.updateServerInfo=true' '
+ test_server_info_cleanup &&
+ git -C update-server-info -c repack.updateServerInfo=true repack -n &&
+ test_server_info_missing
+'
+
test_done
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index 424c31c..6935601 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -98,6 +98,37 @@ test_expect_success 'grep should not segfault with a bad input' '
test_invalid_grep_expression --and -e A
+test_pattern_type () {
+ H=$1 &&
+ HC=$2 &&
+ L=$3 &&
+ type=$4 &&
+ shift 4 &&
+
+ expected_str= &&
+ case "$type" in
+ BRE)
+ expected_str="${HC}ab:a+bc"
+ ;;
+ ERE)
+ expected_str="${HC}ab:abc"
+ ;;
+ FIX)
+ expected_str="${HC}ab:a+b*c"
+ ;;
+ *)
+ BUG "unknown pattern type '$type'"
+ ;;
+ esac &&
+ config_str="$@" &&
+
+ test_expect_success "grep $L with '$config_str' interpreted as $type" '
+ echo $expected_str >expected &&
+ git $config_str grep "a+b*c" $H ab >actual &&
+ test_cmp expected actual
+ '
+}
+
for H in HEAD ''
do
case "$H" in
@@ -393,35 +424,13 @@ do
git grep --no-recursive -n -e vvv $H -- t . >actual &&
test_cmp expected actual
'
- test_expect_success "grep $L with grep.extendedRegexp=false" '
- echo "${HC}ab:a+bc" >expected &&
- git -c grep.extendedRegexp=false grep "a+b*c" $H ab >actual &&
- test_cmp expected actual
- '
- test_expect_success "grep $L with grep.extendedRegexp=true" '
- echo "${HC}ab:abc" >expected &&
- git -c grep.extendedRegexp=true grep "a+b*c" $H ab >actual &&
- test_cmp expected actual
- '
- test_expect_success "grep $L with grep.patterntype=basic" '
- echo "${HC}ab:a+bc" >expected &&
- git -c grep.patterntype=basic grep "a+b*c" $H ab >actual &&
- test_cmp expected actual
- '
-
- test_expect_success "grep $L with grep.patterntype=extended" '
- echo "${HC}ab:abc" >expected &&
- git -c grep.patterntype=extended grep "a+b*c" $H ab >actual &&
- test_cmp expected actual
- '
-
- test_expect_success "grep $L with grep.patterntype=fixed" '
- echo "${HC}ab:a+b*c" >expected &&
- git -c grep.patterntype=fixed grep "a+b*c" $H ab >actual &&
- test_cmp expected actual
- '
+ test_pattern_type "$H" "$HC" "$L" BRE -c grep.extendedRegexp=false
+ test_pattern_type "$H" "$HC" "$L" ERE -c grep.extendedRegexp=true
+ test_pattern_type "$H" "$HC" "$L" BRE -c grep.patternType=basic
+ test_pattern_type "$H" "$HC" "$L" ERE -c grep.patternType=extended
+ test_pattern_type "$H" "$HC" "$L" FIX -c grep.patternType=fixed
test_expect_success PCRE "grep $L with grep.patterntype=perl" '
echo "${HC}ab:a+b*c" >expected &&
@@ -433,59 +442,76 @@ do
test_must_fail git -c grep.patterntype=perl grep "foo.*bar"
'
- test_expect_success "grep $L with grep.patternType=default and grep.extendedRegexp=true" '
- echo "${HC}ab:abc" >expected &&
- git \
- -c grep.patternType=default \
- -c grep.extendedRegexp=true \
- grep "a+b*c" $H ab >actual &&
- test_cmp expected actual
- '
-
- test_expect_success "grep $L with grep.extendedRegexp=true and grep.patternType=default" '
- echo "${HC}ab:abc" >expected &&
- git \
- -c grep.extendedRegexp=true \
- -c grep.patternType=default \
- grep "a+b*c" $H ab >actual &&
- test_cmp expected actual
- '
-
- test_expect_success "grep $L with grep.patternType=extended and grep.extendedRegexp=false" '
- echo "${HC}ab:abc" >expected &&
- git \
- -c grep.patternType=extended \
- -c grep.extendedRegexp=false \
- grep "a+b*c" $H ab >actual &&
- test_cmp expected actual
- '
-
- test_expect_success "grep $L with grep.patternType=basic and grep.extendedRegexp=true" '
- echo "${HC}ab:a+bc" >expected &&
- git \
- -c grep.patternType=basic \
- -c grep.extendedRegexp=true \
- grep "a+b*c" $H ab >actual &&
- test_cmp expected actual
- '
-
- test_expect_success "grep $L with grep.extendedRegexp=false and grep.patternType=extended" '
- echo "${HC}ab:abc" >expected &&
- git \
- -c grep.extendedRegexp=false \
- -c grep.patternType=extended \
- grep "a+b*c" $H ab >actual &&
- test_cmp expected actual
- '
-
- test_expect_success "grep $L with grep.extendedRegexp=true and grep.patternType=basic" '
- echo "${HC}ab:a+bc" >expected &&
- git \
- -c grep.extendedRegexp=true \
- -c grep.patternType=basic \
- grep "a+b*c" $H ab >actual &&
- test_cmp expected actual
- '
+ test_pattern_type "$H" "$HC" "$L" ERE \
+ -c grep.patternType=default \
+ -c grep.extendedRegexp=true
+ test_pattern_type "$H" "$HC" "$L" ERE \
+ -c grep.extendedRegexp=true \
+ -c grep.patternType=default
+ test_pattern_type "$H" "$HC" "$L" ERE \
+ -c grep.patternType=extended \
+ -c grep.extendedRegexp=false
+ test_pattern_type "$H" "$HC" "$L" BRE \
+ -c grep.patternType=basic \
+ -c grep.extendedRegexp=true
+ test_pattern_type "$H" "$HC" "$L" ERE \
+ -c grep.extendedRegexp=false \
+ -c grep.patternType=extended
+ test_pattern_type "$H" "$HC" "$L" BRE \
+ -c grep.extendedRegexp=true \
+ -c grep.patternType=basic
+
+ # grep.extendedRegexp is last-one-wins
+ test_pattern_type "$H" "$HC" "$L" BRE \
+ -c grep.extendedRegexp=true \
+ -c grep.extendedRegexp=false
+
+ # grep.patternType=basic pays no attention to grep.extendedRegexp
+ test_pattern_type "$H" "$HC" "$L" BRE \
+ -c grep.extendedRegexp=true \
+ -c grep.patternType=basic \
+ -c grep.extendedRegexp=false
+
+ # grep.patternType=extended pays no attention to grep.extendedRegexp
+ test_pattern_type "$H" "$HC" "$L" ERE \
+ -c grep.extendedRegexp=true \
+ -c grep.patternType=extended \
+ -c grep.extendedRegexp=false
+
+ # grep.extendedRegexp is used with a last-one-wins grep.patternType=default
+ test_pattern_type "$H" "$HC" "$L" ERE \
+ -c grep.patternType=fixed \
+ -c grep.extendedRegexp=true \
+ -c grep.patternType=default
+
+ # grep.extendedRegexp is used with earlier grep.patternType=default
+ test_pattern_type "$H" "$HC" "$L" ERE \
+ -c grep.extendedRegexp=false \
+ -c grep.patternType=default \
+ -c grep.extendedRegexp=true
+
+ # grep.extendedRegexp is used with a last-one-loses grep.patternType=default
+ test_pattern_type "$H" "$HC" "$L" ERE \
+ -c grep.extendedRegexp=false \
+ -c grep.extendedRegexp=true \
+ -c grep.patternType=default
+
+ # grep.extendedRegexp and grep.patternType are both last-one-wins independently
+ test_pattern_type "$H" "$HC" "$L" BRE \
+ -c grep.patternType=default \
+ -c grep.extendedRegexp=true \
+ -c grep.patternType=basic
+
+ # grep.patternType=extended and grep.patternType=default
+ test_pattern_type "$H" "$HC" "$L" BRE \
+ -c grep.patternType=extended \
+ -c grep.patternType=default
+
+ # grep.patternType=[extended -> default -> fixed] (BRE)" '
+ test_pattern_type "$H" "$HC" "$L" FIX \
+ -c grep.patternType=extended \
+ -c grep.patternType=default \
+ -c grep.patternType=fixed
test_expect_success "grep --count $L" '
echo ${HC}ab:3 >expected &&
diff --git a/t/t7812-grep-icase-non-ascii.sh b/t/t7812-grep-icase-non-ascii.sh
index ca3f24f..9047d66 100755
--- a/t/t7812-grep-icase-non-ascii.sh
+++ b/t/t7812-grep-icase-non-ascii.sh
@@ -11,9 +11,19 @@ test_expect_success GETTEXT_LOCALE 'setup' '
export LC_ALL
'
-test_have_prereq GETTEXT_LOCALE &&
-test-tool regex "HALLÓ" "Halló" ICASE &&
-test_set_prereq REGEX_LOCALE
+test_expect_success GETTEXT_LOCALE 'setup REGEX_LOCALE prerequisite' '
+ # This "test-tool" invocation is identical...
+ if test-tool regex "HALLÓ" "Halló" ICASE
+ then
+ test_set_prereq REGEX_LOCALE
+ else
+
+ # ... to this one, but this way "test_must_fail" will
+ # tell a segfault or abort() from the regexec() test
+ # itself
+ test_must_fail test-tool regex "HALLÓ" "Halló" ICASE
+ fi
+'
test_expect_success REGEX_LOCALE 'grep literal string, no -F' '
git grep -i "TILRAUN: Halló Heimur!" &&
diff --git a/t/t7814-grep-recurse-submodules.sh b/t/t7814-grep-recurse-submodules.sh
index 058e5d0..a4476dc 100755
--- a/t/t7814-grep-recurse-submodules.sh
+++ b/t/t7814-grep-recurse-submodules.sh
@@ -544,4 +544,45 @@ test_expect_failure 'grep saves textconv cache in the appropriate repository' '
test_path_is_file "$sub_textconv_cache"
'
+test_expect_success 'grep partially-cloned submodule' '
+ # Set up clean superproject and submodule for partial cloning.
+ git init super &&
+ git init super/sub &&
+ (
+ cd super &&
+ test_commit --no-tag "Add file in superproject" \
+ super-file "Some content for super-file" &&
+ test_commit -C sub --no-tag "Add file in submodule" \
+ sub-file "Some content for sub-file" &&
+ git submodule add ./sub &&
+ git commit -m "Add other as submodule sub" &&
+ test_tick &&
+ test_commit -C sub --no-tag --append "Update file in submodule" \
+ sub-file "Some more content for sub-file" &&
+ git add sub &&
+ git commit -m "Update submodule" &&
+ test_tick &&
+ git config --local uploadpack.allowfilter 1 &&
+ git config --local uploadpack.allowanysha1inwant 1 &&
+ git -C sub config --local uploadpack.allowfilter 1 &&
+ git -C sub config --local uploadpack.allowanysha1inwant 1
+ ) &&
+ # Clone the superproject & submodule, then make sure we can lazy-fetch submodule objects.
+ git clone --filter=blob:none --also-filter-submodules \
+ --recurse-submodules "file://$(pwd)/super" partial &&
+ (
+ cd partial &&
+ cat >expect <<-\EOF &&
+ HEAD^:sub/sub-file:Some content for sub-file
+ HEAD^:super-file:Some content for super-file
+ EOF
+
+ GIT_TRACE2_EVENT="$(pwd)/trace2.log" git grep -e content \
+ --recurse-submodules HEAD^ >actual &&
+ test_cmp expect actual &&
+ # Verify that we actually fetched data from the promisor remote:
+ grep \"category\":\"promisor\",\"key\":\"fetch_count\",\"value\":\"1\" trace2.log
+ )
+'
+
test_done
diff --git a/t/t7817-grep-sparse-checkout.sh b/t/t7817-grep-sparse-checkout.sh
index 590b99b..eb59564 100755
--- a/t/t7817-grep-sparse-checkout.sh
+++ b/t/t7817-grep-sparse-checkout.sh
@@ -83,10 +83,13 @@ test_expect_success 'setup' '
# 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.
+# manually created after `git sparse-checkout init`). Although b is marked
+# as SKIP_WORKTREE, git grep should notice it IS present in the worktree and
+# report it.
test_expect_success 'working tree grep honors sparse checkout' '
cat >expect <<-EOF &&
a:text
+ b:new-text
EOF
test_when_finished "rm -f b" &&
echo "new-text" >b &&
@@ -126,12 +129,16 @@ test_expect_success 'grep --cached searches entries with the SKIP_WORKTREE bit'
'
# Note that sub2/ is present in the worktree but it is excluded by the sparsity
-# patterns, so grep should not recurse into it.
+# patterns. We also explicitly mark it as SKIP_WORKTREE in case it got cleared
+# by previous git commands. Thus sub2 starts as SKIP_WORKTREE but since it is
+# present in the working tree, grep should recurse into it.
test_expect_success 'grep --recurse-submodules honors sparse checkout in submodule' '
cat >expect <<-EOF &&
a:text
sub/B/b:text
+ sub2/a:text
EOF
+ git update-index --skip-worktree sub2 &&
git grep --recurse-submodules "text" >actual &&
test_cmp expect actual
'
diff --git a/t/t8007-cat-file-textconv.sh b/t/t8007-cat-file-textconv.sh
index eacd49a..b067983 100755
--- a/t/t8007-cat-file-textconv.sh
+++ b/t/t8007-cat-file-textconv.sh
@@ -19,6 +19,48 @@ test_expect_success 'setup ' '
GIT_AUTHOR_NAME=Number2 git commit -a -m Second --date="2010-01-01 20:00:00"
'
+test_expect_success 'usage: <bad rev>' '
+ cat >expect <<-\EOF &&
+ fatal: Not a valid object name HEAD2
+ EOF
+ test_must_fail git cat-file --textconv HEAD2 2>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'usage: <bad rev>:<bad path>' '
+ cat >expect <<-\EOF &&
+ fatal: invalid object name '\''HEAD2'\''.
+ EOF
+ test_must_fail git cat-file --textconv HEAD2:two.bin 2>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'usage: <rev>:<bad path>' '
+ cat >expect <<-\EOF &&
+ fatal: path '\''two.bin'\'' does not exist in '\''HEAD'\''
+ EOF
+ test_must_fail git cat-file --textconv HEAD:two.bin 2>actual &&
+ test_cmp expect actual
+'
+
+
+test_expect_success 'usage: <rev> with no <path>' '
+ cat >expect <<-\EOF &&
+ fatal: <object>:<path> required, only <object> '\''HEAD'\'' given
+ EOF
+ test_must_fail git cat-file --textconv HEAD 2>actual &&
+ test_cmp expect actual
+'
+
+
+test_expect_success 'usage: <bad rev>:<good (in HEAD) path>' '
+ cat >expect <<-\EOF &&
+ fatal: invalid object name '\''HEAD2'\''.
+ EOF
+ test_must_fail git cat-file --textconv HEAD2:one.bin 2>actual &&
+ test_cmp expect actual
+'
+
cat >expected <<EOF
bin: test version 2
EOF
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index aa0c204..42694fe 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -539,7 +539,7 @@ test_expect_success $PREREQ "--validate respects relative core.hooksPath path" '
test_path_is_file my-hooks.ran &&
cat >expect <<-EOF &&
fatal: longline.patch: rejected by sendemail-validate hook
- fatal: command '"'"'my-hooks/sendemail-validate'"'"' died with exit code 1
+ fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
warning: no patches were sent
EOF
test_cmp expect actual
@@ -558,7 +558,7 @@ test_expect_success $PREREQ "--validate respects absolute core.hooksPath path" '
test_path_is_file my-hooks.ran &&
cat >expect <<-EOF &&
fatal: longline.patch: rejected by sendemail-validate hook
- fatal: command '"'"'$hooks_path/sendemail-validate'"'"' died with exit code 1
+ fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
warning: no patches were sent
EOF
test_cmp expect actual
@@ -2288,9 +2288,7 @@ test_expect_success $PREREQ 'cmdline in-reply-to used with --no-thread' '
'
test_expect_success $PREREQ 'invoke hook' '
- mkdir -p .git/hooks &&
-
- write_script .git/hooks/sendemail-validate <<-\EOF &&
+ test_hook sendemail-validate <<-\EOF &&
# test that we have the correct environment variable, pwd, and
# argument
case "$GIT_DIR" in
diff --git a/t/t9102-git-svn-deep-rmdir.sh b/t/t9102-git-svn-deep-rmdir.sh
index 7b2049c..946ef85 100755
--- a/t/t9102-git-svn-deep-rmdir.sh
+++ b/t/t9102-git-svn-deep-rmdir.sh
@@ -1,7 +1,6 @@
#!/bin/sh
test_description='git svn rmdir'
-TEST_PASSES_SANITIZE_LEAK=true
. ./lib-git-svn.sh
test_expect_success 'initialize repo' '
diff --git a/t/t9123-git-svn-rebuild-with-rewriteroot.sh b/t/t9123-git-svn-rebuild-with-rewriteroot.sh
index 3320b1f..ead4045 100755
--- a/t/t9123-git-svn-rebuild-with-rewriteroot.sh
+++ b/t/t9123-git-svn-rebuild-with-rewriteroot.sh
@@ -5,7 +5,6 @@
test_description='git svn respects rewriteRoot during rebuild'
-TEST_PASSES_SANITIZE_LEAK=true
. ./lib-git-svn.sh
mkdir import
diff --git a/t/t9128-git-svn-cmd-branch.sh b/t/t9128-git-svn-cmd-branch.sh
index 9871f5a..783e3ba 100755
--- a/t/t9128-git-svn-cmd-branch.sh
+++ b/t/t9128-git-svn-cmd-branch.sh
@@ -5,7 +5,6 @@
test_description='git svn partial-rebuild tests'
-TEST_PASSES_SANITIZE_LEAK=true
. ./lib-git-svn.sh
test_expect_success 'initialize svnrepo' '
diff --git a/t/t9167-git-svn-cmd-branch-subproject.sh b/t/t9167-git-svn-cmd-branch-subproject.sh
index d9fd111..d812843 100755
--- a/t/t9167-git-svn-cmd-branch-subproject.sh
+++ b/t/t9167-git-svn-cmd-branch-subproject.sh
@@ -5,7 +5,6 @@
test_description='git svn branch for subproject clones'
-TEST_PASSES_SANITIZE_LEAK=true
. ./lib-git-svn.sh
test_expect_success 'initialize svnrepo' '
diff --git a/t/t9502-gitweb-standalone-parse-output.sh b/t/t9502-gitweb-standalone-parse-output.sh
index 3167473..8cb582f 100755
--- a/t/t9502-gitweb-standalone-parse-output.sh
+++ b/t/t9502-gitweb-standalone-parse-output.sh
@@ -34,7 +34,7 @@ EOF
#
# This will check that gitweb HTTP header contains proposed filename
# as <basename> with '.tar' suffix added, and that generated tarfile
-# (gitweb message body) has <prefix> as prefix for al files in tarfile
+# (gitweb message body) has <prefix> as prefix for all files in tarfile
#
# <prefix> default to <basename>
check_snapshot () {
@@ -207,4 +207,17 @@ test_expect_success 'xss checks' '
xss "" "$TAG+"
'
+no_http_equiv_content_type() {
+ gitweb_run "$@" &&
+ ! grep -E "http-equiv=['\"]?content-type" gitweb.body
+}
+
+# See: <https://html.spec.whatwg.org/dev/semantics.html#attr-meta-http-equiv-content-type>
+test_expect_success 'no http-equiv="content-type" in XHTML' '
+ no_http_equiv_content_type &&
+ no_http_equiv_content_type "p=.git" &&
+ no_http_equiv_content_type "p=.git;a=log" &&
+ no_http_equiv_content_type "p=.git;a=tree"
+'
+
test_done
diff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh
index 806005a..8b30062 100755
--- a/t/t9800-git-p4-basic.sh
+++ b/t/t9800-git-p4-basic.sh
@@ -277,16 +277,21 @@ test_expect_success 'run hook p4-pre-submit before submit' '
git commit -m "add hello.txt" &&
git config git-p4.skipSubmitEdit true &&
git p4 submit --dry-run >out &&
- grep "Would apply" out &&
- mkdir -p .git/hooks &&
- write_script .git/hooks/p4-pre-submit <<-\EOF &&
- exit 0
- EOF
+ grep "Would apply" out
+ ) &&
+ test_hook -C "$git" p4-pre-submit <<-\EOF &&
+ exit 0
+ EOF
+ (
+ cd "$git" &&
git p4 submit --dry-run >out &&
- grep "Would apply" out &&
- write_script .git/hooks/p4-pre-submit <<-\EOF &&
- exit 1
- EOF
+ grep "Would apply" out
+ ) &&
+ test_hook -C "$git" --clobber p4-pre-submit <<-\EOF &&
+ exit 1
+ EOF
+ (
+ cd "$git" &&
test_must_fail git p4 submit --dry-run >errs 2>&1 &&
! grep "Would apply" errs
)
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 89705ea..31526e6 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -2551,27 +2551,33 @@ test_expect_success 'options with value' '
'
test_expect_success 'sourcing the completion script clears cached commands' '
- __git_compute_all_commands &&
- verbose test -n "$__git_all_commands" &&
- . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
- verbose test -z "$__git_all_commands"
+ (
+ __git_compute_all_commands &&
+ verbose test -n "$__git_all_commands" &&
+ . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
+ verbose test -z "$__git_all_commands"
+ )
'
test_expect_success 'sourcing the completion script clears cached merge strategies' '
- __git_compute_merge_strategies &&
- verbose test -n "$__git_merge_strategies" &&
- . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
- verbose test -z "$__git_merge_strategies"
+ (
+ __git_compute_merge_strategies &&
+ verbose test -n "$__git_merge_strategies" &&
+ . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
+ verbose test -z "$__git_merge_strategies"
+ )
'
test_expect_success 'sourcing the completion script clears cached --options' '
- __gitcomp_builtin checkout &&
- verbose test -n "$__gitcomp_builtin_checkout" &&
- __gitcomp_builtin notes_edit &&
- verbose test -n "$__gitcomp_builtin_notes_edit" &&
- . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
- verbose test -z "$__gitcomp_builtin_checkout" &&
- verbose test -z "$__gitcomp_builtin_notes_edit"
+ (
+ __gitcomp_builtin checkout &&
+ verbose test -n "$__gitcomp_builtin_checkout" &&
+ __gitcomp_builtin notes_edit &&
+ verbose test -n "$__gitcomp_builtin_notes_edit" &&
+ . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
+ verbose test -z "$__gitcomp_builtin_checkout" &&
+ verbose test -z "$__gitcomp_builtin_notes_edit"
+ )
'
test_expect_success 'option aliases are not shown by default' '
@@ -2579,12 +2585,45 @@ test_expect_success 'option aliases are not shown by default' '
'
test_expect_success 'option aliases are shown with GIT_COMPLETION_SHOW_ALL' '
- . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
- GIT_COMPLETION_SHOW_ALL=1 && export GIT_COMPLETION_SHOW_ALL &&
- test_completion "git clone --recurs" <<-\EOF
- --recurse-submodules Z
- --recursive Z
- EOF
+ (
+ . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
+ GIT_COMPLETION_SHOW_ALL=1 && export GIT_COMPLETION_SHOW_ALL &&
+ test_completion "git clone --recurs" <<-\EOF
+ --recurse-submodules Z
+ --recursive Z
+ EOF
+ )
+'
+
+test_expect_success 'plumbing commands are excluded without GIT_COMPLETION_SHOW_ALL_COMMANDS' '
+ (
+ . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
+ sane_unset GIT_TESTING_PORCELAIN_COMMAND_LIST &&
+
+ # Just mainporcelain, not plumbing commands
+ run_completion "git c" &&
+ grep checkout out &&
+ ! grep cat-file out
+ )
+'
+
+test_expect_success 'all commands are shown with GIT_COMPLETION_SHOW_ALL_COMMANDS (also main non-builtin)' '
+ (
+ . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
+ GIT_COMPLETION_SHOW_ALL_COMMANDS=1 &&
+ export GIT_COMPLETION_SHOW_ALL_COMMANDS &&
+ sane_unset GIT_TESTING_PORCELAIN_COMMAND_LIST &&
+
+ # Both mainporcelain and plumbing commands
+ run_completion "git c" &&
+ grep checkout out &&
+ grep cat-file out &&
+
+ # Check "gitk", a "main" command, but not a built-in + more plumbing
+ run_completion "git g" &&
+ grep gitk out &&
+ grep get-tar-commit-id out
+ )
'
test_expect_success '__git_complete' '
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index c3d38aa..93c0338 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -329,7 +329,7 @@ test_commit () {
else
$echo "${3-$1}" >"$indir$file"
fi &&
- git ${indir:+ -C "$indir"} add "$file" &&
+ git ${indir:+ -C "$indir"} add -- "$file" &&
if test -z "$notick"
then
test_tick
@@ -551,6 +551,82 @@ write_script () {
chmod +x "$1"
}
+# Usage: test_hook [options] <hook-name> <<-\EOF
+#
+# -C <dir>:
+# Run all git commands in directory <dir>
+# --setup
+# Setup a hook for subsequent tests, i.e. don't remove it in a
+# "test_when_finished"
+# --clobber
+# Overwrite an existing <hook-name>, if it exists. Implies
+# --setup (i.e. the "test_when_finished" is assumed to have been
+# set up already).
+# --disable
+# Disable (chmod -x) an existing <hook-name>, which must exist.
+# --remove
+# Remove (rm -f) an existing <hook-name>, which must exist.
+test_hook () {
+ setup= &&
+ clobber= &&
+ disable= &&
+ remove= &&
+ indir= &&
+ while test $# != 0
+ do
+ case "$1" in
+ -C)
+ indir="$2" &&
+ shift
+ ;;
+ --setup)
+ setup=t
+ ;;
+ --clobber)
+ clobber=t
+ ;;
+ --disable)
+ disable=t
+ ;;
+ --remove)
+ remove=t
+ ;;
+ -*)
+ BUG "invalid argument: $1"
+ ;;
+ *)
+ break
+ ;;
+ esac &&
+ shift
+ done &&
+
+ git_dir=$(git -C "$indir" rev-parse --absolute-git-dir) &&
+ hook_dir="$git_dir/hooks" &&
+ hook_file="$hook_dir/$1" &&
+ if test -n "$disable$remove"
+ then
+ test_path_is_file "$hook_file" &&
+ if test -n "$disable"
+ then
+ chmod -x "$hook_file"
+ elif test -n "$remove"
+ then
+ rm -f "$hook_file"
+ fi &&
+ return 0
+ fi &&
+ if test -z "$clobber"
+ then
+ test_path_is_missing "$hook_file"
+ fi &&
+ if test -z "$setup$clobber"
+ then
+ test_when_finished "rm \"$hook_file\""
+ fi &&
+ write_script "$hook_file"
+}
+
# Use test_set_prereq to tell that a particular prerequisite is available.
# The prerequisite can later be checked for in two ways:
#
@@ -856,6 +932,16 @@ test_path_is_file () {
fi
}
+test_path_is_file_not_symlink () {
+ test "$#" -ne 1 && BUG "1 param"
+ test_path_is_file "$1" &&
+ if test -h "$1"
+ then
+ echo "$1 shouldn't be a symbolic link"
+ false
+ fi
+}
+
test_path_is_dir () {
test "$#" -ne 1 && BUG "1 param"
if ! test -d "$1"
@@ -865,6 +951,16 @@ test_path_is_dir () {
fi
}
+test_path_is_dir_not_symlink () {
+ test "$#" -ne 1 && BUG "1 param"
+ test_path_is_dir "$1" &&
+ if test -h "$1"
+ then
+ echo "$1 shouldn't be a symbolic link"
+ false
+ fi
+}
+
test_path_exists () {
test "$#" -ne 1 && BUG "1 param"
if ! test -e "$1"
@@ -874,6 +970,15 @@ test_path_exists () {
fi
}
+test_path_is_symlink () {
+ test "$#" -ne 1 && BUG "1 param"
+ if ! test -h "$1"
+ then
+ echo "Symbolic link $1 doesn't exist"
+ false
+ fi
+}
+
# Check if the directory exists and is empty as expected, barf otherwise.
test_dir_is_empty () {
test "$#" -ne 1 && BUG "1 param"
@@ -1760,40 +1865,6 @@ test_subcommand () {
}
# Check that the given command was invoked as part of the
-# trace2-format trace on stdin, but without an exact set of
-# arguments.
-#
-# test_subcommand [!] <command> <args>... < <trace>
-#
-# For example, to look for an invocation of "git pack-objects"
-# with the "--honor-pack-keep" argument, use
-#
-# GIT_TRACE2_EVENT=event.log git repack ... &&
-# test_subcommand git pack-objects --honor-pack-keep <event.log
-#
-# If the first parameter passed is !, this instead checks that
-# the given command was not called.
-#
-test_subcommand_inexact () {
- local negate=
- if test "$1" = "!"
- then
- negate=t
- shift
- fi
-
- local expr=$(printf '"%s".*' "$@")
- expr="${expr%,}"
-
- if test -n "$negate"
- then
- ! grep "\"event\":\"child_start\".*\[$expr\]"
- else
- grep "\"event\":\"child_start\".*\[$expr\]"
- fi
-}
-
-# Check that the given command was invoked as part of the
# trace2-format trace on stdin.
#
# test_region [!] <category> <label> git <command> <args>...
@@ -1840,3 +1911,36 @@ test_region () {
test_readlink () {
perl -le 'print readlink($_) for @ARGV' "$@"
}
+
+# Set mtime to a fixed "magic" timestamp in mid February 2009, before we
+# run an operation that may or may not touch the file. If the file was
+# touched, its timestamp will not accidentally have such an old timestamp,
+# as long as your filesystem clock is reasonably correct. To verify the
+# timestamp, follow up with test_is_magic_mtime.
+#
+# An optional increment to the magic timestamp may be specified as second
+# argument.
+test_set_magic_mtime () {
+ local inc=${2:-0} &&
+ local mtime=$((1234567890 + $inc)) &&
+ test-tool chmtime =$mtime "$1" &&
+ test_is_magic_mtime "$1" $inc
+}
+
+# Test whether the given file has the "magic" mtime set. This is meant to
+# be used in combination with test_set_magic_mtime.
+#
+# An optional increment to the magic timestamp may be specified as second
+# argument. Usually, this should be the same increment which was used for
+# the associated test_set_magic_mtime.
+test_is_magic_mtime () {
+ local inc=${2:-0} &&
+ local mtime=$((1234567890 + $inc)) &&
+ echo $mtime >.git/test-mtime-expect &&
+ test-tool chmtime --get "$1" >.git/test-mtime-actual &&
+ test_cmp .git/test-mtime-expect .git/test-mtime-actual
+ local ret=$?
+ rm -f .git/test-mtime-expect
+ rm -f .git/test-mtime-actual
+ return $ret
+}
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 0f7a137..531cef0 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -19,13 +19,20 @@
# t/ subdirectory and are run in 'trash directory' subdirectory.
if test -z "$TEST_DIRECTORY"
then
- # We allow tests to override this, in case they want to run tests
- # outside of t/, e.g. for running tests on the test library
- # itself.
- TEST_DIRECTORY=$(pwd)
-else
# ensure that TEST_DIRECTORY is an absolute path so that it
# is valid even if the current working directory is changed
+ TEST_DIRECTORY=$(pwd)
+else
+ # The TEST_DIRECTORY will always be the path to the "t"
+ # directory in the git.git checkout. This is overridden by
+ # e.g. t/lib-subtest.sh, but only because its $(pwd) is
+ # different. Those tests still set "$TEST_DIRECTORY" to the
+ # same path.
+ #
+ # See use of "$GIT_BUILD_DIR" and "$TEST_DIRECTORY" below for
+ # hard assumptions about "$GIT_BUILD_DIR/t" existing and being
+ # the "$TEST_DIRECTORY", and e.g. "$TEST_DIRECTORY/helper"
+ # needing to exist.
TEST_DIRECTORY=$(cd "$TEST_DIRECTORY" && pwd) || exit 1
fi
if test -z "$TEST_OUTPUT_DIRECTORY"
@@ -34,19 +41,42 @@ then
# elsewhere
TEST_OUTPUT_DIRECTORY=$TEST_DIRECTORY
fi
-GIT_BUILD_DIR="$TEST_DIRECTORY"/..
+GIT_BUILD_DIR="${TEST_DIRECTORY%/t}"
+if test "$TEST_DIRECTORY" = "$GIT_BUILD_DIR"
+then
+ echo "PANIC: Running in a $TEST_DIRECTORY that doesn't end in '/t'?" >&2
+ exit 1
+fi
+
+# Prepend a string to a VAR using an arbitrary ":" delimiter, not
+# adding the delimiter if VAR or VALUE is empty. I.e. a generalized:
+#
+# VAR=$1${VAR:+${1:+$2}$VAR}
+#
+# Usage (using ":" as the $2 delimiter):
+#
+# prepend_var VAR : VALUE
+prepend_var () {
+ eval "$1=$3\${$1:+${3:+$2}\$$1}"
+}
+
+# If [AL]SAN is in effect we want to abort so that we notice
+# problems. The GIT_SAN_OPTIONS variable can be used to set common
+# defaults shared between [AL]SAN_OPTIONS.
+prepend_var GIT_SAN_OPTIONS : abort_on_error=1
+prepend_var GIT_SAN_OPTIONS : strip_path_prefix=\"$GIT_BUILD_DIR/\"
# If we were built with ASAN, it may complain about leaks
# of program-lifetime variables. Disable it by default to lower
# the noise level. This needs to happen at the start of the script,
# before we even do our "did we build git yet" check (since we don't
# want that one to complain to stderr).
-: ${ASAN_OPTIONS=detect_leaks=0:abort_on_error=1}
+prepend_var ASAN_OPTIONS : $GIT_SAN_OPTIONS
+prepend_var ASAN_OPTIONS : detect_leaks=0
export ASAN_OPTIONS
-# If LSAN is in effect we _do_ want leak checking, but we still
-# want to abort so that we notice the problems.
-: ${LSAN_OPTIONS=abort_on_error=1}
+prepend_var LSAN_OPTIONS : $GIT_SAN_OPTIONS
+prepend_var LSAN_OPTIONS : fast_unwind_on_malloc=0
export LSAN_OPTIONS
if test ! -f "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS
@@ -449,6 +479,8 @@ unset VISUAL EMAIL LANGUAGE $("$PERL_PATH" -e '
unset XDG_CACHE_HOME
unset XDG_CONFIG_HOME
unset GITPERLLIB
+unset GIT_TRACE2_PARENT_NAME
+unset GIT_TRACE2_PARENT_SID
TEST_AUTHOR_LOCALNAME=author
TEST_AUTHOR_DOMAIN=example.com
GIT_AUTHOR_EMAIL=${TEST_AUTHOR_LOCALNAME}@${TEST_AUTHOR_DOMAIN}
@@ -516,11 +548,29 @@ then
}
else
setup_malloc_check () {
+ local g
+ local t
MALLOC_CHECK_=3 MALLOC_PERTURB_=165
export MALLOC_CHECK_ MALLOC_PERTURB_
+ if _GLIBC_VERSION=$(getconf GNU_LIBC_VERSION 2>/dev/null) &&
+ _GLIBC_VERSION=${_GLIBC_VERSION#"glibc "} &&
+ expr 2.34 \<= "$_GLIBC_VERSION" >/dev/null
+ then
+ g=
+ LD_PRELOAD="libc_malloc_debug.so.0"
+ for t in \
+ glibc.malloc.check=1 \
+ glibc.malloc.perturb=165
+ do
+ g="${g#:}:$t"
+ done
+ GLIBC_TUNABLES=$g
+ export LD_PRELOAD GLIBC_TUNABLES
+ fi
}
teardown_malloc_check () {
unset MALLOC_CHECK_ MALLOC_PERTURB_
+ unset LD_PRELOAD GLIBC_TUNABLES
}
fi
@@ -756,7 +806,11 @@ test_failure_ () {
say_color error "not ok $test_count - $1"
shift
printf '%s\n' "$*" | sed -e 's/^/# /'
- test "$immediate" = "" || _error_exit
+ if test -n "$immediate"
+ then
+ say_color error "1..$test_count"
+ _error_exit
+ fi
}
test_known_broken_ok_ () {
@@ -1797,3 +1851,10 @@ test_lazy_prereq SHA1 '
# Tests that verify the scheduler integration must set this locally
# to avoid errors.
GIT_TEST_MAINT_SCHEDULER="none:exit 1"
+
+# Does this platform support `git fsmonitor--daemon`
+#
+test_lazy_prereq FSMONITOR_DAEMON '
+ git version --build-options >output &&
+ grep "feature: fsmonitor--daemon" output
+'