Week 7

Day 3 - "Rebasing our commitments"

Rebase examples

We are now going to go back to our coderepo folder. This is the one we cloned from in Week 6 to create the coderepo-cl repository. When we left this repository, we were at commit 1c3206a. If you have played with the repository at all, it would be a good opportunity for you to bring the wonderful branch to that point. We are also going to Fast Forward the master branch to that same point too. Before reading on, try to remember what commands we would use to do this and then check below to see if you are right.
john@satsuki:~/coderepo$ git checkout wonderful
Already on 'wonderful'
john@satsuki:~/coderepo$ git reset --hard 1c3206a
HEAD is now at 1c3206a Added a new file
john@satsuki:~/coderepo$

So we begin by ensuring that we are on the wonderful branch. Then we perform a hard reset, to ensure that the HEAD of wonderful points to the commit 1c3206a.
john@satsuki:~/coderepo$ git checkout master
Switched to branch 'master'
john@satsuki:~/coderepo$ git merge wonderful
Updating 37950f8..1c3206a
Fast-forward
newfile3 | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 newfile3
john@satsuki:~/coderepo$

Next we use the git merge command as before to bring the master branch in line with the wonderful branch. As there have been no more commits to master since we worked on wonderful, it means that once again, the merge can be a simple Fast Forward merge, allowing us to simple change which commit HEAD points to within the master branch.
john@satsuki:~/coderepo$ git branch -v
master 1c3206a Added a new file
* wonderful 1c3206a Added a new file
zaney 7cc32db Made another awesome change
john@satsuki:~/coderepo$

Finally, we run a git branch command to confirm that the branches point to the same commit. Remember there are other ways we could have achieved this, using git log for example. Now that we can see they point to the same place, we can continue with our introduction to the git rebase command. We will start by making some commits to the wonderful branch and see how we can update our underlying master branch.
john@satsuki:~/coderepo$ echo "New Changes" >> another_file
john@satsuki:~/coderepo$ git commit -a -m 'Updated another file'
[wonderful c0e2f5b] Updated another file
1 files changed, 1 insertions(+), 0 deletions(-)
john@satsuki:~/coderepo$ echo "More New Changes" >> another_file
john@satsuki:~/coderepo$ git commit -a -m 'Updated another file'
[wonderful 8c6a66b] Updated another file
1 files changed, 1 insertions(+), 0 deletions(-)
john@satsuki:~/coderepo$ echo "More Super New Changes" >> another_file
john@satsuki:~/coderepo$ git commit -a -m 'Updated another file again'
[wonderful b91ec84] Updated another file again
1 files changed, 1 insertions(+), 0 deletions(-)
john@satsuki:~/coderepo$ gitk --all
john@satsuki:~/coderepo$

Before we continue, there is a problem in the trenches.
In the trenches...
"Ahh dang it" shouted Simon. "That's really not very helpful to anyone."

"What's up?" said Martha over the cubicle wall. She stood up, knocking a pile of papers over that were hanging precariously on the edge of the desk. They scattered across the floor creating a white dividing line down the middle of the office. She muttered something under her breath. John and Simon began to help tidy the papers up whilst Simon started stating his problem.

"Well, I commit two commits that used the same commit message, I really wasn't thinking. Plus the fact that they should really have been one commit."

"Just reset back and do the work again," shouted an eavesdropping Klaud unhelpfully. A round of raised eyebrows circled the paper-stackers.

"You could use rebase." Martha was standing next to the desk now and was arranging the stack in a more suitable position on the desk.

"How so?" John looked at Martha inquisitively.

Martha giggled. "Rebase can do a lot more than just replaying commits you know. Some of the more simpler tasks are ... well ... let me show you."

Looking at our example commits, it would appear that we have made the same mistake as Simon. Our commits, c0e2f5b and 8c6a66b have got the same commit message. Not very helpful at all. Let us see how git rebase can help us out here.
john@satsuki:~/coderepo$ git rebase -i HEAD~3

We have told Git to run the rebase command using the -i parameter. This will put Git into interactive mode. We have also asked Git to rebase the last three commits. The HEAD~3 is used like before to tell us to go back three commits from the HEAD references. When we run this command, we are presented with a text file in our default text editor.
pick c0e2f5b Updated another file
pick 8c6a66b Updated another file
pick b91ec84 Updated another file again

# Rebase 1c3206a..b91ec84 onto 1c3206a
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

At the top of the file, you can see the last three commits, along with their commit message, prefixed by the word pick. We will get to what this really means in a few minutes, but as you can see there are a large number of options within the rebase interactive system. If we closed the file and left it unchanged, the rebase would end without altering anything. The options are fairly self explanitory but they allow us to change many elements of a commit or a series of commits.

In our case, we can use this to reword the second commit, 8c6a66b. We are going to modify the lines above to look like the ones below.
pick c0e2f5b Updated another file
r 8c6a66b Updated another file
pick b91ec84 Updated another file again

Notice that we replaced the beginning of the second line, original starting with pick, with the letter r. Using the list of available functions above, we can easily see that the r corresponds to the reword function, which will allow us to change the wording that we have used for that particular commit. On saving this and closing this file, Git quickly presents us with another editor window. This time the window contains a more familiar commit message setup. We will modify it to show the same as below, and then close the editor.
Updated another file 2nd time

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# Not currently on any branch.
# Changes to be committed:
# (use "git reset HEAD^1 <file>..." to unstage)
#
# modified: another_file
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# temp_file

After Git completes working on the rebase, we are presented with the result of our operation.
john@satsuki:~/coderepo$ git rebase -i HEAD~3
[detached HEAD 7c35dde] Updated another file 2nd time
1 files changed, 1 insertions(+), 0 deletions(-)
Successfully rebased and updated refs/heads/wonderful.
john@satsuki:~/coderepo$

So Git has completed the operation, and by running an abbreviated git log command, we can see that the fruits of our labour have resulted in the second commit having its working changed.
john@satsuki:~/coderepo$ git log --graph --pretty=oneline --all --abbrev-commit --decorate -n 4
* aeb5679 (HEAD, wonderful) Updated another file again
* 7c35dde Updated another file 2nd time
* c0e2f5b Updated another file
* 1c3206a (master) Added a new file
john@satsuki:~/coderepo$

Note - Rebasing and the hashes

If you have been paying attention to the SHA-1 hashes as we have been moving through this last piece on rebasing, you may have noticed something interesting. Though there are commits that we have not altered at all, the commit IDs have indeed changed. If we take the example where we re-worded the second commit, it is clear to see that subsequent commits have their IDs changed. In the example, we modified commit 8c6a66b, but we left b91ec84 untouched. In the resulting tree, both have had their IDs changed.

The reason for this is simple, remember we are replaying commits. In a sense we are re-committing the changes that were made during that commit. As we have stated previously, Git is cryptographically secure. By this we mean that each commit relies on the commit that preceeds it. So, if we change the ID of a preceeding commit, all subsequent ones have to change also.

Let us try this rebase again. This time we will use the squash option to merge the two similar commits into one. We will run the same command as before; git rebase -i HEAD~3. This time we will use the s prefix to the line to choose squashing as our method. We could have used the word squash instead of s, but for the laziness in all of us, we will opt for the single letter versions for now.
pick c0e2f5b Updated another file
s 7c35dde Updated another file 2nd time
pick aeb5679 Updated another file again

# Rebase 1c3206a..aeb5679 onto 1c3206a

Now when we save and close the file, we are presented with a slightly different screen. As we are squashing several commits together into one, we need to choose a commit message. The message needs to be descriptive enough that it will accturately let a developer see what has been updated in this single commit. We will delete these lines and replace them with the comment Updated another file with 2 edits.
# This is a combination of 2 commits.
# The first commit's message is:

Updated another file

# This is the 2nd commit message:

Updated another file 2nd time

After completion, Git shows us that the rebase has been successful.
[detached HEAD 1ffe37f] Updated another file with 2 edits
1 files changed, 2 insertions(+), 0 deletions(-)
Successfully rebased and updated refs/heads/wonderful.
john@satsuki:~/coderepo$

By using the git log message, we can see that the two commits have indeed been replaced by one.
john@satsuki:~/coderepo$ git log --graph --pretty=oneline --all --abbrev-commit --decorate -n 4
* 4d91aab (HEAD, wonderful) Updated another file again
* 1ffe37f Updated another file with 2 edits
* 1c3206a (master) Added a new file
* 37950f8 Continued Development
john@satsuki:~/coderepo$

In the trenches...
"Actually that's pretty cool," commented Simon, after Martha had shown him how to use rebase to squash and reword. She smiled, but said nothing. Martha had an uncanny knack for knowing when there was going to be another question. "So, just how would we use git rebase for keeping a development tree up to date?"

Martha ruffled Simon's hair. She liked his youthful enthusiasm. "How about we take a crack at that tomorrow eh?"

Previous Day

Next Day

 
   
home | download | read now | source | feedback | legal stuff