There may come a time when you’ve really botched your commit messages and you need to amend a few of them all at once. You could amend all of them one at a time and then push them to a remote. Or you could just amend them in a large batch and save yourself some time and probably a bit of anxiety.
Remember, by amending commit messages, the metadata of the commits change so it will have a new SHA key – even if you didn’t change any code at all. Obviously, this will create conflicts with your remote, which has all of the old commit SHA keys. So once you’re done with your amendments, be sure to force push your changes to remote.
Checking for commit errors
In class, we’re using Pivotal Tracker (PT) to keep track of ‘stories,’ or tasks, that required to complete for homework. It’s just one of many project management tools out there based on the Agile Way. In addition, we’re using a PT service on GitHub that requires us to add our PT story ID onto each commit message we write on a topic branch. Well guess what? Yours truly totally forgot about this requirement.
To check how badly I messed up, I went back to the branch I needed to amend, which happened to be one called
104389600 is the PT ID,
chapter_1 is the topic branch name, and
master is the branch I branched off of. Then, I ran
git log to see how many amendments I needed to make.
$ git branch 104389594_introduction_master * 104389600_chapter_1_master 104391102_chapter_0_master master $ git log commit d9f5b78f5e4701f0d5052827ea5ec8badc01a3cf Author: Tim <email@example.com> Date: Tue Sep 29 23:40:47 2015 -0600 Add ex1.rb to run chapter exercises commit d8ece159bc942fde9bf0b538c72b2c2df705acd4 Author: Tim <firstname.lastname@example.org> Date: Tue Sep 29 23:40:00 2015 -0600 Added Readme commit 873e4bb55164372f2acec114f4d3fdc1a4dcf895 Author: Tim <email@example.com> Date: Tue Sep 29 18:39:30 2015 -0600 Create chapter_1 directory, and Readme and ex1.rb [#104389600] commit 237eda11a586239ff8b67e06e406485f4b76acfd Author: Tim <firstname.lastname@example.org> Date: Tue Sep 29 18:58:27 2015 -0600 Add file to have rubocop ignore Guardfile commit e1a26f79b86ed9d5b27edf5e930289e4afdc2f78 Author: Tim <email@example.com> Date: Mon Sep 28 20:20:08 2015 -0600 Initial comment
As you can see, going back in time, I have two commit messages that need the PT ID added to the end of the message. The one before correctly shows the ID in brackets preceded by an octothorpe (#). You’ll also notice that the oldest two commit messages don’t have an ID. That’s because those commits were made in the master branch and the PT service aids in tracking topic branches, so it wouldn’t make sense for the master branch to have any ID in the commit message.
Preparing to make amendments
Now that we’ve spotted our problems, we need to start making amendments. To prepare to amend multiple messages, we first have to fetch from origin. Fetching looks for any new changes made in a remote repository. Then we use rebase to update our local repository. Luckily, our current branch is up to date and we don’t have to deal with any other obstacles other than amending our commits.
$ git fetch origin $ git rebase origin/master Current branch 104389600_chapter_1_master is up to date.
Now, let’s start amending our commits. We can accomplish this by typing in:
git rebase origin/master -i
If you read the documentation for
git rebase --help , you would see that the
-i option allows you to “make a list of the commits which are about to be rebased. Let the user edit that list before rebasing.”
Amending multiple commits
Once you type in
git rebase origin/master -i you’ll be placed into vim. There, you want to look at the top, which lists your commits in chronological order.
NOTE: This is the opposite order of the
git log output.
Since I wanted to amend the last two commits I made, I’ll replace the word
reword. Once you’re ready to amend those commits, get back into Normal mode by hitting
ESC and then typing in
:wq. If you’re new to vim, look for some extra help below the image.
New to vim? Navigate to the line with the first commit you want to amend. Go to the first character, which should be ‘p’ in ‘pick.’ Then type
cw on your keyboard – this keystroke tells vim that you want to changeword and place you in insert mode. See how ‘pick’ is now gone? Go ahead and type in reword and then hit
ESC to return to normal mode.
Have multiple commits to amend? Navigate to the next commit you need to amend and return to the first character of the line. This time, hit the
. key. Magic? The ‘dot’ key will create your last keystrokes in vim, which should have been
cw, typing in
reword, and then hitting
:wq to ‘write’ your edits to the file and then ‘quit’ the vim editor.
Editing your commits
Now, all I have to do is add my Pivotal Tracker ID to each commit message. If you recall from before, I name my topic branches off of the PT ID for the story (task) I’m working on. One advantage of this is that when I go to edit commit messages, I know exactly which PT ID I’m using. I then add that ID to the bottom of the message preceded by a # and confined in square brackets. Finally, I go back to Normal mode and then
:wq. Do this for each commit message.
Once you make your amendments, you’ll pop out of vim and back into your terminal. Notice that your have an output saying you successfully rebased.
$ git rebase origin/master -i [detached HEAD 4da44d3] Added Readme Date: Tue Sep 29 23:40:00 2015 -0600 1 file changed, 86 insertions(+) [detached HEAD 58e1c94] Add ex1.rb to run chapter exercises Date: Tue Sep 29 23:40:47 2015 -0600 1 file changed, 9 insertions(+) Successfully rebased and updated refs/heads/104389600_chapter_1_master.
But wait…there’s more!
One last step. When I check
git status , you’ll notice that my branch and origin “have 2 and 2 different commits each.” What the hell does that mean? Well remember that rebasing and then amending your commits changed their SHA keys. Since I amended two commits, my local branch has two new commits that origin doesn’t have and origin has the two old commits that my local branch doesn’t have.
Well I want my origin to reflect the changes I made with adding the Pivotal Tracker ID, which I know are correct. So I force push my changes onto origin with the
-fu option. Run
git status one more time and it looks like you’re all good…
$ git status On branch 104389600_chapter_1_master Your branch and 'origin/104389600_chapter_1_master' have diverged, and have 2 and 2 different commits each, respectively. (use "git pull" to merge the remote branch into yours) nothing to commit, working directory clean $ git push -fu origin 104389600_chapter_1_master Counting objects: 8, done. Delta compression using up to 8 threads. Compressing objects: 100% (8/8), done. Writing objects: 100% (8/8), 2.36 KiB | 0 bytes/s, done. Total 8 (delta 2), reused 0 (delta 0) To firstname.lastname@example.org:timsjpark/lrthw_exercises.git + d9f5b78...58e1c94 104389600_chapter_1_master -> 104389600_chapter_1_master (forced update) Branch 104389600_chapter_1_master set up to track remote branch 104389600_chapter_1_master from origin. $ git status On branch 104389600_chapter_1_master Your branch is up-to-date with 'origin/104389600_chapter_1_master'. nothing to commit, working directory clean
Thanks to Jason Noble for showing me this nice Git feature.