I accidentally committed the wrong files to Git but haven't pushed 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 haven't pushed the commit to the server yet.
How do I undo those commits from the local repository?
For sake of completeness, I will give the one glaringly obvious method that was overlooked by the previous answers.
Since the commit was not pushed, the remote was unchanged, so:
This is sometimes necessary if your fancy Git client goes bye-bye (looking at you, egit).
Don't forget to re-commit your saved changes since the last push.
I have found this site which describes how to undo things that you have committed into the repository.
Some commands:
git commit --amend # Change last commit git reset HEAD~1 --soft # Undo last commit Reference: How to undo last commit in Git?
If you have Git Extensions installed you can easily undo/revert any commit (you can download Git Extensions from here).
Open Git Extensions, right click on the commit you want to revert then select "Revert commit".
A popup will be opened (see the screenshot below)
Select "Automatically create a commit" if you want to directly commit the reverted changes or if you want to manually commit the reverted changes keep the box un-selected and click on "Revert this commit" button.
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
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.
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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 HEAD:
Before reset commit we should know about HEAD... HEAD is nothing but your current state in your working directory. It is represented by a commit number.
Git commit:
Each change assigned under a commit which is represented by a unique tag. Commits can't be deleted. So if you want your last commit, you can simply dive into it using git reset.
You can dive into the last commit using two methods:
Method 1: (if you don't know the commit number, but want to move onto the very first)
git reset HEAD~1 # It will move your head to last commit Method 2: (if you know the commit you simply reset onto your known commit)
git reset 0xab3 # Commit number
Note: if you want to know a recent commit try git log -p -1
Here is the graphical representation:
Before picking specific tools (commands), please pick what you need rather than blindly running commands.
Just in case you want to edit your last commit, there is a command.
Advantage: It allows you to correct the last commit's message as well as add more changes to it.
git commit --amend Really want to undo the last commit (because of massive changes or you want to discard it all).
Advantage: The reset command will return to the one before the current revision, effectively making the last commit undone.
A. Soft Reset
Advantage: A soft flag. It guarantees the preservation of modifications made in undone revisions. The changes appear in your working copy as uncommitted local modifications once you run the command.
git reset --soft HEAD~1 B. Hard Reset
Advantage: 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 Advantage:
This command will tell Git to advance the HEAD pointer back one commit. The files' modifications won't be impacted, though. Now, if you run git status, you ought to still be able to view the local file changes.
git reset HEAD~1 Use according to your needs.
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 \
If you would like to eliminate the wrong files you should do
git reset --soft <your_last_good_commit_hash_here> Here, if you do git status, you will see the files in the staging area. You can select the wrong files and take them down from the staging area.
Like the following.
git reset wrongFile1 wrongFile2 wrongFile3
You can now just add the files that you need to push,
git add goodFile1 goodFile2
Commit them
git commit -v or git commit -am "Message"
And push
git push origin master
However, if you do not care about the changed files you can hard reset to previous good commit and push everything to the server.
By
git reset --hard <your_last_good_commit_hash_here> git push origin master
If you already published your wrong files to the server, you can use the --force flag to push to the server and edit the history.
git push --force origin master
To undo the last commit in Git but keep the changes in your working directory, you can use the following command:
git reset --soft HEAD~1 git reset: This command undoes commits.--soft: It undoes the commit but leaves the changes staged (ready for the next commit).HEAD~1: This specifies the last commit (one commit before HEAD).If you'd like the changes to stay in your working directory but not staged for commit, use:
git reset HEAD~1 git reset --mixed HEAD~1 After running any of these commands, you can:
git commit -m "new message".git reset --hard HEAD [commit] In case you want to reset and jump back to a specific commit. This is good when you want to reset 2 or more commits. You can also check and bookmark this free git cheat-sheet here: git-cheat-sheet.jrguazon.comRebasing 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.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.
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.
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 . 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.
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 undocommand to undo the most recent commit. I use it all of the time when I just committed something (and haven't pushed yet) and need to add an unstaged file or change the commit comment.git reset --mixedis the default action forgit reset, you should ponder upon the reason for this, thus you will have a clear expectation on codebase management before digging into git usage.