The Throbbing Brain

Technology musings for the modern pragmatist

Git Tips and Tricks

I’ve been using Git for quite some time and I’ve come to really enjoy it. It might be a little weird to say that I enjoy my source control system, but it makes development so much easier in so many ways. Now, I will admit that our relationship wasn’t always awesome; working with Git can have a steep learning curve. I’ve invested a lot of time in learning to use Git, so I’ve put together a few helpful tips for you.

Change your Text Editor

I love using Git from the command line, but it’s not perfect. If you’re developing in Windows, formatting your commit messages from the command line is about as enjoyable as a dead fish in the backseat of your car on a hot and humid summer day. Set Git up to use a graphical text editor and you’ll be writing better commit messages in no time.

My text editor of choice is Sublime Text 2, though this will work for any text editor you might be using.

Configure a Text Editor - Sublime Text 2
1
git config --global core.editor "'C:/Program Files/Sublime Text 2/sublime_text.exe' -w"
Configure a Text Editor - Notepad++
1
git config --global core.editor "'C:/Program Files (x86)/Notepad++/notepad++.exe' -multiInst -nosession -noPlugin"

You are writing good commit messages right?

Use a Graphical Merge Tool

Now that you have a graphical text editor, why not use a diff/merge tool that you’ll be productive with? There are a lot of options here, and today I’m using DiffMerge.

When I set up my diff/merge tool I tend to just edit my .gitconfig file directly since it’s faster for me. If you want to add all this crap in via individual commands in Git that’s cool, but my recommendation is to save some time and just edit this by hand.

Configure Git to use DiffMerge
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[diff]
    tool = diffmerge
    guitool = diffmerge
[difftool]
    keepBackup = false
    trustExitCode = true
[difftool "diffmerge"]
    name = DiffMerge
    path = \"C:/Program Files/SourceGear/Common/DiffMerge/sgdm.exe\"
    cmd = sgdm --nosplash \"$LOCAL\" \"$REMOTE\"
[merge]
    tool = diffmerge
    guitool = diffmerge
[mergetool]
    prompt = false
    keepBackup = false
    keepTemporaries = false
    trustExitCode = true
[mergetool "diffmerge"]
    name = DiffMerge
    path = \"C:/Program Files/SourceGear/Common/DiffMerge/sgdm.exe\"
    cmd = sgdm --nosplash --merge --result=\"$MERGED\" \"$LOCAL\" \"$BASE\" \"$REMOTE\"

The right Diff/Merge tool makes all the difference when working on a project where you can have conflicts that need addressing.

Take some time and play around with some of the different tools and setting them up to work the way that makes sense for how you work. Today I’m using DiffMerge and in the past I’ve used WinMerge; both are great. But, with that in mind, I’ve been taking a serious look at Semantic Merge and it looks to be really promising.

Set Up Some Aliases

I wrote about aliases last week. Make your life easier by finding the most common commands you’re using and alias them to something short and sweet.

Use a Network Repository

Whenever I’m going program something that is more than just a quick snippet, I create a Git repo and stuff my code into it. If it’s something that I’m doing professionally or something I want to share with all of you, I push it up to either a public or private repository on Github. I like this approach because I get cloud backup of my repo and if something happens to my local one, eh, who cares. But not everthing should go out into the wild, and for those projects I will work local and create a bare repository on a network share.

If you think to yourself “why, this can’t be a big deal, I’ll just copy the repo from my machine to the share and start pushing to it” you’d be wrong! If you do, you’ll get the following error message:

Pushing to a non-bare Git Remote
1
2
3
4
5
6
7
8
9
10
11
12
13
14
remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsistent
remote: error: with what you pushed, and will require 'git reset --hard' to match
remote: error: the work tree to HEAD.
remote: error:
remote: error: You can set 'receive.denyCurrentBranch' configuration variable to
remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into
remote: error: its current branch; however, this is not recommended unless you
remote: error: arranged to update its work tree to match what you pushed in some
remote: error: other way.
remote: error:
remote: error: To squelch this message and still keep the default behaviour, set
remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.

This happens because when you’re working on your repository on your machine, you’re working in an ititialized repository that has a working directory with the .git sub-directory that contains all your version controlled stuff. When you copy this to your network share, Git becomes a sad panda and won’t let you push to it. Fortunately, getting this to work is trivial by simply creating a “bare” repository, which in essence is a Git repository that doesn’t have a working directory, only version control information.

To create the bare repository, just navigate to the folder where you want the repository to be created and execute:

Create a Bare Git Repository
1
git init --bare

Once you’ve done that, setting up the remote is super simple. In this example I’m creating a remote called “JoshNetworkShare” that maps to H:\Repositories\name-of-my-repository:

Create a Git Remote for a Repository on a Network Share
1
git remote add JoshNetworkShare file://H:\Repositories\name-of-my-repository

Substitute the name of the remote and the path on your network to the bare repository that you created with your values and a whole new world opens up to you.

Use an Established Workflow

Git changes how you think about writing software and promotes using workflows to establish a consistent development and source code management process. You might think that the process you used in TFS or Subversion or Perforce or CVS (god help you…) will work, but you won’t get the full benefit of Git if you go that route. Git isn’t one of those other SCM’s, so don’t treat it like it is; get yourself a nice, simple Git workflow and move along.

Both personally and professionally I’ve followed Scott Chicon’s workflow. It works great for me on the large teams at work as well as my own one-man projects. There are others out there but since I firmly believe in shipping working software often, the flexibility of this workflow scales really well. If you don’t believe me, Github uses it for well over 100 develops across all of thier projects and it works well for them.

Regardless, find a workflow that you like and stick to it. The consistency will be invaluable.

Delete Unused Branches

If you work on repositories that have a large number of fast and furious branches for things like support tickets, bug fixes and whatnot you’ll find you have a LOT of branches that have limited value once merged into master. You can clean up this clutter by running ‘git branch –list’ to get a list of all the branches, and individually run the ‘git branch -d [branch name]’ command for each branch you want to delete. Sound a bit sketchy? Yeah, it is; you can accidentally delete branches that have running work in them rather than the one you wanted simply by being a touch careless.

Ask me how I know…

Fortunately there is an easier way to check which branches are safe to delete and automate their deletion.

Check which branches are merged into your current branch
1
git branch --merged
Check which branches are NOT merged into your current branch
1
git branch --no-merged
Safely delete the branches that have been merged into your current branch
1
git branch --merged | xargs git branch -d

Comments