Git Revert and Reset
Understand how to revert (undo) changes made in commits using 'git revert'. Learn the different types of reset (soft, mixed, hard) and their effects using 'git reset'.
Git Revert - Practical Examples
This guide demonstrates practical scenarios of using git revert
to undo specific commits in Git. Unlike git reset
, git revert
creates a new commit that undoes the changes made by a specified commit. This preserves your Git history and is generally safer, especially in collaborative environments.
Understanding Git Revert
git revert
creates a new commit that contains the inverse changes of the commit you're reverting. It essentially "undoes" the effects of the original commit without altering the original commit itself. This is a non-destructive operation that maintains your project's history. This makes it ideal when working with others, as it avoids rewriting shared history.
Basic Usage
The basic syntax for reverting a commit is:
git revert <commit-hash>
Replace <commit-hash>
with the SHA-1 hash of the commit you want to revert. You can find the commit hash using git log
.
Example: Reverting the last commit
git revert HEAD
This command will revert the most recent commit on your current branch. Git will then open your configured text editor, allowing you to edit the commit message for the revert commit. You can accept the default message or provide a more descriptive one.
Practical Scenarios
Scenario 1: Undoing a Bug Fix That Introduced a New Bug
Let's say you made a commit that was intended to fix a bug, but it inadvertently introduced a new, more severe bug. You want to remove the original fix without losing the changes made in other commits.
- First, find the commit hash of the bug fix commit using
git log
:git log
- Then, use
git revert
to undo the commit:git revert <bug-fix-commit-hash>
- Git will create a new commit that reverses the changes introduced by the bug fix. Review the changes in your working directory and commit the revert.
Scenario 2: Reverting a Merge Commit
Reverting a merge commit requires specifying the parent number to use as the mainline. The mainline is the branch that was merged into the current branch. If you do not specify the mainline, git will not know which side of the merge to keep and may not be able to automatically revert the commit.
To identify the parents of a merge commit, use git log --graph
.
git log --graph --oneline
The output will show the merge commit and its parent commits. The first parent is usually the branch you were on when you performed the merge. The second (and subsequent) parents are the branches that were merged in.
To revert a merge commit, use the -m
or --mainline
option followed by the parent number.
git revert -m 1 <merge-commit-hash>
In this example, -m 1
specifies that the first parent is the mainline. If you need to use the second parent as the mainline, use -m 2
, and so on. Choosing the wrong parent can corrupt the history, so make sure to specify the correct parent number.
Scenario 3: Reverting Multiple Commits
You can revert a range of commits. This is useful when you need to undo a series of changes. There are a couple ways to revert a range of commits.
Method 1: Reverting a Range with a Single Command (Creates a Revert Commit for Each)
This method creates a separate revert commit for each commit in the range. The syntax is:
git revert <start-commit-hash>..<end-commit-hash>
This will revert all commits from <start-commit-hash>
up to and including <end-commit-hash>
, in reverse order. Git will open your editor for each revert commit.
Method 2: Reverting a Range Interactively (Creates a Single Revert Commit)
This method allows you to revert a range of commits as a single atomic revert commit. You'll need to use the --no-commit
option, which prevents git from immediately creating commits. Then, commit the changes manually.
git revert --no-commit <start-commit-hash>..<end-commit-hash>
After running this command, the changes will be staged in your working directory. You can then review the changes and commit them with a single commit message:
git commit -m "Reverted range of commits"
Handling Conflicts
Sometimes, reverting a commit can lead to conflicts. This happens when the changes introduced by the revert conflict with changes made in subsequent commits. Git will halt the revert process and mark the conflicting files.
- When a conflict occurs, Git will output a message similar to this:
CONFLICT (content): Merge conflict in <file-name> Automatic revert failed; fix conflicts and then commit the result.
- Open the conflicting file(s) in your editor. The conflicting sections will be marked with
<<<<<<<
,=======
, and>>>>>>>
. - Resolve the conflicts by choosing which changes to keep or by merging the changes manually.
- After resolving the conflicts, stage the resolved file(s):
git add <file-name>
- Continue the revert process:
git revert --continue
- If you want to abort the revert, you can use:
git revert --abort
Example of a Conflict
Let's say you have the following content in my_file.txt
:
This is the original line.
This line was added in commit A.
This line was added in commit B.
You revert commit A. If commit B also modified the line added in commit A, you'll encounter a conflict. The conflicting file would look like this:
<<<<<<< HEAD
This is the original line.
This line was added in commit B.
=======
This is the original line.
>>>>>>> Revert "Add line A"
You need to manually edit the file to resolve the conflict. For example, you might choose to keep the changes from commit B:
This is the original line.
This line was added in commit B.
Then, stage the resolved file and continue the revert.
Best Practices
- Understand the Impact: Before reverting, carefully consider the impact on other developers working on the same branch.
- Communicate: If you're working in a team, communicate your intention to revert a commit, especially if it's a shared branch.
- Test Thoroughly: After reverting, test your application to ensure that the changes were successfully reverted and that no new issues were introduced.
- Prefer Revert over Reset in Shared Branches: Avoid using
git reset
on shared branches, as it rewrites history and can cause problems for other developers.git revert
is a safer alternative.
Conclusion
git revert
is a powerful tool for undoing changes in Git while preserving your project's history. By understanding the different scenarios and how to handle conflicts, you can use git revert
effectively to manage your codebase and collaborate with others.