2010-10-06 72 views
2

反正有没有删除一个分支几个连续提交?修剪几个连续提交

让我们说,历史是这样的:

     A -> B -> C -> D 

现在,我想删除B,C所带来的变化,所以历史上的样子:

      A -> D 

例如,典型的情况是,在提交B和C致力于垃圾醉酒开发商,而在D.

写的好东西,我想出了一个相当差的(也可能不是非常可靠的方法要做到这一点):

# Get a patch for the good things 
# Context lines are set to zero so applying 
# the patch won't choke because of missing lines 
# that were added by C or D 
git format-patch --stdout -U0 revC..revD > CtoD 

# Go back in time to last good revision before mayhem 
git reset --hard revA 

# Apply good things at this point 
git apply --stat CtoD 
git apply --check CtoD 
git apply CtoD 

# Add new files from patch 
git add <any files that were created in CtoD patch> 

# And commit 
git commit -a -m "Removed B and C commits. Drunk dev fired" 

这样做并不完美。删除背景的差异可能会做出许多情况下混帐申请扼流圈和文件必须由手工混帐add'ed。 我也可能错过了这一点完全在这里...

有人能指出我这样做的正确方法?

感谢您的阅读!


编辑:

我忘了说了,我要所有这些东西推送到远程仓库,所以我尝试RAFL建议,虽然它在克隆好吧,这是不可能的正确地将东西推到原点。

这里是什么已经做了详细的(长,对不起!)名单:

## 
# Create test environment 
## 
# all will happen below 'testing', so the mess can easily be wiped out 
mkdir testing 
cd testing 

# Create 'origin' (sandbox_project) and the working clone (work) 
mkdir sandbox_project work 

# Create origin repos 
cd sandbox_project 
git init --bare 

# Clone it 
cd ../work 
git clone ../sandbox_project 
cd sandbox_project 

# Create a few files : 
# at each rev (A, B, C, D) we respectively create a fileA .. fileD 
# at each rev, we also add a line to fileA 

echo "This file was created in A" > fileA 
git add . 
git commit -a -m 'First revision' 
git tag "revA" 

for i in B C D; do 
    echo "This file was created in $i" >> file$i 
    echo "This change was done in $i" >> fileA 
    git add file$i 
    git commit -a -m "revision $i" 
    git tag "rev$i" 
done 

# We push changes to origin 
git push origin master 

现在,它看起来像这样:

$ git log --graph --decorate --pretty=oneline --abbrev-commit 

* e3dc9b7 (HEAD, revD, origin/master, master) revision D 
* e21fd6a (revC) revision C 
* a9192ec (revB) revision B 
* a16c9dd (revA) First revision 

我想删除什么了在B和C介绍:

$ git rebase -i HEAD~3 

Automatic cherry-pick failed. After resolving the conflicts, 
mark the corrected paths with 'git add <paths>', and 
run 'git rebase --continue' 
Could not apply e3dc9b7... revision D 

$ git status 

# Not currently on any branch. 
# Changes to be committed: 
# (use "git reset HEAD <file>..." to unstage) 
# 
# new file: fileD 
# 
# Unmerged paths: 
# (use "git reset HEAD <file>..." to unstage) 
# (use "git add/rm <file>..." as appropriate to mark resolution) 
# 
# both modified:  fileA 
# 

当然,存在具有的fileA的问题(问题我通过施加与我的解决办法来解决用-U0生成的diff。 在这里,我编辑的fileA,删除冲突的线,并继续底垫:

This file was created in A 
<<<<<<< HEAD 
======= 
This change was done in B 
This change was done in C 
This change was done in D 
>>>>>>> e3dc9b7... revision D 

被编辑成:

This file was created in A 
This change was done in D 

然后:

$ git add fileA 
$ git rebase --continue 

# leave mesasge as-is 

[detached HEAD e2d4032] revision D 
2 files changed, 2 insertions(+), 0 deletions(-) 
create mode 100644 fileD 
Successfully rebased and updated refs/heads/master. 

$ git push 

To ../sandbox_project 
! [rejected]  master -> master (non-fast-forward) 
error: failed to push some refs to '../sandbox_project' 
To prevent you from losing history, non-fast-forward updates were rejected 
Merge the remote changes before pushing again. See the 'Note about 
fast-forwards' section of 'git push --help' for details. 

嗯,这看起来正常我,因为我重订基期,所以我尝试:

$ git pull 
Auto-merging fileA 
CONFLICT (content): Merge conflict in fileA 
Automatic merge failed; fix conflicts and then commit the result. 

$ git log --graph --decorate --pretty=oneline --abbrev-commit 

* e2d4032 (HEAD, master) revision D 
* a16c9dd (revA) First revision 

再次,fileA不能合并,因为它有修订B和C cruft。在这里,我们再次去编辑fileA,并删除由C和C引入的更改。

然后:

$ git add fileA 
$ git commit -a 
[master b592261] Merge branch 'master' of ../sandbox_project 
$ git push 
Counting objects: 9, done. 
Compressing objects: 100% (5/5), done. 
Unpacking objects: 100% (5/5), done. 
Writing objects: 100% (5/5), 674 bytes, done. 
Total 5 (delta 0), reused 0 (delta 0) 
To ../sandbox_project 
    e3dc9b7..b592261 master -> master 

看起来不错,但:

$ git log --graph --decorate --pretty=oneline --abbrev-commit 

* b592261 (HEAD, origin/master, master) Merge branch 'master' of ../sandbox_project 
|\ 
| * e3dc9b7 (revD) revision D 
| * e21fd6a (revC) revision C 
| * a9192ec (revB) revision B 
* | e2d4032 revision D 
|/ 
* a16c9dd (revA) First revision 

虽然在最后,的fileA是好的,我仍然有FILEB和fileC我不想。在过程中,我必须解决两次fileA的合并冲突。

任何线索?

回答

4

我会用git rebase -i HEAD~4

这会产生一个文件,其中包含HEAD~4HEAD之间的每个提交一行的文件$EDITOR。删除您要扔掉,保存并退出编辑器中提交的线条,和git将只适用于你的HEAD~4顶部的文件中留下的提交。

然而,由于这实际上重写你的历史,它往往无法推动任何地方的结果,而不拧紧所有其他波普也工作过该资源库的。

作为替代方案,你可以做你会用几乎做所有其他版本控制系统,以及:恢复坏的提交。

$ git revert $commit_sha 

这将创建一个新的提交,反向应用$commit_sha的差异。

+0

感谢RAFL你的答案。虽然这对克隆工作正常,但我无法将更改推送给原始主数据。我很抱歉没有提到我必须将这些更改推送到远程存储库,对此抱歉。我编辑我的问题更清楚。谢谢 ! – leucos 2010-10-06 10:38:52

+0

推进,这将是一个非快进,你已经改写历史公布。你可以强迫推,也可以采用不同的方式,因为我会在一秒之内回答我的答案。你应该阅读一般重写历史和非快进的内容。 – rafl 2010-10-06 10:42:43

+0

谢谢拉夫,这是诀窍。恢复这两个提交,沿着解决方案编辑fileA做我想要的。我需要确认! – leucos 2010-10-06 14:33:34