Due to some bad cherry-picking, my local Git repository is currently five commits ahead of the origin, and not in a good state. I want to get rid of all these commits and start over again.
Obviously, deleting my working directory and re-cloning would do it, but downloading everything from GitHub again seems like overkill, and not a good use of my time.
Maybe git revert
is what I need, but I don't want to end up 10 commits ahead of the origin (or even six), even if it does get the code itself back to the right state. I just want to pretend the last half-hour never happened.
Is there a simple command that will do this? It seems like an obvious use case, but I'm not finding any examples of it.
Note that this question is specifically about commits, not about:
- untracked files
- unstaged changes
- 开发者_Python百科staged, but uncommitted changes
If your excess commits are only visible to you, you can just do
git reset --hard origin/<branch_name>
to move back to where the origin is. This will reset the state of the repository to the previous commit, and it will discard all local changes.
Doing a git revert
makes new commits to remove old commits in a way that keeps everyone's history sane.
Delete the most recent commit, without destroying the work you've done:
git reset --soft HEAD~1
Delete the most recent commit and remove changes:
git reset --hard HEAD~1
Simply delete your local master branch and recreate it like so:
git branch -D master
git checkout origin/master -b master
Try:
git reset --hard <the sha1 hash>
to reset your head to wherever you want to be. Use gitk to see which commit you want to be at. You can do reset within gitk as well.
On your branch attempt:
git reset --hard origin/<branch_name>
Validate the reversal (to the state, with no local commits), using "git log
" or "git status
" hence.
If you are using Atlassian SourceTree app, you could use the reset option in the context menu.
Simple Solution will be to match local master branch HEAD to origin/master branch HEAD
git reset --hard origin/master
PS: origin/master - is remote pointer to master branch. You can replace master with any branch name
git reset --hard @{u}
* deletes all your local changes on the current branch, including commits. I'm surprised no one has posted this yet considering you won't have to look up what commit to revert to or play with branches.
* That is, reset to the current branch at @{upstream}
—commonly origin/<branchname>
, but not always
You can use this git command
git reset --hard origin/<branch_name>
Before answering let's add some background, explaining what is this HEAD
. since some of the options below will result in detached head
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 HEAD
If you are not on the latest commit - meaning that HEAD
is pointing to a prior commit in history its 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
A few options on how to recover from a detached HEAD:
git checkout
git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back
This will checkout 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 reflog
You 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.
- Note: (Since Git 2.7)
you can also use thegit 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 the history as well.
# add 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
.
TL;DR
on your branch
git reset --hard HEAD^
will throw away the last local commit
git reset --hard HEAD~n
will throw away the last n
local commits
Use any number of times, to revert back to the last commit without deleting any files that you have recently created.
git reset --soft HEAD~1
Then use
git reset HEAD <name-of-file/files*>
to unstage, or untrack.
Remove untracked files (uncommitted local changes)
git clean -df
Permanently deleting all local commits and get latest remote commit
git reset --hard origin/<branch_name>
I had a situation where I wanted to remove a commit that wasn't pushed, but the commit was before another one. To do so, I've used the following command
git rebase -i HEAD~2
-> it will rebase the last two commits
And I used 'drop' for the commit signature that I wanted to remove.
To see/get the SHA-1 id of the commit you want to come back too
gitk --all
To roll back to that commit
git reset --hard sha1_id
!Note. All the commits that were made after that commit will be deleted (and all your modification to the project). So first better clone the project to another branch or copy to another directory.
If
Your branch is ahead of 'origin/XXX
' by 5 commits.
You can issue:
git reset --hard HEAD~5
And it should remove the last 5 commits.
For local commits which are not being pushed, you can also use git rebase -i
to delete or squash a commit.
For those interested in the Visual Studio solution, here is the drill:
- In the
Team Explorer
window, connect to the target repo. - Then from
Branches
, right-click the branch of interest and selectView history
. - Right-click a commit in the
History
window and chooseReset -> Delete changes (--hard)
.
That will throw away your local commits and reset the state of your repo to the selected commit. I.e. the changes after you pulled the repo will be lost.
UPDATE
The above procedure works fine up until VS2019; in VS2022 there is the New Git Experience. The workflow is similar but the UI is a bit different. Instead of Team Explorer
, use Manage Branches
from the Git
menu. Now just click a branch on the left and its history is displayed on the right. Then go Right Click -> Reset -> Delete Changes (--hard)
If you just want to throw away local commits and keep the modifications done in files then do
git reset @~
Other answers addressed the hard reset
Find the sha1 for the commit you want to revert to:
za$ git reflog
... snip ...
cf42fa2... HEAD@{0}: commit: fixed misc bugs
~
~
cf42fa2... HEAD@{84}: commit: fixed params for .....
73b9363... HEAD@{85}: commit: Don't symlink to themes on deployment.
547cc1b... HEAD@{86}: commit: Deploy to effectif.com web server.
1dc3298... HEAD@{87}: commit: Updated the theme.
18c3f51... HEAD@{88}: commit: Verify with Google webmaster tools.
26fbb9c... HEAD@{89}: checkout: moving to effectif
And then use --mixed flag so that you "reset HEAD and index":
za$ git reset --mixed cf42fa2
Available flags:
za$ git reset -h
-q, --quiet be quiet, only report errors
--mixed reset HEAD and index
--soft reset only HEAD
--hard reset HEAD, index and working tree
--merge reset HEAD, index and working tree
--keep reset HEAD but keep local changes
--recurse-submodules[=<reset>]
control recursive updating of submodules
-p, --patch select hunks interactively
-N, --intent-to-add
git reset --hard <SHA-Code>
This will come in handy if you have made some mistakes on your local copy that you want to make sure doesn't get pushed to your remote branch by mistake.
The SHA-Code can be obtained by looking at webVersion of your git dashboard for the last commit on the branch.
This way you can get synchronized with the last commit on the branch.
You can do git pull
after you have successfully completed the hard reset to confirm nothing new to syn i.e. you get to see the message.
Your branch is up to date with Origin/<Branch Name>
Updated:
You can use new GIT LFS here: https://git-lfs.github.com/
git lfs migrate import --include="*.file_type"
then git push
You could look at using an interactive rebase with the drop command
So for say the last three commits...
git rebase -i HEAD~3
Swap out the pick commands
pick <hash1> Commit message 1
pick <hash2> Commit message 2
pick <hash3> Commit message 3
for drop commands
drop <hash1> Commit message 1
drop <hash2> Commit message 2
drop <hash3> Commit message 3
If you get your local repo into a complete mess, then a reliable way to throw away local commits in Git is to...
- Use "git config --get remote.origin.url" to get URL of remote origin
- Rename local git folder to "my_broken_local_repo"
- Use "git clone <url_from_1>" to get fresh local copy of remote git repository
In my experience Eclipse handles the world changing around it quite well. However, you may need to select affected projects in Eclipse and clean them to force Eclipse to rebuild them. I guess other IDEs may need a forced rebuild too.
A side benefit of the above procedure is that you will find out if your project relies on local files that were not put into git. If you find you are missing files then you can copy them in from "my_broken_local_repo" and add them to git. Once you have confidence that your new local repo has everything you need then you can delete "my_broken_local_repo".
For all unstaged changes git checkout -- .
for specific file git checkout -- path/to/file/to/revert
$ git fetch origin
$ git reset --hard origin/master
This will download the latest version of the remote branch and overwrite the local branch with it, effectively discarding all local commits. Replace origin/master
with the appropriate remote branch name if necessary.
精彩评论