Git - Commit History and Reordering Commits Using Rebase

July 6, 2023

In my last post, we covered Clones, Forks, and Pull Request in the context of several contributors working on a project as a team.

 

In this post, we're going to cover commit history and the rebase command. Using the rebase command can be dangerous, because it has the capability to rewrite commit history. If not used properly, it can cause data loss, create headaches for team members, and rearrange the logical development history of the project which can cause confusion.

#1 Rule to Rebase: Don't use it if you don't know exactly what you're doing!

Commit History

Commits happen in a chronological sequence, each capturing a specific set of changes made to the codebase. Commands to explore the commit history can provide a ton of good information, including who made the changes, when they were made, and the exact modifications performed. It's essential to understand these commands for better collaboration, debugging, and tracking the evolution of the codebase.

The "git log" command will display the commit history in the terminal, starting from the most recent commit.

 

I created a new folder on my desktop named "rebase", then changed into that directory and initialized git using the "git init" command.  I then added an empty file "test.js" using the command "touch test.js", and added it to the git tracker with the command "git add test.js" I have not pushed that to my remote repository, we're only working locally.

I then modified "test.js" to include the following text. "Sentence One." I then committed the file with the commit message "Sentence One Commit."

 

I then modified "test.js" a third time to add a sentence below the first, "Sentence Two". I will now commit this change using the commit message "Blarg blarg blarg".

 

This is what my "git log" command will produce:

Now since "Blarg blarg blarg" isn't a very helpful comment for anyone, I can amend this commit as long as the commit hasn't been pushed to the remote repository. Again, we've only been working locally. Here's what it looks like when I run the "git  commit --amend" command to clean up that message.

What you're seeing is the comment within the Vim editor that has been opened automatically. If you're not familiar with Vim, I encourage you to search online for tutorials and videos to become familiar with the basics. For this example I'll use the i character to edit the text on screen and change "Blarg blarg blarg" to "Sentence Two Commit" and save using the Vim editor commands  [ESC] :wq

 

Now you can see the revised git log:

Reorder Local Commit History

There is a way to reorder local commit history using the interactive rebase command. I have 3 commits from the previous operations.

     
  • Initial Commit
  • Sentence One Commit
  • Sentence Two Commit

To reorder the last two commits, we would use the command "git rebase -i HEAD~2".

 

Here is what we see when I enter that command:

It's important to note that I committed these in the order "Sentence One Commit" then "Sentence Two Commit". But what shows up most recently in the interactive rebase session is "Sentence One Commit", which the first commit I made out of the two. So it's showing the commits in reverse order.

 

Let's say we want to remove any of the local commit history. We could simply delete one of the commit lines that shows the hash from this screen and save, which would erase that commit. We can also reorder the commit history by rewriting the order. Here I'll interchange the two commits. In order to edit the text while in the Vim editor, I'll hit lowercase i on the keyboard.

Since we're in the Vim editor, we can save the change to the file by hitting [ESC] : wq

 

The reason we're getting an error message is that the text inside our "test.js" file differs between the two commits.

Let's examine the test.js file and see what it looks like now.

We covered merge conflicts in a previous blog post Git - Branches and Merges. This is the same type of behavior as a merge conflict. Our test.js file has been marked up, showing us the difference in the texts in test.js between the two commits. What we'll need to do is clean it up then continue the rebase. Here I went ahead and changed the order of the text as well.

And now that this is complete, we will need to re-add the file using "git add test.js". We can now run "git rebase --continue" and we'll arrive at the following screen.

Now you'll edit the commit message and save with [ESC] :wq

You'll then see this screen:

Which warns you that the Sentence One Commit still needs to be dealt with. We'd go in and edit this file just like we did with the previous, and find the following result, that the rebase has been successful.

Now if we run "git log" we see the following:

If you compare that to our earlier "git log" before the rebase, Sentence One Commit and Sentence Two Commit have changed places!

As you can see, rebasing can get pretty involved. And there is a lot more to it, you should have a feeling by now of the trouble it can cause if used without care.