Undoing a git rebase

前端 未结 18 1426
孤城傲影
孤城傲影 2020-11-22 02:41

Does anybody know how to easily undo a git rebase?

The only way that comes to mind is to go at it manually:

  • git checkout the commit parent to both of t
相关标签:
18条回答
  • 2020-11-22 02:52

    If you are on a branch you can use:

    git reset --hard @{1}
    

    There is not only a reference log for HEAD (obtained by git reflog), there are also reflogs for each branch (obtained by git reflog <branch>). So, if you are on master then git reflog master will list all changes to that branch. You can refer to that changes by master@{1}, master@{2}, etc.

    git rebase will usually change HEAD multiple times but the current branch will be updated only once.

    @{1} is simply a shortcut for the current branch, so it's equal to master@{1} if you are on master.

    git reset --hard ORIG_HEAD will not work if you used git reset during an interactive rebase.

    0 讨论(0)
  • 2020-11-22 02:55

    If you don't want to do a hard reset...

    You can checkout the commit from the reflog, and then save it as a new branch:

    git reflog
    

    Find the commit just before you started rebasing. You may need to scroll further down to find it (press Enter or PageDown). Take note of the HEAD number and replace 57:

    git checkout HEAD@{57}
    

    Review the branch/commits, and if it's correct then create a new branch using this HEAD:

    git checkout -b new_branch_name
    
    0 讨论(0)
  • 2020-11-22 02:59

    If you successfully rebased against remote branch and can not git rebase --abort you still can do some tricks to save your work and don't have forced pushes. Suppose your current branch that was rebased by mistake is called your-branch and is tracking origin/your-branch

    • git branch -m your-branch-rebased # rename current branch
    • git checkout origin/your-branch # checkout to latest state that is known to origin
    • git checkout -b your-branch
    • check git log your-branch-rebased, compare to git log your-branch and define commits that are missing from your-branch
    • git cherry-pick COMMIT_HASH for every commit in your-branch-rebased
    • push your changes. Please aware that two local branches are associated with remote/your-branch and you should push only your-branch
    0 讨论(0)
  • 2020-11-22 03:02

    In case you had pushed your branch to remote repository (usually it's origin) and then you've done a succesfull rebase (without merge) (git rebase --abort gives "No rebase in progress") you can easily reset branch using command:

    git reset --hard origin/{branchName}

    Example:

    $ ~/work/projects/{ProjectName} $ git status
    On branch {branchName}
    Your branch is ahead of 'origin/{branchName}' by 135 commits.
      (use "git push" to publish your local commits)
    
    nothing to commit, working directory clean
    
    $ ~/work/projects/{ProjectName} $ git reset --hard origin/{branchName}
    HEAD is now at 6df5719 "Commit message".
    
    $ ~/work/projects/{ProjectName} $ git status
    On branch {branchName}
    Your branch is up-to-date with 'origin/{branchName}.
    
    nothing to commit, working directory clean
    
    0 讨论(0)
  • 2020-11-22 03:04

    Following the solution of @Allan and @Zearin, I wish I could simply do a comment though but I don't enough reputation, so I have used the following command:

    Instead of doing git rebase -i --abort (note the -i) I had to simply do git rebase --abort (without the -i).

    Using both -i and --abort at the same time causes Git to show me a list of usage/options.

    So my previous and current branch status with this solution is:

    matbhz@myPc /my/project/environment (branch-123|REBASE-i)
    $ git rebase --abort
    
    matbhz@myPc /my/project/environment (branch-123)
    $
    
    0 讨论(0)
  • 2020-11-22 03:05

    It annoys me to no end that none of these answers is fully automatic, despite the fact that it should be automatable (at least mostly). I created a set of aliases to try to remedy this:

    # Useful commands
    #################
    
    # Undo the last rebase
    undo-rebase = "! f() { : git reset ; PREV_COMMIT=`git x-rev-before-rebase` && git reset --merge \"$PREV_COMMIT\" \"$@\";}; f"
    
    # See what changed since the last rebase
    rdiff = "!f() { : git diff ; git diff `git x-rev-before-rebase` "$@";}; f"
    
    # Helpers
    ########
    # Get the revision before the last rebase started
    x-rev-before-rebase = !git reflog --skip=1 -1 \"`git x-start-of-rebase`\" --format=\"%gD\"
    
    # Get the revision that started the rebase
    x-start-of-rebase = reflog --grep-reflog '^rebase (start)' -1 --format="%gD"
    

    You should be able to tweak this to allow going back an arbitrary number of rebases pretty easily (juggling the args is the trickiest part), which can be useful if you do a number of rebases in quick succession and mess something up along the way.

    Caveats

    It will get confused if any commit messages begin with "rebase (start)" (please don't do this). You could make the regex more resilient to improve the situation by matching something like this for your regex:

     --grep-reflog "^rebase (start): checkout " 
    

    WARNING: not tested (regex may need adjustments)

    The reason I haven't done this is because I'm not 100% that a rebase always begins with a checkout. Can anyone confirm this?

    [If you're curious about the null (:) commands at the beginning of the function, that's a way of setting up bash completions for the aliases]

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