Using Git Rebase to rewrite the history of a project
Introduction
In our open-source course at Seneca, this week's task was to refactor our code for our command-line tools. If you’ve been following my blog, you’re probably aware of GitHub Echo, a command-line tool I’ve been developing that fetches actionable insights from GitHub repositories for open-source enthusiasts and contributors.
This week’s goal was to learn how to use rebase
to rewrite the project history, utilizing the --amend
option with commits and merging. Compared to previous weeks, this task is straightforward since it doesn’t involve collaboration with others, allowing us to focus solely on our individual work. This is why I'm writing this blog at 3 AM after finishing my lab, which I started at 1 AM!
First Steps
The initial steps are pretty simple—just the regular drill. We start by pulling the latest changes using:
git pull origin main
Next, I opened an issue to work on my code. Here’s the link to the issue: GitHub Issue #48. After that, I checked out a new branch for refactoring from the main branch:
git checkout -b refactoring
Here’s what running git log --all --graph
looks like right now:
Refactoring Process
After checking out the branch, I began looking for improvements in my code. I made the following commits during the refactoring process:
Shorten Docstrings
Shorten comments and remove unnecessary ones + type safety
Shorten comments + make function names more descriptive + add more type safety
Refactor entry point file to break it into multiple functions
Since I had been focusing on keeping my code clean since the project's inception, I didn’t have to work hard to finish this task. Most of my changes involved removing unnecessary comments, as I noticed during Hacktoberfest that many large open-source projects avoid excessive comments and lengthy docstrings.
I also refactored repetitive code into functions and organized them into different files, making the code much easier to maintain.
Preparing to Merge: Squashing Commits
Now that we've finished our refactoring, it’s time to merge our work into the main branch.
However, before doing that, let’s squash all the commits into a single commit. Although we made four commits to refactor the code, the end product is essentially one cohesive change. To do this, we’ll use the following command to start an interactive rebase:
git rebase main -i
This command will open an editor allowing us to specify what to do with each commit. We want to squash the last four commits into the first one. We do this by replacing the pick
action with the s
or squash
option in the text editor that git
opens for us.
After saving the file, Git will create a new commit that combines the changes from all five commits into a single commit. The log message will include the combined messages of all five commits.
Next, run git log —all —graph
to confirm that the squashing was successful.
Amending a Commit
Just as I was about to finish, I wanted to change my commit message. To change it before merging, we’ll perform an amended commit:
git commit --amend
This command will open the editor again with the previous log message, which we can then modify to whatever we want it to be.
Once we save the changes, the commit will be updated with the new message. Verify the changes with git log —all —graph
again.
Merging into main
Now that our refactoring branch is complete, we’re ready to merge it into the main branch:
git checkout main
git merge --ff-only refactoring
git push origin main
The --ff-only
flag ensures that we perform a fast-forward merge. This type of merge occurs when the branch being merged is ahead of the current branch and has no divergent commits. It simply moves the pointer of the main branch forward to the latest commit of the refactoring branch, keeping a clean and linear project history.
After merging, the main branch now points to the same commit as the refactoring
branch.
Conclusion
In conclusion, I successfully refactored the GitHub Echo tool and learned how to use rebase
and squash
to maintain a clean commit history. Rebasing allows developers to integrate changes from one branch into another while keeping a linear project history. This process eliminates unnecessary merge commits and helps in avoiding a complex commit history, which can be hard to follow.
Many open-source projects utilize rebasing and squashing to keep their commit history clean and understandable. This not only makes it easier for contributors to review changes but also simplifies tracking the evolution of the codebase. By focusing on the end result rather than the process, we can produce a more meaningful and concise commit history, making it easier for others to understand the project’s development over time.
That is all for this blog. See ya soon 🔜
Subscribe to my newsletter
Read articles from Aryan Khurana directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by