Skip to content

Commit 5907f97

Browse files
committed
Allow overriding which POSIX shell to use
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 <johannes.schindelin@gmx.de>
1 parent 761600d commit 5907f97

5 files changed

Lines changed: 43 additions & 5 deletions

File tree

Documentation/config/core.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,3 +807,7 @@ core.WSLCompat::
807807
The default value is false. When set to true, Git will set the mode
808808
bits of the file in the way of wsl, so that the executable flag of
809809
files can be set or read correctly.
810+
811+
core.shell::
812+
Set the absolute path to the executable to use as a POSIX shell;
813+
This will also set/override the environment variable `SHELL`.

help.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,7 @@ void get_version_info(struct strbuf *buf, int show_build_options)
793793
strbuf_addstr(buf, "no commit associated with this build\n");
794794
strbuf_addf(buf, "sizeof-long: %d\n", (int)sizeof(long));
795795
strbuf_addf(buf, "sizeof-size_t: %d\n", (int)sizeof(size_t));
796-
strbuf_addf(buf, "shell-path: %s\n", SHELL_PATH);
796+
strbuf_addf(buf, "shell-path: %s\n", get_shell_path(SHELL_PATH));
797797
/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
798798

799799
#if defined WITH_RUST

run-command.c

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#define DISABLE_SIGN_COMPARE_WARNINGS
2+
#define USE_THE_REPOSITORY_VARIABLE
23

34
#include "git-compat-util.h"
45
#include "run-command.h"
@@ -18,6 +19,20 @@
1819
#include "packfile.h"
1920
#include "compat/nonblock.h"
2021

22+
const char *get_shell_path(const char *fallback)
23+
{
24+
static char *shell;
25+
static int initialized;
26+
27+
if (!initialized) {
28+
if (!repo_config_get_pathname(the_repository, "core.shell", &shell))
29+
setenv("SHELL", shell, 1);
30+
initialized = 1;
31+
}
32+
33+
return shell ? shell : fallback;
34+
}
35+
2136
void child_process_init(struct child_process *child)
2237
{
2338
struct child_process blank = CHILD_PROCESS_INIT;
@@ -276,12 +291,19 @@ int sane_execvp(const char *file, char * const argv[])
276291

277292
char *git_shell_path(void)
278293
{
294+
const char *shell = get_shell_path(NULL);
295+
296+
if (shell)
297+
return xstrdup(shell);
298+
279299
#ifndef GIT_WINDOWS_NATIVE
280300
return xstrdup(SHELL_PATH);
281301
#else
282-
char *p = locate_in_PATH("sh");
283-
convert_slashes(p);
284-
return p;
302+
{
303+
char *p = locate_in_PATH("sh");
304+
convert_slashes(p);
305+
return p;
306+
}
285307
#endif
286308
}
287309

@@ -416,7 +438,7 @@ static int prepare_cmd(struct strvec *out, const struct child_process *cmd)
416438
* Add SHELL_PATH so in the event exec fails with ENOEXEC we can
417439
* attempt to interpret the command with 'sh'.
418440
*/
419-
strvec_push(out, SHELL_PATH);
441+
strvec_push(out, get_shell_path(SHELL_PATH));
420442

421443
if (cmd->git_cmd) {
422444
prepare_git_cmd(out, cmd->args.v);

run-command.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,4 +616,9 @@ enum start_bg_result start_bg_command(struct child_process *cmd,
616616

617617
int sane_execvp(const char *file, char *const argv[]);
618618

619+
/*
620+
* Get the path of the POSIX shell to use in `start_command()`.
621+
*/
622+
const char *get_shell_path(const char *fallback);
623+
619624
#endif

t/t0061-run-command.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,4 +291,11 @@ test_expect_success MINGW 'can spawn .bat with argv[0] containing spaces' '
291291
test_grep "arg with spaces" out
292292
'
293293

294+
SQ="'"
295+
test_expect_success 'core.shell' '
296+
test_config_global core.shell "$GIT_EXEC_PATH/git$X" &&
297+
test_must_fail git -c alias.eq="!a.b=c" eq 2>actual &&
298+
grep "${SQ}a.b=c${SQ} is not a git command" actual
299+
'
300+
294301
test_done

0 commit comments

Comments
 (0)