Break a previous commit into multiple commits

前端 未结 14 2062
渐次进展
渐次进展 2020-12-20 13:09

Without creating a branch and doing a bunch of funky work on a new branch, is it possible to break a single commit into a few different commits after it\'s been committed to

14条回答
  •  自闭症患者
    2020-12-20 13:29

    Previous answers have covered the use of git rebase -i to edit the commit that you want to split, and committing it in parts.

    This works well when splitting the files into different commits, but if you want to break apart changes to the individual files, there's more you need to know.

    Having got to the commit you want to split, using rebase -i and marking it for edit, you have two options.

    1. After using git reset HEAD~, go through the patches individually using git add -p to select the ones you want in each commit

    2. Edit the working copy to remove the changes you do not want; commit that interim state; and then pull back the full commit for the next round.

    Option 2 is useful if you're splitting a large commit, as it lets you check that the interim versions build and run properly as part of the merge. This proceeds as follows.

    After using rebase -i and editing the commit, use

    git reset --soft HEAD~
    

    to undo the commit, but leave the committed files in the index. You can also do a mixed reset by omitting --soft, depending on how close to the final result your initial commit is going to be. The only difference is whether you start with all the changes staged or with them all unstaged.

    Now go in and edit the code. You can remove changes, delete added files, and do whatever you want to construct the first commit of the series you're looking for. You can also build it, run it, and confirm that you have a consistent set of source.

    Once you're happy, stage/unstage the files as needed (I like to use git gui for this), and commit the changes through the UI or the command line

    git commit
    

    That's the first commit done. Now you want to restore your working copy to the state it had after the commit you are splitting, so that you can take more of the changes for your next commit. To find the sha1 of the commit you're editing, use git status. In the first few lines of the status you'll see the rebase command that is currently executing, in which you can find the sha1 of your original commit:

    $ git status
    interactive rebase in progress; onto be83b41
    Last commands done (3 commands done):
       pick 4847406 US135756: add debugging to the file download code
       e 65dfb6a US135756: write data and download from remote
      (see more in file .git/rebase-merge/done)
    ...
    

    In this case, the commit I'm editing has sha1 65dfb6a. Knowing that, I can check out the content of that commit over my working directory using the form of git checkout which takes both a commit and a file location. Here I use . as the file location to replace the whole working copy:

    git checkout 65dfb6a .
    

    Don't miss the dot on the end!

    This will check out, and stage, the files as they were after the commit you're editing, but relative to the previous commit you made, so any changes you already committed won't be part of the commit.

    You can either go ahead now and commit it as-is to finish the split, or go around again, deleting some parts of the commit before making another interim commit.

    If you want to reuse the original commit message for one or more commits, you can use it straight from the rebase's working files:

    git commit --file .git/rebase-merge/message
    

    Finally, once you've committed all the changes,

    git rebase --continue
    

    will carry on and complete the rebase operation.

提交回复
热议问题