Log In

Protecting Shared History When Undoing Git Changes

Teams that share repositories need reliable ways to correct mistakes without breaking the commit history others depend on. Git provides restore, revert, and reset for different situations. Choosing the wrong one on a public branch can force teammates to resolve confusing conflicts or lose work. The key distinction is whether an operation rewrites existing commits or adds new ones that everyone can pull safely. Revert always adds a new commit that undoes the target, preserving the original record. Reset moves the branch pointer and can discard commits entirely. Restore updates files in the working tree or index without touching history. Understanding these effects on the three Git trees—working directory, index, and commit history—helps you pick the command that matches the scope of your change and the visibility of your branch.

How the three commands affect repository state

Git tracks three separate areas: the working directory that holds your files, the index that stages changes for the next commit, and the commit history that records snapshots. Each undo command touches these areas differently. Revert operates only at the commit level by creating an inverse patch and recording it as a new commit. It never alters the working directory or index unless you have uncommitted changes that conflict. Reset can update all three areas depending on the mode you choose. The default mixed mode updates the index to match the target commit while leaving the working directory untouched. Hard mode overwrites both the index and working directory. Restore focuses on paths rather than commits and pulls content from a source commit or the index into the working tree or staging area.

Quick rule Use revert on any branch that has been pushed and shared. Reserve reset and restore for branches that only you have cloned.

Safe undo on branches others have cloned

Once a branch is pushed and teammates have fetched it, any command that rewrites commits creates divergent histories. Revert is the standard tool for these situations because it adds a new commit that everyone can merge or pull without force-pushing. The command inspects the patch introduced by the target commit and records the opposite changes. You can revert a single commit or a range, and Git will create one new commit per reverted commit by default. After the revert commit is pushed, the original faulty commit remains visible in the log, which helps future debugging and code review.

Always run git status first to confirm the working tree is clean. If uncommitted changes exist, stash or commit them before reverting. Revert will prompt you to resolve conflicts if the inverse patch overlaps with later work. The resulting commit message starts with Revert and includes the original commit subject, making the intent clear in the history.

Using reset on private branches only

Reset is appropriate when you have not yet shared the commits you want to discard. It moves the current branch pointer to a different commit and optionally updates the index and working tree. Because it removes commits from the visible history, teammates who have already fetched those commits will encounter errors on their next pull. The safest practice is to run reset only on local feature branches that you created and have not pushed, or on branches you are willing to force-push after coordinating with the team.

Choose the mode carefully. Soft mode is useful when you want to combine several small commits into one larger commit. Mixed mode, the default, unstages changes so you can edit them before committing again. Hard mode is the most destructive because it permanently discards uncommitted work in the working directory. Before using hard mode, consider whether git stash or git checkout would preserve the changes instead.

Restoring files without moving history

Restore is the right choice when you need to recover the contents of specific files rather than entire commits. It can pull a file from HEAD, from the index, or from any other commit. Because it does not change which commit HEAD points to, it is safe on both private and shared branches. The command is especially helpful after you have accidentally edited a file or when you want to unstage a single file without affecting other staged changes.

By default, restore pulls from the index into the working tree. Adding the --staged flag restores the index from HEAD. You can combine both flags to restore a file completely to the state recorded in HEAD. When you need content from an older commit, supply the --source option followed by a commit reference.

Practical decision checklist

Before running any undo command, answer three questions: Has the commit been pushed? Do you need to change history or only files? Are other people depending on the current state? If the answer to the first question is yes, reach for revert. If the branch is private and you want to discard commits, reset is acceptable. If you only need to fix file contents, restore is usually sufficient. After any operation that changes history, run git status and git log to verify the result before pushing.

Sources

See our free AI tools →