I accidentally committed the wrong files to Git, but didn't push the commit to the server yet. How do I undo those commits from the local repository?
I accidentally committed the wrong files to Git, but didn't push the commit to the server yet. How do I undo those commits from the local repository?
$ git commit -m "Something terribly misguided" # (0: Your Accident)
$ git reset HEAD~ # (1)
[ edit files as necessary ] # (2)
$ git add . # (3)
$ git commit -c ORIG_HEAD # (4)
git reset is the command responsible for the undo. It will undo your last commit while leaving your working tree (the state of your files on disk) untouched. You'll need to add them again before you can commit them again).git add anything that you want to include in your new commit.reset copied the old head to .git/ORIG_HEAD; commit with -c ORIG_HEAD will open an editor, which initially contains the log message from the old commit and allows you to edit it. If you do not need to edit the message, you could use the -C option.Alternatively, to edit the previous commit (or just its commit message), commit --amend will add changes within the current index to the previous commit.
To remove (not revert) a commit that has been pushed to the server, rewriting history with git push origin main --force[-with-lease] is necessary. It's almost always a bad idea to use --force; prefer --force-with-lease instead, and as noted in the git manual:
You should understand the implications of rewriting history if you [rewrite history] has already been published.
You can use git reflog to determine the SHA-1 for the commit to which you wish to revert. Once you have this value, use the sequence of commands as explained above.
HEAD~ is the same as HEAD~1. The article What is the HEAD in git? is helpful if you want to uncommit multiple commits.
Add/remove files to get things the way you want:
git rm classdir
git add sourcedir
Then amend the commit:
git commit --amend
The previous, erroneous commit will be edited to reflect the new index state - in other words, it'll be like you never made the mistake in the first place.
Note that you should only do this if you haven't pushed yet. If you have pushed, then you'll just have to commit a fix normally.
This will add a new commit which deletes the added files.
git rm yourfiles/*.class
git commit -a -m "deleted all class files in folder 'yourfiles'"
Or you can rewrite history to undo the last commit.
Warning: this command will permanently remove the modifications to the .java files (and any other files) that you committed -- and delete all your changes from your working directory:
git reset --hard HEAD~1
The hard reset to HEAD-1 will set your working copy to the state of the commit before your wrong commit.
I wanted to undo the latest five commits in our shared repository. I looked up the revision id that I wanted to rollback to. Then I typed in the following.
prompt> git reset --hard 5a7404742c85
HEAD is now at 5a74047 Added one more page to catalogue
prompt> git push origin master --force
Total 0 (delta 0), reused 0 (delta 0)
remote: bb/acl: neoneye is allowed. accepted payload.
To git@bitbucket.org:thecompany/prometheus.git
+ 09a6480...5a74047 master -> master (forced update)
prompt>
If you want to revert the last commit but still want to keep the changes locally that were made in the commit, use this command:
git reset HEAD~1 --mixed
Everybody comments in such a complicated manner.
If you want to remove the last commit from your branch, the simplest way to do it is:
git reset --hard HEAD~1
Now to actually push that change to get rid of your last commit, you have to
git push --force
And that's it. This will remove your last commit.
In these cases, the "reset" command is your best friend:
git reset --soft HEAD~1
Reset will rewind your current HEAD branch to the specified revision. In our example above, we'd like to return to the one before the current revision - effectively making our last commit undone.
Note the --soft flag: this makes sure that the changes in undone revisions are preserved. After running the command, you'll find the changes as uncommitted local modifications in your working copy.
If you don't want to keep these changes, simply use the --hard flag. Be sure to only do this when you're sure you don't need these changes anymore.
git reset --hard HEAD~1
Do as the following steps.
Step 1
Hit git log
From the list of log, find the last commit hash code and then enter:
Step 2
git reset <hash code>
In order to remove some files from a Git commit, use the “git reset” command with the “–soft” option and specify the commit before HEAD.
$ git reset --soft HEAD~1
When running this command, you will be presented with the files from the most recent commit (HEAD) and you will be able to commit them.
Now that your files are in the staging area, you can remove them (or unstage them) using the “git reset” command again.
$ git reset HEAD <file>
Note: this time, you are resetting from HEAD as you simply want to exclude files from your staging area
If you are simply not interested in this file any more, you can use the “git rm” command in order to delete the file from the index (also called the staging area).
$ git rm --cached <file>
When you are done with the modifications, you can simply commit your changes again with the “–amend” option.
$ git commit --amend
To verify that the files were correctly removed from the repository, you can run the “git ls-files” command and check that the file does not appear in the file (if it was a new one of course)
$ git ls-files
<file1>
<file2>
Since Git 2.23, there is a new way to remove files from commit, but you will have to make sure that you are using a Git version greater or equal than 2.23.
$ git --version
Git version 2.24.1
Note: Git 2.23 was released in August 2019 and you may not have this version already available on your computer.
To install newer versions of Git, you can check this tutorial. To remove files from commits, use the “git restore” command, specify the source using the “–source” option and the file to be removed from the repository.
For example, in order to remove the file named “myfile” from the HEAD, you would write the following command
$ git restore --source=HEAD^ --staged -- <file>
As an example, let’s pretend that you edited a file in your most recent commit on your “master” branch.
The file is correctly committed but you want to remove it from your Git repository.
To remove your file from the Git repository, you want first to restore it.
$ git restore --source=HEAD^ --staged -- newfile
$ git status
Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits)
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: newfile
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: newfile
As you can see, your file is back to the staging area.
From there, you have two choices, you can choose to edit your file in order to re-commit it again, or to simply delete it from your Git repository.
In this section, we are going to describe the steps in order to remove the file from your Git repository.
First, you need to unstage your file as you won’t be able to remove it if it is staged.
To unstage a file, use the “git reset” command and specify the HEAD as source.
$ git reset HEAD newfile
When your file is correctly unstaged, use the “git rm” command with the “–cached” option in order to remove this file from the Git index (this won’t delete the file on disk)
$ git rm --cached newfile
rm 'newfile'
Now if you check the repository status, you will be able to see that Git staged a deletion commit.
$ git status
Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits)
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
deleted: newfile
Now that your file is staged, simply use the “git commit” with the “–amend” option in order to amend the most recent commit from your repository.
`$ git commit --amend
[master 90f8bb1] Commit from HEAD
Date: Fri Dec 20 03:29:50 2019 -0500
1 file changed, 2 deletions(-)
delete mode 100644 newfile
`As you can see, this won’t create a new commit but it will essentially modify the most recent commit in order to include your changes.
In some cases, you don’t want all the files to be staged again: you only one to modify one very specific file of your repository.
In order to remove a specific file from a Git commit, use the “git reset” command with the “–soft” option, specify the commit before HEAD and the file that you want to remove.
$ git reset HEAD^ -- <file>
When you are done with the modifications, your file will be back in the staging area.
First, you can choose to remove the file from the staging area by using the “git reset” command and specify that you want to reset from the HEAD.
$ git reset HEAD <file>
Note: it does not mean that you will lose the changes on this file, just that the file will be removed from the staging area.
If you want to completely remove the file from the index, you will have to use the “git rm” command with the “–cached” option.
$ git reset HEAD <file>
In order to make sure that your file was correctly removed from the staging area, use the “git ls-files” command to list files that belong to the index.
$ git ls-files
When you are completely done with your modifications, you can amend the commit you removed the files from by using the “git commit” command with the “–amend” option.
$ git commit --amend
git reset --soft HEAD~1
Reset will rewind your current HEAD branch to the specified revision.
Note the --soft flag: this makes sure that the changes in undone revisions are preserved. After running the command, you'll find the changes as uncommitted local modifications in your working copy.
If you don't want to keep these changes, simply use the --hard flag. Be sure to only do this when you're sure you don't need these changes anymore.
git reset --hard HEAD~1
Undoing Multiple Commits
git reset --hard 0ad5a7a6
Keep in mind, however, that using the reset command undoes all commits that came after the one you returned to:
The simplest way to undo the last commit is
git reset HEAD^
This will bring the project state before you have made the commit.
Prerequisite: When a modification to an existing file in your repository is made, this change is initially considered as unstaged. In order to commit the changes, it needs to be staged which means adding it to the index using
git add. During a commit operation, the files that are staged gets added to an index.
Let's take an example:
- A - B - C (master)
HEAD points to C and the index matches C.
git reset --soft B with the intention of removing the commit C and pointing the master/HEAD to B. git status you could see the files indexed in commit C as staged. git commit at this point will create a new commit with the same changes as Cgit reset --mixed B. git add and then commit as usual.git reset --hard BHope this comparison of flags that are available to use with git reset command will help someone to use them wisely. Refer these for further details link1 & link2
OP: How do I undo the most recent local commits in Git? I accidentally committed the wrong files [as part of several commits].
There are several ways to "undo" as series of commits, depending on the outcome you're after. Considering the start case below, reset, rebase and filter-branch can all be used to rewrite your history.
How can C1 and C2 be undone to remove the tmp.log file from each commit?
In the examples below, absolute commit references are used, but it works the same way if you're more used to relative references (i.e. HEAD~2 or HEAD@{n}).
reset$ git reset --soft t56pi
With reset, a branch can be reset to a previous state, and any compounded changes be reverted to the Staging Area, from where any unwanted changes can then be discarded.
Note: As reset clusters all previous changes into the Staging Area, individual commit meta-data is lost. If this is not OK with you, chances are you're probably better off with rebase or filter-branch instead.
rebase$ git rebase --interactive t56pi
Using an interactive rebase each offending commit in the branch can be rewritten, allowing you to modify and discard unwanted changes. In the infographic above, the source tree on the right illustrates the state post rebase.
Step-by-step
t56pi)pick with edit. Save and close.HEAD, remove the unwanted files, and create brand new commits.Note: With rebase much of the commit meta data is kept, in contrast to the reset alternative above. This is most likely a preferred option, if you want to keep much of your history but only remove the unwanted files.
filter-branch$ git filter-branch --tree-filter 'rm -r ./tmp.log' t56pi..HEAD
Above command would filter out the file ./tmp.log from all commits in the desired range t56pi..HEAD (assuming our initial start case from above). See below illustration for clarity.
Similar to rebase, filter-branch can be used to wipe unwanted files from a subsection of a branch. Instead of manually editing each commit through the rebase process, filter-branch can automatically preformed the desired action on each commit.
Note: Just like rebase, filter-branch would preserve the rest of the commit meta-data, by only discarding the desired file. Notice how C1 and C2 have been rewritten, and the log-file discarded from each commit.
Just like anything related to software development, there are multiple ways to achieve the same (or similar) outcome for a give problem. You just need to pick the one most suitable for your particular case.
Do note that all three alternatives above rewrites the history completely. Unless you know exactly what you're doing and have good communication within your team - only rewrite commits that have not yet been published remotely!
Source: All examples above are borrowed from this blog.
I validate an efficient method proposed, and here is a concrete example using it:
In case you want to permanently undo/cancel your last commit (and so on, one by one, as many as you want) three steps:
1: Get the id = SHA of the commit you want to arrive on with, of course
$ git log
2: Delete your previous commit with
$ git reset --hard 'your SHA'
3: Force the new local history upon your origin GitHub with the -f option (the last commit track will be erased from the GitHub history)
$ git push origin master -f
$ git log
Last commit to cancel
commit e305d21bdcdc51d623faec631ced72645cca9131 (HEAD -> master, origin/master, origin/HEAD)
Author: Christophe <blabla@bla.com>
Date: Thu Jul 30 03:42:26 2020 +0200
U2_30 S45; updating files package.json & yarn.lock for GitHub Web Page from docs/CV_Portfolio...
Commit we want now on HEAD
commit 36212a48b0123456789e01a6c174103be9a11e61
Author: Christophe <blabla@bla.com>
Date: Thu Jul 30 02:38:01 2020 +0200
First commit, new title
$ git reset --hard 36212a4
HEAD is now at 36212a4 First commit, new title
$ git log
commit 36212a48b0123456789e01a6c174103be9a11e61 (HEAD -> master)
Author: Christophe <blabla@bla.com>
Date: Thu Jul 30 02:38:01 2020 +0200
First commit, new title
$ git status
On branch master
Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)
nothing to commit, working tree clean
$ git push origin master -f
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/ GitUser bla bla/React-Apps.git
+ e305d21...36212a4 master -> master (forced update)
$ git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
Before answering, let's add some background, explaining what this HEAD is.
First of all what is HEAD?HEAD is simply a reference to the current commit (latest) on the current branch.
There can only be a single HEAD at any given time (excluding git worktree).
The content of HEAD is stored inside .git/HEAD and it contains the 40 bytes SHA-1 of the current commit.
detached HEADIf you are not on the latest commit - meaning that HEAD is pointing to a prior commit in history it's called detached HEAD.
On the command line, it will look like this - SHA-1 instead of the branch name since the HEAD is not pointing to the tip of the current branch:
git checkoutgit checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits to go back
This will checkout the new branch pointing to the desired commit.
This command will checkout to a given commit.
At this point, you can create a branch and start to work from this point on.
# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>
# Create a new branch forked to the given commit
git checkout -b <branch name>
git reflogYou can always use the reflog as well.
git reflog will display any change which updated the HEAD and checking out the desired reflog entry will set the HEAD back to this commit.
Every time the HEAD is modified there will be a new entry in the reflog
git reflog
git checkout HEAD@{...}
This will get you back to your desired commit
git reset --hard <commit_id>"Move" your HEAD back to the desired commit.
# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32
# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
git rebase --no-autostash as well.git revert <sha-1>"Undo" the given commit or commit range.
The reset command will "undo" any changes made in the given commit.
A new commit with the undo patch will be committed while the original commit will remain in history as well.
# Add a new commit with the undo of the original one.
# The <sha-1> can be any commit(s) or commit range
git revert <sha-1>
This schema illustrates which command does what.
As you can see there, reset && checkout modify the HEAD.
git reset --soft HEAD~1
git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)Changes to be committed:
(use "git restore --staged ..." to unstage) new file: file1
git log --oneline --graph
- 90f8bb1 (HEAD -> master) Second commit \
- 7083e29 Initial repository commit \
Rebasing and dropping commits are the best when you want to keep the history clean useful when proposing patches to a public branch etc.
If you have to drop the topmost commit then the following one-liner helps
git rebase --onto HEAD~1 HEAD
But if you want to drop 1 of many commits you did say
a -> b -> c -> d -> master
and you want to drop commit 'c'
git rebase --onto b c
This will make 'b' as the new base of 'd' eliminating 'c'
What I do each time I need to undo a commit/commits are:
git reset HEAD~<n> // the number of last commits I need to undo
git status // optional. All files are now in red (unstaged).
Now, I can add & commit just the files that I need:
git add <file names> & git commit -m "message" -m "details"git checkout <filename>git push origin <branch name> -f // use -f to force the push.To undo the last local commit, without throwing away its changes, I have this handy alias in ~/.gitconfig
[alias]
undo = reset --soft HEAD^
Then I simply use git undo which is super-easy to remember.
Replace your local version, including your changes with the server version. These two lines of code will force Git to pull and overwrite local.
Open a command prompt and navigate to the Git project root. If you use Visual Studio, click on Team, Sync and click on "Open Command Prompt" (see the image) below.
Once in the Cmd prompt, go ahead with the following two instructions.
git fetch --all
Then you do
git reset --hard origin/master
This will overwrite the existing local version with the one on the Git server.
I wrote about this ages ago after having these same problems myself:
How to delete/revert a Git commit
Basically you just need to do:
git log, get the first seven characters of the SHA hash, and then do a git revert <sha> followed by git push --force.
You can also revert this by using the Git revert command as follows: git revert <sha> -m -1 and then git push.
If you simply want to trash all your local changes/commits and make your local branch look like the origin branch you started from...
git reset --hard origin/branch-name
You'll encounter this problem:
$ git reset HEAD~
fatal: ambiguous argument 'HEAD~': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
The error occurs because if the last commit is the initial commit (or no parents) of the repository, there is no HEAD~.
If you want to reset the only commit on "master" branch
$ git update-ref -d HEAD
$ git rm --cached -r .
Get last commit ID by using this command (in the log one on the top it is the latest one):
git log
Get the commit id (GUID) and run this command:
git revert <commit_id>
#1) $ git commit -m "Something terribly misguided"
#2) $ git reset HEAD~
[ edit files as necessary ]
#3) $ git add .
#4) $ git commit -c ORIG_HEAD
git revert commit
This will generate the opposite changes from the commit which you want to revert back, and then just commit that changes. I think this is the simplest way.
Generally I don't want to undo a bunch of commits, but rather edit an earlier commit to how I wish I had committed it in the first place.
I found myself fixing a past commit frequently enough that I wrote a script for it.
Here's the workflow:
git commit-edit <commit-hash>
This will drop you at the commit you want to edit.
The changes of the commit will be unstaged, ready to be staged as you wish it was the first time.
Fix and stage the commit as you wish it had been in the first place.
(You may want to use git stash save --keep-index to squirrel away any files you're not committing)
Redo the commit with --amend, eg:
git commit --amend
Complete the rebase:
git rebase --continue
Call this following git-commit-edit and put it in your $PATH:
#!/bin/bash
# Do an automatic git rebase --interactive, editing the specified commit
# Revert the index and working tree to the point before the commit was staged
# https://stackoverflow.com/a/52324605/5353461
set -euo pipefail
script_name=${0##*/}
warn () { printf '%s: %s\n' "$script_name" "$*" >&2; }
die () { warn "$@"; exit 1; }
[[ $# -ge 2 ]] && die "Expected single commit to edit. Defaults to HEAD~"
# Default to editing the parent of the most recent commit
# The most recent commit can be edited with `git commit --amend`
commit=$(git rev-parse --short "${1:-HEAD~}")
# Be able to show what commit we're editing to the user
if git config --get alias.print-commit-1 &>/dev/null; then
message=$(git print-commit-1 "$commit")
else
message=$(git log -1 --format='%h %s' "$commit")
fi
if [[ $OSTYPE =~ ^darwin ]]; then
sed_inplace=(sed -Ei "")
else
sed_inplace=(sed -Ei)
fi
export GIT_SEQUENCE_EDITOR="${sed_inplace[*]} "' "s/^pick ('"$commit"' .*)/edit \\1/"'
git rebase --quiet --interactive --autostash --autosquash "$commit"~
git reset --quiet @~ "$(git rev-parse --show-toplevel)" # Reset the cache of the toplevel directory to the previous commit
git commit --quiet --amend --no-edit --allow-empty # Commit an empty commit so that that cache diffs are un-reversed
echo
echo "Editing commit: $message" >&2
echo
$ git commit -m 'Initial commit'
$ git add forgotten_file
$ git commit --amend
It’s important to understand that when you’re amending your last commit, you’re not so much fixing it as replacing it entirely with a new, improved commit that pushes the old commit out of the way and puts the new commit in its place. Effectively, it’s as if the previous commit never happened, and it won’t show up in your repository history.
The obvious value to amending commits is to make minor improvements to your last commit, without cluttering your repository history with commit messages of the form, “Oops, forgot to add a file” or “Darn, fixing a typo in last commit”.
I usually first find the commit hash of my recent commit:
git log
It looks like this: commit {long_hash}
Copy this long_hash and reset to it (go back to same files/state it was on that commit):
git reset --hard {insert long_hash without braces}
git push --delete (branch_name) //this will be removing the public version of your branch
git push origin (branch_name) //This will add the previous version back
git reset HEAD@{n} will reset your last n actions.
For reset, for the last action, use git reset HEAD@{1}.
If the repository has been committed locally and not yet pushed to the server, another crude/layman way of solving it would be:
Firstly, run this command to reset the commit:
git reset --hard HEAD~1
Secondly, run this command to push the new commit:
git push upstream head -f
git reset --soft HEAD~1
Soft: This will remove the commit from local only and keep the changes done in files as it is.
git reset --hard HEAD~1
git push origin master
Hard: This will remove that commit from local and remote and remove changes done in files.
If you have made local commits that you don't like, and they have not been pushed yet you can reset things back to a previous good commit. It will be as if the bad commits never happened. Here's how:
In your terminal (Terminal, Git Bash, or Windows Command Prompt), navigate to the folder for your Git repo. Run git status and make sure you have a clean working tree. Each commit has a unique hash (which looks something like 2f5451f). You need to find the hash for the last good commit (the one you want to revert back to). Here are two places you can see the hash for commits: In the commit history on GitHub or Bitbucket or website. In your terminal (Terminal, Git Bash, or Windows Command Prompt) run the command git log --online Once you know the hash for the last good commit (the one you want to revert back to), run the following command (replacing 2f5451f with your commit's hash):
git reset 2f5451f
git reset --hard 2f5451f
NOTE: If you do git reset the commits will be removed, but the changes will appear as uncommitted, giving you access to the code. This is the safest option because maybe you wanted some of that code and you can now make changes and new commits that are good. Often though you'll want to undo the commits and throw away the code, which is what git reset --hard does.
You can use the git reset unwanted_file command with the file you don't want to stage. By using this command, we can move the changed file from the staging area to the working directory.
IN CASE IF YOU WANT TO REVET TO A LAST COMMIT AND REMOVE THE LOG HISTORY AS WELL
Use below command lets say you want to go to previous commit which has commitID SHA - 71e2e57458bde883a37b332035f784c6653ec509 the you can point to this commit it will not display any log message after this commit and all history will be erased after that.
git push origin +71e2e57458bde883a37b332035f784c6653ec509^:master