我把我的历史搞砸了,想对它做些修改。问题是,我有一个包含两个不相关更改的提交,并且这个提交被本地(非推送的)历史记录中的一些其他更改包围。
我想在推出这个提交之前拆分它,但我看到的大多数指南都与拆分最近的提交或未提交的本地更改有关。对一个在历史中隐藏了一点的提交执行此操作,而不必从那时起“重新执行”我的提交,这可行吗?
我把我的历史搞砸了,想对它做些修改。问题是,我有一个包含两个不相关更改的提交,并且这个提交被本地(非推送的)历史记录中的一些其他更改包围。
我想在推出这个提交之前拆分它,但我看到的大多数指南都与拆分最近的提交或未提交的本地更改有关。对一个在历史中隐藏了一点的提交执行此操作,而不必从那时起“重新执行”我的提交,这可行吗?
当前回答
如果你只想从一个文件中提取内容,还有一个更快的版本。它更快,因为交互式rebase实际上不再是交互式的(当然,如果您想从上次提交中提取,那么根本不需要rebase,那么它甚至更快)
Use your editor and delete the lines you want to extract from the_file. Close the_file. That's the only edition you need, all the rest is just git commands. Stage that deletion in the index: git add the_file Restore the lines you just deleted back into the file without affecting the index! git show HEAD:./the_file > the_file "SHA1" is the commit you want to extract the lines from: git commit -m 'fixup! SHA1' Create the second, brand new commit with the content to extract restored by step 3: git commit -m 'second and new commit' the_file Don't edit, don't stop/continue - just accept everything: git rebase --autosquash -i SHA1~1
当然,如果要提取的commit是最后一次提交,则会更快:
4. git commit -C HEAD --amend
5. git commit -m 'second and new commit' thefile
6. no rebase, nothing
如果你使用magit,那么第4步,第5步和第6步是一个动作:提交,立即修复
其他回答
如果你还没有推送,请使用git rebase。更好的是,使用git rebase -i来交互地移动提交。您可以将有问题的提交移到前面,然后根据需要将其拆分并将补丁移到后面(如果需要的话)。
在rebase manpage中有一个拆分提交的指南。简要总结如下:
Perform an interactive rebase including the target commit (e.g. git rebase -i <commit-to-split>^ branch) and mark it to be edited. When the rebase reaches that commit, use git reset HEAD^ to reset to before the commit, but keep your work tree intact. Incrementally add changes and commit them, making as many commits as desired. add -p can be useful to add only some of the changes in a given file. Use commit -c ORIG_HEAD if you want to re-use the original commit message for a certain commit. If you want to test what you're committing (good idea!) use git stash to hide away the part you haven't committed (or stash --keep-index before you even commit it), test, then git stash pop to return the rest to the work tree. Keep making commits until you get all modifications committed, i.e. have a clean work tree. Run git rebase --continue to proceed applying the commits after the now-split commit.
如果你只想从一个文件中提取内容,还有一个更快的版本。它更快,因为交互式rebase实际上不再是交互式的(当然,如果您想从上次提交中提取,那么根本不需要rebase,那么它甚至更快)
Use your editor and delete the lines you want to extract from the_file. Close the_file. That's the only edition you need, all the rest is just git commands. Stage that deletion in the index: git add the_file Restore the lines you just deleted back into the file without affecting the index! git show HEAD:./the_file > the_file "SHA1" is the commit you want to extract the lines from: git commit -m 'fixup! SHA1' Create the second, brand new commit with the content to extract restored by step 3: git commit -m 'second and new commit' the_file Don't edit, don't stop/continue - just accept everything: git rebase --autosquash -i SHA1~1
当然,如果要提取的commit是最后一次提交,则会更快:
4. git commit -C HEAD --amend
5. git commit -m 'second and new commit' thefile
6. no rebase, nothing
如果你使用magit,那么第4步,第5步和第6步是一个动作:提交,立即修复
拆分一个<commit>的提交,并在此之前添加新的提交,并保存<commit>的作者日期,-步骤如下:
Edit the commit before <commit> git rebase -i <commit>^^ NB: perhaps it will be also needed to edit <commit> as well. Cherry pick <commit> into the index git cherry-pick -n <commit> Interactively reset unneeded changes from the index and reset the working tree git reset -p && git checkout-index -f -a As alternative, just stash unneeded changes interactively: git stash push -p -m "tmp other changes" Make other changes (if any) and create the new commit git commit -m "upd something" . Optionally, repeat the items 2-4 to add more intermediate commits. Continue rebasing git rebase --continue
在某些情况下,手动纠正历史也可以。
我更喜欢使用我的git GUI(而不是命令行),我有问题的提交只提交了3次,我还没有推送任何文件,下面的文件也不完全整洁,所以我选择通过精选完全重建所有文件,这比通过命令行使用交互式rebase编辑更快,但方法相似。
下面是我如何在我最喜欢的git GUI(我个人使用SourceTree)中做到这一点:
Create a tag on the current state so that it isn't lost. Now move your actual local branch pointer to the messy commit. Reset (mixed) to the previous one, so that the files from the commit in (2) are kept. You can now split the commit in two or more by staging files that are needed and commiting with the correct message, until there's no unstaged files left. Cherry pick the next commit in line (from the history you've tagged). You do this by right clicking the desired commit and choosing "cherry pick". Goto (4), do until no more unaccounted commits left. Don't worry if as a result you have some commits that would be best squashed into one. You can squash them with an optional interactive rebase in GUI. It's as simple right-clicking the commit before the mess & clicking "Interactive rebase" then dragging commits onto each other to squash (fix the commit message to keep it simple), or move them up or down as desired. Remove the tag created in (1).