假设我们的 commit tree 如下:
R–A–B–C–D–E–HEAD
准备工作:
rm -rf .git test.txt
touch test.txt && git init && git add .echo "R" >> test.txt && git ci -a -m "R"
echo "A" >> test.txt && git ci -a -m "A"
echo "B" >> test.txt && git ci -a -m "B"
echo "C" >> test.txt && git ci -a -m "C"
echo "D" >> test.txt && git ci -a -m "D"
echo "E" >> test.txt && git ci -a -m "E"
接下来要移除 B 跟 C 的 commit tree,变成
R–A -- D–E–HEAD
这儿有两种方法移除 B & C:
方法一:
# detach head and move to D commit
git checkout <SHA1-for-D>
# move HEAD to A, but leave the index and working tree as for D
git reset --soft <SHA1-for-A>
# Redo the D commit re-using the commit message, but now on top of A
git commit -C <SHA1-for-D>
在这儿,你可以增加,删除(某些意外提交的临时文件)然后提交。
git rebase --onto HEAD <SHA1-for-D> master
# push it
git push --force
方法二: 利用 cherry-pick
git rereset --hard <SHA1 of A>
git cherry-pick <SHA1 of D>
git cherry-pick <SHA1 of E>
中间可能出现的问题
http://rwmj.wordpress.com/2010/05/14/git-cherry-pick-wins/
If it’s unable to apply the patch directly, then you’ll see a message
like this:Automatic cherry-pick failed. After resolving the conflicts,
mark the corrected paths with 'git add <paths>' or 'git rm <paths>' and commit the result.
When commiting, use the option '-c 94e310d' to retain authorship and message.
This is fairly self-explanatory. Use “git status” to see which files
are problematic:
Edit the file to manually resolve the conflict, add the file, and then
commit with the “-c” option noted in the original message.
cherry-pick不好的地方在于,如果有D后面有多次提交的话,要多次执行该命令,而且可能有冲突需要手动解决。
这两种方法都会直接忽略 B 跟 C 的 history,,但是B 和C 所做更改依然存在,只是把
commit history移出了而已。
详细资料可以查询 git help cherry-pick 或者是 git help rebase
参考:
Git: removing selected commits from repository
http://stackoverflow.com/questions/495345/git-removing-selected-commits-from-repository
Git: how to remove file and commit from history
http://bogdan.org.ua/2009/02/13/git-how-to-remove-file-commit-from-history.html
Re: ! [rejected] master -> master (non-fast forward)
http://kerneltrap.org/mailarchive/git/2007/11/18/425729