diff --git a/Documentation/config.adoc b/Documentation/config.adoc index d3c9fce4f9fdc6..ad6a2f50677ca1 100644 --- a/Documentation/config.adoc +++ b/Documentation/config.adoc @@ -490,6 +490,8 @@ include::config/pack.adoc[] include::config/pager.adoc[] +include::config/postcommand.adoc[] + include::config/pretty.adoc[] include::config/promisor.adoc[] diff --git a/Documentation/config/postcommand.adoc b/Documentation/config/postcommand.adoc new file mode 100644 index 00000000000000..b1425cec989b08 --- /dev/null +++ b/Documentation/config/postcommand.adoc @@ -0,0 +1,13 @@ +postCommand.strategy:: + The `post-command` hook is run on every Git process by default. This + config option allows running the hook only conditionally, according + to these values: ++ +---- +`always`;; + run the `post-command` hook on every process (default). + +`post-index-change`;; + run the `post-command` hook only if the current process wrote to + the index. +---- diff --git a/Documentation/config/protocol.adoc b/Documentation/config/protocol.adoc index a9bf187a933a24..01c399e99bb5d3 100644 --- a/Documentation/config/protocol.adoc +++ b/Documentation/config/protocol.adoc @@ -6,7 +6,7 @@ protocol.allow:: default policy of `never`, and all other protocols (including file) have a default policy of `user`. Supported policies: + --- +---- * `always` - protocol is always able to be used. @@ -18,7 +18,7 @@ protocol.allow:: execute clone/fetch/push commands without user input, e.g. recursive submodule initialization. --- +---- protocol..allow:: Set a policy to be used by protocol `` with clone/fetch/push @@ -26,7 +26,7 @@ protocol..allow:: + The protocol names currently used by git are: + --- +---- - `file`: any local file-based path (including `file://` URLs, or local paths) @@ -42,7 +42,7 @@ The protocol names currently used by git are: - any external helpers are named by their protocol (e.g., use `hg` to allow the `git-remote-hg` helper) --- +---- protocol.version:: If set, clients will attempt to communicate with a server @@ -51,7 +51,7 @@ protocol.version:: If unset, the default is `2`. Supported versions: + --- +---- * `0` - the original wire protocol. @@ -60,4 +60,4 @@ protocol.version:: * `2` - Wire protocol version 2, see linkgit:gitprotocol-v2[5]. --- +---- diff --git a/Documentation/config/push.adoc b/Documentation/config/push.adoc index 0acbbea18a320f..83282312262106 100644 --- a/Documentation/config/push.adoc +++ b/Documentation/config/push.adoc @@ -17,7 +17,7 @@ push.default:: (i.e. the fetch source is equal to the push destination), `upstream` is probably what you want. Possible values are: + --- +---- * `nothing` - do not push anything (error out) unless a refspec is given. This is primarily meant for people who want to @@ -64,7 +64,7 @@ branches outside your control. This used to be the default, but not since Git 2.0 (`simple` is the new default). --- +---- push.followTags:: If set to true, enable `--follow-tags` option by default. You diff --git a/Documentation/config/sendemail.adoc b/Documentation/config/sendemail.adoc index 5ffcfc9f2a76f7..f1a9fb7e9b3a5d 100644 --- a/Documentation/config/sendemail.adoc +++ b/Documentation/config/sendemail.adoc @@ -58,7 +58,7 @@ the documentation of the email program of the same name. The differences and limitations from the standard formats are described below: + --- +---- sendmail;; * Quoted aliases and quoted addresses are not supported: lines that contain a `"` symbol are ignored. @@ -68,7 +68,7 @@ sendmail;; * Warnings are printed on the standard error output for any explicitly unsupported constructs, and any other lines that are not recognized by the parser. --- +---- sendemail.annotate:: sendemail.bcc:: sendemail.cc:: diff --git a/Documentation/config/sideband.adoc b/Documentation/config/sideband.adoc index f347fd6b33004a..33cbe08bfab200 100644 --- a/Documentation/config/sideband.adoc +++ b/Documentation/config/sideband.adoc @@ -4,7 +4,7 @@ sideband.allowControlCharacters:: unwanted ANSI escape sequences from being sent to the terminal. Use this config setting to override this behavior: + --- +---- color:: Allow ANSI color sequences, line feeds and horizontal tabs, but mask all other control characters. This is the default. @@ -13,4 +13,4 @@ sideband.allowControlCharacters:: horizontal tabs. true:: Allow all control characters to be sent to the terminal. --- +---- diff --git a/Documentation/config/ssh.adoc b/Documentation/config/ssh.adoc index 2ca4bf93e1e30f..4f61c9351f3815 100644 --- a/Documentation/config/ssh.adoc +++ b/Documentation/config/ssh.adoc @@ -19,7 +19,7 @@ overridden via the environment variable `GIT_SSH_VARIANT`. The current command-line parameters used for each variant are as follows: + --- +---- * `ssh` - [-p port] [-4] [-6] [-o option] [username@]host command @@ -29,7 +29,7 @@ follows: * `tortoiseplink` - [-P port] [-4] [-6] -batch [username@]host command --- +---- + Except for the `simple` variant, command-line parameters are likely to change as git gains new features. diff --git a/Documentation/config/status.adoc b/Documentation/config/status.adoc index 4d863fdaaec2eb..fa393e703eb01c 100644 --- a/Documentation/config/status.adoc +++ b/Documentation/config/status.adoc @@ -50,11 +50,11 @@ status.showUntrackedFiles:: systems. So, this variable controls how the commands display the untracked files. Possible values are: + --- +---- * `no` - Show no untracked files. * `normal` - Show untracked files and directories. * `all` - Show also individual files in untracked directories. --- +---- + If this variable is not specified, it defaults to 'normal'. All usual spellings for Boolean value `true` are taken as `normal` @@ -90,7 +90,7 @@ status.deserializeWait:: fall-back and compute status normally. This will be overridden by `--deserialize-wait=` on the command line. + --- +---- * `fail` - cause git to exit with an error when the status cache file is stale; this is intended for testing and debugging. * `block` - cause git to spin and periodically retry the cache file @@ -98,4 +98,4 @@ every 100 ms; this is intended to help coordinate with another git instance concurrently computing the cache file. * `no` - to immediately fall-back if cache file is stale. This is the default. * `` - time (in tenths of a second) to spin and retry. --- +---- diff --git a/Documentation/config/survey.adoc b/Documentation/config/survey.adoc index f3ae768933fe1b..ae327075e2c6f9 100644 --- a/Documentation/config/survey.adoc +++ b/Documentation/config/survey.adoc @@ -3,7 +3,7 @@ survey.*:: command. The intention is that this command could be run in the background with these options. + --- +---- survey.namerev:: Boolean to show/hide `git name-rev` information for each reported commit and the containing commit of each @@ -44,4 +44,4 @@ survey.*:: long file or subdirectory entry names. Provides a default value for `--tree-sizes=` in linkgit:git-survey[1]. --- +---- diff --git a/Documentation/config/trace2.adoc b/Documentation/config/trace2.adoc index 05639ce33f908a..f5d730934c8354 100644 --- a/Documentation/config/trace2.adoc +++ b/Documentation/config/trace2.adoc @@ -16,7 +16,7 @@ trace2.eventTarget:: This variable controls the event target destination. It may be overridden by the `GIT_TRACE2_EVENT` environment variable. The following table shows possible values. -+ + include::../trace2-target-values.adoc[] trace2.normalBrief:: diff --git a/Documentation/trace2-target-values.adoc b/Documentation/trace2-target-values.adoc index 06f19533134f9d..503d9f13864c27 100644 --- a/Documentation/trace2-target-values.adoc +++ b/Documentation/trace2-target-values.adoc @@ -1,12 +1,12 @@ --- +---- * `0` or `false` - Disables the target. * `1` or `true` - Writes to `STDERR`. * `[2-9]` - Writes to the already opened file descriptor. * `` - Writes to the file in append mode. If the target -already exists and is a directory, the traces will be written to files (one -per process) underneath the given directory. + already exists and is a directory, the traces will be written to files (one + per process) underneath the given directory. * `af_unix:[:]` - Write to a -Unix DomainSocket (on platforms that support them). Socket -type can be either `stream` or `dgram`; if omitted Git will -try both. --- + Unix DomainSocket (on platforms that support them). Socket + type can be either `stream` or `dgram`; if omitted Git will + try both. +---- \ No newline at end of file diff --git a/git.c b/git.c index dc740e74dbc107..58f0f032493f54 100644 --- a/git.c +++ b/git.c @@ -494,6 +494,7 @@ static int run_post_command_hook(struct repository *r) run_post_hook = 0; strvec_clear(&sargv); + strvec_clear(&opt.args); setenv("COMMAND_HOOK_LOCK", "false", 1); return ret; } diff --git a/hook.c b/hook.c index 072fca9df74a5b..67bc0f65c036d8 100644 --- a/hook.c +++ b/hook.c @@ -1,6 +1,7 @@ #define USE_THE_REPOSITORY_VARIABLE #include "git-compat-util.h" +#include "trace2/tr2_sid.h" #include "abspath.h" #include "environment.h" #include "advice.h" @@ -176,6 +177,58 @@ static void run_hooks_opt_clear(struct run_hooks_opt *options) strvec_clear(&options->args); } +static char *get_post_index_change_sentinel_name(struct repository *r) +{ + struct strbuf path = STRBUF_INIT; + const char *sid = tr2_sid_get(); + char *slash = strchr(sid, '/'); + + /* + * Name is based on top-level SID, so children can indicate that + * the top-level process should run the post-command hook. + */ + if (slash) + *slash = 0; + + repo_git_path_replace(r, &path, "hooks/index-change-%s.snt", sid); + + return strbuf_detach(&path, NULL); +} + +static int write_post_index_change_sentinel(struct repository *r) +{ + char *path = get_post_index_change_sentinel_name(r); + FILE *fp = xfopen(path, "w"); + + if (fp) { + fprintf(fp, "run post-command hook"); + fclose(fp); + } + + free(path); + return fp ? 0 : -1; +} + +/** + * Try to delete the sentinel file for this repository. If that succeeds, then + * return 1. + */ +static int post_index_change_sentinel_exists(struct repository *r) +{ + char *path = get_post_index_change_sentinel_name(r); + int res = 1; + + if (unlink(path)) { + if (is_missing_file_error(errno)) + res = 0; + else + warning_errno("failed to remove index-change sentinel file '%s'", path); + } + + free(path); + return res; +} + int run_hooks_opt(struct repository *r, const char *hook_name, struct run_hooks_opt *options) { @@ -185,7 +238,7 @@ int run_hooks_opt(struct repository *r, const char *hook_name, .hook_name = hook_name, .options = options, }; - const char *hook_path = find_hook(r, hook_name); + const char *hook_path; int ret = 0; const struct run_process_parallel_opts opts = { .tr2_category = "hook", @@ -201,6 +254,21 @@ int run_hooks_opt(struct repository *r, const char *hook_name, .data = &cb_data, }; + /* Interject hook behavior depending on strategy. */ + if (r && r->gitdir) { + const char *strval; + if (!repo_config_get_string_tmp(r, "postcommand.strategy", &strval) && + !strcasecmp(strval, "post-index-change")) { + if (!strcmp(hook_name, "post-index-change")) + return write_post_index_change_sentinel(r); + if (!strcmp(hook_name, "post-command") && + !post_index_change_sentinel_exists(r)) + return 0; + } + } + + hook_path = find_hook(r, hook_name); + /* * Backwards compatibility hack in VFS for Git: when originally * introduced (and used!), it was called `post-indexchanged`, but this @@ -252,6 +320,7 @@ int run_hooks_l(struct repository *r, const char *hook_name, ...) { struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT; va_list ap; + int result; const char *arg; va_start(ap, hook_name); @@ -259,5 +328,7 @@ int run_hooks_l(struct repository *r, const char *hook_name, ...) strvec_push(&opt.args, arg); va_end(ap); - return run_hooks_opt(r, hook_name, &opt); + result = run_hooks_opt(r, hook_name, &opt); + strvec_clear(&opt.args); + return result; } diff --git a/t/t0401-post-command-hook.sh b/t/t0401-post-command-hook.sh index fcbfc4a0c79c1e..4da639e754504f 100755 --- a/t/t0401-post-command-hook.sh +++ b/t/t0401-post-command-hook.sh @@ -22,6 +22,7 @@ test_expect_success 'with succeeding hook' ' ' test_expect_success 'with failing pre-command hook' ' + test_when_finished rm -f .git/hooks/pre-command && write_script .git/hooks/pre-command <<-EOF && exit 1 EOF @@ -30,4 +31,45 @@ test_expect_success 'with failing pre-command hook' ' test_path_is_missing "$(cat .git/post-command.out)" ' +test_expect_success 'with post-index-change config' ' + mkdir -p .git/hooks && + write_script .git/hooks/post-command <<-EOF && + echo ran >post-command.out + EOF + write_script .git/hooks/post-index-change <<-EOF && + echo ran >post-index-change.out + EOF + + # First, show expected behavior. + echo ran >expect && + rm -f post-command.out post-index-change.out && + + # rev-parse leaves index intact, but runs post-command. + git rev-parse HEAD && + test_path_is_missing post-index-change.out && + test_cmp expect post-command.out && + rm -f post-command.out && + + echo stuff >>file && + # add updates the index and runs post-command. + git add file && + test_cmp expect post-index-change.out && + test_cmp expect post-command.out && + + # Now, show configured behavior + git config postCommand.strategy post-index-change && + rm -f post-command.out post-index-change.out && + + # rev-parse leaves index intact and thus skips post-command. + git rev-parse HEAD && + test_path_is_missing post-index-change.out && + test_path_is_missing post-command.out && + + echo stuff >>file && + # add updates the index and runs post-command. + git add file && + test_path_is_missing post-index-change.out && + test_cmp expect post-command.out +' + test_done