Three tips for creating the “best ever” git command line!

As a recovering CVS user turned svn master, and now an aspiring git ninja, I am sharing some of the tips and tricks to make my git environment as enjoyable and effective as possible.  First a little tough love: if you are not using the git command line, then just move along… these aren’t the droids you’re looking for.  But seriously, if you want to learn how to use git better you MUST MUST MUST use the command line. But if you are going to use a GUI, then PLEASE do us all a favor and avoid Github for Mac and instead get a tool like Tower.

So if you are still reading you are in the right place! :)

Tip #1:  If you are not using bash-completion, start now! Seriously! Stop reading this post and go install bash-completion immediately! This is the single biggest time saver; period. It provides completions via a deep knowledge of common tools such as git, ssh, jar, java, man, etc. For example:

  1. cd <your favorite git project>
  2. git checkout origin/<TAB><TAB>
  3. You will see all of the branches from the remote repo appear like magic!
  4. The git bash-completion knows about git commands, tags, branches, repositories, etc. So cool!
  5. Now try: git log –<TAB><TAB>
  6. It shows you all of the command line options for git log. With each git command having a wealth of options, this is a huge sanity saver.

Tip #2: Now that you have bash completing your git commands for you, how about we add some color to the results of git commands? Yes, seeing the output of a “git diff” colorized with additions in green and subtractions in red is, well after you get used to it, simply required.

Edit your ~/.gitconfig and add the following section:

[color]
  diff = auto
  status = auto
  branch = auto
  interactive = auto
  ui = auto

And while you are in there add this section to automatically run garbage collection for you!

[gc]
  auto = 1

Tip #3: Tired of typing “git status” to figure out if your branch is clean or dirty? Or if you need to push or pull to get caught up with a remote repo? The next git trick will really knock your socks off! Via the bash prompt, it displays the git branch you are currently on. If the branch is dirty the name of the branch is displayed in red. If the branch is clean the name is displayed in green. For example:

…clean…

    [develop] /Develop/k2/rsmart/nakamura

…dirty…

    [develop] /Develop/k2/rsmart/nakamura

…ahead…

    [develop↑] /Develop/k2/rsmart/nakamura

…behind…

    [develop↓] /Develop/k2/rsmart/nakamura

…branches have diverged…

    [develop↕] /Develop/k2/rsmart/nakamura

Curious yet? Here are the arcane .bash_profile incantations to make this a reality:

c_cyan=`tput setaf 6`
c_red=`tput setaf 1`
c_green=`tput setaf 2`
c_sgr0=`tput sgr0`
parse_git_branch ()
{
    if git rev-parse --git-dir >/dev/null 2>&1
    then
        git_status="$(git status 2> /dev/null)"
        branch_pattern="^# On branch ([^${IFS}]*)"
        remote_pattern="# Your branch is (.*) of"
        diverge_pattern="# Your branch and (.*) have diverged"
        # add an else if or two here if you want to get more specific
        if [[ ${git_status} =~ ${remote_pattern} ]]; then
          if [[ ${BASH_REMATCH[1]} == "ahead" ]]; then
            remote="↑"
          elif [ ${BASH_REMATCH[1]} == "behind" ]]; then
            remote="↓"
          fi
        fi
        if [[ ${git_status} =~ ${diverge_pattern} ]]; then
          remote="↕"
        fi
        if [[ ${git_status} =~ ${branch_pattern} ]]; then
          branch=${BASH_REMATCH[1]}
          echo "${branch}${remote}"
        fi
    else
        return 0
    fi
}
branch_color ()
{
    if git rev-parse --git-dir >/dev/null 2>&1
    then
        git_status="$(git status 2> /dev/null)"
        color=""
        if [[ ${git_status} =~ "working directory clean" ]]; then
            color="${c_green}"
        else
            color=${c_red}
        fi
    else
        return 0
    fi
    echo -ne $color
}
export PS1='[\[$(branch_color)\]$(parse_git_branch)\[${c_sgr0}\]] \w\[${c_sgr0}\]$ '

With this information in hand, you should be well on your way to leveling-up your git ninja (ginja?) skills… :)

About these ads

6 Comments

Filed under Technology, Tools

6 responses to “Three tips for creating the “best ever” git command line!

  1. I switched to zsh a while back. You can get all these goodies by installing Oh My Zsh.

  2. Thanks for tip 3 – that’s very useful.

    How to I change it so that it only shows me the folder I am in – currently is shows this:

    /usr/local/etc/httpd/sitename.com

    I would like it just show /sitename.com

    Possible?

    Thanks

  3. Jerry

    I modified your script to use the more script friendly git commands. (Newer versions of git status wording has changed, which breaks your bash_profile PS1).

    c_cyan=`tput setaf 6`
    c_red=`tput setaf 1`
    c_green=`tput setaf 2`
    c_sgr0=`tput sgr0`
    c_pink=`tput setaf 5`
    parse_git_branch ()
    {
    git rev-parse –git-dir >/dev/null 2>&1
    if [ $? -eq 0 ]; then
    remote=””
    git_status=”$(git status 2> /dev/null)”
    if [ $? -eq 128 ]; then
    echo ” (!GIT_DIR!)”
    else
    branch=`git rev-parse –abbrev-ref HEAD`
    git config –get branch.$branch.remote >/dev/null 2>&1
    if [ $? -eq 0 ]; then
    #its a tracking branch
    behind=`git log ..@{u} –pretty=oneline | wc -l | sed -e ‘s/[ \t]*//g’`
    ahead=`git log @{u}.. –pretty=oneline | wc -l | sed -e ‘s/[ \t]*//g’`
    diverged=`git log @{u}… –pretty=oneline | wc -l | sed -e ‘s/[ \t]*//g’`

    if [ $diverged -ne 0 ]; then

    if [ "$behind" == "$diverged" ]; then
    #remote=” [$behind]↓”
    remote=”↓”
    elif [ "$ahead" == "$diverged" ]; then
    #remote=” [$ahead]
    remote=”↑”
    else
    remote=”↕”
    #remote=” [$behind]↓ [$ahead]↑”
    fi
    fi
    fi
    echo ” (${branch}${remote})”
    fi
    else
    return 0
    fi
    }
    branch_color ()
    {
    color=””
    git rev-parse –git-dir >/dev/null 2>&1
    if [ $? -eq 0 ]; then
    git status –untracked-files=no –porcelain >/dev/null 2>&1
    if [ $? -eq 128 ]; then
    color=${c_pink}
    elif [ -z "$(git status --untracked-files=no --porcelain)" ]; then
    color=”${c_green}”
    else
    color=${c_red}
    fi
    else
    return 0
    fi
    echo -ne $color
    }

    export PS1=’\[33[1;32m\]\u\[33[0m\]@\[33[1;36m\]\h\[33[0m\] \W\[$(branch_color)\]$(parse_git_branch)\[33[0m\] \$ ‘

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s