How to Safely Roll Back Code in Git: Revert, Reset, Rebase, and File Tricks
When a critical bug and a performance‑heavy jar collide, this guide walks through four practical Git rollback strategies—revert, reset, rebase + revert, and a pure file‑copy method—explaining their commands, pitfalls, and when each is appropriate.
Background
A project was upgraded from version N to A . The upgrade introduced a third‑party JAR that caused severe performance degradation. Subsequent releases B and C were built on top of A , so the problematic JAR was present in all of them. An urgent bug also needed to be fixed, forcing the team to roll back the code to a state before A while preserving the ability to continue development.
Revert
The command git revert <commit_id> creates a new commit that undoes the changes introduced by the specified commit. In this repository the history contains dozens of regular commits and several merge commits. Reverting each commit individually would require dozens of commands in reverse order, and for every merge commit the -m (mainline) option must be supplied. Determining the correct mainline for merges between feature branches is error‑prone, making a pure revert approach impractical for this situation.
Reset
git reset --hard <commit_id>moves HEAD to the given commit and discards later commits from the current branch. This works on a private branch, but after resetting a feature branch it falls behind develop. Merging the reset branch back into develop then produces conflicts because the branch no longer contains the newer history. Moreover, the master (or main) branch is protected in GitLab, so a forced push ( git push --force) is prohibited. Using reflog to recover the discarded history would be cumbersome, and the team wants to keep the full commit log for future debugging.
git reset --hard <commit_id>
git push --force origin masterRebase + Revert (Upgrade Fusion)
This method combines an interactive rebase that squashes a series of commits into a single one, followed by a single revert of that squashed commit. The steps are:
Create a new branch F from master (or the current main line) and locate the commit N that marks the point to roll back to, using git log.
Run git rebase -i N. In the opened editor change the oldest commit to pick and change all newer commits to squash. This merges the later commits into the first one.
Save the file and edit the resulting commit message. Git rewrites the history, producing a new commit (e.g., commit5) that replaces the original series commit1‑commit4.
Merge the current master into branch F so that F contains the latest upstream changes. The merge succeeds because the content of commit5 is identical to the combined changes of commit1‑commit4.
Execute git revert <commit5> on branch F. This creates a single revert commit that effectively undoes the entire set of original commits.
The approach keeps a clean, linear history and leaves a clear audit trail, but it rewrites shared history, so it should only be used on branches where exclusive access can be guaranteed.
File‑Operation Method
When any history‑rewriting operation is too risky, a straightforward file‑level rollback can be performed:
Create a branch F that points to the same commit as master (i.e., git checkout -b F master).
Copy the entire project directory to a temporary location bak.
In bak, run git checkout N where N is the commit to roll back to. The working tree in bak now reflects the old state.
Copy all files from bak back into the original working directory, **excluding** the .git folder.
Stage the changes ( git add .) and commit them ( git commit -m "Rollback to N"). This produces a normal commit that records the rollback without altering the commit graph.
This technique relies on Git’s file‑change detection and leaves the original history untouched.
Summary of Techniques
Revert : Suitable when only a few non‑conflicting commits need to be undone.
Reset + force push : Works when the protected branch can be overwritten and the team wants no trace of the reverted commits in git log.
Rebase + revert : Provides a tidy, auditable rollback while preserving history, but requires exclusive access to the branch because it rewrites shared commits.
File‑operation : The safest and simplest option when history manipulation is prohibited; it creates a regular commit that represents the rollback.
Mastering these Git commands enables developers to handle complex rollback scenarios while balancing the need for history preservation against operational constraints.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
