d2w7oa
Last Updated: February 25, 2016
·
2.305K
· jacaetevha

Auto-Completion Within Complex Git Alias

UPDATE 2013-11-25: Prefixed commands in the Git aliases with !

DISCLAIMER: Bash only. I haven't explored other shells (like Fish or ZSH).

Git aliases are really helpful for saving you some typing. When the alias is simple, as in

[alias]
  co = checkout

Git auto-completion looks up the valid completions for the checkout command (e.g. branch names or refs) when you press the <TAB> key. However, when your Git alias is more complex (using more than one command, using a custom function) auto-completion won't work.

To enable auto-completion for your complex Git aliases you need to define a function that Git can use to determine what should be completed. That function will follow this convention: _git_<the name of your alias>.

Example

If we wanted to create an alias called rtrack that will

  • make sure we have all the latest code from the remote repository
  • setup a remote tracking branch for us
  • and then check out that new branch

... we'd create a function called _git_rtrack in our Bash profile:

function _git_rtrack() {
  _git_branch
}

In this example my alias will be working with branch names, so I simply delegate to _git_branch.

Next, in our Git config (globally or in a project configuration file) we could define rtrack in the alias section as

[alias]
  rtrack = "!git fetch origin;git branch --track $1 origin/$1;git checkout $1"

Note the ! in front of the command. This is necessary in order to execute anything other than a Git command directly.

More Examples

Here are a few examples translated from the grb Ruby gem into Git aliases (including the rtrack alias).

In your Git config, add:

# ~/.gitconfig
[alias]
  # create a new branch off of a local branch and check it out locally, defaults to master
  rcreate = "!git push origin ${2:-master}:refs/heads/$1;git fetch origin;git branch --track $1 origin/$1;git checkout $1"

  # rename a branch ($1) to something else ($2)
  rmove = "!git push origin $1:refs/heads/$2;git fetch origin;git branch --track $2 origin/$2;git checkout $2;git branch -d $1;git push origin :refs/heads/$1"

  # push a local branch to the remote called origin and check it out locally
  rpush = "!git push origin $1:refs/heads/$1;git fetch origin;git config branch.$1.remote origin;git config branch.$1.merge refs/heads/$1;git checkout $1"

  # remove a branch
  rrm = "!git push origin :refs/heads/$1;git branch -d $1"

  # track a remote branch locally and check it out locally
  rtrack = "!git fetch origin;git branch --track $1 origin/$1;git checkout $1"

Then in your Bash profile add:

# ~/.bash_functions, sourced from ~/.bash_profile
function _git_rcreate() {
  _git_branch
}

function _git_rmove() {
  _git_branch
}

function _git_rpush() {
  _git_branch
}

function _git_rrm() {
  _git_branch
}

function _git_rtrack() {
  _git_branch
}

Enjoy!