36

I'm trying to use to use the same name for an alias as the existing command, so that the alias shadows the original command (preventing me from deleting files off the working tree).

[alias]
   rm = rm --cached
   diff = diff --color

Unfortunatly this is not working. Does anyone know a workaround? Thanks.

Edit Setting color.diff = true gives colored output as default.

M.Hebot
  • 363
  • 3
  • 7

4 Answers4

25

As a workaround, you can define aliases in Bash to get the result you want. Here's something I just knocked up for a pet peeve of mine - that 'git add' is not verbose by default. (And there's no config setting for it).

Put this in your ~/.bash_profile or ~/.bash_rc

function do_git {
  cmd=$1
  shift
  extra=""
  if [ "$cmd" == "add" ]; then
    extra="-v"
  elif [ "$cmd" == "rm" ]; then
    extra="--cached"
  fi
  git="$(which git)"
  ex="$git $cmd $extra $@"
  ${ex}
}
alias  git='do_git'

Then just call it like normal:

$ git add .
add 'foo'
Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
Steve Bennett
  • 114,604
  • 39
  • 168
  • 219
  • 2
    your git command didn't work for me...this worked better: git="$(which git)" ex="$git $cmd $extra $@" ${ex} – VTS12 Mar 08 '16 at 15:44
  • To me the two statements look equivalent. I wonder why one didn't work? – Steve Bennett Apr 09 '18 at 00:35
  • `which git` is an unnecessary process call, can just use `command git` (`command` is a bash built-in that doesn't look up aliases and functions). for proper quotes of args with spaces, should use `"$@"`. So, the last three lines of your function should be replaced with `command git $cmd $extra "$@"` – Gene Pavlovsky Feb 01 '23 at 09:19
  • Another suggestion, use `local` keyword when defining variables in functions (for arrays, use `declare`). By default variables are created (or overwrite existing ones) in the global scope. – Gene Pavlovsky Feb 01 '23 at 09:22
24

For commands like rm --cached that don't have configurable options, your best bet is to just make an alias named differently. For example:

[alias]
        rmc = rm --cached

You may have already figured this out, but Git aliases cannot shadow existing Git commands. From the git-config man page:

To avoid confusion and troubles with script usage, aliases that hide existing git commands are ignored.

Michael
  • 8,362
  • 6
  • 61
  • 88
mipadi
  • 398,885
  • 90
  • 523
  • 479
  • [The git mailing list had a discussion about the rationale behind this](http://git.661346.n2.nabble.com/allowing-aliases-to-override-builtins-to-support-default-options-td2438491.html). tl;dr KISS – Bengt Mar 09 '13 at 19:37
  • 4
    Ugh. What a stupid, obnoxious conclusion that thread has. It is not very easy to defend, because it prevents me making `git clone` recursive by default. Idiotic. – Jez Mar 18 '16 at 15:47
2

Steve Bennett's answer works for simple commands, but breaks when you have quoted arguments like the following:

$ git commit -m "foo bar" --allow-empty
error: pathspec 'bar' did not match any file(s) known to git.

Preserving the full list of arguments as an array seems to work:

function do_git {
  cmd=$1
  shift
  myArgs=( "$@" )

  if [ "$cmd" == "add" ]; then
    myArgs=( "-v" "${myArgs[@]}" )
  elif [ "$cmd" == "rm" ]; then
    myArgs=( "--cached" "${myArgs[@]}" )
  fi
  myArgs=( "$cmd" "${myArgs[@]}" )
  $(which git) "${myArgs[@]}"
}
alias  git='do_git'

Now the command succeeds:

$ git commit -m "foo bar" --allow-empty
/usr/bin/git commit -m foo bar --allow-empty
[master 699af14] foo bar
Lucas Wiman
  • 10,021
  • 2
  • 37
  • 41
  • 1
    Only thing that could make this better is using a Bash v4.4+ associative array to define `cmd: extra,args` if you want to add multiple like `--recursive` and `--shallow-fetch` to make `git clone` against huge repositories really snappy. – dragon788 May 10 '22 at 17:57
  • 1
    Using an array is the way. You can also just call the function `git` and then call the actual command with `command git "${myArgs[@]}"` without needing to resort to `which` – ilkkachu Oct 17 '22 at 12:43
  • 1
    Another suggestion, use `local` keyword when defining variables in functions (for arrays, use `declare`). By default variables are created (or overwrite existing ones) in the global scope. – Gene Pavlovsky Feb 01 '23 at 09:22
0

This is the answer of Steve Bennett translated for oh-my-zsh

function do_git {
  cmd=$1
  shift
  extra=""
  if [ "$cmd" '==' "add" ]; then
    extra="-v"
  elif [ "$cmd" '==' "rm" ]; then
    extra="--cached"
  fi
  "`whence -p git`" "$cmd" "$extra" "$@"
}
alias  git='do_git'

The equals sign needs to be wrapped in quotes. And which doesn't work as it just return that 'git' is an alias.

Tom Maeckelberghe
  • 1,969
  • 3
  • 21
  • 24