Getting up speed with Git

Rewriting history

Before pushing commits to a remote location, it's recommended to get the history back into shape. This way, other developers deal with a clean history.

Each commit should preferably, describe just one feature or fix.

Just to let you know...
Commands which rewrite history, should be used with private commits only. By default, it's not possible to push a rewrite of the shared history.

Fixing the last commit

When a file was forgotten, or a line had to be removed, it's simple to fix. Just stage those changes, and run:

Fixing the last commit:
git commit --amend

The staged changes will be used to correct the last commit.

Removing a commit

Removing the last commit happens with the reset command:

Naming reasons
This is called the "reset" command because it resets the location of HEAD, and optionally the staging area or working tree.
Undo a commit:
git reset HEAD^         # short for git reset --mixed HEAD^

The changes of the commit are loaded back in the staging area. There are two other options as well:

Undo a commit:
git reset --soft HEAD^  # remove a commit, keep staged and working changes
git reset --hard HEAD^  # remove a commit, delete working copy changes and staged changes

Redoing history

With git rebase -i, Git allows you to redo parts of your commit history. First select the starting point or commit, after which Git should start.

Starting the interactive rebase:
git rebase -i commit
git rebase -i HEAD~4           # rebase the last 4 commits

This can be any commit beyond the origin/... branch, or simply:

Rebasing unpushed commits:
git rebase -i origin/master    # start after the last shared commit

A text editor will open, listing all commits. Edit the file to tell Git what should happen:

After you save & quit the text editor, Git will start the rebase.

The rebase proces

The rebase starts by rewinding history back to the old state. Next, the old history is replayed, by applying the commits one by one.

When git needs assistence, the rebase pauses. After committing the fixes, the rebase can continue:

Resuming a rebase:
git rebase --continue


In case things went wrong, the rebase can be aborted:

Aborting a rebase:
git rebase --abort     # abort the rebase, back to the original situation
git rebase --skip      # skip the commit if it causes trouble (deletes it)

Splitting commits

With the edit modifier, git rebase allows you to redo history. Any extra commit you make, will be inserted in the history.

So again, start git rebase -i commit and replace the word pick with edit for the commit that needs to be split. Save & quit the file so the rebase process starts.

The rebase command pauses precisely after the moment in time when the commit was made. To split it, the following is needed:

Splitting a commit:
git reset HEAD^    # Undo the commit, load all changes in the working tree
git add file1
git commit         # commit the first part
git add file2
git commit         # commit the second part
git rebase --continue

Amend an older commit

To amend an older commit, the following procedure works nicely:

After closing the file, git will process to fix the history.

Undoing everything

Git internals: the revlog

The revlog tracks the previous value of HEAD for about 30 days.

Commits which are no longer referenced by any object, get cleaned up automatically.

In case you totally screwed up, things can be fixed with the revlog

Fixing a total screw up:
git revlog                  # find the past version of HEAD
git reset --hard HEAD@{nr}   # return to that commit

Last but not least

One extreme form of rewriting is the filter-branch tool. It can be useful for a few situations:

This is a typical command you'll likely never need, but in case you really have to, it's nice to know these things are possible.

Anything next?

This is the last chapter of the tutorial. There are still some things to talk about, e.g. svn, submodule and bisect commands. There are some tricks and links as appendices, for further reading.


If you have any commits, feel free to send me your feedback.

blog comments powered by Disqus