Git alias could run in dash, not bash — even if `/bin/bash` exists
I Wrote a git alias using [[ ... ]] and =~. Works fine in my interactive bash. Run the alias and it explodes:
$ git co master
... Syntax error: "(" unexpected (expecting "then")
First instinct: "but I have bash installed":
$ ls -l /bin/bash
-rwxr-xr-x 1 root root 1298416 ... /bin/bash
$ /bin/bash --version
GNU bash, version 5.2.37(1)-release ...
Doesn't matter. A git alias starting with ! is hardcoded to run under /bin/sh — it doesn't read $SHELL, doesn't care what your login shell is. On Debian/Ubuntu /bin/sh -> dash, and dash doesn't understand [[, =~, == or other bash extensions:
$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 ... /bin/sh -> dash
$ echo '[[ "a" == a* ]]' | /bin/sh
/bin/sh: 1: [[: not found
The source is run-command.c::prepare_shell_cmd() in git itself — it literally calls sh -c.
Two fixes:
Wrap in bash -c explicitly (minimal change, but the nested quoting inside an alias gets ugly fast):
co = "!bash -c 'f() { ...bash syntax... }; f \"$@\"' _"
Rewrite as POSIX sh (preferred). Common substitutions:
[[ "$x" == -* ]]→case "$x" in -*) ... ;; esac[[ "$x" =~ ^HEAD~ ]]→case "$x" in HEAD~*) ... ;; esac[[ "$a" == "$b" ]]→[ "$a" = "$b" ][[ -f foo ]]→[ -f foo ](already POSIX, no reason to use[[)
Lesson: write git aliases as if dash is the only shell on the planet. Don't reach for [[ because it feels nicer — either wrap with bash -c or just use case.