Git · Version control

The wonders of git

I’ve been wanting to write about git for a very long time. It’s a tool used for managing versions of software (but it can be used for other things).

One of the reasons that I haven’t written much about git is that, quite frankly, there’s a lot to learn.

I use git from the command line, because it’s the most flexible way I know, and I am about to show an example of what I had to do today, which will demonstrate git’s strength (I hope).

Before I start, if you’re unfamiliar with the terminology used here, I recommend reading the first 3 or 4 chapters of the Git book (it’s well worth the effort).

Right, some context. Today I was working on creating a topic branch because I had a change to write for the code at work. As I worked on the change I realised that I really needed to break the branch up into two branches, one with a large amount of change that prepared the way for the actual change that I was working on. Reviewing the two changes togather would be tiresome, and might lead to things being missed.

I created the preparation branch, with a commit inside it, and pushed it to our shared repository.

I then pushed the remaining change in the topic branch to the same repository.

Our CI runs on every branch, triggered by the push, and I duly got an email saying that tests had failed on the preparation branch, and I realised that I had included some of the change meant for the preparation branch in the topic branch. And this is what I did to get myself into a position where the preparation branch had the code it needed, and the topic branch no longer did.

git checkout <topic branch>
git reset HEAD~1
git add -p
<add the stuff meant for the preparation branch>
git commit -m "move me"
git commit -m "the rest" .
git log -n2
<grab the sha1>
git checkout <preparation branch>
git cherry-pick <saved sha1>
git rebase -i HEAD~2
<squash the two commits>
git push --force
git checkout <topic branch>
git rebase <preparation branch>
git push --force

Let’s break that down into (hopefully) manageable bites.

1) git checkout <topic branch>

This tells git which branch it is working on. Work on one branch at a time. Git will apply the commands to this branch, until told otherwise.

2) git reset HEAD~1

This “undoes” the last commit. But it’s a soft reset, meaning that the changes in that commit are now unstaged.

3) git add -p

(add the stuff meant for the preparation branch)

Git allows you to add parts of a change, hunk by hunk, and you can edit what is being added using this command.

4) git commit -m "move me"; git commit -m "the rest" .

These two commands commit the changes, the first is a commit comprised of what I had staged in the add -p step above, the second commits the rest. The -m tells git to use the message supplied, instead of going into the editor and mucking about.

5) git log -n2

I used this to show me a synopsis of the two commits that I had just created, and allowed me to copy the sha1 hash of the commit that I had named “move me” which contained the changes that I wanted to move.

6) git checkout <preparation branch>

Git is now applying the commands to the preparation branch.

7) git cherry-pick <saved sha1>

This moves the commit from the topic branch to the preparation branch.

8) git rebase -i HEAD~2

Moving into interactive mode, git willapply some rebase commands, in this case I squashed the two commits together (the existing commit in the preparation branch, and the commit that I just moved to this branch).

9) git push --force

Updating the remote repository with the new state of the preparation branch. The push must be forced because of the change to the commit made in the previous step.

10) git checkout <topic branch>

Git is now applying the commands to the topic branch.

11) git rebase <preparation branch>

This tells git to move the topic branch such that it is branched from the new tip of the preparation branch.

12) git push --force

The previous command had changed the branch in such a way that the remote repository needed to be forced to accept the new understanding of this branch.

That was a LOT of fun to actually do :)

Published:
comments powered by Disqus