Is there anyway to undo git push -f?

后端 未结 1 916
感动是毒
感动是毒 2020-12-05 15:15

If I use push -f to overlap the last commit, namely A, on remote repository, and others have pulled A before I pushed.

Anyway to undo this in case not

相关标签:
1条回答
  • 2020-12-05 15:21

    There are a few ways to find out the original HEAD before the push (ORIG_HEAD is probably not one of them):

    Terminal scrollback

    If you're lucky enough to have the terminal open still, there will be some output when the push was made that looks like this:

    ...
    To user@host:repo.git
     + abcdef0...1234567 HEAD -> branchname (forced update)
    

    Here, abcdef0 was the previous HEAD (your A) and 1234567 was what you forced it to be instead.

    git reflog

    The output of git reflog tells you the chronological history of what you did. You basically want to go back to the line in question (where you had checked out your branch before the changes) and grab the commit ID from the first column.

    The most helpful command here is git reflog show remotes/origin/branchname. This should show you your forced update (1234567) and the previous commit ID (abcdef0) as the top two lines.

    Previous reference

    A couple of commit references might be useful here:

    • @{1} (or branchname@{1}, if you are not on that branch) is the prior value of that reference. Only works if you haven't done any other commits to your local branch.
    • Similarly, remotes/origin/branchname@{1} will be the prior value of the ref on the remote. Only works if someone else hasn't pushed to the remote.

    Checking you've got the correct ID

    If you want to confirm that the ID you've grabbed from one of the above methods is correct, simply check it out:

    git checkout abcdef0
    

    and have a look around. If the git log looks familiar (I also recommend tig for browsing your repository, and you can even run tig abcdef0 to look at the log from a given commit), then you can be confident that you're resetting to the right place.

    Resetting to the previous state

    Once you have the previous commit ID, you can reset to that and force push again:

    git checkout branchname # if you're not on it already
    git reset --hard abcdef0
    git push -f
    

    or just:

    git push -f origin abcdef0:branchname
    

    This will restore the state of the branch to the state before the forced push. (Quick note: that first snippet will update your local branch as well as the remote; the second one only updates the remote.)

    What’s the impact?

    If people have pulled the branch since you force pushed, if you were to force push back to the original then they will run into problems when subsequently updating. If they've not made any commits to that branch, they can either just delete their local branch and re-checkout (after a git fetch to make sure they have up-to-date references), or the following will do the same:

    git fetch
    git checkout branchname # if you're not on it already
    git reset --hard origin/branchname
    

    If they have made local commits, then they will need to rebase those changes onto the correct history (and possibly resolve any conflicts):

    git fetch
    git checkout branchname # if you're not on it already
    git rebase --onto origin/branchname 1234567
    

    The above means "replay all commits after 1234567 (the incorrect head) on top of origin/branchname (the correct head)."

    0 讨论(0)
提交回复
热议问题