How to revert a Git commit without losing changes

GitBeginner
Practice Now

Introduction

Git is a powerful version control system that allows developers to manage their codebase effectively. A common task is undoing changes. While commands like git reset can alter commit history, git revert provides a safer, non-destructive way to undo commits, especially in collaborative projects. This lab will guide you through using git revert to undo a commit and how to use its options to preserve your changes for further modification.

Inspecting the Commit History

Before we make any changes, it's essential to understand the current state of our project. The lab environment has been pre-configured with a Git repository containing a file named story.txt and a few commits. Let's inspect the commit history.

First, use the git log command with the --oneline option to get a compact view of the commit history. This command lists each commit on a single line, showing the commit hash and the commit message.

git log --oneline

You should see an output similar to this. Note that your commit hashes will be different:

c7a3e69 (HEAD -> master) Add a second, unwanted line
a9b2d5f Add the first line to the story
f3e1c8a Initial commit: Add story.txt

This log shows three commits. The most recent commit, at the top, has the message "Add a second, unwanted line". Let's pretend this commit introduced an error that we need to undo.

Let's also view the current content of the file story.txt:

cat story.txt

The output will be:

Once upon a time, in a land of code.
The hero of our story was a brave developer.
Suddenly, a wild bug appeared!

Our goal is to remove the last line, "Suddenly, a wild bug appeared!", which was added in our most recent commit.

Using git revert for a Safe Undo

The git revert command is used to create a new commit that undoes the changes from a previous commit. This is a safe method for undoing changes because it doesn't alter the project's history.

First, copy the commit hash of the commit you want to revert. From the output in the previous step, this is the commit with the message "Add a second, unwanted line".

Now, run the git revert command with that hash.

Please replace <your-commit-hash> with the actual hash from your terminal.

git revert <your-commit-hash>

After you run this command, Git will open your default text editor (nano) to allow you to edit the commit message for this new revert commit. The default message is usually sufficient.

To save and exit nano:

  1. Press Ctrl+O (Write Out) and then Enter to confirm the filename.
  2. Press Ctrl+X to exit.

Now, let's check the commit history again:

git log --oneline

You will see a new commit at the top:

e0d5f1b (HEAD -> master) Revert "Add a second, unwanted line"
c7a3e69 Add a second, unwanted line
a9b2d5f Add the first line to the story
f3e1c8a Initial commit: Add story.txt

Notice that the original "unwanted" commit is still in the history, but a new "Revert" commit has been added. This new commit reverses the changes made by the unwanted one.

Finally, check the content of story.txt to confirm the change has been undone:

cat story.txt

The output should now be:

Once upon a time, in a land of code.
The hero of our story was a brave developer.

The unwanted line has been successfully removed.

Reverting While Keeping Changes with --no-commit

Sometimes, you want to undo the changes from a commit but keep them in your working directory to modify them. For example, you might want to fix a mistake in the commit rather than discarding it entirely. The --no-commit (or -n) option is perfect for this.

First, let's reset our repository to the state before our last revert, so we can try a different approach. We will use git reset for this. This command moves the HEAD pointer, and --hard updates the files in your working directory to match.

git reset --hard HEAD~1

This command removes the "Revert" commit we just made. You can confirm this by running git log --oneline.

Now, let's revert the "unwanted" commit again, but this time using the --no-commit option. Remember to use the hash for the "Add a second, unwanted line" commit.

Please replace <your-commit-hash> with the actual hash from your terminal.

git revert --no-commit <your-commit-hash>

This time, no editor pops up. The revert is prepared, but not committed. Check the status of your repository:

git status

The output will show that story.txt is staged for commit:

On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   story.txt

The changes from the reverted commit are now in your staging area. You can now modify them. Let's replace the unwanted line with a better one. Open story.txt with nano:

nano story.txt

The file will look like it did after the revert in Step 2. Add a new, better line to the end of the file:

And they lived happily ever after.

Save and exit nano (Ctrl+O, Enter, Ctrl+X).

Now, add your changes to the staging area and commit them with a new, descriptive message:

git add story.txt
git commit -m "Replace unwanted line with a proper conclusion"

Finally, check the log and the file content to see the result:

git log --oneline
cat story.txt

The log shows your new commit, and story.txt has the corrected content. You have successfully reverted a commit while preserving and modifying its changes.

Summary

In this lab, you have learned how to safely revert a Git commit without losing your work. You practiced inspecting the commit history with git log, performing a standard git revert to create a new commit that undoes previous changes, and using the git revert --no-commit option to revert changes to your staging area, allowing you to modify them before creating a new commit. These techniques are essential for managing your project's history cleanly and safely, especially in a team environment.