Skip to content

Commit

Permalink
Allow overriding which POSIX shell to use
Browse files Browse the repository at this point in the history
Right now, the compiled-in default is used always, which can be
overridden at compile time via the `SHELL_PATH` variable.

However, in Git for Windows' context, there is a scenario where this is
not good enough: the BusyBox flavor of MinGit wants to use BusyBox'
`ash` instead.

To allow for that, let's introduce a new config variable: `core.shell`.
Its value is expected to be the absolute path to a valid, working POSIX
shell. This shell will be then used by `git.exe` whenever it needs to
execute something via shell, such as moderately complex aliases.

And it is not only Git that is expected to use that `ash`, it is also
OpenSSH (e.g. when running any configured `ProxyCommand`): programs
spawned from `git.exe` may need to run a shell and look at the
environment variable `SHELL` for that. Therefore, let's set that, too.

Signed-off-by: Johannes Schindelin <[email protected]>
  • Loading branch information
dscho committed Jul 1, 2021
1 parent ebf3c04 commit 0246cd9
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 4 deletions.
4 changes: 4 additions & 0 deletions Documentation/config/core.txt
Original file line number Diff line number Diff line change
Expand Up @@ -628,3 +628,7 @@ core.abbrev::
If set to "no", no abbreviation is made and the object names
are shown in their full length.
The minimum length is 4.

core.shell::
Set the absolute path to the executable to use as a POSIX shell;
This will also set/override the environment variable `SHELL`.
2 changes: 1 addition & 1 deletion help.c
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ void get_version_info(struct strbuf *buf, int show_build_options)
strbuf_addstr(buf, "no commit associated with this build\n");
strbuf_addf(buf, "sizeof-long: %d\n", (int)sizeof(long));
strbuf_addf(buf, "sizeof-size_t: %d\n", (int)sizeof(size_t));
strbuf_addf(buf, "shell-path: %s\n", SHELL_PATH);
strbuf_addf(buf, "shell-path: %s\n", get_shell_path(SHELL_PATH));
/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
}
}
Expand Down
20 changes: 17 additions & 3 deletions run-command.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@
#include "quote.h"
#include "config.h"

const char *get_shell_path(const char *fallback)
{
static const char *shell;
static int initialized;

if (!initialized) {
if (git_config_get_pathname("core.shell", &shell))
setenv("SHELL", shell, 1);
initialized = 1;
}

return shell ? shell : fallback;
}

void child_process_init(struct child_process *child)
{
memset(child, 0, sizeof(*child));
Expand Down Expand Up @@ -271,9 +285,9 @@ static const char **prepare_shell_cmd(struct strvec *out, const char **argv)

if (strcspn(argv[0], "|&;<>()$`\\\"' \t\n*?[#~=%") != strlen(argv[0])) {
#ifndef GIT_WINDOWS_NATIVE
strvec_push(out, SHELL_PATH);
strvec_push(out, get_shell_path(SHELL_PATH));
#else
strvec_push(out, "sh");
strvec_push(out, get_shell_path("sh"));
#endif
strvec_push(out, "-c");

Expand Down Expand Up @@ -411,7 +425,7 @@ static int prepare_cmd(struct strvec *out, const struct child_process *cmd)
* Add SHELL_PATH so in the event exec fails with ENOEXEC we can
* attempt to interpret the command with 'sh'.
*/
strvec_push(out, SHELL_PATH);
strvec_push(out, get_shell_path(SHELL_PATH));

if (cmd->git_cmd) {
prepare_git_cmd(out, cmd->argv);
Expand Down
5 changes: 5 additions & 0 deletions run-command.h
Original file line number Diff line number Diff line change
Expand Up @@ -483,4 +483,9 @@ int run_processes_parallel_tr2(int n, get_next_task_fn, start_failure_fn,
task_finished_fn, void *pp_cb,
const char *tr2_category, const char *tr2_label);

/*
* Get the path of the POSIX shell to use in `start_command()`.
*/
const char *get_shell_path(const char *fallback);

#endif

0 comments on commit 0246cd9

Please sign in to comment.