Reordering of commits

前端 未结 5 753
旧巷少年郎
旧巷少年郎 2020-11-28 02:33

I\'m currently working on a branch and want some commits to merge into other branches:

    a-b-c-d-e-f-g (branchA)
   /
--o-x-x-x-x-x-x-x-x-x-x (master)
   \         


        
相关标签:
5条回答
  • 2020-11-28 03:14

    git rebase --interactive is the command you want.

    Example:

    The current status is this:

    bernt@le3180:~/src/stackoverflow/reordering_of_commits
    $ git status
    On branch master
    nothing to commit, working tree clean
    bernt@le3180:~/src/stackoverflow/reordering_of_commits
    $ git log --oneline
    a6e3c6a (HEAD -> master) Fourth commit
    9a24b81 Third commit
    7bdfb68 Second commit
    186d1e0 First commit
    

    I want to reorder commits 9a24b81 (Third commit) and 7bdfb68 (Second commit). To do this, I first find the commit before the first commit we want to change. This is commit 186d1e0 (First commit).

    The command to execute is git rebase --interactive COMMIT-BEFORE-FIRST-COMMIT-WE-WANT-TO-CHANGE, in this case:

    bernt@le3180:~/src/stackoverflow/reordering_of_commits
    $ git rebase --interactive 186d1e0
    

    This opens up a file in the default editor with the following contents:

    pick 7bdfb68 Second commit
    pick 9a24b81 Third commit
    pick a6e3c6a Fourth commit
    
    # Rebase 186d1e0..a6e3c6a onto 186d1e0 (3 commands)
    #
    # Commands:
    # p, pick = use commit
    # r, reword = use commit, but edit the commit message
    # e, edit = use commit, but stop for amending
    # s, squash = use commit, but meld into previous commit
    # f, fixup = like "squash", but discard this commit's log message
    # x, exec = run command (the rest of the line) using shell
    # d, drop = remove commit
    #
    # These lines can be re-ordered; they are executed from top to bottom.
    #
    # If you remove a line here THAT COMMIT WILL BE LOST.
    #
    

    Note that the ordering of commits in the file is opposite the one used for git log. In git log, the most recent commit is at the top. In this file, the most recent commit is at the bottom.

    As the comment at the bottom of the file explains there are various things I can do, like squashing, dropping and reordering commits. To re-order commits, I edit the file so it looks like this (the bottom comments not displayed):

    pick 9a24b81 Third commit
    pick 7bdfb68 Second commit
    pick a6e3c6a Fourth commit
    

    The pick command at the start of each line means "use (i.e. include) this commit" and when I save the temp file with the rebase commands and exit the editor, git will execute the commands and update the repository and working directory:

    $ git rebase --interactive 186d1e0
    Successfully rebased and updated refs/heads/master.
    bernt@le3180:~/src/stackoverflow/reordering_of_commits
    $ git log --oneline
    ba48fc9 (HEAD -> master) Fourth commit
    119639c Second commit
    9716581 Third commit
    186d1e0 First commit
    

    Note the rewritten commit history.

    Links:

    • http://www.google.com/search?q=git+rebase+interactive
    0 讨论(0)
  • 2020-11-28 03:16
    git rebase -i HEAD~3
    

    Where 3 is the number of commits that need reordering (source).

    This will open vi, listing commits from oldest (top) to newest (bottom).
    Now reorder the lines, save, and exit the editor.

    ddp will move current line down
    ddkP will move current line up (source)

    0 讨论(0)
  • 2020-11-28 03:24

    git rebase is what you want. Check out the --interactive option.

    0 讨论(0)
  • 2020-11-28 03:26

    If you want to reorder only last two commits, you can you this git reorder alias: https://stackoverflow.com/a/33388211/338581

    0 讨论(0)
  • 2020-11-28 03:37

    The command you're looking for is git rebase, specifically the -i/--interactive option.

    I'm going to assume you want to leave commit c on branch A, and that you really do mean you want to move the other commits to the other branches, rather than merging, since merges are straightforward. Let's start by manipulating branch A.

    git rebase -i <SHA1 of commit a>^ branchA
    

    The ^ means the previous commit, so this command says to rebase branch A using the commit before "a" as the base. Git will present you with a list of the commits in this range. Reorder them and tell git to squash the appropriate ones:

    pick c ...
    pick a ...
    squash d ...
    squash e ...
    squash g ...
    pick b
    squash f
    

    Now the history should look like this:

        c - [a+d+e+g] - [b+f] (branchA)
       /
    --o-x-x-x-x-x-x-x-x-x-x (master)
    

    Now, let's grab the newly-squashed commit b+f for branchB.

    git checkout branchB
    git cherry-pick branchA  # cherry-pick one commit, the tip of branchA
    

    And the same for a+d+e+g for master:

    git checkout master
    git cherry-pick branchA^
    

    Finally, update branchA so it points to c:

    git branch -f branchA branchA^^
    

    We should now have:

        c (branch A) - [a+d+e+g] - [b+f] (dangling commits)
       /
    --o-x-x-x-x-x-x-x-x-x-x-[a+d+e+g] (master)
       \
        x-x-x-x-x-[b+f] (branchB)
    

    Note that if you had multiple commits you wanted to move between branches, you could use rebase again (non-interactively):

    # create a temporary branch
    git branch fromAtoB branchA
    # move branchA back two commits
    git branch -f branchA branchA~2
    # rebase those two commits onto branchB
    git rebase --onto branchB branchA fromAtoB
    # merge (fast-forward) these into branchB
    git checkout branchB
    git merge fromAtoB
    # clean up
    git branch -d fromAtoB
    

    Finally, a disclaimer: It's quite possible to reorder commits in such a way that some no longer apply cleanly. This could be because you chose a bad order (putting a patch before the commit introducing the feature it patched); in that case you'll want to abort the rebase (git rebase --abort). Otherwise, you'll have to intelligently fix the conflicts (just as you do with merge conflicts), add the fixes, then run git rebase --continue to move on. These instructions are also provided by the error message printed when the conflict occurs.

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