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.

  1. First, find the commit hash of the bug fix commit using git log:
    git log
  2. Then, use git revert to undo the commit:
    git revert <bug-fix-commit-hash>
  3. 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.

  1. 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.
  2. Open the conflicting file(s) in your editor. The conflicting sections will be marked with <<<<<<<, =======, and >>>>>>>.
  3. Resolve the conflicts by choosing which changes to keep or by merging the changes manually.
  4. After resolving the conflicts, stage the resolved file(s):
    git add <file-name>
  5. Continue the revert process:
    git revert --continue
  6. 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.

<<<<<<< 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.