Practical Git: Rewriting Commit History

Though a large part of our day-to-day Git usage is centered around making commits and forging ahead to build a version history, it’s not uncommon to need to edit or adapt this history. Below I’ll be looking at some common scenarios and commands that can be used to have greater control over commits.

Like the previous post Practical Git Branching – Software Consulting – Intertech, the workflows below are part of a practical toolset for reoccurring situations when working in a repository. This post assumes the reader has a working familiarity with Git, including writing commits, branching, and an understanding of local vs remote repositories.

Adding a specific commit to a branch

Cherry Picking

If we’d like to add a commit from one branch to another, but not combine the entire history of both branches through a merge, we should cherry-pick the commit. This is a viable solution no matter where the commit is in the other branch’s history. Cherry picking is typically used to add a hotfix or small bug-patching commit.

Let’s imagine that in the process of implementing a feature for user forms, a developer working on their own branch has fixed an existing bug. We want the bug fix, but not their in-progress work or commits.

We’ll first fetch their branch from the remote and checkout the branch.

Then run “git log” to show commit history.

git log 
We find the commit with hash 50d29c55 pertaining to the bug fix. Next, we’ll checkout our working branch and run:
git cherry-pick 50d29c55
Note: In many cases, regardless of the command, Git only requires the first 6-8 characters of the hash.
The commit has been successfully added to our working branch “feature-d”

Undoing Commits When Working Solo

Soft Resetting

Performing a soft reset is a quick and handy way to rework a commit. This allows us to remove the commit from branch history while restaging the changes that were tracked for that commit.

Make note that if the branch was previously pushed or published, a reset will cause problems for collaborating developers who have pulled from the remote branch in between this reset. If we’re working in a collaborative team scenario, this negative side-effect can be combatted by instead using the revert command mentioned in the next section.

Let’s say we’ve just committed work which adds styling for a header, footer, and our primary site container. We soon learn that the client would like these app components styled differently and we must make changes. We can reset that most recent commit and update the implementation from our restaged changes.

Run the below command to reset the single most recent commit, in this case the HEAD of the branch.
git reset —soft HEAD~1
Observe that our HEAD now points to the earlier commit ca92875b

The number after the tilde represents n number of commits going backward in the branch history. For example, if we entered “HEAD~3” we’d see the last three commits removed, with modifications returned to staging status.

Undoing Commits When Working with a Team

Reverting a Commit

When we revert a commit, we’re simply adding a new commit that reverses the changes of the commit or commits we specify. This command is hugely valuable because the reversal is performed by Git, not the developer.

A specific commit anywhere in the repo’s history can be reverted by running

git revert <commit-hash>
This command functions similarly to reset in that we can supply n number of commits. We can also enter a range of commits we’d like to revert, separated by ellipses. For example, the below command will revert 2 commits starting from the HEAD, working backward in time.
git revert HEAD~2..HEAD
Or we can enter a range of commit hashes:
git revert 0756c88..323hfd3
Note: the min/max of these ranges in both cases are inclusive.

Just like the above example, we’ll revert the two commits shown below by specifying the range.

git revert cddaa15..331ddac
After running the revert command, Git will open the system’s default editor (i.e. VScode, vim, nano, etc) and allow you to edit the commit message. In the screen below, we’ll leave the default “Configure app entry point”, with no changes.
Finally, if we want to keep the branch clean or aren’t needing to refer to these changes in the future, we can do a no commit revert by using the “—n” flag.

In Conclusion

We’ve reviewed three helpful methods for reworking and managing commit history. In the next post, I’ll show ways we can manipulate multiple commits and branch history within a broader scope.

About Intertech

Intertech is a Software Development Consulting Firm that provides single and multiple turnkey software development teams, available on your schedule and configured to achieve success as defined by your requirements independently or in co-development with your team. Intertech teams combine proven full-stack, DevOps, Agile-experienced lead consultants with Delivery Management, User Experience, Software Development, and QA experts in Business Process Automation (BPA), Microservices, Client- and Server-Side Web Frameworks of multiple technologies, Custom Portal and Dashboard development, Cloud Integration and Migration (Azure and AWS), and so much more. Each Intertech employee leads with the soft skills necessary to explain complex concepts to stakeholders and team members alike and makes your business more efficient, your data more valuable, and your team better. In addition, Intertech is a trusted partner of more than 4000 satisfied customers and has a 99.70% “would recommend” rating.