Git Tips

This is a collection of git tips from various sources and tailored to my needs. The tips are known to work under git 1.7.3.

Updates 2010-10-20:

  • Updated git version known to work against to 1.7.3 as I’ve not tested any new features on old versions
  • Improved some aliases based on Mislav’s post
  • I no longer use core.autocrlf setting, so set to false
  • Covered push -u for setting up remote tracking

Read the community documentation

There is a lot of really good community documentation out there. The primary git-scm site is a good start, as well as git ready.

Useful global config

To show who you are:

git config --global user.name "Kris Brown"
git config --global user.email kris@kris.me.uk

To colourise the outputs:

git config --global color.diff auto
git config --global color.status auto
git config --global color.branch auto

To add some useful aliases:

git config --global alias.ci commit
git config --global alias.st "status -sb"
git config --global alias.qlog "log --oneline -n 10 --decorate"
git config --global alias.glog "log --oneline -n 10 --decorate --graph"
git config --global alias.co checkout
git config --global alias.svnup "svn rebase"
git config --global alias.svnci "svn dcommit --rmdir"

Github goodies:

git config --global github.user krisb
git config --global github.token $tokenhash

Handling CR+LF issues:

git config --global core.autocrlf false

Defaulting to rebase pulls to reduce merge commits:

git config branch.master.rebase true
git config --global branch.autosetuprebase always

System wide ignores (mac + windows):

git config --global core.excludesfile ~/.gitignore
echo .DS_Store >> ~/.gitignore
echo Thumbs.db >> ~/.gitignore
echo ehthumbs_vista.db >> ~/.gitignore

In git version 1.6.3, pushing no longer defaults to anything (it did default to matching previously). To set the default to current (i.e. just the current branch), modify the config:

git config --global push.default current

Project setup

Cloning an existing repository

Cloning an existing repository tracks that remote repository by default:

git clone git://github.com/$username/$project.git
cd $project

Creating a new project

Creating a new project, touching the readme and then performing the initial commit:

mkdir $project
cd $project
git init
touch README
git add README
git commit -m "first commit"

Modifying code and committing

In git, changes can be in one of 3 locations:

  • working tree which contains your local modifications on the file system
  • index or staging area which contains your local modifications on the file system and indexes changes that are staged ready for committing
  • repository which contains your committed modifications. This can be local or remote.

The basic work flow is to check your status, diff your changes and review them, add to the index and then commit to the repository.

<modify some files>
git status
git diff
git add -A
git commit -m "a suitably good description of the change"

There are many variations on the above, commands in git are very powerful and can be used in a variety of ways. git add -A will ensure that any deletions or new files are also indexed.

Once commits are in repositories can then be fetched, pushed, pulled, merged, rebased and many other things. Technically there is another location, the stash, think of this as a modifiable local branch.

Adding a remote

If you created a new project, or you want to add another remote to an existing project:

git remote add origin git@github.com:$username/$project.git
git push -u origin master

The -u option is optional and sets up tracking if present.

Tracking a remote

If you did not branch/clone from a repository initially or use the push -u option then you can add the tracking manually. This is also applicable if you wish to change the remote being tracked. For example, to track origin from master:

git config branch.master.remote origin
git config branch.master.merge refs/heads/master

This then allows you to pull and push without specifying the local and remote branches:

git pull
git push

git status also plays nicely with tracked remotes, showing if you are ahead or behind and by how many commits.

Patching

The following examples assume that the master is the main development branch and feature_branch is the feature branch.

Preparation

To create clean patches, the modifications should be made on a branch:

git checkout master
git branch feature_branch
git checkout feature_branch

The last 2 commands could be done in a single command using:

git checkout -b feature_branch

Updating

Before submitting a patch it is good practice to pull in the latest changes and rebase the branch to ensure the patch will work against the latest version:

git checkout master
git pull
git checkout feature_branch
git rebase master

The 1st and 2nd commands ensure that master is up to date, the 3rd and 4th commands rebase the feature branch to master. If the feature branch has been remoted already then you’ll have to merge instead, i.e. git merge master

Email style patches

This method is the recommended way of doing patches in git. The author is still credited with the changes and it is easy to commit. Run the following from the feature branch:

git format-patch master --stdout > patch.diff

The committer can then apply the patch using:

git am < patch.diff

The commiter may choose to use git apply if they wish to make alterations.

Traditional style patches

Git also allows the traditional way of patching using a diff but this does not preserve the commit history of the author. Run the following from the feature branch:

git diff > patch.diff

The committer can then apply the patch using:

patch -p1 < patch.diff

-p1 is needed rather than the usual -p0 due to the extra a/ and b/ prefixes in the git diff output. Alternatively, git diff can be supplied the --no-prefix option and patch supplied the -p0 option.

Tidying up

Checking if a branch contains commits or other branches

git branch --contains branch-to-delete
git branch --merged
git branch --no-merged

Deleting a remote branch

git push origin :branch

Finding duplicates

This is a really handy little script I use a lot of my photo archive to find and remove duplicates. Its based on the script from StackOverflow but I had to modify the regex to allow any characters in the filename as I have spaces in there. I create two scripts, one called gitdup that handles the usage comment in the second script, called gitdup_collate

#!/usr/bin/perl
# usage: git ls-tree -r HEAD | gitdup_collate

use strict;
use warnings;

my $sha1_path = {};

while (my $line = <STDIN>) {
    chomp $line;
    if ($line =~ m{ \A \d+ \s+ \w+ \s+ (\w+) \s+ (.+)}xms) {
        my $sha1 = $1;
        my $path = $2;
        push @{$sha1_path->{$sha1}}, $path;
    }
}

foreach my $sha1 (keys %$sha1_path) {
    if (scalar @{$sha1_path->{$sha1}} > 1) {
        foreach my $path (@{$sha1_path->{$sha1}}) {
            print "$sha1  $path\n";
        }
        print '-' x 40, "\n";
    }
}

Comments

blog comments powered by Disqus
Fork me on GitHub