diff --git a/Documentation/git.txt b/Documentation/git.txt index 73dc0ad0a0..179615195f 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -913,6 +913,10 @@ for further details. and read the password from its STDOUT. See also the 'core.askpass' option in linkgit:git-config[1]. +'GIT_TERMINAL_PROMPT':: + If this environment variable is set to `0`, git will not prompt + on the terminal (e.g., when asking for HTTP authentication). + 'GIT_CONFIG_NOSYSTEM':: Whether to skip reading settings from the system-wide `$(prefix)/etc/gitconfig` file. This environment variable can diff --git a/Documentation/technical/api-credentials.txt b/Documentation/technical/api-credentials.txt index c1b42a40d3..e44426dd04 100644 --- a/Documentation/technical/api-credentials.txt +++ b/Documentation/technical/api-credentials.txt @@ -248,7 +248,10 @@ FORMAT` in linkgit:git-credential[7] for a detailed specification). For a `get` operation, the helper should produce a list of attributes on stdout in the same format. A helper is free to produce a subset, or even no values at all if it has nothing useful to provide. Any provided -attributes will overwrite those already known about by Git. +attributes will overwrite those already known about by Git. If a helper +outputs a `quit` attribute with a value of `true` or `1`, no further +helpers will be consulted, nor will the user be prompted (if no +credential has been provided, the operation will then fail). For a `store` or `erase` operation, the helper's output is ignored. If it fails to perform the requested operation, it may complain to diff --git a/credential.c b/credential.c index 1886ea50b3..b146ad8481 100644 --- a/credential.c +++ b/credential.c @@ -173,6 +173,8 @@ int credential_read(struct credential *c, FILE *fp) c->path = xstrdup(value); } else if (!strcmp(key, "url")) { credential_from_url(c, value); + } else if (!strcmp(key, "quit")) { + c->quit = !!git_config_bool("quit", value); } /* * Ignore other lines; we don't know what they mean, but @@ -274,6 +276,9 @@ void credential_fill(struct credential *c) credential_do(c, c->helpers.items[i].string, "get"); if (c->username && c->password) return; + if (c->quit) + die("credential helper '%s' told us to quit", + c->helpers.items[i].string); } credential_getpass(c); diff --git a/credential.h b/credential.h index 0c3e85e8e4..6b0cd16be2 100644 --- a/credential.h +++ b/credential.h @@ -7,6 +7,7 @@ struct credential { struct string_list helpers; unsigned approved:1, configured:1, + quit:1, use_http_path:1; char *username; diff --git a/prompt.c b/prompt.c index e5b4938efc..8181eebbfc 100644 --- a/prompt.c +++ b/prompt.c @@ -57,11 +57,19 @@ char *git_prompt(const char *prompt, int flags) r = do_askpass(askpass, prompt); } - if (!r) - r = git_terminal_prompt(prompt, flags & PROMPT_ECHO); if (!r) { - /* prompts already contain ": " at the end */ - die("could not read %s%s", prompt, strerror(errno)); + const char *err; + + if (git_env_bool("GIT_TERMINAL_PROMPT", 1)) { + r = git_terminal_prompt(prompt, flags & PROMPT_ECHO); + err = strerror(errno); + } else { + err = "terminal prompts disabled"; + } + if (!r) { + /* prompts already contain ": " at the end */ + die("could not read %s%s", prompt, err); + } } return r; } diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh index 57ea5a10c5..d7ef44b4a2 100755 --- a/t/t0300-credentials.sh +++ b/t/t0300-credentials.sh @@ -289,4 +289,13 @@ test_expect_success 'http paths can be part of context' ' EOF ' +test_expect_success 'helpers can abort the process' ' + test_must_fail git \ + -c credential.helper="!f() { echo quit=1; }; f" \ + -c credential.helper="verbatim foo bar" \ + credential fill >stdout && + >expect && + test_cmp expect stdout +' + test_done