Close

Learn how to undo changes in Git using Bitbucket Cloud

Objective

Learn how to undo changes on your local machine and a Bitbucket Cloud repository while collaborating with others.

Mission Brief

Commands covered in this tutorial:

  • git revert, git reset, git log, an git status

Time

40 minutes

Audience

This tutorial assumes familiarity with git commands:git clone, git commit, git pull, and git push

Everyone makes mistakes. Not every push is perfect so this tutorial will help you use the most common git functions to undo a change or changes safely.

This tutorial assumes familiarity with the following git commands:

If you don't know those commands we can help you Learn git with Bitbucket Cloud. Then come back here and learn how to undo changes. These git commands are applicable to a windows or unix environment. This tutorial will utilize unix command line utilities when instructing file system navigation.


Undoing changes on your local machine


When the change you want to undo is on your local system and hasn't been pushed to a remote repository there are two primary ways to undo your change:

Command

Definition

git revert

Definition

An 'undo' command, though not a traditional undo operation. Instead of removing the commit, it figures out how to invert the changes in the commit, then appends a new commit with the inverse content. This prevents Git from losing history, which is important for the integrity of your revision history and for reliable collaboration.

git reset

Definition

A versatile git command undoing changes. The git reset command has a powerful set of options but we'll just be using the following reset modes for this tutorial:

  • --soft: Only resets the HEAD to the commit you select. Works basically the same as git checkout but does not create a detached head state.
  • --mixed: Resets the HEAD to the commit you select in both the history and undoes the changes in the index.
  • --hard: Resets the HEAD to the commit you select in both the history, undoes the changes in the index, and undoes the changes in your working directory. We won't be testing a hard reset for this tutorial.

For a complete description of how git reset works see git-scm.com's Git Tools - Reset Demystified.

Bitbucket logo
SEE SOLUTION

Advanced Git tutorials

Git logo
related material

Git commands

As you progress through the tutorial you'll learn several other git commands as part of learning how to undo changes, so let's get started.

Fork a repository


Let's begin by creating a unique repository with all the code from the original. This process is called “forking a repository”. Forking is an extended git process that is enabled when a shared repository is hosted with a 3rd party hosting service like Bitbucket.

1. Click or enter the following URL: https://bitbucket.org/atlassian/tutorial-documentation-tests/commits/all

2. Click the + symbol on the left sidebar, then select Fork this repository, review the dialog and click Fork repository.

3. You should be taken to the overview of the new repository.

4. Click the + symbol and select Clone this repository.

5. On your computer clone the repository.

6. Navigate to the directory containing the cloned repository.

Now that you've got a repository full of code and an existing history on your local system you're ready to begin undoing some changes.

Find changes on your local system


You'll have to be able to find and reference the change you want to undo. This can be accomplished by browsing the commit UI on Bitbucket and there are a few command line utilities that can locate a specific change.

git status


You'll have to be able to find and reference the change you want to undo. This can be accomplished by browsing the commit UI on Bitbucket and there are a few command line utilities that can locate a specific change.

$ git status
On branch main
Your branch is up-to-date with 'origin/main'.
nothing to commit, working tree clean

The output of git status here shows us that everything is up-to-date with the remote main branch and there are no pending changes are waiting to be committed. In the next example we will make some edits to the repository and examine it in a pending changes state. This means you have changes to files in the repository on your local system that you haven't prepared (or staged) to be added to the project history.

To demonstrate this next example, first open the myquote2.html file. Make some modifications to the contents of myquote2.html, save and exit the file. Let us once again execute git status to examine the repository in this state.

$ git status
On branch main
Your branch is up-to-date with 'origin/main'.
 
Changes not staged for commit:
 (use "git add <file>..." to update what will be committed)
 (use "git checkout -- <file>..." to discard changes in working directory)
 
 Modified: myquote2.html
 
no changes added to commit (use "git add" and/or "git commit -a")
--

The output here shows that the repository has pending modifications to myquote2.html. Good news! If the change you want to undo has, like the example above, not been added to the staging area yet you can just edit the file and keep going. Git only starts tracking a change when you add it to the staging area and then commit it to the project history.

Let us now “undo” the changes we have made to myquote2.html. Because this is a simplified example with minimal changes, we have two available methods for undoing the changes. If we execute git checkout myquote2.html The repository will restore myquote2.html to the previously committed version. Alternatively, we can execute git reset --hard which will revert the whole repository to the last commit.

git log


The git log command lets you list the project history, filter it, and search for specific changes. While git status lets you inspect the working directory and the staging area, git log only shows the committed history.

The same log of commited history can be found within the Bitbucket UI by accessing the “commits” view of a repository. The commits view for our demo repository can be found at: https://bitbucket.org/dans9190/tutorial-documentation-tests/commits/all. This view will have similar output to the git log command line utility. It can be used to find and identify a commit to undo.

In the following example you can see several things in the history but each change is, at it's root, a commit so that's what we'll need to find and undo.

$ git status
On branch main
Your branch is up-to-date with 'origin/main'.

nothing to commit, working tree clean

$ git log

commit 1f08a70e28d84d5034a8076db9103f22ec2e982c
Author: Daniel Stevens <dstevens@atlassian.com>
Date:   Wed Feb 7 17:06:50 2018 +0000

    Initial Bitbucket Pipelines configuration

commit 52f823ca251a132225dd1cc18ad768de8d336e84
Author: Daniel Stevens <dstevens@atlassian.com>
Date:   Fri Sep 30 15:50:58 2016 -0700

    repeated quote to show how a change moves through the process

commit 4801b87c2147dce83f1bf31acfcffa6cb1d7e0a5
Merge: 1a6a403 3b29606
Author: Dan Stevens [Atlassian] <dstevens@atlassian.com>
Date:   Fri Jul 29 18:45:34 2016 +0000

    Merged in changes (pull request #6)

    Changes

Let's look a little closer at one of the commits in the list:

commit 52f823ca251a132225dd1cc18ad768de8d336e84
Author: Daniel Stevens <dstevens@atlassian.com>
Date:   Fri Sep 30 15:50:58 2016 -0700
 
    repeated quote to show how a change moves through the process

What you can see is each commit message has four elements:

Element

Description

Commit hash

Description

An alphanumeric string (SHA-1 encoded) that identifies this specific change

Author

Description

The person who committed the change

Date

Description

The date the change was committed to the project

Commit message

Description

A text string that describes the change(s).

Best practice tip: write short descriptive commit messages and you'll help create a more harmonious working repository for everyone.

Locate a specific commit


Most likely the change you want to undo will be somewhere further back in the project history which can be quite extensive. So let's learn a couple basic operations using git log to find a specific change.

1. Go to your terminal window and navigate to the top level of your local repository using the cd (change directory) command.

$ cd ~/repos/tutorial-documentation-tests/

Enter the git log --oneline command. Adding --oneline will display each commit on a single line that allows you to see more history in your terminal.

Press the q key to exit the commit log and return to your command prompt at any time.

You should see something like the following example:

$ git log --oneline
1f08a70 (HEAD -> main, origin/main, origin/HEAD) Initial Bitbucket Pipelines configuration
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
3b29606 (origin/changes) myquote2.html edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
235b9a7 testing prs
c5826da more changes
...

2. Press the q key to return to your command prompt.

3. Locate the commit with the hash c5826da and more changes in the list the git log command produced. Someone didn't write a descriptive commit message so we'll have to figure out if that's got the changes we need.

4. Highlight and copy the commit hash c5826da from the git log result in your terminal window.

5. Type git show then paste or transcribe the commit hash you copied and press enter. You should see something like this:

$git show c5826daeb6ee3fd89e63ce35fc9f3594fe243605
commit c5826daeb6ee3fd89e63ce35fc9f3594fe243605
Author: Daniel Stevens <dstevens@atlassian.com>
Date:   Tue Sep 8 13:50:23 2015 -0700

    more changes

diff --git a/README.md b/README.md
index bdaee88..6bb2629 100644
--- a/README.md
+++ b/README.md
@@ -11,12 +11,7 @@ This README would normally document whatever steps are necessary to get your app
 ### How do I get set up? ###

 * Summary of set up
-* Configuration
-* Dependencies
-* Database configuration
-* How to run tests
-* Deployment instructions
-* more stuff and things
:

The prompt at the bottom will continue to fill in until it shows the entire change. Press q to exit to your command prompt.

Filter the git log to find a specific commit


This filter

Does this

This example command

Would result in

-

Does this

Limits the number of commits shown

This example command

git log -10

Would result in

The 10 most recent commits in the history

--after

--before

Does this

Limits the commits shown to the correlating time frame

You can also use
--after "yyyy-mm-dd" --before "yyyy-mm-dd"

This example command

git log --after 2017-07-04

Would result in

All commits after July 4, 2017

--author="name"

Does this

Lists all commits whose author matches the name

This example command

git log --author="Alana"

Would result in

All commits made by any author with Alana in the name field

--grep="message string"

Does this

Returns any commit with a commit message which matches the string you entered

This example command

git log --grep="HOT-"

Would result in

All commits with HOT- as a text string in their messages

This was a very brief look at the git log command if you like working in the command like you'll probably want to check out the advanced git log tutorial.

Undo a change with git reset


To get started let's just undo the latest commit in the history. In this case let's say you just enabled Bitbucket's CI/CD solution pipelines but realized the script isn't quite right.

1. Enter git log --oneline in your terminal window.

2. Copy the commit hash for the second commit in the log: 52f823c then press q to exit the log.

3. Enter git reset --soft 52f823c in your terminal window. The command should run in the background if successful. That's it, you've undone your first change. Now let's see the result of this action.

4. Enter git status in your terminal window and you will see the commit was undone and is now an uncommitted change. It should look something like this:

$ git status
On branch main
Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded.
  (use "git pull" to update your local branch)
 
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
 
    new file:   bitbucket-pipelines.yml

5. Enter git log --oneline in your terminal window. You should see something like this:

$ git log --oneline
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
3b29606 (origin/changes) myquote2.html edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
235b9a7 testing prs
c5826da more changes
43a87f4 remivng
d5c4c62 a few small changes
23a7476 Merged in new-feature2 (pull request #3)
5cc4e1e add a commit message
cbbb5d6 trying a thing
438f956 adding section for permissions and cleaning up some formatting
23251c1 updated snipptes.xml organization into resources. other files misc changes
3f630f8 Adding file to track changes

6. You can see the new HEAD of the branch is commit 52f823c which is exactly what you wanted.

7. Press q to exit the log. Leave your terminal open because now that you've learned how to do a simple reset, let's try something a little more complex.

Undo several changes with git reset


To get started let's just undo the latest commit in the history. In this case let's say you just enabled Bitbucket's CI/CD solution pipelines but realized the script isn't quite right.

1. Enter git log --online

2. Copy the commit hash 1a6a403 (myquote edited online with Bitbucket) which is the commit just below pull request #6 which has the changes we want to undo.

3. Enter git reset 1a6a403 in your terminal window. The output should look something like this:

$ git reset 1a6a403
Unstaged changes after reset:
M README.md
M myquote2.html

You can see that the changes are now in an uncommitted state. This means that now we've removed several changes from both the history of the project and the staging area.

4. Enter git status in your terminal window. The output should look something like this:

$ git status
On branch main
Your branch is behind 'origin/main' by 6 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)
 
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
 
    modified:   README.md
    modified:   myquote2.html
 
Untracked files:
  (use "git add <file>..." to include in what will be committed)
 
    bitbucket-pipelines.yml
 
no changes added to commit (use "git add" and/or "git commit -a")

Now you can see that the first change we undid (the bitbucket-pipelines.yml file) is now completely untracked by git. This is because invoking git reset removes the change from both the head of the branch and the tracking or index area of git. The underlying process is a bit more complex than we can cover here, you can read more in git reset.

5. Enter git log --oneline in your terminal window.

1a6a403 myquote edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
43a87f4 remivng
d5c4c62 a few small changes
23a7476 Merged in new-feature2 (pull request #3)
5cc4e1e add a commit message
cbbb5d6 trying a thing
438f956 adding section for permissions and cleaning up some formatting
23251c1 updated snipptes.xml organization into resources. other files misc changes
3f630f8 Adding file to track changes
e52470d README.md edited online with Bitbucket
e2fad94 README.md edited online with Bitbucket
592f84f Merge branch 'main' into new-feature2 Merge branch  especially if it merges an updated upstream into a topic branch.
7d0bab8 added a line
879f965 adding to the quote file
8994332 Merged in HOT-235 (pull request #2)
b4a0b43 removed sarcastic remarks because they violate policy.
b5f5199 myquote2.html created online with Bitbucket
b851618 adding my first file
5b43509 writing and using tests

The log output now shows the commit history has also been modified and begins at commit 1a6a403. For the sake of demonstration and further example, Let’s say we want to now undo the reset we just did. After further consideration, maybe we wanted to keep the contents of pull request #6.

Pushing resets to Bitbucket


Git resets are one of a few “undo” methods git offers. Resets are generally considered an ‘unsafe’ option for undoing changes. Resets are fine when working locally on isolated code but become risky when shared with team members.

In order to share a branch that has been reset with a remote team a ‘forced push’ has to be executed. A ‘forced push’ is initiated by executing git push -f. A forced push will destroy any history on the branch that was built after the point of the push.

An example of this ‘unsafe’ scenario is followed:

  • Dev A has been working on a branch developing a new feature.
  • Dev B has been working on the same branch developing a separate feature.
  • Dev B decides to reset the branch to an earlier state before both Dev A and Dev B started work.
  • Dev B then force pushes the reset branch to the remote repository.
  • Dev A pulls the branch to receive any updates. During this pull Dev A receives the forced update. This resets Dev A’s local branch back in time before any of their feature work was done and loses their commits.

Undo a git reset


So far we have been passing git commit Sha hashes to git reset. The git log output is now missing commits that we have reset. How will we get those commits back? Git never fully deletes commit unless it has become detached any pointers to it. Furthermore git stores a separate log of all ref movement called “the reflog”. We can examine the reflog by executing git reflog.

1a6a403 HEAD@{0}: reset: moving to 1a6a403
1f08a70 HEAD@{1}: reset: moving to origin/main
1f08a70 HEAD@{2}: clone: from git@bitbucket.org:dans9190/tutorial-documentation-tests.git

Your output from git reflog should be similar to the above. You can see a history of actions on the repo. The top line is a reference to the reset we did to reset pull request #6. Let us now reset the reset to restore pull request #6. The second column of this reflog output indicates a ref pointer to a modification action take on the repo. Here HEAD@{0} is a reference to the reset command we previously executed. We do not want to replay that reset command so we will restore the repo to HEAD@{1}.

$ git reset --hard HEAD@{1}
HEAD is now at 1f08a70 Initial Bitbucket Pipelines configuration

Let us now examine the repos commit history with git log --oneline:

$git log --online
1f08a70 Initial Bitbucket Pipelines configuration
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
3b29606 myquote2.html edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
235b9a7 testing prs
c5826da more changes
43a87f4 remivng
d5c4c62 a few small changes
23a7476 Merged in new-feature2 (pull request #3)
5cc4e1e add a commit message
cbbb5d6 trying a thing
438f956 adding section for permissions and cleaning up some formatting
23251c1 updated snipptes.xml organization into resources. other files misc changes
3f630f8 Adding file to track changes
e52470d README.md edited online with Bitbucket
e2fad94 README.md edited online with Bitbucket
592f84f Merge branch 'main' into new-feature2 Merge branch  especially if it merges an updated upstream into a topic branch.
7d0bab8 added a line
:

The log output now shows the commit history has also been modified and begins at commit 1a6a403. For the sake of demonstration and further example, Let’s say we want to now undo the reset we just did. After further consideration, maybe we wanted to keep the contents of pull request #6.

git revert


The previous set of examples did some serious time traveling undo operations using git reset and git reflog. Git contains another ‘undo’ utility which is often considered ‘safer’ than reseting. Reverting creates new commits which contain an inverse of the specified commits changes. These revert commits can then be safely pushed to remote repositories to share with other developers.

The following section will demonstrate git revert usage. Let us continue with our example from the previous section. To start let us examine the log and find a commit to revert.

$ git log --online
1f08a70 Initial Bitbucket Pipelines configuration
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
1f08a70 Initial Bitbucket Pipelines configuration
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
3b29606 myquote2.html edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
235b9a7 testing prs
c5826da more changes
43a87f4 remivng
d5c4c62 a few small changes
23a7476 Merged in new-feature2 (pull request #3)
5cc4e1e add a commit message
cbbb5d6 trying a thing
438f956 adding section for permissions and cleaning up some formatting
23251c1 updated snipptes.xml organization into resources. other files misc changes
3f630f8 Adding file to track changes
e52470d README.md edited online with Bitbucket
e2fad94 README.md edited online with Bitbucket
592f84f Merge branch 'main' into new-feature2 Merge branch  especially if it merges an updated upstream into a topic branch.
7d0bab8 added a line
:

For this example let’s pick the most recent commit 1f08a70 as our commit to operate on. For this scenario let's say that we want to undo the edits made in that commit. Execute:

$ git revert 1f08a70

This will kick off a git merge workflow. Git will create a new commit thats content is a reverse of the commit that was specified for the revert. Git will then open up a configured text editor to prompt for a new commit message. Reverts are considered the safer undo option because of this commit workflow. The creation of revert commits leave a clear trail in the commit history of when an undo operation was executed.

You just learned how to undo changes!


Congratulations, you’re done! Come back to this tutorial any time or head to the Undoing Changes section to go more in depth. Keep up the good work in Bitbucket!


Share this article

Recommended reading

Bookmark these resources to learn about types of DevOps teams, or for ongoing updates about DevOps at Atlassian.

Devops illustration

DevOps community

Devops illustration

Simulation workshop

Map illustration

Get started for free

Sign up for our DevOps newsletter

Thank you for signing up