Interactive rebasing is a powerful feature in Git that allows you to modify, reorder, squash, or edit commits in a branch's history. This feature is crucial when you want to keep a clean and meaningful commit history, especially when collaborating with a team or preparing code for production. This chapter will cover interactive rebasing in great detail, explaining its use cases, commands, and workflows, with practical examples.
Git’s history rewriting features provide developers with powerful tools to alter commit history. Interactive rebasing is one of those tools. It allows you to pick, edit, reword, squash, drop, and reorder commits. Unlike the standard rebase (which only applies commits from one branch on top of another), interactive rebase enables more control and flexibility.
The process begins by specifying which commit range you want to rebase. Git opens an editor where you can modify the commit list. You decide what happens to each commit through a set of commands.
Interactive rebasing is particularly useful when:
It helps to make the commit history more linear, which makes it easier to read and understand by others. For example, instead of showing multiple fixes for a single feature, you can squash them into a single meaningful commit.
Before diving into interactive rebasing, it’s essential to understand a few key concepts:
Rebase: Re-apply commits on top of another base tip. The new branch history looks as though the changes were made sequentially after the base.
Interactive Mode: During a rebase, you can decide how each commit should be handled.
Branch Divergence: Rebasing changes the commit history, which means the commit SHA-1 hashes will differ from their pre-rebase versions.
Command Overview: The command to initiate an interactive rebase is:
git rebase -i
Here, <commit>
is the parent of the commit range you want to interact with. For example, to interact with the last 3 commits:
git rebase -i HEAD~3
Let’s look at the interactive rebasing process step-by-step.
Suppose you have the following commit history:
commit A - Initial commit
commit B - Add header
commit C - Fix header
commit D - Add footer
To start an interactive rebase for the last three commits (B, C, and D), you would use:
git rebase -i HEAD~3
Git will open a text editor with the following:
pick b123456 Add header
pick c789012 Fix header
pick d345678 Add footer
Here, pick
means that you want to keep the commit as it is. You can change the command in front of each commit to perform different actions (which we’ll explore later).
After editing the file, save and close it. Git will proceed with the rebasing process according to your instructions.
During an interactive rebase, you can use the following commands:
Now that we’ve covered the basics, let’s explore advanced techniques:
Squashing combines multiple commits into a single commit. This is useful when you’ve made several small commits that are logically related and can be grouped into one.
Example:
You have these commits:
pick b123456 Add header
pick c789012 Fix header
pick d345678 Add footer
If you want to squash “Fix header” (commit C) into “Add header” (commit B), change the commands like this:
pick b123456 Add header
squash c789012 Fix header
pick d345678 Add footer
When you save and close the editor, Git will prompt you to edit the commit message for the squashed commits. The result will be:
commit A - Initial commit
commit B - Add header (includes Fix header)
commit D - Add footer
Sometimes, a commit message doesn’t accurately reflect the changes made. To change it, use the reword
command:
reword b123456 Add header
pick c789012 Fix header
pick d345678 Add footer
After saving the file, Git will prompt you to enter a new commit message for “Add header.”
You may want to remove unnecessary commits from history. Use the drop
command to delete a commit:
pick b123456 Add header
drop c789012 Fix header
pick d345678 Add footer
After the rebase, the commit “Fix header” will be removed from the history.
Rebasing often leads to merge conflicts, especially if you are changing a commit that touches the same lines of code as another commit.
When a conflict occurs, Git will pause the rebase and ask you to resolve the conflict manually. After resolving the conflict, use the following commands to continue:
git add
git rebase --continue
If you want to abort the rebase and go back to the original state:
git rebase --abort
Avoid rebasing commits that have been pushed: Rebasing rewrites history, and this can cause issues for collaborators who have already based work on the original commits.
Use frequently for local branches: It’s safe to use interactive rebasing in local branches to clean up work before merging or sharing.
Keep commit history meaningful: A clean commit history helps others understand why changes were made.
pick b123456 Add header
pick c789012 Fix header
pick d345678 Add footer
If you want to move “Add footer” (D) before “Fix header” (C), you can reorder the lines:
pick b123456 Add header
pick d345678 Add footer
pick c789012 Fix header
Suppose you accidentally added too many changes in one commit and want to split it into two. Use the edit
command:
edit b123456 Add header and footer
pick c789012 Fix header
After Git pauses, use:
git reset HEAD^
Now, stage the changes you want in the first commit:
git add
git commit
Then commit the remaining changes.
Interactive rebasing in Git is a versatile tool that allows you to alter commit history in powerful ways. By mastering interactive rebasing, you can ensure your project’s commit history remains clean, readable, and logical. Whether you need to squash commits, reword messages, or reorder changes, this feature provides the control you need to refine your history before sharing it with others. Happy coding !❤️