summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/RelNotes/2.36.0.txt4
-rw-r--r--Documentation/config.txt2
-rw-r--r--Documentation/config/advice.txt8
-rw-r--r--Documentation/config/reset.txt2
-rw-r--r--Documentation/git-bundle.txt10
-rw-r--r--Documentation/git-ls-tree.txt68
-rw-r--r--Documentation/git-reset.txt9
-rw-r--r--advice.c2
-rw-r--r--advice.h2
-rw-r--r--branch.c47
-rw-r--r--builtin/fetch-pack.c4
-rw-r--r--builtin/ls-tree.c366
-rw-r--r--builtin/pack-objects.c55
-rw-r--r--builtin/reflog.c146
-rw-r--r--builtin/reset.c13
-rw-r--r--builtin/stash.c5
-rw-r--r--builtin/submodule--helper.c698
-rw-r--r--builtin/worktree.c1
-rw-r--r--bundle.c11
-rw-r--r--cache.h4
-rw-r--r--commit.c1
-rw-r--r--compat/terminal.c238
-rw-r--r--compat/terminal.h9
-rw-r--r--config.c2
-rw-r--r--contrib/coccinelle/strbuf.cocci6
-rw-r--r--contrib/completion/git-prompt.sh59
-rw-r--r--contrib/scalar/scalar.c1
-rwxr-xr-xgit-submodule.sh105
-rw-r--r--list-objects-filter-options.c4
-rw-r--r--list-objects-filter-options.h27
-rw-r--r--object-file.c8
-rw-r--r--reflog.c20
-rw-r--r--reftable/generic.c8
-rw-r--r--reftable/record_test.c4
-rw-r--r--reftable/writer.c12
-rw-r--r--revision.c4
-rw-r--r--shared.mak2
-rwxr-xr-xt/t0000-basic.sh13
-rwxr-xr-xt/t0029-core-unsetenvvars.sh3
-rwxr-xr-xt/t0091-bugreport.sh26
-rwxr-xr-xt/t1350-config-hooks-path.sh4
-rwxr-xr-xt/t1410-reflog.sh22
-rwxr-xr-xt/t1411-reflog-show.sh5
-rwxr-xr-xt/t1416-ref-transaction-hooks.sh27
-rwxr-xr-xt/t1418-reflog-exists.sh37
-rwxr-xr-xt/t1800-hook.sh45
-rwxr-xr-xt/t2400-worktree-add.sh5
-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/t3207-branch-submodule.sh38
-rwxr-xr-xt/t3404-rebase-interactive.sh10
-rwxr-xr-xt/t3412-rebase-root.sh18
-rwxr-xr-xt/t3413-rebase-hook.sh18
-rwxr-xr-xt/t3430-rebase-merges.sh6
-rwxr-xr-xt/t3903-stash.sh33
-rwxr-xr-xt/t4150-am.sh24
-rwxr-xr-xt/t5401-update-hooks.sh64
-rwxr-xr-xt/t5402-post-merge-hook.sh16
-rwxr-xr-xt/t5403-post-checkout-hook.sh3
-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/t5503-tagfollow.sh4
-rwxr-xr-xt/t5510-fetch.sh8
-rwxr-xr-xt/t5516-fetch-push.sh192
-rwxr-xr-xt/t5521-pull-options.sh4
-rwxr-xr-xt/t5534-push-signed.sh26
-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.sh38
-rwxr-xr-xt/t5601-clone.sh4
-rwxr-xr-xt/t6020-bundle-misc.sh26
-rwxr-xr-xt/t6500-gc.sh22
-rwxr-xr-xt/t7102-reset.sh40
-rwxr-xr-xt/t7113-post-index-change-hook.sh7
-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/t7519-status-fsmonitor.sh20
-rwxr-xr-xt/t7520-ignored-hook-warning.sh11
-rwxr-xr-xt/t7700-repack.sh57
-rwxr-xr-xt/t9001-send-email.sh4
-rwxr-xr-xt/t9800-git-p4-basic.sh23
-rw-r--r--t/test-lib-functions.sh112
-rw-r--r--t/test-lib.sh6
117 files changed, 2195 insertions, 1412 deletions
diff --git a/Documentation/RelNotes/2.36.0.txt b/Documentation/RelNotes/2.36.0.txt
index c4ca105e3c..ffabec17b5 100644
--- a/Documentation/RelNotes/2.36.0.txt
+++ b/Documentation/RelNotes/2.36.0.txt
@@ -84,6 +84,10 @@ UI, Workflows & Features
age-old "update-server-info" command, which is rarely useful these
days.
+ * "git stash" does not allow subcommands it internally runs as its
+ implementation detail, except for "git reset", to emit messages;
+ now "git reset" part has also been squelched.
+
Performance, Internal Implementation, Development Support etc.
diff --git a/Documentation/config.txt b/Documentation/config.txt
index f0fb25a371..43f5e6fd6d 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -495,8 +495,6 @@ include::config/repack.txt[]
include::config/rerere.txt[]
-include::config/reset.txt[]
-
include::config/sendemail.txt[]
include::config/sequencer.txt[]
diff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt
index c40eb09cb7..83c2a95661 100644
--- a/Documentation/config/advice.txt
+++ b/Documentation/config/advice.txt
@@ -67,10 +67,10 @@ advice.*::
commitBeforeMerge::
Advice shown when linkgit:git-merge[1] refuses to
merge to avoid overwriting local changes.
- resetQuiet::
- Advice to consider using the `--quiet` option to linkgit:git-reset[1]
- when the command takes more than 2 seconds to enumerate unstaged
- changes after reset.
+ resetNoRefresh::
+ Advice to consider using the `--no-refresh` option to
+ linkgit:git-reset[1] when the command takes more than 2 seconds
+ to refresh the index after reset.
resolveConflict::
Advice shown by various commands when conflicts
prevent the operation from being performed.
diff --git a/Documentation/config/reset.txt b/Documentation/config/reset.txt
deleted file mode 100644
index 63b7c45aac..0000000000
--- a/Documentation/config/reset.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-reset.quiet::
- When set to true, 'git reset' will default to the '--quiet' option.
diff --git a/Documentation/git-bundle.txt b/Documentation/git-bundle.txt
index ac4c4352aa..7685b57045 100644
--- a/Documentation/git-bundle.txt
+++ b/Documentation/git-bundle.txt
@@ -75,11 +75,11 @@ verify <file>::
cleanly to the current repository. This includes checks on the
bundle format itself as well as checking that the prerequisite
commits exist and are fully linked in the current repository.
- Information about additional capabilities, such as "object filter",
- is printed. See "Capabilities" in link:technical/bundle-format.html
- for more information. Finally, 'git bundle' prints a list of
- missing commits, if any. The exit code is zero for success, but
- will be nonzero if the bundle file is invalid.
+ Then, 'git bundle' prints a list of missing commits, if any.
+ Finally, information about additional capabilities, such as "object
+ filter", is printed. See "Capabilities" in link:technical/bundle-format.html
+ for more information. The exit code is zero for success, but will
+ be nonzero if the bundle file is invalid.
list-heads <file>::
Lists the references defined in the bundle. If followed by a
diff --git a/Documentation/git-ls-tree.txt b/Documentation/git-ls-tree.txt
index db02d6d79a..43aebb9938 100644
--- a/Documentation/git-ls-tree.txt
+++ b/Documentation/git-ls-tree.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git ls-tree' [-d] [-r] [-t] [-l] [-z]
- [--name-only] [--name-status] [--full-name] [--full-tree] [--abbrev[=<n>]]
+ [--name-only] [--name-status] [--object-only] [--full-name] [--full-tree] [--abbrev[=<n>]] [--format=<format>]
<tree-ish> [<path>...]
DESCRIPTION
@@ -59,6 +59,15 @@ OPTIONS
--name-only::
--name-status::
List only filenames (instead of the "long" output), one per line.
+ Cannot be combined with `--object-only`.
+
+--object-only::
+ List only names of the objects, one per line. Cannot be combined
+ with `--name-only` or `--name-status`.
+ This is equivalent to specifying `--format='%(objectname)'`, but
+ for both this option and that exact format the command takes a
+ hand-optimized codepath instead of going through the generic
+ formatting mechanism.
--abbrev[=<n>]::
Instead of showing the full 40-byte hexadecimal object
@@ -74,6 +83,16 @@ OPTIONS
Do not limit the listing to the current working directory.
Implies --full-name.
+--format=<format>::
+ A string that interpolates `%(fieldname)` from the result
+ being shown. It also interpolates `%%` to `%`, and
+ `%xx` where `xx` are hex digits interpolates to character
+ with hex code `xx`; for example `%00` interpolates to
+ `\0` (NUL), `%09` to `\t` (TAB) and `%0a` to `\n` (LF).
+ When specified, `--format` cannot be combined with other
+ format-altering options, including `--long`, `--name-only`
+ and `--object-only`.
+
[<path>...]::
When paths are given, show them (note that this isn't really raw
pathnames, but rather a list of patterns to match). Otherwise
@@ -82,16 +101,29 @@ OPTIONS
Output Format
-------------
- <mode> SP <type> SP <object> TAB <file>
+
+The output format of `ls-tree` is determined by either the `--format`
+option, or other format-altering options such as `--name-only` etc.
+(see `--format` above).
+
+The use of certain `--format` directives is equivalent to using those
+options, but invoking the full formatting machinery can be slower than
+using an appropriate formatting option.
+
+In cases where the `--format` would exactly map to an existing option
+`ls-tree` will use the appropriate faster path. Thus the default format
+is equivalent to:
+
+ %(objectmode) %(objecttype) %(objectname)%x09%(path)
This output format is compatible with what `--index-info --stdin` of
'git update-index' expects.
When the `-l` option is used, format changes to
- <mode> SP <type> SP <object> SP <object size> TAB <file>
+ %(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)
-Object size identified by <object> is given in bytes, and right-justified
+Object size identified by <objectname> is given in bytes, and right-justified
with minimum width of 7 characters. Object size is given only for blobs
(file) entries; for other entries `-` character is used in place of size.
@@ -100,6 +132,34 @@ quoted as explained for the configuration variable `core.quotePath`
(see linkgit:git-config[1]). Using `-z` the filename is output
verbatim and the line is terminated by a NUL byte.
+Customized format:
+
+It is possible to print in a custom format by using the `--format` option,
+which is able to interpolate different fields using a `%(fieldname)` notation.
+For example, if you only care about the "objectname" and "path" fields, you
+can execute with a specific "--format" like
+
+ git ls-tree --format='%(objectname) %(path)' <tree-ish>
+
+FIELD NAMES
+-----------
+
+Various values from structured fields can be used to interpolate
+into the resulting output. For each outputing line, the following
+names can be used:
+
+objectmode::
+ The mode of the object.
+objecttype::
+ The type of the object (`blob` or `tree`).
+objectname::
+ The name of the object.
+objectsize[:padded]::
+ The size of the object ("-" if it's a tree).
+ It also supports a padded format of size with "%(size:padded)".
+path::
+ The pathname of the object.
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt
index 6f7685f53d..01cb4c9b9c 100644
--- a/Documentation/git-reset.txt
+++ b/Documentation/git-reset.txt
@@ -105,10 +105,11 @@ OPTIONS
-q::
--quiet::
---no-quiet::
- Be quiet, only report errors. The default behavior is set by the
- `reset.quiet` config option. `--quiet` and `--no-quiet` will
- override the default behavior.
+ Be quiet, only report errors.
+
+--refresh::
+--no-refresh::
+ Refresh the index after a mixed reset. Enabled by default.
--pathspec-from-file=<file>::
Pathspec is passed in `<file>` instead of commandline args. If
diff --git a/advice.c b/advice.c
index 2e1fd48304..cb755c551a 100644
--- a/advice.c
+++ b/advice.c
@@ -61,7 +61,7 @@ static struct {
[ADVICE_PUSH_NON_FF_MATCHING] = { "pushNonFFMatching", 1 },
[ADVICE_PUSH_UNQUALIFIED_REF_NAME] = { "pushUnqualifiedRefName", 1 },
[ADVICE_PUSH_UPDATE_REJECTED] = { "pushUpdateRejected", 1 },
- [ADVICE_RESET_QUIET_WARNING] = { "resetQuiet", 1 },
+ [ADVICE_RESET_NO_REFRESH_WARNING] = { "resetNoRefresh", 1 },
[ADVICE_RESOLVE_CONFLICT] = { "resolveConflict", 1 },
[ADVICE_RM_HINTS] = { "rmHints", 1 },
[ADVICE_SEQUENCER_IN_USE] = { "sequencerInUse", 1 },
diff --git a/advice.h b/advice.h
index a3957123a1..f95af70ced 100644
--- a/advice.h
+++ b/advice.h
@@ -36,7 +36,7 @@ struct string_list;
ADVICE_PUSH_UPDATE_REJECTED_ALIAS,
ADVICE_PUSH_UPDATE_REJECTED,
ADVICE_PUSH_REF_NEEDS_UPDATE,
- ADVICE_RESET_QUIET_WARNING,
+ ADVICE_RESET_NO_REFRESH_WARNING,
ADVICE_RESOLVE_CONFLICT,
ADVICE_RM_HINTS,
ADVICE_SEQUENCER_IN_USE,
diff --git a/branch.c b/branch.c
index 6b31df539a..581afd634d 100644
--- a/branch.c
+++ b/branch.c
@@ -233,6 +233,9 @@ static void setup_tracking(const char *new_ref, const char *orig_ref,
struct string_list tracking_srcs = STRING_LIST_INIT_DUP;
int config_flags = quiet ? 0 : BRANCH_CONFIG_VERBOSE;
+ if (!track)
+ BUG("asked to set up tracking, but tracking is disallowed");
+
memset(&tracking, 0, sizeof(tracking));
tracking.spec.dst = (char *)orig_ref;
tracking.srcs = &tracking_srcs;
@@ -260,7 +263,7 @@ static void setup_tracking(const char *new_ref, const char *orig_ref,
string_list_append(tracking.srcs, orig_ref);
if (install_branch_config_multiple_remotes(config_flags, new_ref,
tracking.remote, tracking.srcs) < 0)
- exit(-1);
+ exit(1);
cleanup:
string_list_clear(&tracking_srcs, 0);
@@ -385,12 +388,10 @@ static void dwim_branch_start(struct repository *r, const char *start_name,
real_ref = NULL;
if (get_oid_mb(start_name, &oid)) {
if (explicit_tracking) {
- if (advice_enabled(ADVICE_SET_UPSTREAM_FAILURE)) {
- error(_(upstream_missing), start_name);
- advise(_(upstream_advice));
- exit(1);
- }
- die(_(upstream_missing), start_name);
+ int code = die_message(_(upstream_missing), start_name);
+ advise_if_enabled(ADVICE_SET_UPSTREAM_FAILURE,
+ _(upstream_advice));
+ exit(code);
}
die(_("not a valid object name: '%s'"), start_name);
}
@@ -534,8 +535,27 @@ static int submodule_create_branch(struct repository *r,
strvec_push(&child.args, "--quiet");
if (reflog)
strvec_push(&child.args, "--create-reflog");
- if (track == BRANCH_TRACK_ALWAYS || track == BRANCH_TRACK_EXPLICIT)
- strvec_push(&child.args, "--track");
+
+ switch (track) {
+ case BRANCH_TRACK_NEVER:
+ strvec_push(&child.args, "--no-track");
+ break;
+ case BRANCH_TRACK_ALWAYS:
+ case BRANCH_TRACK_EXPLICIT:
+ strvec_push(&child.args, "--track=direct");
+ break;
+ case BRANCH_TRACK_OVERRIDE:
+ BUG("BRANCH_TRACK_OVERRIDE cannot be used when creating a branch.");
+ break;
+ case BRANCH_TRACK_INHERIT:
+ strvec_push(&child.args, "--track=inherit");
+ break;
+ case BRANCH_TRACK_UNSPECIFIED:
+ /* Default for "git checkout". Do not pass --track. */
+ case BRANCH_TRACK_REMOTE:
+ /* Default for "git branch". Do not pass --track. */
+ break;
+ }
strvec_pushl(&child.args, name, start_oid, tracking_name, NULL);
@@ -585,11 +605,13 @@ void create_branches_recursively(struct repository *r, const char *name,
*/
for (i = 0; i < submodule_entry_list.entry_nr; i++) {
if (submodule_entry_list.entries[i].repo == NULL) {
+ int code = die_message(
+ _("submodule '%s': unable to find submodule"),
+ submodule_entry_list.entries[i].submodule->name);
if (advice_enabled(ADVICE_SUBMODULES_NOT_UPDATED))
advise(_("You may try updating the submodules using 'git checkout %s && git submodule update --init'"),
start_commitish);
- die(_("submodule '%s': unable to find submodule"),
- submodule_entry_list.entries[i].submodule->name);
+ exit(code);
}
if (submodule_create_branch(
@@ -614,7 +636,8 @@ void create_branches_recursively(struct repository *r, const char *name,
* tedious to determine whether or not tracking was set up in the
* superproject.
*/
- setup_tracking(name, tracking_name, track, quiet);
+ if (track)
+ setup_tracking(name, tracking_name, track, quiet);
for (i = 0; i < submodule_entry_list.entry_nr; i++) {
if (submodule_create_branch(
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index c2d96f4c89..c4b9104f9b 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -153,11 +153,11 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
args.from_promisor = 1;
continue;
}
- if (skip_prefix(arg, ("--" CL_ARG__FILTER "="), &arg)) {
+ if (skip_prefix(arg, ("--filter="), &arg)) {
parse_list_objects_filter(&args.filter_options, arg);
continue;
}
- if (!strcmp(arg, ("--no-" CL_ARG__FILTER))) {
+ if (!strcmp(arg, ("--no-filter"))) {
list_objects_filter_set_no_filter(&args.filter_options);
continue;
}
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 6cb554cbb0..5dac9ee5b9 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -16,22 +16,102 @@
static int line_termination = '\n';
#define LS_RECURSIVE 1
-#define LS_TREE_ONLY 2
-#define LS_SHOW_TREES 4
-#define LS_NAME_ONLY 8
-#define LS_SHOW_SIZE 16
+#define LS_TREE_ONLY (1 << 1)
+#define LS_SHOW_TREES (1 << 2)
static int abbrev;
static int ls_options;
static struct pathspec pathspec;
static int chomp_prefix;
static const char *ls_tree_prefix;
+static const char *format;
+struct show_tree_data {
+ unsigned mode;
+ enum object_type type;
+ const struct object_id *oid;
+ const char *pathname;
+ struct strbuf *base;
+};
static const char * const ls_tree_usage[] = {
N_("git ls-tree [<options>] <tree-ish> [<path>...]"),
NULL
};
-static int show_recursive(const char *base, int baselen, const char *pathname)
+static enum ls_tree_cmdmode {
+ MODE_DEFAULT = 0,
+ MODE_LONG,
+ MODE_NAME_ONLY,
+ MODE_NAME_STATUS,
+ MODE_OBJECT_ONLY,
+} cmdmode;
+
+static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
+ const enum object_type type, unsigned int padded)
+{
+ if (type == OBJ_BLOB) {
+ unsigned long size;
+ if (oid_object_info(the_repository, oid, &size) < 0)
+ die(_("could not get object info about '%s'"),
+ oid_to_hex(oid));
+ if (padded)
+ strbuf_addf(line, "%7"PRIuMAX, (uintmax_t)size);
+ else
+ strbuf_addf(line, "%"PRIuMAX, (uintmax_t)size);
+ } else if (padded) {
+ strbuf_addf(line, "%7s", "-");
+ } else {
+ strbuf_addstr(line, "-");
+ }
+}
+
+static size_t expand_show_tree(struct strbuf *sb, const char *start,
+ void *context)
+{
+ struct show_tree_data *data = context;
+ const char *end;
+ const char *p;
+ unsigned int errlen;
+ size_t len = strbuf_expand_literal_cb(sb, start, NULL);
+
+ if (len)
+ return len;
+ if (*start != '(')
+ die(_("bad ls-tree format: element '%s' does not start with '('"), start);
+
+ end = strchr(start + 1, ')');
+ if (!end)
+ die(_("bad ls-tree format: element '%s' does not end in ')'"), start);
+
+ len = end - start + 1;
+ if (skip_prefix(start, "(objectmode)", &p)) {
+ strbuf_addf(sb, "%06o", data->mode);
+ } else if (skip_prefix(start, "(objecttype)", &p)) {
+ strbuf_addstr(sb, type_name(data->type));
+ } else if (skip_prefix(start, "(objectsize:padded)", &p)) {
+ expand_objectsize(sb, data->oid, data->type, 1);
+ } else if (skip_prefix(start, "(objectsize)", &p)) {
+ expand_objectsize(sb, data->oid, data->type, 0);
+ } else if (skip_prefix(start, "(objectname)", &p)) {
+ strbuf_add_unique_abbrev(sb, data->oid, abbrev);
+ } else if (skip_prefix(start, "(path)", &p)) {
+ const char *name = data->base->buf;
+ const char *prefix = chomp_prefix ? ls_tree_prefix : NULL;
+ struct strbuf quoted = STRBUF_INIT;
+ struct strbuf sbuf = STRBUF_INIT;
+ strbuf_addstr(data->base, data->pathname);
+ name = relative_path(data->base->buf, prefix, &sbuf);
+ quote_c_style(name, &quoted, NULL, 0);
+ strbuf_addbuf(sb, &quoted);
+ strbuf_release(&sbuf);
+ strbuf_release(&quoted);
+ } else {
+ errlen = (unsigned long)len;
+ die(_("bad ls-tree format: %%%.*s"), errlen, start);
+ }
+ return len;
+}
+
+static int show_recursive(const char *base, size_t baselen, const char *pathname)
{
int i;
@@ -43,7 +123,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
for (i = 0; i < pathspec.nr; i++) {
const char *spec = pathspec.items[i].match;
- int len, speclen;
+ size_t len, speclen;
if (strncmp(base, spec, baselen))
continue;
@@ -61,69 +141,197 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
return 0;
}
-static int show_tree(const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode, void *context)
+static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
+ const char *pathname, unsigned mode, void *context)
{
- int retval = 0;
- int baselen;
- const char *type = blob_type;
-
- if (S_ISGITLINK(mode)) {
- /*
- * Maybe we want to have some recursive version here?
- *
- * Something similar to this incomplete example:
- *
- if (show_subprojects(base, baselen, pathname))
- retval = READ_TREE_RECURSIVE;
- *
- */
- type = commit_type;
- } else if (S_ISDIR(mode)) {
- if (show_recursive(base->buf, base->len, pathname)) {
- retval = READ_TREE_RECURSIVE;
- if (!(ls_options & LS_SHOW_TREES))
- return retval;
- }
- type = tree_type;
- }
- else if (ls_options & LS_TREE_ONLY)
+ size_t baselen;
+ int recurse = 0;
+ struct strbuf sb = STRBUF_INIT;
+ enum object_type type = object_type(mode);
+
+ struct show_tree_data data = {
+ .mode = mode,
+ .type = type,
+ .oid = oid,
+ .pathname = pathname,
+ .base = base,
+ };
+
+ if (type == OBJ_TREE && show_recursive(base->buf, base->len, pathname))
+ recurse = READ_TREE_RECURSIVE;
+ if (type == OBJ_TREE && recurse && !(ls_options & LS_SHOW_TREES))
+ return recurse;
+ if (type == OBJ_BLOB && (ls_options & LS_TREE_ONLY))
return 0;
- if (!(ls_options & LS_NAME_ONLY)) {
- if (ls_options & LS_SHOW_SIZE) {
- char size_text[24];
- if (!strcmp(type, blob_type)) {
- unsigned long size;
- if (oid_object_info(the_repository, oid, &size) == OBJ_BAD)
- xsnprintf(size_text, sizeof(size_text),
- "BAD");
- else
- xsnprintf(size_text, sizeof(size_text),
- "%"PRIuMAX, (uintmax_t)size);
- } else
- xsnprintf(size_text, sizeof(size_text), "-");
- printf("%06o %s %s %7s\t", mode, type,
- find_unique_abbrev(oid, abbrev),
- size_text);
- } else
- printf("%06o %s %s\t", mode, type,
- find_unique_abbrev(oid, abbrev));
- }
baselen = base->len;
+ strbuf_expand(&sb, format, expand_show_tree, &data);
+ strbuf_addch(&sb, line_termination);
+ fwrite(sb.buf, sb.len, 1, stdout);
+ strbuf_release(&sb);
+ strbuf_setlen(base, baselen);
+ return recurse;
+}
+
+static int show_tree_common(struct show_tree_data *data, int *recurse,
+ const struct object_id *oid, struct strbuf *base,
+ const char *pathname, unsigned mode)
+{
+ enum object_type type = object_type(mode);
+ int ret = -1;
+
+ *recurse = 0;
+ data->mode = mode;
+ data->type = type;
+ data->oid = oid;
+ data->pathname = pathname;
+ data->base = base;
+
+ if (type == OBJ_BLOB) {
+ if (ls_options & LS_TREE_ONLY)
+ ret = 0;
+ } else if (type == OBJ_TREE &&
+ show_recursive(base->buf, base->len, pathname)) {
+ *recurse = READ_TREE_RECURSIVE;
+ if (!(ls_options & LS_SHOW_TREES))
+ ret = *recurse;
+ }
+
+ return ret;
+}
+
+static void show_tree_common_default_long(struct strbuf *base,
+ const char *pathname,
+ const size_t baselen)
+{
+ strbuf_addstr(base, pathname);
+ write_name_quoted_relative(base->buf,
+ chomp_prefix ? ls_tree_prefix : NULL, stdout,
+ line_termination);
+ strbuf_setlen(base, baselen);
+}
+
+static int show_tree_default(const struct object_id *oid, struct strbuf *base,
+ const char *pathname, unsigned mode,
+ void *context)
+{
+ int early;
+ int recurse;
+ struct show_tree_data data = { 0 };
+
+ early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ if (early >= 0)
+ return early;
+
+ printf("%06o %s %s\t", data.mode, type_name(data.type),
+ find_unique_abbrev(data.oid, abbrev));
+ show_tree_common_default_long(base, pathname, data.base->len);
+ return recurse;
+}
+
+static int show_tree_long(const struct object_id *oid, struct strbuf *base,
+ const char *pathname, unsigned mode, void *context)
+{
+ int early;
+ int recurse;
+ struct show_tree_data data = { 0 };
+ char size_text[24];
+
+ early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ if (early >= 0)
+ return early;
+
+ if (data.type == OBJ_BLOB) {
+ unsigned long size;
+ if (oid_object_info(the_repository, data.oid, &size) == OBJ_BAD)
+ xsnprintf(size_text, sizeof(size_text), "BAD");
+ else
+ xsnprintf(size_text, sizeof(size_text),
+ "%" PRIuMAX, (uintmax_t)size);
+ } else {
+ xsnprintf(size_text, sizeof(size_text), "-");
+ }
+
+ printf("%06o %s %s %7s\t", data.mode, type_name(data.type),
+ find_unique_abbrev(data.oid, abbrev), size_text);
+ show_tree_common_default_long(base, pathname, data.base->len);
+ return 1;
+}
+
+static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
+ const char *pathname, unsigned mode, void *context)
+{
+ int early;
+ int recurse;
+ const size_t baselen = base->len;
+ struct show_tree_data data = { 0 };
+
+ early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ if (early >= 0)
+ return early;
+
strbuf_addstr(base, pathname);
write_name_quoted_relative(base->buf,
chomp_prefix ? ls_tree_prefix : NULL,
stdout, line_termination);
strbuf_setlen(base, baselen);
- return retval;
+ return recurse;
+}
+
+static int show_tree_object(const struct object_id *oid, struct strbuf *base,
+ const char *pathname, unsigned mode, void *context)
+{
+ int early;
+ int recurse;
+ struct show_tree_data data = { 0 };
+
+ early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ if (early >= 0)
+ return early;
+
+ printf("%s%c", find_unique_abbrev(oid, abbrev), line_termination);
+ return recurse;
}
+struct ls_tree_cmdmode_to_fmt {
+ enum ls_tree_cmdmode mode;
+ const char *const fmt;
+ read_tree_fn_t fn;
+};
+
+static struct ls_tree_cmdmode_to_fmt ls_tree_cmdmode_format[] = {
+ {
+ .mode = MODE_DEFAULT,
+ .fmt = "%(objectmode) %(objecttype) %(objectname)%x09%(path)",
+ .fn = show_tree_default,
+ },
+ {
+ .mode = MODE_LONG,
+ .fmt = "%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)",
+ .fn = show_tree_long,
+ },
+ {
+ .mode = MODE_NAME_ONLY, /* And MODE_NAME_STATUS */
+ .fmt = "%(path)",
+ .fn = show_tree_name_only,
+ },
+ {
+ .mode = MODE_OBJECT_ONLY,
+ .fmt = "%(objectname)",
+ .fn = show_tree_object
+ },
+ {
+ /* fallback */
+ .fn = show_tree_default,
+ },
+};
+
int cmd_ls_tree(int argc, const char **argv, const char *prefix)
{
struct object_id oid;
struct tree *tree;
int i, full_tree = 0;
+ read_tree_fn_t fn = NULL;
const struct option ls_tree_options[] = {
OPT_BIT('d', NULL, &ls_options, N_("only show trees"),
LS_TREE_ONLY),
@@ -133,20 +341,26 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
LS_SHOW_TREES),
OPT_SET_INT('z', NULL, &line_termination,
N_("terminate entries with NUL byte"), 0),
- OPT_BIT('l', "long", &ls_options, N_("include object size"),
- LS_SHOW_SIZE),
- OPT_BIT(0, "name-only", &ls_options, N_("list only filenames"),
- LS_NAME_ONLY),
- OPT_BIT(0, "name-status", &ls_options, N_("list only filenames"),
- LS_NAME_ONLY),
+ OPT_CMDMODE('l', "long", &cmdmode, N_("include object size"),
+ MODE_LONG),
+ OPT_CMDMODE(0, "name-only", &cmdmode, N_("list only filenames"),
+ MODE_NAME_ONLY),
+ OPT_CMDMODE(0, "name-status", &cmdmode, N_("list only filenames"),
+ MODE_NAME_STATUS),
+ OPT_CMDMODE(0, "object-only", &cmdmode, N_("list only objects"),
+ MODE_OBJECT_ONLY),
OPT_SET_INT(0, "full-name", &chomp_prefix,
N_("use full path names"), 0),
OPT_BOOL(0, "full-tree", &full_tree,
N_("list entire tree; not just current directory "
"(implies --full-name)")),
+ OPT_STRING_F(0, "format", &format, N_("format"),
+ N_("format to use for the output"),
+ PARSE_OPT_NONEG),
OPT__ABBREV(&abbrev),
OPT_END()
};
+ struct ls_tree_cmdmode_to_fmt *m2f = ls_tree_cmdmode_format;
git_config(git_default_config, NULL);
ls_tree_prefix = prefix;
@@ -159,11 +373,23 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
ls_tree_prefix = prefix = NULL;
chomp_prefix = 0;
}
+ /*
+ * We wanted to detect conflicts between --name-only and
+ * --name-status, but once we're done with that subsequent
+ * code should only need to check the primary name.
+ */
+ if (cmdmode == MODE_NAME_STATUS)
+ cmdmode = MODE_NAME_ONLY;
+
/* -d -r should imply -t, but -d by itself should not have to. */
if ( (LS_TREE_ONLY|LS_RECURSIVE) ==
((LS_TREE_ONLY|LS_RECURSIVE) & ls_options))
ls_options |= LS_SHOW_TREES;
+ if (format && cmdmode)
+ usage_msg_opt(
+ _("--format can't be combined with other format-altering options"),
+ ls_tree_usage, ls_tree_options);
if (argc < 1)
usage_with_options(ls_tree_usage, ls_tree_options);
if (get_oid(argv[0], &oid))
@@ -185,6 +411,24 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
tree = parse_tree_indirect(&oid);
if (!tree)
die("not a tree object");
- return !!read_tree(the_repository, tree,
- &pathspec, show_tree, NULL);
+ /*
+ * The generic show_tree_fmt() is slower than show_tree(), so
+ * take the fast path if possible.
+ */
+ while (m2f) {
+ if (!m2f->fmt) {
+ fn = format ? show_tree_fmt : show_tree_default;
+ } else if (format && !strcmp(format, m2f->fmt)) {
+ cmdmode = m2f->mode;
+ fn = m2f->fn;
+ } else if (!format && cmdmode == m2f->mode) {
+ fn = m2f->fn;
+ } else {
+ m2f++;
+ continue;
+ }
+ break;
+ }
+
+ return !!read_tree(the_repository, tree, &pathspec, fn, NULL);
}
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index c23b788ac8..014dcd4bc9 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -237,8 +237,6 @@ static unsigned long cache_max_small_delta_size = 1000;
static unsigned long window_memory_limit = 0;
-static struct list_objects_filter_options filter_options;
-
static struct string_list uri_protocols = STRING_LIST_INIT_NODUP;
enum missing_action {
@@ -3724,9 +3722,8 @@ static void mark_bitmap_preferred_tips(void)
}
}
-static void get_object_list(int ac, const char **av)
+static void get_object_list(struct rev_info *revs, int ac, const char **av)
{
- struct rev_info revs;
struct setup_revision_opt s_r_opt = {
.allow_exclude_promisor_objects = 1,
};
@@ -3734,10 +3731,8 @@ static void get_object_list(int ac, const char **av)
int flags = 0;
int save_warning;
- repo_init_revisions(the_repository, &revs, NULL);
save_commit_buffer = 0;
- setup_revisions(ac, av, &revs, &s_r_opt);
- list_objects_filter_copy(&revs.filter, &filter_options);
+ setup_revisions(ac, av, revs, &s_r_opt);
/* make sure shallows are read */
is_repository_shallow(the_repository);
@@ -3767,13 +3762,13 @@ static void get_object_list(int ac, const char **av)
}
die(_("not a rev '%s'"), line);
}
- if (handle_revision_arg(line, &revs, flags, REVARG_CANNOT_BE_FILENAME))
+ if (handle_revision_arg(line, revs, flags, REVARG_CANNOT_BE_FILENAME))
die(_("bad revision '%s'"), line);
}
warn_on_object_refname_ambiguity = save_warning;
- if (use_bitmap_index && !get_object_list_from_bitmap(&revs))
+ if (use_bitmap_index && !get_object_list_from_bitmap(revs))
return;
if (use_delta_islands)
@@ -3782,24 +3777,24 @@ static void get_object_list(int ac, const char **av)
if (write_bitmap_index)
mark_bitmap_preferred_tips();
- if (prepare_revision_walk(&revs))
+ if (prepare_revision_walk(revs))
die(_("revision walk setup failed"));
- mark_edges_uninteresting(&revs, show_edge, sparse);
+ mark_edges_uninteresting(revs, show_edge, sparse);
if (!fn_show_object)
fn_show_object = show_object;
- traverse_commit_list(&revs,
+ traverse_commit_list(revs,
show_commit, fn_show_object,
NULL);
if (unpack_unreachable_expiration) {
- revs.ignore_missing_links = 1;
- if (add_unseen_recent_objects_to_traversal(&revs,
+ revs->ignore_missing_links = 1;
+ if (add_unseen_recent_objects_to_traversal(revs,
unpack_unreachable_expiration))
die(_("unable to add recent objects"));
- if (prepare_revision_walk(&revs))
+ if (prepare_revision_walk(revs))
die(_("revision walk setup failed"));
- traverse_commit_list(&revs, record_recent_commit,
+ traverse_commit_list(revs, record_recent_commit,
record_recent_object, NULL);
}
@@ -3872,6 +3867,21 @@ static int option_parse_unpack_unreachable(const struct option *opt,
return 0;
}
+struct po_filter_data {
+ unsigned have_revs:1;
+ struct rev_info revs;
+};
+
+static struct list_objects_filter_options *po_filter_revs_init(void *value)
+{
+ struct po_filter_data *data = value;
+
+ repo_init_revisions(the_repository, &data->revs, NULL);
+ data->have_revs = 1;
+
+ return &data->revs.filter;
+}
+
int cmd_pack_objects(int argc, const char **argv, const char *prefix)
{
int use_internal_rev_list = 0;
@@ -3882,6 +3892,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
int rev_list_index = 0;
int stdin_packs = 0;
struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
+ struct po_filter_data pfd = { .have_revs = 0 };
+
struct option pack_objects_options[] = {
OPT_SET_INT('q', "quiet", &progress,
N_("do not show progress meter"), 0),
@@ -3967,7 +3979,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
&write_bitmap_index,
N_("write a bitmap index if possible"),
WRITE_BITMAP_QUIET, PARSE_OPT_HIDDEN),
- OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
+ OPT_PARSE_LIST_OBJECTS_FILTER_INIT(&pfd, po_filter_revs_init),
OPT_CALLBACK_F(0, "missing", NULL, N_("action"),
N_("handling for missing objects"), PARSE_OPT_NONEG,
option_parse_missing_action),
@@ -4087,7 +4099,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (!rev_list_all || !rev_list_reflog || !rev_list_index)
unpack_unreachable_expiration = 0;
- if (filter_options.choice) {
+ if (pfd.have_revs && pfd.revs.filter.choice) {
if (!pack_to_stdout)
die(_("cannot use --filter without --stdout"));
if (stdin_packs)
@@ -4163,8 +4175,13 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
add_unreachable_loose_objects();
} else if (!use_internal_rev_list) {
read_object_list_from_stdin();
+ } else if (pfd.have_revs) {
+ get_object_list(&pfd.revs, rp.nr, rp.v);
} else {
- get_object_list(rp.nr, rp.v);
+ struct rev_info revs;
+
+ repo_init_revisions(the_repository, &revs, NULL);
+ get_object_list(&revs, rp.nr, rp.v);
}
cleanup_preferred_base();
if (include_tag && nr_result)
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 9407f835cb..c943c2aabe 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -5,8 +5,48 @@
#include "worktree.h"
#include "reflog.h"
-static const char reflog_exists_usage[] =
-N_("git reflog exists <ref>");
+#define BUILTIN_REFLOG_SHOW_USAGE \
+ N_("git reflog [show] [<log-options>] [<ref>]")
+
+#define BUILTIN_REFLOG_EXPIRE_USAGE \
+ N_("git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n" \
+ " [--rewrite] [--updateref] [--stale-fix]\n" \
+ " [--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]")
+
+#define BUILTIN_REFLOG_DELETE_USAGE \
+ N_("git reflog delete [--rewrite] [--updateref]\n" \
+ " [--dry-run | -n] [--verbose] <ref>@{<specifier>}...")
+
+#define BUILTIN_REFLOG_EXISTS_USAGE \
+ N_("git reflog exists <ref>")
+
+static const char *const reflog_show_usage[] = {
+ BUILTIN_REFLOG_SHOW_USAGE,
+ NULL,
+};
+
+static const char *const reflog_expire_usage[] = {
+ BUILTIN_REFLOG_EXPIRE_USAGE,
+ NULL
+};
+
+static const char *const reflog_delete_usage[] = {
+ BUILTIN_REFLOG_DELETE_USAGE,
+ NULL
+};
+
+static const char *const reflog_exists_usage[] = {
+ BUILTIN_REFLOG_EXISTS_USAGE,
+ NULL,
+};
+
+static const char *const reflog_usage[] = {
+ BUILTIN_REFLOG_SHOW_USAGE,
+ BUILTIN_REFLOG_EXPIRE_USAGE,
+ BUILTIN_REFLOG_DELETE_USAGE,
+ BUILTIN_REFLOG_EXISTS_USAGE,
+ NULL
+};
static timestamp_t default_reflog_expire;
static timestamp_t default_reflog_expire_unreachable;
@@ -147,14 +187,6 @@ static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, const char
cb->expire_unreachable = default_reflog_expire_unreachable;
}
-static const char * reflog_expire_usage[] = {
- N_("git reflog expire [--expire=<time>] "
- "[--expire-unreachable=<time>] "
- "[--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] "
- "[--verbose] [--all] <refs>..."),
- NULL
-};
-
static int expire_unreachable_callback(const struct option *opt,
const char *arg,
int unset)
@@ -183,6 +215,19 @@ static int expire_total_callback(const struct option *opt,
return 0;
}
+static int cmd_reflog_show(int argc, const char **argv, const char *prefix)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+
+ parse_options(argc, argv, prefix, options, reflog_show_usage,
+ PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0 |
+ PARSE_OPT_KEEP_UNKNOWN);
+
+ return cmd_log_reflog(argc, argv, prefix);
+}
+
static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
{
struct cmd_reflog_expire_cb cmd = { 0 };
@@ -304,12 +349,6 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
return status;
}
-static const char * reflog_delete_usage[] = {
- N_("git reflog delete [--rewrite] [--updateref] "
- "[--dry-run | -n] [--verbose] <refs>..."),
- NULL
-};
-
static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
{
int i, status = 0;
@@ -342,57 +381,62 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
static int cmd_reflog_exists(int argc, const char **argv, const char *prefix)
{
- int i, start = 0;
-
- for (i = 1; i < argc; i++) {
- const char *arg = argv[i];
- if (!strcmp(arg, "--")) {
- i++;
- break;
- }
- else if (arg[0] == '-')
- usage(_(reflog_exists_usage));
- else
- break;
- }
-
- start = i;
+ struct option options[] = {
+ OPT_END()
+ };
+ const char *refname;
- if (argc - start != 1)
- usage(_(reflog_exists_usage));
+ argc = parse_options(argc, argv, prefix, options, reflog_exists_usage,
+ 0);
+ if (!argc)
+ usage_with_options(reflog_exists_usage, options);
- if (check_refname_format(argv[start], REFNAME_ALLOW_ONELEVEL))
- die(_("invalid ref format: %s"), argv[start]);
- return !reflog_exists(argv[start]);
+ refname = argv[0];
+ if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
+ die(_("invalid ref format: %s"), refname);
+ return !reflog_exists(refname);
}
/*
* main "reflog"
*/
-static const char reflog_usage[] =
-"git reflog [ show | expire | delete | exists ]";
-
int cmd_reflog(int argc, const char **argv, const char *prefix)
{
- if (argc > 1 && !strcmp(argv[1], "-h"))
- usage(_(reflog_usage));
+ struct option options[] = {
+ OPT_END()
+ };
- /* With no command, we default to showing it. */
- if (argc < 2 || *argv[1] == '-')
- return cmd_log_reflog(argc, argv, prefix);
+ argc = parse_options(argc, argv, prefix, options, reflog_usage,
+ PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0 |
+ PARSE_OPT_KEEP_UNKNOWN |
+ PARSE_OPT_NO_INTERNAL_HELP);
- if (!strcmp(argv[1], "show"))
- return cmd_log_reflog(argc - 1, argv + 1, prefix);
+ /*
+ * With "git reflog" we default to showing it. !argc is
+ * impossible with PARSE_OPT_KEEP_ARGV0.
+ */
+ if (argc == 1)
+ goto log_reflog;
- if (!strcmp(argv[1], "expire"))
- return cmd_reflog_expire(argc - 1, argv + 1, prefix);
+ if (!strcmp(argv[1], "-h"))
+ usage_with_options(reflog_usage, options);
+ else if (*argv[1] == '-')
+ goto log_reflog;
- if (!strcmp(argv[1], "delete"))
+ if (!strcmp(argv[1], "show"))
+ return cmd_reflog_show(argc - 1, argv + 1, prefix);
+ else if (!strcmp(argv[1], "expire"))
+ return cmd_reflog_expire(argc - 1, argv + 1, prefix);
+ else if (!strcmp(argv[1], "delete"))
return cmd_reflog_delete(argc - 1, argv + 1, prefix);
-
- if (!strcmp(argv[1], "exists"))
+ else if (!strcmp(argv[1], "exists"))
return cmd_reflog_exists(argc - 1, argv + 1, prefix);
+ /*
+ * Fall-through for e.g. "git reflog -1", "git reflog master",
+ * as well as the plain "git reflog" above goto above.
+ */
+log_reflog:
return cmd_log_reflog(argc, argv, prefix);
}
diff --git a/builtin/reset.c b/builtin/reset.c
index 6e65e90c5d..344fff8f3a 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -392,6 +392,7 @@ static int git_reset_config(const char *var, const char *value, void *cb)
int cmd_reset(int argc, const char **argv, const char *prefix)
{
int reset_type = NONE, update_ref_status = 0, quiet = 0;
+ int no_refresh = 0;
int patch_mode = 0, pathspec_file_nul = 0, unborn;
const char *rev, *pathspec_from_file = NULL;
struct object_id oid;
@@ -399,6 +400,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
int intent_to_add = 0;
const struct option options[] = {
OPT__QUIET(&quiet, N_("be quiet, only report errors")),
+ OPT_BOOL(0, "no-refresh", &no_refresh,
+ N_("skip refreshing the index after reset")),
OPT_SET_INT(0, "mixed", &reset_type,
N_("reset HEAD and index"), MIXED),
OPT_SET_INT(0, "soft", &reset_type, N_("reset only HEAD"), SOFT),
@@ -420,7 +423,6 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
};
git_config(git_reset_config, NULL);
- git_config_get_bool("reset.quiet", &quiet);
argc = parse_options(argc, argv, prefix, options, git_reset_usage,
PARSE_OPT_KEEP_DASHDASH);
@@ -517,17 +519,16 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (read_from_tree(&pathspec, &oid, intent_to_add))
return 1;
the_index.updated_skipworktree = 1;
- if (!quiet && get_git_work_tree()) {
+ if (!no_refresh && get_git_work_tree()) {
uint64_t t_begin, t_delta_in_ms;
t_begin = getnanotime();
refresh_index(&the_index, flags, NULL, NULL,
_("Unstaged changes after reset:"));
t_delta_in_ms = (getnanotime() - t_begin) / 1000000;
- if (advice_enabled(ADVICE_RESET_QUIET_WARNING) && t_delta_in_ms > REFRESH_INDEX_DELAY_WARNING_IN_MS) {
- printf(_("\nIt took %.2f seconds to enumerate unstaged changes after reset. You can\n"
- "use '--quiet' to avoid this. Set the config setting reset.quiet to true\n"
- "to make this the default.\n"), t_delta_in_ms / 1000.0);
+ if (!quiet && advice_enabled(ADVICE_RESET_NO_REFRESH_WARNING) && t_delta_in_ms > REFRESH_INDEX_DELAY_WARNING_IN_MS) {
+ advise(_("It took %.2f seconds to refresh the index after reset. You can use\n"
+ "'--no-refresh' to avoid this."), t_delta_in_ms / 1000.0);
}
}
} else {
diff --git a/builtin/stash.c b/builtin/stash.c
index ccdfdab44b..0c7b6a9588 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -310,7 +310,7 @@ static int reset_head(void)
* API for resetting.
*/
cp.git_cmd = 1;
- strvec_push(&cp.args, "reset");
+ strvec_pushl(&cp.args, "reset", "--quiet", "--refresh", NULL);
return run_command(&cp);
}
@@ -1622,7 +1622,8 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
struct child_process cp = CHILD_PROCESS_INIT;
cp.git_cmd = 1;
- strvec_pushl(&cp.args, "reset", "-q", "--", NULL);
+ strvec_pushl(&cp.args, "reset", "-q", "--refresh", "--",
+ NULL);
add_pathspecs(&cp.args, ps);
if (run_command(&cp)) {
ret = -1;
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 5301612d24..c3e0d4570f 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1643,7 +1643,10 @@ struct module_clone_data {
unsigned int require_init: 1;
int single_branch;
};
-#define MODULE_CLONE_DATA_INIT { .reference = STRING_LIST_INIT_NODUP, .single_branch = -1 }
+#define MODULE_CLONE_DATA_INIT { \
+ .reference = STRING_LIST_INIT_NODUP, \
+ .single_branch = -1, \
+}
struct submodule_alternate_setup {
const char *submodule_name;
@@ -1967,28 +1970,13 @@ struct update_clone_data {
};
struct submodule_update_clone {
- /* index into 'list', the list of submodules to look into for cloning */
+ /* index into 'update_data.list', the list of submodules to look into for cloning */
int current;
- struct module_list list;
- unsigned warn_if_uninitialized : 1;
-
- /* update parameter passed via commandline */
- struct submodule_update_strategy update;
/* configuration parameters which are passed on to the children */
- int progress;
- int quiet;
- int recommend_shallow;
- struct string_list references;
- int dissociate;
- unsigned require_init;
- const char *depth;
- const char *recursive_prefix;
- const char *prefix;
- int single_branch;
- struct list_objects_filter_options *filter_options;
+ struct update_data *update_data;
- /* to be consumed by git-submodule.sh */
+ /* to be consumed by update_submodule() */
struct update_clone_data *update_clone;
int update_clone_nr; int update_clone_alloc;
@@ -1998,34 +1986,48 @@ struct submodule_update_clone {
/* failed clones to be retried again */
const struct cache_entry **failed_clones;
int failed_clones_nr, failed_clones_alloc;
-
- int max_jobs;
- unsigned int init;
};
-#define SUBMODULE_UPDATE_CLONE_INIT { \
- .list = MODULE_LIST_INIT, \
- .update = SUBMODULE_UPDATE_STRATEGY_INIT, \
- .recommend_shallow = -1, \
- .references = STRING_LIST_INIT_DUP, \
- .single_branch = -1, \
- .max_jobs = 1, \
-}
+#define SUBMODULE_UPDATE_CLONE_INIT { 0 }
struct update_data {
+ const char *prefix;
const char *recursive_prefix;
- const char *sm_path;
const char *displaypath;
- struct object_id oid;
+ const char *update_default;
struct object_id suboid;
+ struct string_list references;
struct submodule_update_strategy update_strategy;
+ struct list_objects_filter_options *filter_options;
+ struct module_list list;
int depth;
+ int max_jobs;
+ int single_branch;
+ int recommend_shallow;
+ unsigned int require_init;
unsigned int force;
unsigned int quiet;
unsigned int nofetch;
- unsigned int just_cloned;
unsigned int remote;
+ unsigned int progress;
+ unsigned int dissociate;
+ unsigned int init;
+ unsigned int warn_if_uninitialized;
+ unsigned int recursive;
+
+ /* copied over from update_clone_data */
+ struct object_id oid;
+ unsigned int just_cloned;
+ const char *sm_path;
};
-#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }
+#define UPDATE_DATA_INIT { \
+ .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
+ .list = MODULE_LIST_INIT, \
+ .recommend_shallow = -1, \
+ .references = STRING_LIST_INIT_DUP, \
+ .single_branch = -1, \
+ .max_jobs = 1, \
+ .warn_if_uninitialized = 1, \
+}
static void next_submodule_warn_missing(struct submodule_update_clone *suc,
struct strbuf *out, const char *displaypath)
@@ -2034,7 +2036,7 @@ static void next_submodule_warn_missing(struct submodule_update_clone *suc,
* Only mention uninitialized submodules when their
* paths have been specified.
*/
- if (suc->warn_if_uninitialized) {
+ if (suc->update_data->warn_if_uninitialized) {
strbuf_addf(out,
_("Submodule path '%s' not initialized"),
displaypath);
@@ -2066,8 +2068,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
int need_free_url = 0;
if (ce_stage(ce)) {
- if (suc->recursive_prefix)
- strbuf_addf(&sb, "%s/%s", suc->recursive_prefix, ce->name);
+ if (suc->update_data->recursive_prefix)
+ strbuf_addf(&sb, "%s/%s", suc->update_data->recursive_prefix, ce->name);
else
strbuf_addstr(&sb, ce->name);
strbuf_addf(out, _("Skipping unmerged submodule %s"), sb.buf);
@@ -2077,8 +2079,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
sub = submodule_from_path(the_repository, null_oid(), ce->name);
- if (suc->recursive_prefix)
- displaypath = relative_path(suc->recursive_prefix,
+ if (suc->update_data->recursive_prefix)
+ displaypath = relative_path(suc->update_data->recursive_prefix,
ce->name, &displaypath_sb);
else
displaypath = ce->name;
@@ -2096,8 +2098,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
}
free(key);
- if (suc->update.type == SM_UPDATE_NONE
- || (suc->update.type == SM_UPDATE_UNSPECIFIED
+ if (suc->update_data->update_strategy.type == SM_UPDATE_NONE
+ || (suc->update_data->update_strategy.type == SM_UPDATE_UNSPECIFIED
&& update_type == SM_UPDATE_NONE)) {
strbuf_addf(out, _("Skipping submodule '%s'"), displaypath);
strbuf_addch(out, '\n');
@@ -2141,33 +2143,33 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
child->err = -1;
strvec_push(&child->args, "submodule--helper");
strvec_push(&child->args, "clone");
- if (suc->progress)
+ if (suc->update_data->progress)
strvec_push(&child->args, "--progress");
- if (suc->quiet)
+ if (suc->update_data->quiet)
strvec_push(&child->args, "--quiet");
- if (suc->prefix)
- strvec_pushl(&child->args, "--prefix", suc->prefix, NULL);
- if (suc->recommend_shallow && sub->recommend_shallow == 1)
+ if (suc->update_data->prefix)
+ strvec_pushl(&child->args, "--prefix", suc->update_data->prefix, NULL);
+ if (suc->update_data->recommend_shallow && sub->recommend_shallow == 1)
strvec_push(&child->args, "--depth=1");
- if (suc->filter_options && suc->filter_options->choice)
+ else if (suc->update_data->depth)
+ strvec_pushf(&child->args, "--depth=%d", suc->update_data->depth);
+ if (suc->update_data->filter_options && suc->update_data->filter_options->choice)
strvec_pushf(&child->args, "--filter=%s",
- expand_list_objects_filter_spec(suc->filter_options));
- if (suc->require_init)
+ expand_list_objects_filter_spec(suc->update_data->filter_options));
+ if (suc->update_data->require_init)
strvec_push(&child->args, "--require-init");
strvec_pushl(&child->args, "--path", sub->path, NULL);
strvec_pushl(&child->args, "--name", sub->name, NULL);
strvec_pushl(&child->args, "--url", url, NULL);
- if (suc->references.nr) {
+ if (suc->update_data->references.nr) {
struct string_list_item *item;
- for_each_string_list_item(item, &suc->references)
+ for_each_string_list_item(item, &suc->update_data->references)
strvec_pushl(&child->args, "--reference", item->string, NULL);
}
- if (suc->dissociate)
+ if (suc->update_data->dissociate)
strvec_push(&child->args, "--dissociate");
- if (suc->depth)
- strvec_push(&child->args, suc->depth);
- if (suc->single_branch >= 0)
- strvec_push(&child->args, suc->single_branch ?
+ if (suc->update_data->single_branch >= 0)
+ strvec_push(&child->args, suc->update_data->single_branch ?
"--single-branch" :
"--no-single-branch");
@@ -2189,8 +2191,8 @@ static int update_clone_get_next_task(struct child_process *child,
const struct cache_entry *ce;
int index;
- for (; suc->current < suc->list.nr; suc->current++) {
- ce = suc->list.entries[suc->current];
+ for (; suc->current < suc->update_data->list.nr; suc->current++) {
+ ce = suc->update_data->list.entries[suc->current];
if (prepare_to_clone_next_submodule(ce, child, suc, err)) {
int *p = xmalloc(sizeof(*p));
*p = suc->current;
@@ -2205,7 +2207,7 @@ static int update_clone_get_next_task(struct child_process *child,
* stragglers again, which we can imagine as an extension of the
* entry list.
*/
- index = suc->current - suc->list.nr;
+ index = suc->current - suc->update_data->list.nr;
if (index < suc->failed_clones_nr) {
int *p;
ce = suc->failed_clones[index];
@@ -2250,8 +2252,8 @@ static int update_clone_task_finished(int result,
if (!result)
return 0;
- if (idx < suc->list.nr) {
- ce = suc->list.entries[idx];
+ if (idx < suc->update_data->list.nr) {
+ ce = suc->update_data->list.entries[idx];
strbuf_addf(err, _("Failed to clone '%s'. Retry scheduled"),
ce->name);
strbuf_addch(err, '\n');
@@ -2261,7 +2263,7 @@ static int update_clone_task_finished(int result,
suc->failed_clones[suc->failed_clones_nr++] = ce;
return 0;
} else {
- idx -= suc->list.nr;
+ idx -= suc->update_data->list.nr;
ce = suc->failed_clones[idx];
strbuf_addf(err, _("Failed to clone '%s' a second time, aborting"),
ce->name);
@@ -2325,83 +2327,76 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str
static int run_update_command(struct update_data *ud, int subforce)
{
- struct strvec args = STRVEC_INIT;
- struct strvec child_env = STRVEC_INIT;
+ struct child_process cp = CHILD_PROCESS_INIT;
char *oid = oid_to_hex(&ud->oid);
int must_die_on_failure = 0;
- int git_cmd;
switch (ud->update_strategy.type) {
case SM_UPDATE_CHECKOUT:
- git_cmd = 1;
- strvec_pushl(&args, "checkout", "-q", NULL);
+ cp.git_cmd = 1;
+ strvec_pushl(&cp.args, "checkout", "-q", NULL);
if (subforce)
- strvec_push(&args, "-f");
+ strvec_push(&cp.args, "-f");
break;
case SM_UPDATE_REBASE:
- git_cmd = 1;
- strvec_push(&args, "rebase");
+ cp.git_cmd = 1;
+ strvec_push(&cp.args, "rebase");
if (ud->quiet)
- strvec_push(&args, "--quiet");
+ strvec_push(&cp.args, "--quiet");
must_die_on_failure = 1;
break;
case SM_UPDATE_MERGE:
- git_cmd = 1;
- strvec_push(&args, "merge");
+ cp.git_cmd = 1;
+ strvec_push(&cp.args, "merge");
if (ud->quiet)
- strvec_push(&args, "--quiet");
+ strvec_push(&cp.args, "--quiet");
must_die_on_failure = 1;
break;
case SM_UPDATE_COMMAND:
- git_cmd = 0;
- strvec_push(&args, ud->update_strategy.command);
+ cp.use_shell = 1;
+ strvec_push(&cp.args, ud->update_strategy.command);
must_die_on_failure = 1;
break;
default:
BUG("unexpected update strategy type: %s",
submodule_strategy_to_string(&ud->update_strategy));
}
- strvec_push(&args, oid);
+ strvec_push(&cp.args, oid);
- prepare_submodule_repo_env(&child_env);
- if (run_command_v_opt_cd_env(args.v, git_cmd ? RUN_GIT_CMD : RUN_USING_SHELL,
- ud->sm_path, child_env.v)) {
+ cp.dir = xstrdup(ud->sm_path);
+ prepare_submodule_repo_env(&cp.env_array);
+ if (run_command(&cp)) {
switch (ud->update_strategy.type) {
case SM_UPDATE_CHECKOUT:
- printf(_("Unable to checkout '%s' in submodule path '%s'"),
- oid, ud->displaypath);
+ die_message(_("Unable to checkout '%s' in submodule path '%s'"),
+ oid, ud->displaypath);
break;
case SM_UPDATE_REBASE:
- printf(_("Unable to rebase '%s' in submodule path '%s'"),
- oid, ud->displaypath);
+ die_message(_("Unable to rebase '%s' in submodule path '%s'"),
+ oid, ud->displaypath);
break;
case SM_UPDATE_MERGE:
- printf(_("Unable to merge '%s' in submodule path '%s'"),
- oid, ud->displaypath);
+ die_message(_("Unable to merge '%s' in submodule path '%s'"),
+ oid, ud->displaypath);
break;
case SM_UPDATE_COMMAND:
- printf(_("Execution of '%s %s' failed in submodule path '%s'"),
- ud->update_strategy.command, oid, ud->displaypath);
+ die_message(_("Execution of '%s %s' failed in submodule path '%s'"),
+ ud->update_strategy.command, oid, ud->displaypath);
break;
default:
BUG("unexpected update strategy type: %s",
submodule_strategy_to_string(&ud->update_strategy));
}
- /*
- * NEEDSWORK: We are currently printing to stdout with error
- * return so that the shell caller handles the error output
- * properly. Once we start handling the error messages within
- * C, we should use die() instead.
- */
if (must_die_on_failure)
- return 2;
- /*
- * This signifies to the caller in shell that the command
- * failed without dying
- */
+ exit(128);
+
+ /* the command failed, but update must continue */
return 1;
}
+ if (ud->quiet)
+ return 0;
+
switch (ud->update_strategy.type) {
case SM_UPDATE_CHECKOUT:
printf(_("Submodule path '%s': checked out '%s'\n"),
@@ -2427,7 +2422,7 @@ static int run_update_command(struct update_data *ud, int subforce)
return 0;
}
-static int do_run_update_procedure(struct update_data *ud)
+static int run_update_procedure(struct update_data *ud)
{
int subforce = is_null_oid(&ud->suboid) || ud->force;
@@ -2457,31 +2452,211 @@ static int do_run_update_procedure(struct update_data *ud)
return run_update_command(ud, subforce);
}
-/*
- * NEEDSWORK: As we convert "git submodule update" to C,
- * update_submodule2() will invoke more and more functions, making it
- * difficult to preserve the function ordering without forward
- * declarations.
- *
- * When the conversion is complete, this forward declaration will be
- * unnecessary and should be removed.
- */
-static int update_submodule2(struct update_data *update_data);
-static void update_submodule(struct update_clone_data *ucd)
+static const char *remote_submodule_branch(const char *path)
+{
+ const struct submodule *sub;
+ const char *branch = NULL;
+ char *key;
+
+ sub = submodule_from_path(the_repository, null_oid(), path);
+ if (!sub)
+ return NULL;
+
+ key = xstrfmt("submodule.%s.branch", sub->name);
+ if (repo_config_get_string_tmp(the_repository, key, &branch))
+ branch = sub->branch;
+ free(key);
+
+ if (!branch)
+ return "HEAD";
+
+ if (!strcmp(branch, ".")) {
+ const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
+
+ if (!refname)
+ die(_("No such ref: %s"), "HEAD");
+
+ /* detached HEAD */
+ if (!strcmp(refname, "HEAD"))
+ die(_("Submodule (%s) branch configured to inherit "
+ "branch from superproject, but the superproject "
+ "is not on any branch"), sub->name);
+
+ if (!skip_prefix(refname, "refs/heads/", &refname))
+ die(_("Expecting a full ref name, got %s"), refname);
+ return refname;
+ }
+
+ return branch;
+}
+
+static void ensure_core_worktree(const char *path)
{
- fprintf(stdout, "dummy %s %d\t%s\n",
- oid_to_hex(&ucd->oid),
- ucd->just_cloned,
- ucd->sub->path);
+ const char *cw;
+ struct repository subrepo;
+
+ if (repo_submodule_init(&subrepo, the_repository, path, null_oid()))
+ die(_("could not get a repository handle for submodule '%s'"), path);
+
+ if (!repo_config_get_string_tmp(&subrepo, "core.worktree", &cw)) {
+ char *cfg_file, *abs_path;
+ const char *rel_path;
+ struct strbuf sb = STRBUF_INIT;
+
+ cfg_file = repo_git_path(&subrepo, "config");
+
+ abs_path = absolute_pathdup(path);
+ rel_path = relative_path(abs_path, subrepo.gitdir, &sb);
+
+ git_config_set_in_file(cfg_file, "core.worktree", rel_path);
+
+ free(cfg_file);
+ free(abs_path);
+ strbuf_release(&sb);
+ }
+}
+
+static void update_data_to_args(struct update_data *update_data, struct strvec *args)
+{
+ strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
+ strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
+ if (update_data->recursive_prefix)
+ strvec_pushl(args, "--recursive-prefix",
+ update_data->recursive_prefix, NULL);
+ if (update_data->quiet)
+ strvec_push(args, "--quiet");
+ if (update_data->force)
+ strvec_push(args, "--force");
+ if (update_data->init)
+ strvec_push(args, "--init");
+ if (update_data->remote)
+ strvec_push(args, "--remote");
+ if (update_data->nofetch)
+ strvec_push(args, "--no-fetch");
+ if (update_data->dissociate)
+ strvec_push(args, "--dissociate");
+ if (update_data->progress)
+ strvec_push(args, "--progress");
+ if (update_data->require_init)
+ strvec_push(args, "--require-init");
+ if (update_data->depth)
+ strvec_pushf(args, "--depth=%d", update_data->depth);
+ if (update_data->update_default)
+ strvec_pushl(args, "--update", update_data->update_default, NULL);
+ if (update_data->references.nr) {
+ struct string_list_item *item;
+ for_each_string_list_item(item, &update_data->references)
+ strvec_pushl(args, "--reference", item->string, NULL);
+ }
+ if (update_data->filter_options && update_data->filter_options->choice)
+ strvec_pushf(args, "--filter=%s",
+ expand_list_objects_filter_spec(
+ update_data->filter_options));
+ if (update_data->recommend_shallow == 0)
+ strvec_push(args, "--no-recommend-shallow");
+ else if (update_data->recommend_shallow == 1)
+ strvec_push(args, "--recommend-shallow");
+ if (update_data->single_branch >= 0)
+ strvec_push(args, update_data->single_branch ?
+ "--single-branch" :
+ "--no-single-branch");
}
-static int update_submodules(struct submodule_update_clone *suc)
+static int update_submodule(struct update_data *update_data)
{
- int i;
+ char *prefixed_path;
+
+ ensure_core_worktree(update_data->sm_path);
+
+ if (update_data->recursive_prefix)
+ prefixed_path = xstrfmt("%s%s", update_data->recursive_prefix,
+ update_data->sm_path);
+ else
+ prefixed_path = xstrdup(update_data->sm_path);
+
+ update_data->displaypath = get_submodule_displaypath(prefixed_path,
+ update_data->prefix);
+ free(prefixed_path);
+
+ determine_submodule_update_strategy(the_repository, update_data->just_cloned,
+ update_data->sm_path, update_data->update_default,
+ &update_data->update_strategy);
+
+ if (update_data->just_cloned)
+ oidcpy(&update_data->suboid, null_oid());
+ else if (resolve_gitlink_ref(update_data->sm_path, "HEAD", &update_data->suboid))
+ die(_("Unable to find current revision in submodule path '%s'"),
+ update_data->displaypath);
+
+ if (update_data->remote) {
+ char *remote_name = get_default_remote_submodule(update_data->sm_path);
+ const char *branch = remote_submodule_branch(update_data->sm_path);
+ char *remote_ref = xstrfmt("refs/remotes/%s/%s", remote_name, branch);
+
+ if (!update_data->nofetch) {
+ if (fetch_in_submodule(update_data->sm_path, update_data->depth,
+ 0, NULL))
+ die(_("Unable to fetch in submodule path '%s'"),
+ update_data->sm_path);
+ }
+
+ if (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))
+ die(_("Unable to find %s revision in submodule path '%s'"),
+ remote_ref, update_data->sm_path);
+
+ free(remote_ref);
+ }
+
+ if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
+ if (run_update_procedure(update_data))
+ return 1;
+
+ if (update_data->recursive) {
+ struct child_process cp = CHILD_PROCESS_INIT;
+ struct update_data next = *update_data;
+ int res;
+
+ if (update_data->recursive_prefix)
+ prefixed_path = xstrfmt("%s%s/", update_data->recursive_prefix,
+ update_data->sm_path);
+ else
+ prefixed_path = xstrfmt("%s/", update_data->sm_path);
+
+ next.recursive_prefix = get_submodule_displaypath(prefixed_path,
+ update_data->prefix);
+ next.prefix = NULL;
+ oidcpy(&next.oid, null_oid());
+ oidcpy(&next.suboid, null_oid());
+
+ cp.dir = update_data->sm_path;
+ cp.git_cmd = 1;
+ prepare_submodule_repo_env(&cp.env_array);
+ update_data_to_args(&next, &cp.args);
- run_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,
+ /* die() if child process die()'d */
+ res = run_command(&cp);
+ if (!res)
+ return 0;
+ die_message(_("Failed to recurse into submodule path '%s'"),
+ update_data->displaypath);
+ if (res == 128)
+ exit(res);
+ else if (res)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int update_submodules(struct update_data *update_data)
+{
+ int i, res = 0;
+ struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
+
+ suc.update_data = update_data;
+ run_processes_parallel_tr2(suc.update_data->max_jobs, update_clone_get_next_task,
update_clone_start_failure,
- update_clone_task_finished, suc, "submodule",
+ update_clone_task_finished, &suc, "submodule",
"parallel/update");
/*
@@ -2492,53 +2667,71 @@ static int update_submodules(struct submodule_update_clone *suc)
* checkout involve more straightforward sequential I/O.
* - the listener can avoid doing any work if fetching failed.
*/
- if (suc->quickstop)
- return 1;
+ if (suc.quickstop) {
+ res = 1;
+ goto cleanup;
+ }
- for (i = 0; i < suc->update_clone_nr; i++)
- update_submodule(&suc->update_clone[i]);
+ for (i = 0; i < suc.update_clone_nr; i++) {
+ struct update_clone_data ucd = suc.update_clone[i];
- return 0;
+ oidcpy(&update_data->oid, &ucd.oid);
+ update_data->just_cloned = ucd.just_cloned;
+ update_data->sm_path = ucd.sub->path;
+
+ if (update_submodule(update_data))
+ res = 1;
+ }
+
+cleanup:
+ string_list_clear(&update_data->references, 0);
+ return res;
}
-static int update_clone(int argc, const char **argv, const char *prefix)
+static int module_update(int argc, const char **argv, const char *prefix)
{
- const char *update = NULL;
struct pathspec pathspec;
- struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
+ struct update_data opt = UPDATE_DATA_INIT;
struct list_objects_filter_options filter_options;
int ret;
- struct option module_update_clone_options[] = {
- OPT_BOOL(0, "init", &suc.init,
+ struct option module_update_options[] = {
+ OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
+ OPT_BOOL(0, "init", &opt.init,
N_("initialize uninitialized submodules before update")),
- OPT_STRING(0, "prefix", &prefix,
+ OPT_BOOL(0, "remote", &opt.remote,
+ N_("use SHA-1 of submodule's remote tracking branch")),
+ OPT_BOOL(0, "recursive", &opt.recursive,
+ N_("traverse submodules recursively")),
+ OPT_BOOL('N', "no-fetch", &opt.nofetch,
+ N_("don't fetch new objects from the remote site")),
+ OPT_STRING(0, "prefix", &opt.prefix,
N_("path"),
N_("path into the working tree")),
- OPT_STRING(0, "recursive-prefix", &suc.recursive_prefix,
+ OPT_STRING(0, "recursive-prefix", &opt.recursive_prefix,
N_("path"),
N_("path into the working tree, across nested "
"submodule boundaries")),
- OPT_STRING(0, "update", &update,
+ OPT_STRING(0, "update", &opt.update_default,
N_("string"),
N_("rebase, merge, checkout or none")),
- OPT_STRING_LIST(0, "reference", &suc.references, N_("repo"),
+ OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"),
N_("reference repository")),
- OPT_BOOL(0, "dissociate", &suc.dissociate,
+ OPT_BOOL(0, "dissociate", &opt.dissociate,
N_("use --reference only while cloning")),
- OPT_STRING(0, "depth", &suc.depth, "<depth>",
+ OPT_INTEGER(0, "depth", &opt.depth,
N_("create a shallow clone truncated to the "
"specified number of revisions")),
- OPT_INTEGER('j', "jobs", &suc.max_jobs,
+ OPT_INTEGER('j', "jobs", &opt.max_jobs,
N_("parallel jobs")),
- OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
+ OPT_BOOL(0, "recommend-shallow", &opt.recommend_shallow,
N_("whether the initial clone should follow the shallow recommendation")),
- OPT__QUIET(&suc.quiet, N_("don't print cloning progress")),
- OPT_BOOL(0, "progress", &suc.progress,
+ OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
+ OPT_BOOL(0, "progress", &opt.progress,
N_("force cloning progress")),
- OPT_BOOL(0, "require-init", &suc.require_init,
+ OPT_BOOL(0, "require-init", &opt.require_init,
N_("disallow cloning into non-empty directory")),
- OPT_BOOL(0, "single-branch", &suc.single_branch,
+ OPT_BOOL(0, "single-branch", &opt.single_branch,
N_("clone only one branch, HEAD or --branch")),
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
OPT_END()
@@ -2553,46 +2746,39 @@ static int update_clone(int argc, const char **argv, const char *prefix)
" [--recursive] [--[no-]single-branch] [--] [<path>...]"),
NULL
};
- suc.prefix = prefix;
- update_clone_config_from_gitmodules(&suc.max_jobs);
- git_config(git_update_clone_config, &suc.max_jobs);
+ update_clone_config_from_gitmodules(&opt.max_jobs);
+ git_config(git_update_clone_config, &opt.max_jobs);
memset(&filter_options, 0, sizeof(filter_options));
- argc = parse_options(argc, argv, prefix, module_update_clone_options,
+ argc = parse_options(argc, argv, prefix, module_update_options,
git_submodule_helper_usage, 0);
- if (filter_options.choice && !suc.init) {
- /*
- * NEEDSWORK: Don't use usage_with_options() because the
- * usage string is for "git submodule update", but the
- * options are for "git submodule--helper update-clone".
- *
- * This will no longer be an issue when "update-clone"
- * is replaced by "git submodule--helper update".
- */
- usage(git_submodule_helper_usage[0]);
+ if (filter_options.choice && !opt.init) {
+ usage_with_options(git_submodule_helper_usage,
+ module_update_options);
}
- suc.filter_options = &filter_options;
+ opt.filter_options = &filter_options;
- if (update)
- if (parse_submodule_update_strategy(update, &suc.update) < 0)
+ if (opt.update_default)
+ if (parse_submodule_update_strategy(opt.update_default,
+ &opt.update_strategy) < 0)
die(_("bad value for update parameter"));
- if (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0) {
+ if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0) {
list_objects_filter_release(&filter_options);
return 1;
}
if (pathspec.nr)
- suc.warn_if_uninitialized = 1;
+ opt.warn_if_uninitialized = 1;
- if (suc.init) {
+ if (opt.init) {
struct module_list list = MODULE_LIST_INIT;
struct init_cb info = INIT_CB_INIT;
- if (module_list_compute(argc, argv, suc.prefix,
+ if (module_list_compute(argc, argv, opt.prefix,
&pathspec, &list) < 0)
return 1;
@@ -2603,127 +2789,19 @@ static int update_clone(int argc, const char **argv, const char *prefix)
if (!argc && git_config_get_value_multi("submodule.active"))
module_list_active(&list);
- info.prefix = suc.prefix;
- info.superprefix = suc.recursive_prefix;
- if (suc.quiet)
+ info.prefix = opt.prefix;
+ info.superprefix = opt.recursive_prefix;
+ if (opt.quiet)
info.flags |= OPT_QUIET;
for_each_listed_submodule(&list, init_submodule_cb, &info);
}
- ret = update_submodules(&suc);
+ ret = update_submodules(&opt);
list_objects_filter_release(&filter_options);
return ret;
}
-static int run_update_procedure(int argc, const char **argv, const char *prefix)
-{
- char *prefixed_path, *update = NULL;
- struct update_data update_data = UPDATE_DATA_INIT;
-
- struct option options[] = {
- OPT__QUIET(&update_data.quiet,
- N_("suppress output for update by rebase or merge")),
- OPT__FORCE(&update_data.force, N_("force checkout updates"),
- 0),
- OPT_BOOL('N', "no-fetch", &update_data.nofetch,
- N_("don't fetch new objects from the remote site")),
- OPT_BOOL(0, "just-cloned", &update_data.just_cloned,
- N_("overrides update mode in case the repository is a fresh clone")),
- OPT_INTEGER(0, "depth", &update_data.depth, N_("depth for shallow fetch")),
- OPT_STRING(0, "prefix", &prefix,
- N_("path"),
- N_("path into the working tree")),
- OPT_STRING(0, "update", &update,
- N_("string"),
- N_("rebase, merge, checkout or none")),
- OPT_STRING(0, "recursive-prefix", &update_data.recursive_prefix, N_("path"),
- N_("path into the working tree, across nested "
- "submodule boundaries")),
- OPT_CALLBACK_F(0, "oid", &update_data.oid, N_("sha1"),
- N_("SHA1 expected by superproject"), PARSE_OPT_NONEG,
- parse_opt_object_id),
- OPT_BOOL(0, "remote", &update_data.remote,
- N_("use SHA-1 of submodule's remote tracking branch")),
- OPT_END()
- };
-
- const char *const usage[] = {
- N_("git submodule--helper run-update-procedure [<options>] <path>"),
- NULL
- };
-
- argc = parse_options(argc, argv, prefix, options, usage, 0);
-
- if (argc != 1)
- usage_with_options(usage, options);
-
- update_data.sm_path = argv[0];
-
- if (update_data.recursive_prefix)
- prefixed_path = xstrfmt("%s%s", update_data.recursive_prefix, update_data.sm_path);
- else
- prefixed_path = xstrdup(update_data.sm_path);
-
- update_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);
-
- determine_submodule_update_strategy(the_repository, update_data.just_cloned,
- update_data.sm_path, update,
- &update_data.update_strategy);
-
- free(prefixed_path);
- return update_submodule2(&update_data);
-}
-
-static int resolve_relative_path(int argc, const char **argv, const char *prefix)
-{
- struct strbuf sb = STRBUF_INIT;
- if (argc != 3)
- die("submodule--helper relative-path takes exactly 2 arguments, got %d", argc);
-
- printf("%s", relative_path(argv[1], argv[2], &sb));
- strbuf_release(&sb);
- return 0;
-}
-
-static const char *remote_submodule_branch(const char *path)
-{
- const struct submodule *sub;
- const char *branch = NULL;
- char *key;
-
- sub = submodule_from_path(the_repository, null_oid(), path);
- if (!sub)
- return NULL;
-
- key = xstrfmt("submodule.%s.branch", sub->name);
- if (repo_config_get_string_tmp(the_repository, key, &branch))
- branch = sub->branch;
- free(key);
-
- if (!branch)
- return "HEAD";
-
- if (!strcmp(branch, ".")) {
- const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
-
- if (!refname)
- die(_("No such ref: %s"), "HEAD");
-
- /* detached HEAD */
- if (!strcmp(refname, "HEAD"))
- die(_("Submodule (%s) branch configured to inherit "
- "branch from superproject, but the superproject "
- "is not on any branch"), sub->name);
-
- if (!skip_prefix(refname, "refs/heads/", &refname))
- die(_("Expecting a full ref name, got %s"), refname);
- return refname;
- }
-
- return branch;
-}
-
static int push_check(int argc, const char **argv, const char *prefix)
{
struct remote *remote;
@@ -2801,32 +2879,6 @@ static int push_check(int argc, const char **argv, const char *prefix)
return 0;
}
-static void ensure_core_worktree(const char *path)
-{
- const char *cw;
- struct repository subrepo;
-
- if (repo_submodule_init(&subrepo, the_repository, path, null_oid()))
- die(_("could not get a repository handle for submodule '%s'"), path);
-
- if (!repo_config_get_string_tmp(&subrepo, "core.worktree", &cw)) {
- char *cfg_file, *abs_path;
- const char *rel_path;
- struct strbuf sb = STRBUF_INIT;
-
- cfg_file = repo_git_path(&subrepo, "config");
-
- abs_path = absolute_pathdup(path);
- rel_path = relative_path(abs_path, subrepo.gitdir, &sb);
-
- git_config_set_in_file(cfg_file, "core.worktree", rel_path);
-
- free(cfg_file);
- free(abs_path);
- strbuf_release(&sb);
- }
-}
-
static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
{
int i;
@@ -3021,9 +3073,10 @@ static int module_create_branch(int argc, const char **argv, const char *prefix)
OPT__FORCE(&force, N_("force creation"), 0),
OPT_BOOL(0, "create-reflog", &reflog,
N_("create the branch's reflog")),
- OPT_SET_INT('t', "track", &track,
- N_("set up tracking mode (see git-pull(1))"),
- BRANCH_TRACK_EXPLICIT),
+ OPT_CALLBACK_F('t', "track", &track, "(direct|inherit)",
+ N_("set branch tracking configuration"),
+ PARSE_OPT_OPTARG,
+ parse_opt_tracking_mode),
OPT__DRY_RUN(&dry_run,
N_("show whether the branch would be created")),
OPT_END()
@@ -3048,41 +3101,6 @@ static int module_create_branch(int argc, const char **argv, const char *prefix)
return 0;
}
-/* NEEDSWORK: this is a temporary name until we delete update_submodule() */
-static int update_submodule2(struct update_data *update_data)
-{
- ensure_core_worktree(update_data->sm_path);
- if (update_data->just_cloned)
- oidcpy(&update_data->suboid, null_oid());
- else if (resolve_gitlink_ref(update_data->sm_path, "HEAD", &update_data->suboid))
- die(_("Unable to find current revision in submodule path '%s'"),
- update_data->displaypath);
-
- if (update_data->remote) {
- char *remote_name = get_default_remote_submodule(update_data->sm_path);
- const char *branch = remote_submodule_branch(update_data->sm_path);
- char *remote_ref = xstrfmt("refs/remotes/%s/%s", remote_name, branch);
-
- if (!update_data->nofetch) {
- if (fetch_in_submodule(update_data->sm_path, update_data->depth,
- 0, NULL))
- die(_("Unable to fetch in submodule path '%s'"),
- update_data->sm_path);
- }
-
- if (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))
- die(_("Unable to find %s revision in submodule path '%s'"),
- remote_ref, update_data->sm_path);
-
- free(remote_ref);
- }
-
- if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
- return do_run_update_procedure(update_data);
-
- return 3;
-}
-
struct add_data {
const char *prefix;
const char *branch;
@@ -3471,9 +3489,7 @@ static struct cmd_struct commands[] = {
{"name", module_name, 0},
{"clone", module_clone, 0},
{"add", module_add, SUPPORT_SUPER_PREFIX},
- {"update-clone", update_clone, 0},
- {"run-update-procedure", run_update_procedure, 0},
- {"relative-path", resolve_relative_path, 0},
+ {"update", module_update, 0},
{"resolve-relative-url-test", resolve_relative_url_test, 0},
{"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
{"init", module_init, SUPPORT_SUPER_PREFIX},
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 4eaba2a8fd..9a9ee24abb 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -22,6 +22,7 @@ static const char * const worktree_usage[] = {
N_("git worktree move <worktree> <new-path>"),
N_("git worktree prune [<options>]"),
N_("git worktree remove [<options>] <worktree>"),
+ N_("git worktree repair [<path>...]"),
N_("git worktree unlock <path>"),
NULL
};
diff --git a/bundle.c b/bundle.c
index e359370cfc..d50cfb5aa7 100644
--- a/bundle.c
+++ b/bundle.c
@@ -267,11 +267,6 @@ int verify_bundle(struct repository *r,
(uintmax_t)r->nr);
list_refs(r, 0, NULL);
- if (header->filter.choice) {
- printf_ln("The bundle uses this filter: %s",
- list_objects_filter_spec(&header->filter));
- }
-
r = &header->prerequisites;
if (!r->nr) {
printf_ln(_("The bundle records a complete history."));
@@ -282,6 +277,12 @@ int verify_bundle(struct repository *r,
(uintmax_t)r->nr);
list_refs(r, 0, NULL);
}
+
+ printf_ln("The bundle uses this hash algorithm: %s",
+ header->hash_algo->name);
+ if (header->filter.choice)
+ printf_ln("The bundle uses this filter: %s",
+ list_objects_filter_spec(&header->filter));
}
return ret;
}
diff --git a/cache.h b/cache.h
index ef7d34b7a0..ee9549c460 100644
--- a/cache.h
+++ b/cache.h
@@ -1014,8 +1014,8 @@ enum fsync_component {
#define FSYNC_COMPONENTS_DERIVED_METADATA (FSYNC_COMPONENT_PACK_METADATA | \
FSYNC_COMPONENT_COMMIT_GRAPH)
-#define FSYNC_COMPONENTS_DEFAULT (FSYNC_COMPONENTS_OBJECTS | \
- FSYNC_COMPONENTS_DERIVED_METADATA | \
+#define FSYNC_COMPONENTS_DEFAULT ((FSYNC_COMPONENTS_OBJECTS | \
+ FSYNC_COMPONENTS_DERIVED_METADATA) & \
~FSYNC_COMPONENT_LOOSE_OBJECT)
#define FSYNC_COMPONENTS_COMMITTED (FSYNC_COMPONENTS_OBJECTS | \
diff --git a/commit.c b/commit.c
index ffcc4a97cd..59b6c3e455 100644
--- a/commit.c
+++ b/commit.c
@@ -1742,5 +1742,6 @@ int run_commit_hook(int editor_is_used, const char *index_file,
strvec_push(&opt.args, arg);
va_end(args);
+ opt.invoked_hook = invoked_hook;
return run_hooks_opt(name, &opt);
}
diff --git a/compat/terminal.c b/compat/terminal.c
index 3620184e79..7db330c52d 100644
--- a/compat/terminal.c
+++ b/compat/terminal.c
@@ -1,4 +1,4 @@
-#include "git-compat-util.h"
+#include "cache.h"
#include "compat/terminal.h"
#include "sigchain.h"
#include "strbuf.h"
@@ -20,39 +20,171 @@ static void restore_term_on_signal(int sig)
#define INPUT_PATH "/dev/tty"
#define OUTPUT_PATH "/dev/tty"
+static volatile sig_atomic_t term_fd_needs_closing;
static int term_fd = -1;
static struct termios old_term;
+static const char *background_resume_msg;
+static const char *restore_error_msg;
+static volatile sig_atomic_t ttou_received;
+
+/* async safe error function for use by signal handlers. */
+static void write_err(const char *msg)
+{
+ write_in_full(2, "error: ", strlen("error: "));
+ write_in_full(2, msg, strlen(msg));
+ write_in_full(2, "\n", 1);
+}
+
+static void print_background_resume_msg(int signo)
+{
+ int saved_errno = errno;
+ sigset_t mask;
+ struct sigaction old_sa;
+ struct sigaction sa = { .sa_handler = SIG_DFL };
+
+ ttou_received = 1;
+ write_err(background_resume_msg);
+ sigaction(signo, &sa, &old_sa);
+ raise(signo);
+ sigemptyset(&mask);
+ sigaddset(&mask, signo);
+ sigprocmask(SIG_UNBLOCK, &mask, NULL);
+ /* Stopped here */
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+ sigaction(signo, &old_sa, NULL);
+ errno = saved_errno;
+}
+
+static void restore_terminal_on_suspend(int signo)
+{
+ int saved_errno = errno;
+ int res;
+ struct termios t;
+ sigset_t mask;
+ struct sigaction old_sa;
+ struct sigaction sa = { .sa_handler = SIG_DFL };
+ int can_restore = 1;
+
+ if (tcgetattr(term_fd, &t) < 0)
+ can_restore = 0;
+
+ if (tcsetattr(term_fd, TCSAFLUSH, &old_term) < 0)
+ write_err(restore_error_msg);
+
+ sigaction(signo, &sa, &old_sa);
+ raise(signo);
+ sigemptyset(&mask);
+ sigaddset(&mask, signo);
+ sigprocmask(SIG_UNBLOCK, &mask, NULL);
+ /* Stopped here */
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+ sigaction(signo, &old_sa, NULL);
+ if (!can_restore) {
+ write_err(restore_error_msg);
+ goto out;
+ }
+ /*
+ * If we resume in the background then we receive SIGTTOU when calling
+ * tcsetattr() below. Set up a handler to print an error message in that
+ * case.
+ */
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGTTOU);
+ sa.sa_mask = old_sa.sa_mask;
+ sa.sa_handler = print_background_resume_msg;
+ sa.sa_flags = SA_RESTART;
+ sigaction(SIGTTOU, &sa, &old_sa);
+ again:
+ ttou_received = 0;
+ sigprocmask(SIG_UNBLOCK, &mask, NULL);
+ res = tcsetattr(term_fd, TCSAFLUSH, &t);
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+ if (ttou_received)
+ goto again;
+ else if (res < 0)
+ write_err(restore_error_msg);
+ sigaction(SIGTTOU, &old_sa, NULL);
+ out:
+ errno = saved_errno;
+}
+
+static void reset_job_signals(void)
+{
+ if (restore_error_msg) {
+ signal(SIGTTIN, SIG_DFL);
+ signal(SIGTTOU, SIG_DFL);
+ signal(SIGTSTP, SIG_DFL);
+ restore_error_msg = NULL;
+ background_resume_msg = NULL;
+ }
+}
+
+static void close_term_fd(void)
+{
+ if (term_fd_needs_closing)
+ close(term_fd);
+ term_fd_needs_closing = 0;
+ term_fd = -1;
+}
+
void restore_term(void)
{
if (term_fd < 0)
return;
tcsetattr(term_fd, TCSAFLUSH, &old_term);
- close(term_fd);
- term_fd = -1;
+ close_term_fd();
sigchain_pop_common();
+ reset_job_signals();
}
-int save_term(int full_duplex)
+int save_term(enum save_term_flags flags)
{
+ struct sigaction sa;
+
if (term_fd < 0)
- term_fd = open("/dev/tty", O_RDWR);
+ term_fd = ((flags & SAVE_TERM_STDIN)
+ ? 0
+ : open("/dev/tty", O_RDWR));
if (term_fd < 0)
return -1;
- if (tcgetattr(term_fd, &old_term) < 0)
+ term_fd_needs_closing = !(flags & SAVE_TERM_STDIN);
+ if (tcgetattr(term_fd, &old_term) < 0) {
+ close_term_fd();
return -1;
+ }
sigchain_push_common(restore_term_on_signal);
+ /*
+ * If job control is disabled then the shell will have set the
+ * disposition of SIGTSTP to SIG_IGN.
+ */
+ sigaction(SIGTSTP, NULL, &sa);
+ if (sa.sa_handler == SIG_IGN)
+ return 0;
+
+ /* avoid calling gettext() from signal handler */
+ background_resume_msg = _("cannot resume in the background, please use 'fg' to resume");
+ restore_error_msg = _("cannot restore terminal settings");
+ sa.sa_handler = restore_terminal_on_suspend;
+ sa.sa_flags = SA_RESTART;
+ sigemptyset(&sa.sa_mask);
+ sigaddset(&sa.sa_mask, SIGTSTP);
+ sigaddset(&sa.sa_mask, SIGTTIN);
+ sigaddset(&sa.sa_mask, SIGTTOU);
+ sigaction(SIGTSTP, &sa, NULL);
+ sigaction(SIGTTIN, &sa, NULL);
+ sigaction(SIGTTOU, &sa, NULL);
return 0;
}
-static int disable_bits(tcflag_t bits)
+static int disable_bits(enum save_term_flags flags, tcflag_t bits)
{
struct termios t;
- if (save_term(0) < 0)
- goto error;
+ if (save_term(flags) < 0)
+ return -1;
t = old_term;
@@ -65,20 +197,50 @@ static int disable_bits(tcflag_t bits)
return 0;
sigchain_pop_common();
-error:
- close(term_fd);
- term_fd = -1;
+ reset_job_signals();
+ close_term_fd();
return -1;
}
-static int disable_echo(void)
+static int disable_echo(enum save_term_flags flags)
{
- return disable_bits(ECHO);
+ return disable_bits(flags, ECHO);
}
-static int enable_non_canonical(void)
+static int enable_non_canonical(enum save_term_flags flags)
{
- return disable_bits(ICANON | ECHO);
+ return disable_bits(flags, ICANON | ECHO);
+}
+
+/*
+ * On macos it is not possible to use poll() with a terminal so use select
+ * instead.
+ */
+static int getchar_with_timeout(int timeout)
+{
+ struct timeval tv, *tvp = NULL;
+ fd_set readfds;
+ int res;
+
+ again:
+ if (timeout >= 0) {
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ tvp = &tv;
+ }
+
+ FD_ZERO(&readfds);
+ FD_SET(0, &readfds);
+ res = select(1, &readfds, NULL, NULL, tvp);
+ if (!res)
+ return EOF;
+ if (res < 0) {
+ if (errno == EINTR)
+ goto again;
+ else
+ return EOF;
+ }
+ return getchar();
}
#elif defined(GIT_WINDOWS_NATIVE)
@@ -126,7 +288,7 @@ void restore_term(void)
hconin = hconout = INVALID_HANDLE_VALUE;
}
-int save_term(int full_duplex)
+int save_term(enum save_term_flags flags)
{
hconin = CreateFileA("CONIN$", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
@@ -134,7 +296,7 @@ int save_term(int full_duplex)
if (hconin == INVALID_HANDLE_VALUE)
return -1;
- if (full_duplex) {
+ if (flags & SAVE_TERM_DUPLEX) {
hconout = CreateFileA("CONOUT$", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
@@ -154,7 +316,7 @@ error:
return -1;
}
-static int disable_bits(DWORD bits)
+static int disable_bits(enum save_term_flags flags, DWORD bits)
{
if (use_stty) {
struct child_process cp = CHILD_PROCESS_INIT;
@@ -191,7 +353,7 @@ static int disable_bits(DWORD bits)
use_stty = 0;
}
- if (save_term(0) < 0)
+ if (save_term(flags) < 0)
return -1;
if (!SetConsoleMode(hconin, cmode_in & ~bits)) {
@@ -204,14 +366,15 @@ static int disable_bits(DWORD bits)
return 0;
}
-static int disable_echo(void)
+static int disable_echo(enum save_term_flags flags)
{
- return disable_bits(ENABLE_ECHO_INPUT);
+ return disable_bits(flags, ENABLE_ECHO_INPUT);
}
-static int enable_non_canonical(void)
+static int enable_non_canonical(enum save_term_flags flags)
{
- return disable_bits(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
+ return disable_bits(flags,
+ ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
}
/*
@@ -245,6 +408,16 @@ static int mingw_getchar(void)
}
#define getchar mingw_getchar
+static int getchar_with_timeout(int timeout)
+{
+ struct pollfd pfd = { .fd = 0, .events = POLLIN };
+
+ if (poll(&pfd, 1, timeout) < 1)
+ return EOF;
+
+ return getchar();
+}
+
#endif
#ifndef FORCE_TEXT
@@ -267,7 +440,7 @@ char *git_terminal_prompt(const char *prompt, int echo)
return NULL;
}
- if (!echo && disable_echo()) {
+ if (!echo && disable_echo(0)) {
fclose(input_fh);
fclose(output_fh);
return NULL;
@@ -361,7 +534,7 @@ int read_key_without_echo(struct strbuf *buf)
static int warning_displayed;
int ch;
- if (warning_displayed || enable_non_canonical() < 0) {
+ if (warning_displayed || enable_non_canonical(SAVE_TERM_STDIN) < 0) {
if (!warning_displayed) {
warning("reading single keystrokes not supported on "
"this platform; reading line instead");
@@ -395,12 +568,7 @@ int read_key_without_echo(struct strbuf *buf)
* half a second when we know that the sequence is complete.
*/
while (!is_known_escape_sequence(buf->buf)) {
- struct pollfd pfd = { .fd = 0, .events = POLLIN };
-
- if (poll(&pfd, 1, 500) < 1)
- break;
-
- ch = getchar();
+ ch = getchar_with_timeout(500);
if (ch == EOF)
break;
strbuf_addch(buf, ch);
@@ -413,10 +581,10 @@ int read_key_without_echo(struct strbuf *buf)
#else
-int save_term(int full_duplex)
+int save_term(enum save_term_flags flags)
{
- /* full_duplex == 1, but no support available */
- return -full_duplex;
+ /* no duplex support available */
+ return -!!(flags & SAVE_TERM_DUPLEX);
}
void restore_term(void)
diff --git a/compat/terminal.h b/compat/terminal.h
index 0fb9fa147c..79ed00cf61 100644
--- a/compat/terminal.h
+++ b/compat/terminal.h
@@ -1,6 +1,13 @@
#ifndef COMPAT_TERMINAL_H
#define COMPAT_TERMINAL_H
+enum save_term_flags {
+ /* Save input and output settings */
+ SAVE_TERM_DUPLEX = 1 << 0,
+ /* Save stdin rather than /dev/tty (fails if stdin is not a terminal) */
+ SAVE_TERM_STDIN = 1 << 1,
+};
+
/*
* Save the terminal attributes so they can be restored later by a
* call to restore_term(). Note that every successful call to
@@ -8,7 +15,7 @@
* attributes have not been changed. Returns 0 on success, -1 on
* failure.
*/
-int save_term(int full_duplex);
+int save_term(enum save_term_flags flags);
/* Restore the terminal attributes that were saved with save_term() */
void restore_term(void);
diff --git a/config.c b/config.c
index 3c9b6b589a..9eb0dbb448 100644
--- a/config.c
+++ b/config.c
@@ -1695,7 +1695,7 @@ static int git_default_core_config(const char *var, const char *value, void *cb)
if (!strcmp(var, "core.fsyncobjectfiles")) {
if (fsync_object_files < 0)
- warning(_("core.fsyncobjectfiles is deprecated; use core.fsync instead"));
+ warning(_("core.fsyncObjectFiles is deprecated; use core.fsync instead"));
fsync_object_files = git_config_bool(var, value);
return 0;
}
diff --git a/contrib/coccinelle/strbuf.cocci b/contrib/coccinelle/strbuf.cocci
index d9ada69b43..0970d98ad7 100644
--- a/contrib/coccinelle/strbuf.cocci
+++ b/contrib/coccinelle/strbuf.cocci
@@ -15,7 +15,7 @@ constant fmt !~ "%";
@@
expression E;
struct strbuf SB;
-format F =~ "s";
+format F =~ "^s$";
@@
- strbuf_addf(E, "%@F@", SB.buf);
+ strbuf_addbuf(E, &SB);
@@ -23,7 +23,7 @@ format F =~ "s";
@@
expression E;
struct strbuf *SBP;
-format F =~ "s";
+format F =~ "^s$";
@@
- strbuf_addf(E, "%@F@", SBP->buf);
+ strbuf_addbuf(E, SBP);
@@ -44,7 +44,7 @@ struct strbuf *SBP;
@@
expression E1, E2;
-format F =~ "s";
+format F =~ "^s$";
@@
- strbuf_addf(E1, "%@F@", E2);
+ strbuf_addstr(E1, E2);
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
index db7c0068fb..87b2b916c0 100644
--- a/contrib/completion/git-prompt.sh
+++ b/contrib/completion/git-prompt.sh
@@ -66,6 +66,11 @@
# git always compare HEAD to @{upstream}
# svn always compare HEAD to your SVN upstream
#
+# By default, __git_ps1 will compare HEAD to your SVN upstream if it can
+# find one, or @{upstream} otherwise. Once you have set
+# GIT_PS1_SHOWUPSTREAM, you can override it on a per-repository basis by
+# setting the bash.showUpstream config variable.
+#
# You can change the separator between the branch name and the above
# state symbols by setting GIT_PS1_STATESEPARATOR. The default separator
# is SP.
@@ -79,11 +84,6 @@
# single '?' character by setting GIT_PS1_COMPRESSSPARSESTATE, or omitted
# by setting GIT_PS1_OMITSPARSESTATE.
#
-# By default, __git_ps1 will compare HEAD to your SVN upstream if it can
-# find one, or @{upstream} otherwise. Once you have set
-# GIT_PS1_SHOWUPSTREAM, you can override it on a per-repository basis by
-# setting the bash.showUpstream config variable.
-#
# If you would like to see more information about the identity of
# commits checked out as a detached HEAD, set GIT_PS1_DESCRIBE_STYLE
# to one of these values:
@@ -115,7 +115,7 @@ __git_ps1_show_upstream ()
{
local key value
local svn_remote svn_url_pattern count n
- local upstream=git legacy="" verbose="" name=""
+ local upstream_type=git legacy="" verbose="" name=""
svn_remote=()
# get some config options from git-config
@@ -132,7 +132,7 @@ __git_ps1_show_upstream ()
svn-remote.*.url)
svn_remote[$((${#svn_remote[@]} + 1))]="$value"
svn_url_pattern="$svn_url_pattern\\|$value"
- upstream=svn+git # default upstream is SVN if available, else git
+ upstream_type=svn+git # default upstream type is SVN if available, else git
;;
esac
done <<< "$output"
@@ -141,16 +141,16 @@ __git_ps1_show_upstream ()
local option
for option in ${GIT_PS1_SHOWUPSTREAM}; do
case "$option" in
- git|svn) upstream="$option" ;;
+ git|svn) upstream_type="$option" ;;
verbose) verbose=1 ;;
legacy) legacy=1 ;;
name) name=1 ;;
esac
done
- # Find our upstream
- case "$upstream" in
- git) upstream="@{upstream}" ;;
+ # Find our upstream type
+ case "$upstream_type" in
+ git) upstream_type="@{upstream}" ;;
svn*)
# get the upstream from the "git-svn-id: ..." in a commit message
# (git-svn uses essentially the same procedure internally)
@@ -167,12 +167,12 @@ __git_ps1_show_upstream ()
if [[ -z "$svn_upstream" ]]; then
# default branch name for checkouts with no layout:
- upstream=${GIT_SVN_ID:-git-svn}
+ upstream_type=${GIT_SVN_ID:-git-svn}
else
- upstream=${svn_upstream#/}
+ upstream_type=${svn_upstream#/}
fi
- elif [[ "svn+git" = "$upstream" ]]; then
- upstream="@{upstream}"
+ elif [[ "svn+git" = "$upstream_type" ]]; then
+ upstream_type="@{upstream}"
fi
;;
esac
@@ -180,11 +180,11 @@ __git_ps1_show_upstream ()
# Find how many commits we are ahead/behind our upstream
if [[ -z "$legacy" ]]; then
count="$(git rev-list --count --left-right \
- "$upstream"...HEAD 2>/dev/null)"
+ "$upstream_type"...HEAD 2>/dev/null)"
else
# produce equivalent output to --count for older versions of git
local commits
- if commits="$(git rev-list --left-right "$upstream"...HEAD 2>/dev/null)"
+ if commits="$(git rev-list --left-right "$upstream_type"...HEAD 2>/dev/null)"
then
local commit behind=0 ahead=0
for commit in $commits
@@ -214,26 +214,26 @@ __git_ps1_show_upstream ()
*) # diverged from upstream
p="<>" ;;
esac
- else
+ else # verbose, set upstream instead of p
case "$count" in
"") # no upstream
- p="" ;;
+ upstream="" ;;
"0 0") # equal to upstream
- p=" u=" ;;
+ upstream="|u=" ;;
"0 "*) # ahead of upstream
- p=" u+${count#0 }" ;;
+ upstream="|u+${count#0 }" ;;
*" 0") # behind upstream
- p=" u-${count% 0}" ;;
+ upstream="|u-${count% 0}" ;;
*) # diverged from upstream
- p=" u+${count#* }-${count% *}" ;;
+ upstream="|u+${count#* }-${count% *}" ;;
esac
if [[ -n "$count" && -n "$name" ]]; then
__git_ps1_upstream_name=$(git rev-parse \
- --abbrev-ref "$upstream" 2>/dev/null)
+ --abbrev-ref "$upstream_type" 2>/dev/null)
if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then
- p="$p \${__git_ps1_upstream_name}"
+ upstream="$upstream \${__git_ps1_upstream_name}"
else
- p="$p ${__git_ps1_upstream_name}"
+ upstream="$upstream ${__git_ps1_upstream_name}"
# not needed anymore; keep user's
# environment clean
unset __git_ps1_upstream_name
@@ -512,7 +512,8 @@ __git_ps1 ()
local u=""
local h=""
local c=""
- local p=""
+ local p="" # short version of upstream state indicator
+ local upstream="" # verbose version of upstream state indicator
if [ "true" = "$inside_gitdir" ]; then
if [ "true" = "$bare_repo" ]; then
@@ -568,8 +569,8 @@ __git_ps1 ()
b="\${__git_ps1_branch_name}"
fi
- local f="$h$w$i$s$u"
- local gitstring="$c$b${f:+$z$f}${sparse}$r$p"
+ local f="$h$w$i$s$u$p"
+ local gitstring="$c$b${f:+$z$f}${sparse}$r${upstream}"
if [ $pcmode = yes ]; then
if [ "${__git_printf_supports_v-}" != yes ]; then
diff --git a/contrib/scalar/scalar.c b/contrib/scalar/scalar.c
index 7db2a97416..58ca0e56f1 100644
--- a/contrib/scalar/scalar.c
+++ b/contrib/scalar/scalar.c
@@ -152,7 +152,6 @@ static int set_recommended_config(int reconfigure)
{ "pack.useBitmaps", "false", 1 },
{ "pack.useSparse", "true", 1 },
{ "receive.autoGC", "false", 1 },
- { "reset.quiet", "true", 1 },
{ "feature.manyFiles", "false", 1 },
{ "feature.experimental", "false", 1 },
{ "fetch.unpackLimit", "1", 1 },
diff --git a/git-submodule.sh b/git-submodule.sh
index aa8bdfca9d..fd0b4a2c94 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -51,14 +51,6 @@ jobs=
recommend_shallow=
filter=
-die_if_unmatched ()
-{
- if test "$1" = "#unmatched"
- then
- exit ${2:-1}
- fi
-}
-
isnumber()
{
n=$(($1 + 0)) 2>/dev/null && test "$n" = "$1"
@@ -356,109 +348,28 @@ cmd_update()
shift
done
- {
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper update-clone \
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper update \
${GIT_QUIET:+--quiet} \
+ ${force:+--force} \
${progress:+"--progress"} \
+ ${remote:+--remote} \
+ ${recursive:+--recursive} \
${init:+--init} \
+ ${nofetch:+--no-fetch} \
${wt_prefix:+--prefix "$wt_prefix"} \
${prefix:+--recursive-prefix "$prefix"} \
${update:+--update "$update"} \
${reference:+"$reference"} \
${dissociate:+"--dissociate"} \
- ${depth:+--depth "$depth"} \
+ ${depth:+"$depth"} \
${require_init:+--require-init} \
+ ${dissociate:+"--dissociate"} \
$single_branch \
$recommend_shallow \
$jobs \
$filter \
-- \
- "$@" || echo "#unmatched" $?
- } | {
- err=
- while read -r quickabort sha1 just_cloned sm_path
- do
- die_if_unmatched "$quickabort" "$sha1"
-
- displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
-
- if test $just_cloned -eq 0
- then
- just_cloned=
- fi
-
- out=$(git submodule--helper run-update-procedure \
- ${wt_prefix:+--prefix "$wt_prefix"} \
- ${GIT_QUIET:+--quiet} \
- ${force:+--force} \
- ${just_cloned:+--just-cloned} \
- ${nofetch:+--no-fetch} \
- ${depth:+"$depth"} \
- ${update:+--update "$update"} \
- ${prefix:+--recursive-prefix "$prefix"} \
- ${sha1:+--oid "$sha1"} \
- ${remote:+--remote} \
- "--" \
- "$sm_path")
-
- # exit codes for run-update-procedure:
- # 0: update was successful, say command output
- # 1: update procedure failed, but should not die
- # 2 or 128: subcommand died during execution
- # 3: no update procedure was run
- res="$?"
- case $res in
- 0)
- say "$out"
- ;;
- 1)
- err="${err};fatal: $out"
- continue
- ;;
- 2|128)
- die_with_status $res "fatal: $out"
- ;;
- esac
-
- if test -n "$recursive"
- then
- (
- prefix=$(git submodule--helper relative-path "$prefix$sm_path/" "$wt_prefix")
- wt_prefix=
- sanitize_submodule_env
- cd "$sm_path" &&
- eval cmd_update
- )
- res=$?
- if test $res -gt 0
- then
- die_msg="fatal: $(eval_gettext "Failed to recurse into submodule path '\$displaypath'")"
- if test $res -ne 2
- then
- err="${err};$die_msg"
- continue
- else
- die_with_status $res "$die_msg"
- fi
- fi
- fi
- done
-
- if test -n "$err"
- then
- OIFS=$IFS
- IFS=';'
- for e in $err
- do
- if test -n "$e"
- then
- echo >&2 "$e"
- fi
- done
- IFS=$OIFS
- exit 1
- fi
- }
+ "$@"
}
#
diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c
index f02d8df142..4b25287886 100644
--- a/list-objects-filter-options.c
+++ b/list-objects-filter-options.c
@@ -285,6 +285,10 @@ int opt_parse_list_objects_filter(const struct option *opt,
const char *arg, int unset)
{
struct list_objects_filter_options *filter_options = opt->value;
+ opt_lof_init init = (opt_lof_init)opt->defval;
+
+ if (init)
+ filter_options = init(opt->value);
if (unset || !arg)
list_objects_filter_set_no_filter(filter_options);
diff --git a/list-objects-filter-options.h b/list-objects-filter-options.h
index 2eb6c98394..ffc02d77e7 100644
--- a/list-objects-filter-options.h
+++ b/list-objects-filter-options.h
@@ -69,9 +69,6 @@ struct list_objects_filter_options {
*/
};
-/* Normalized command line arguments */
-#define CL_ARG__FILTER "filter"
-
/*
* Parse value of the argument to the "filter" keyword.
* On the command line this looks like:
@@ -107,13 +104,31 @@ void parse_list_objects_filter(
struct list_objects_filter_options *filter_options,
const char *arg);
+/**
+ * The opt->value to opt_parse_list_objects_filter() is either a
+ * "struct list_objects_filter_option *" when using
+ * OPT_PARSE_LIST_OBJECTS_FILTER().
+ *
+ * Or, if using no "struct option" field is used by the callback,
+ * except the "defval" which is expected to be an "opt_lof_init"
+ * function, which is called with the "opt->value" and must return a
+ * pointer to the ""struct list_objects_filter_option *" to be used.
+ *
+ * The OPT_PARSE_LIST_OBJECTS_FILTER_INIT() can be used e.g. the
+ * "struct list_objects_filter_option" is embedded in a "struct
+ * rev_info", which the "defval" could be tasked with lazily
+ * initializing. See cmd_pack_objects() for an example.
+ */
int opt_parse_list_objects_filter(const struct option *opt,
const char *arg, int unset);
+typedef struct list_objects_filter_options *(*opt_lof_init)(void *);
+#define OPT_PARSE_LIST_OBJECTS_FILTER_INIT(fo, init) \
+ { OPTION_CALLBACK, 0, "filter", (fo), N_("args"), \
+ N_("object filtering"), 0, opt_parse_list_objects_filter, \
+ (intptr_t)(init) }
#define OPT_PARSE_LIST_OBJECTS_FILTER(fo) \
- OPT_CALLBACK(0, CL_ARG__FILTER, fo, N_("args"), \
- N_("object filtering"), \
- opt_parse_list_objects_filter)
+ OPT_PARSE_LIST_OBJECTS_FILTER_INIT((fo), NULL)
/*
* Translates abbreviated numbers in the filter's filter_spec into their
diff --git a/object-file.c b/object-file.c
index b254bc50d7..5ffbf3d4fd 100644
--- a/object-file.c
+++ b/object-file.c
@@ -1888,16 +1888,16 @@ void hash_object_file(const struct git_hash_algo *algo, const void *buf,
}
/* Finalize a file on disk, and close it. */
-static void close_loose_object(int fd)
+static void close_loose_object(int fd, const char *filename)
{
if (the_repository->objects->odb->will_destroy)
goto out;
if (fsync_object_files > 0)
- fsync_or_die(fd, "loose object file");
+ fsync_or_die(fd, filename);
else
fsync_component_or_die(FSYNC_COMPONENT_LOOSE_OBJECT, fd,
- "loose object file");
+ filename);
out:
if (close(fd) != 0)
@@ -2011,7 +2011,7 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
die(_("confused by unstable object source data for %s"),
oid_to_hex(oid));
- close_loose_object(fd);
+ close_loose_object(fd, tmp_file.buf);
if (mtime) {
struct utimbuf utb;
diff --git a/reflog.c b/reflog.c
index 47ba8620c5..135a1a6e41 100644
--- a/reflog.c
+++ b/reflog.c
@@ -240,8 +240,8 @@ static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit
* Return true iff the specified reflog entry should be expired.
*/
int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
- const char *email, timestamp_t timestamp, int tz,
- const char *message, void *cb_data)
+ const char *email, timestamp_t timestamp, int tz,
+ const char *message, void *cb_data)
{
struct expire_reflog_policy_cb *cb = cb_data;
struct commit *old_commit, *new_commit;
@@ -273,10 +273,10 @@ int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
}
int should_expire_reflog_ent_verbose(struct object_id *ooid,
- struct object_id *noid,
- const char *email,
- timestamp_t timestamp, int tz,
- const char *message, void *cb_data)
+ struct object_id *noid,
+ const char *email,
+ timestamp_t timestamp, int tz,
+ const char *message, void *cb_data)
{
struct expire_reflog_policy_cb *cb = cb_data;
int expire;
@@ -323,8 +323,8 @@ static int is_head(const char *refname)
}
void reflog_expiry_prepare(const char *refname,
- const struct object_id *oid,
- void *cb_data)
+ const struct object_id *oid,
+ void *cb_data)
{
struct expire_reflog_policy_cb *cb = cb_data;
struct commit_list *elem;
@@ -379,8 +379,8 @@ void reflog_expiry_cleanup(void *cb_data)
}
int count_reflog_ent(struct object_id *ooid, struct object_id *noid,
- const char *email, timestamp_t timestamp, int tz,
- const char *message, void *cb_data)
+ const char *email, timestamp_t timestamp, int tz,
+ const char *message, void *cb_data)
{
struct cmd_reflog_expire_cb *cb = cb_data;
if (!cb->expire_total || timestamp < cb->expire_total)
diff --git a/reftable/generic.c b/reftable/generic.c
index b27d152e89..57f8032db9 100644
--- a/reftable/generic.c
+++ b/reftable/generic.c
@@ -130,7 +130,9 @@ int reftable_iterator_next_ref(struct reftable_iterator *it,
{
struct reftable_record rec = {
.type = BLOCK_TYPE_REF,
- .u.ref = *ref,
+ .u = {
+ .ref = *ref
+ },
};
int err = iterator_next(it, &rec);
*ref = rec.u.ref;
@@ -142,7 +144,9 @@ int reftable_iterator_next_log(struct reftable_iterator *it,
{
struct reftable_record rec = {
.type = BLOCK_TYPE_LOG,
- .u.log = *log,
+ .u = {
+ .log = *log,
+ },
};
int err = iterator_next(it, &rec);
*log = rec.u.log;
diff --git a/reftable/record_test.c b/reftable/record_test.c
index f91ea5e883..70ae78feca 100644
--- a/reftable/record_test.c
+++ b/reftable/record_test.c
@@ -339,7 +339,9 @@ static void test_reftable_obj_record_roundtrip(void)
};
struct reftable_record in = {
.type = BLOCK_TYPE_OBJ,
- .u.obj = recs[i],
+ .u = {
+ .obj = recs[i],
+ },
};
struct strbuf key = STRBUF_INIT;
struct reftable_record out = { .type = BLOCK_TYPE_OBJ };
diff --git a/reftable/writer.c b/reftable/writer.c
index 6d979e245f..427f1317c6 100644
--- a/reftable/writer.c
+++ b/reftable/writer.c
@@ -257,7 +257,9 @@ int reftable_writer_add_ref(struct reftable_writer *w,
{
struct reftable_record rec = {
.type = BLOCK_TYPE_REF,
- .u.ref = *ref,
+ .u = {
+ .ref = *ref
+ },
};
int err = 0;
@@ -308,7 +310,9 @@ static int reftable_writer_add_log_verbatim(struct reftable_writer *w,
{
struct reftable_record rec = {
.type = BLOCK_TYPE_LOG,
- .u.log = *log,
+ .u = {
+ .log = *log,
+ },
};
if (w->block_writer &&
block_writer_type(w->block_writer) == BLOCK_TYPE_REF) {
@@ -401,7 +405,9 @@ static int writer_finish_section(struct reftable_writer *w)
for (i = 0; i < idx_len; i++) {
struct reftable_record rec = {
.type = BLOCK_TYPE_INDEX,
- .u.idx = idx[i],
+ .u = {
+ .idx = idx[i],
+ },
};
if (block_writer_add(w->block_writer, &rec) == 0) {
continue;
diff --git a/revision.c b/revision.c
index 2646b78990..7d435f8048 100644
--- a/revision.c
+++ b/revision.c
@@ -2691,9 +2691,9 @@ static int handle_revision_pseudo_opt(struct rev_info *revs,
revs->no_walk = 0;
} else if (!strcmp(arg, "--single-worktree")) {
revs->single_worktree = 1;
- } else if (skip_prefix(arg, ("--" CL_ARG__FILTER "="), &arg)) {
+ } else if (skip_prefix(arg, ("--filter="), &arg)) {
parse_list_objects_filter(&revs->filter, arg);
- } else if (!strcmp(arg, ("--no-" CL_ARG__FILTER))) {
+ } else if (!strcmp(arg, ("--no-filter"))) {
list_objects_filter_set_no_filter(&revs->filter);
} else {
return 0;
diff --git a/shared.mak b/shared.mak
index 4e1b62ee99..50d4596f0d 100644
--- a/shared.mak
+++ b/shared.mak
@@ -53,7 +53,7 @@ ifndef V
QUIET = @
QUIET_GEN = @echo ' ' GEN $@;
- QUIET_MKDIR_P_PARENT = @echo $(wspfx_SQ) MKDIR -p $(@D);
+ QUIET_MKDIR_P_PARENT = @echo ' ' MKDIR -p $(@D);
## Used in "Makefile"
QUIET_CC = @echo ' ' CC $@;
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 9dcbf518a7..17a268ccd1 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"
diff --git a/t/t0029-core-unsetenvvars.sh b/t/t0029-core-unsetenvvars.sh
index b138e1d9cb..4e8e90dd98 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/t0091-bugreport.sh b/t/t0091-bugreport.sh
index eeedbfa919..08f5fe9cae 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/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh
index fa9647a7c0..f6dc83e2aa 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/t1410-reflog.sh b/t/t1410-reflog.sh
index ea8e6ac2a0..aa59954f6c 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 &&
diff --git a/t/t1411-reflog-show.sh b/t/t1411-reflog-show.sh
index 0bb319b944..975c4ea83a 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 4e1e84a91f..085a7a46f2 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
@@ -140,7 +137,7 @@ 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 &&
- write_script .git/hooks/reference-transaction <<-\EOF &&
+ test_hook reference-transaction <<-\EOF &&
echo "$@" >>actual
cat >>actual
EOF
@@ -166,7 +163,7 @@ test_expect_success 'deleting packed ref calls hook once' '
git update-ref refs/heads/to-be-deleted $POST_OID &&
git pack-refs --all &&
- write_script .git/hooks/reference-transaction <<-\EOF &&
+ test_hook reference-transaction <<-\EOF &&
echo "$@" >>actual
cat >>actual
EOF
diff --git a/t/t1418-reflog-exists.sh b/t/t1418-reflog-exists.sh
new file mode 100755
index 0000000000..d51ecd5e92
--- /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/t1800-hook.sh b/t/t1800-hook.sh
index 29718aa991..26ed5e11bc 100755
--- a/t/t1800-hook.sh
+++ b/t/t1800-hook.sh
@@ -27,7 +27,7 @@ test_expect_success 'git hook run: nonexistent hook with --ignore-missing' '
'
test_expect_success 'git hook run: basic' '
- write_script .git/hooks/test-hook <<-EOF &&
+ test_hook test-hook <<-EOF &&
echo Test hook
EOF
@@ -39,7 +39,7 @@ test_expect_success 'git hook run: basic' '
'
test_expect_success 'git hook run: stdout and stderr both write to our stderr' '
- write_script .git/hooks/test-hook <<-EOF &&
+ test_hook test-hook <<-EOF &&
echo >&1 Will end up on stderr
echo >&2 Will end up on stderr
EOF
@@ -53,38 +53,23 @@ test_expect_success 'git hook run: stdout and stderr both write to our stderr' '
test_must_be_empty stdout.actual
'
-test_expect_success 'git hook run: exit codes are passed along' '
- write_script .git/hooks/test-hook <<-EOF &&
- exit 1
- EOF
-
- test_expect_code 1 git hook run test-hook &&
-
- write_script .git/hooks/test-hook <<-EOF &&
- exit 2
- EOF
-
- test_expect_code 2 git hook run test-hook &&
-
- write_script .git/hooks/test-hook <<-EOF &&
- exit 128
- EOF
+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 128 git hook run test-hook &&
-
- write_script .git/hooks/test-hook <<-EOF &&
- exit 129
- EOF
-
- test_expect_code 129 git hook run test-hook
-'
+ 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' '
- write_script .git/hooks/test-hook <<-\EOF &&
+ test_hook test-hook <<-\EOF &&
echo $1
echo $2
EOF
@@ -99,7 +84,7 @@ test_expect_success 'git hook run -- pass arguments' '
'
test_expect_success 'git hook run -- out-of-repo runs excluded' '
- write_script .git/hooks/test-hook <<-EOF &&
+ test_hook test-hook <<-EOF &&
echo Test hook
EOF
@@ -120,6 +105,10 @@ test_expect_success 'git -c core.hooksPath=<PATH> hook run' '
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 &&
diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh
index 43139af08f..2f564d533d 100755
--- a/t/t2400-worktree-add.sh
+++ b/t/t2400-worktree-add.sh
@@ -559,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/t3101-ls-tree-dirname.sh b/t/t3101-ls-tree-dirname.sh
index 05fde64225..217006d1bf 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 d18ba1bd84..81c6343962 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 0000000000..0769a933d6
--- /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/t3207-branch-submodule.sh b/t/t3207-branch-submodule.sh
index 0d93f7516c..cfde6b237f 100755
--- a/t/t3207-branch-submodule.sh
+++ b/t/t3207-branch-submodule.sh
@@ -260,7 +260,7 @@ test_expect_success 'should get fatal error upon branch creation when submodule
)
'
-test_expect_success 'should set up tracking of remote-tracking branches' '
+test_expect_success 'should set up tracking of remote-tracking branches by default' '
test_when_finished "reset_remote_test" &&
(
cd super-clone &&
@@ -289,4 +289,40 @@ test_expect_success 'should not fail when unable to set up tracking in submodule
)
'
+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/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index a38f2da769..f31afd4a54 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/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
index 1e9f7833dd..58371d8a54 100755
--- a/t/t3412-rebase-root.sh
+++ b/t/t3412-rebase-root.sh
@@ -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 b4acb3be5c..9fab0d779b 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/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh
index 43c82d9a33..f351701fec 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/t3903-stash.sh b/t/t3903-stash.sh
index 42638b11d8..4abbc8fcca 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -302,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
@@ -332,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 &&
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 159fae8d01..cdad4b6880 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
diff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh
index 6012cc8172..001b7a17ad 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 3e5e19c719..915af2de95 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 d118181690..978f240cda 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 &&
diff --git a/t/t5406-remote-rejects.sh b/t/t5406-remote-rejects.sh
index 5c509db6fc..dcbeb42082 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 6da8d760e2..5f3ff051ca 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 9f1a483f42..fa5de4500a 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 98b0e81208..92cf52c6d4 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 297b10925d..f9ffb01e50 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 0c3490c9b1..98a9d13041 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 2393b04ad9..67ca6dc4f8 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 c08a00ded2..8d22e17aee 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 3eaa597e0f..298a3d1fec 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 e915dbc28d..6347c9629b 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 2a392e099b..502b34fe3d 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 f7a494bdb9..7744392a62 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 63c479e975..6d116ef692 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 af055aa086..619ca2f421 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 99601ca321..8b3f5d05a3 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 fec5f95793..6dfc7b1c0d 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 8fb75a8789..768880b40f 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 a3a6278213..0f190a6e85 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 0e175388b6..7ec3981263 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 988a4302a6..07733b94b8 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 daacb3d69d..2e1831b104 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 73a47d1ffd..0e37535065 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 c350201107..b9a05181f1 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 8c8a6c16e1..889e97057b 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 bc44810f33..1e523b1c17 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 e63fe7ba11..4c70e84e41 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 99d17b73af..40f4c5b1af 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 2f405adefa..7ae3851efb 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 c88405792e..02e1e084d6 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 31989f0185..7efdfe5598 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/t5503-tagfollow.sh b/t/t5503-tagfollow.sh
index a3c01014b7..acdb731edf 100755
--- a/t/t5503-tagfollow.sh
+++ b/t/t5503-tagfollow.sh
@@ -169,7 +169,7 @@ test_expect_success 'atomic fetch with failing backfill' '
# one of both fails to update correctly.
#
# To trigger failure we simply abort when backfilling a tag.
- write_script clone3/.git/hooks/reference-transaction <<-\EOF &&
+ test_hook -C clone3 reference-transaction <<-\EOF &&
while read oldrev newrev reference
do
if test "$reference" = refs/tags/tag1
@@ -201,7 +201,7 @@ test_expect_success 'atomic fetch with backfill should use single transaction' '
$ZERO_OID $T refs/tags/tag1
EOF
- write_script clone4/.git/hooks/reference-transaction <<-\EOF &&
+ test_hook -C clone4 reference-transaction <<-\EOF &&
( echo "$*" && cat ) >>actual
EOF
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 48e14e2dab..6f38a69fbb 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -273,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
@@ -306,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
@@ -334,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
@@ -364,7 +364,7 @@ test_expect_success 'fetch --atomic --prune executes a single reference transact
$ZERO_OID $head_oid refs/remotes/origin/new-branch
EOF
- write_script atomic/.git/hooks/reference-transaction <<-\EOF &&
+ test_hook -C atomic reference-transaction <<-\EOF &&
( echo "$*" && cat ) >>actual
EOF
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 3137eb8d4d..4dfb080433 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,32 +181,32 @@ 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
@@ -668,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 &&
(
@@ -1330,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 &&
@@ -1340,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 &&
@@ -1365,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 &&
@@ -1389,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 &&
@@ -1411,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 &&
@@ -1440,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 &&
@@ -1463,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 &&
@@ -1502,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
@@ -1515,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 &&
@@ -1533,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 &&
@@ -1554,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 &&
@@ -1656,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 &&
@@ -1678,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 &&
@@ -1740,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 &&
(
diff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh
index 66cfcb09c5..264de29c35 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/t5534-push-signed.sh b/t/t5534-push-signed.sh
index 24d374adba..7c0a148e73 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/t5540-http-push-webdav.sh b/t/t5540-http-push-webdav.sh
index b0dbacf0b9..37db3dec0c 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 8ca50f8b18..2f09ff4fac 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 bfee461861..70431122a4 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 faaa51ccc5..1876fb34e5 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 f11ff57e54..6282728eaf 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 259203926a..f0d9cd584d 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 96d6ecc0af..a11b20e378 100755
--- a/t/t5571-pre-push-hook.sh
+++ b/t/t5571-pre-push-hook.sh
@@ -6,16 +6,11 @@ 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 >actual
-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 &&
@@ -28,15 +23,16 @@ test_expect_success 'setup' '
git push parent1 HEAD:foreign &&
test_cmp expect actual
'
-write_script "$HOOK" <<EOF
-cat >actual
-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 &&
cat >expect <<-EOF &&
HEAD $(git rev-parse HEAD) refs/heads/main $(test_oid zero)
@@ -55,13 +51,13 @@ test_expect_success '--no-verify bypasses hook' '
COMMIT2="$(git rev-parse HEAD)"
export COMMIT2
-write_script "$HOOK" <<'EOF'
-echo "$1" >actual
-echo "$2" >>actual
-cat >>actual
-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
@@ -136,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 83c24fc97a..4a61f2c901 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/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh
index ed95d19542..833205125a 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 |
@@ -510,8 +519,9 @@ do
<TAG-2> refs/tags/v2
<TAG-3> refs/tags/v3
<COMMIT-P> HEAD
- The bundle uses this filter: $filter
The bundle records a complete history.
+ $HASH_MESSAGE
+ The bundle uses this filter: $filter
EOF
test_cmp expect actual &&
diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh
index c2021267f2..cd6c53360d 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/t7102-reset.sh b/t/t7102-reset.sh
index d05426062e..22477f3a31 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/t7113-post-index-change-hook.sh b/t/t7113-post-index-change-hook.sh
index a21781d68a..58e55a7c77 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/t7503-pre-commit-and-pre-merge-commit-hooks.sh b/t/t7503-pre-commit-and-pre-merge-commit-hooks.sh
index 606d8d0f08..ad1eb64ba0 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 bba58f0480..a39de8c112 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 e39c809ca4..2128142a61 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/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh
index fffc57120d..d4f9c6a837 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,7 +321,6 @@ 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 &&
@@ -414,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
@@ -439,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 634fb7f23a..dc57526e6f 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/t7700-repack.sh b/t/t7700-repack.sh
index 770d143204..ca45c4cd2c 100755
--- a/t/t7700-repack.sh
+++ b/t/t7700-repack.sh
@@ -369,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' '
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 84d0f40d76..42694fe584 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -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/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh
index 806005a793..8b30062c0c 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/test-lib-functions.sh b/t/test-lib-functions.sh
index 0f439c99d6..93c03380d4 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:
#
@@ -1789,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>...
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 515b1af7ed..4373f7d70b 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -806,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_ () {