Git还原/切利拾取到合并之外的提交
这就是我的情况: 我正在尝试将先前提交的精确的副本放置在最近提交的副本之上。但是,Git还原/切利拾取到合并之外的提交,git,merge,revert,cherry-pick,Git,Merge,Revert,Cherry Pick,这就是我的情况: 我正在尝试将先前提交的精确的副本放置在最近提交的副本之上。但是, 我已经推到远程,所以不想简单地git重置 --硬的(或者,如果我能以某种方式将先前的提交添加回最新的提交之上,我会很乐意这样做) 在最新提交和所需提交之间,我创建并合并了一个分支,这似乎给我带来了问题/冲突(否则将进行恢复) 我尝试过的任何解决方案似乎都保留了来自另一个分支的额外更改,这是我不想要的(我希望我的副本看起来与先前提交的签出完全相同) 我知道这可能是一个简单的问题,但经过多次搜索/尝试和错误,我仍然找
git重置
--硬的
(或者,如果我能以某种方式将先前的提交添加回最新的提交之上,我会很乐意这样做)git latexdiff
来比较由合并分隔的两个版本
要重现此场景/请参见示例:
为了使此场景重现,下面的命令将创建一个名为tryrevert
的文件夹,该文件夹具有必要的结构:
mkdir tryrevert; cd tryrevert; git init; echo 'line 1 commit 1' > file1.txt; git add .; git commit -m 'commit 1'; echo 'line 2 commit 2 only want these two lines' >> file1.txt; git add .; git commit -m 'commit 2 - WANT THIS ONE'; git branch sidebranch; git checkout sidebranch; echo 'another file - only in sidebranch' > sidefile.txt; git add .; git commit -m 'commit 3 - sidebranch work'; git checkout master; echo 'extra work' >> file1.txt; git add .; git commit -m 'commit 4 - some more work on master'; git merge sidebranch -m 'commit 5 - the merge'; echo 'final work after the merge' >> file1.txt; git add .; git commit -m 'commit 6 - latest commit '
git log --graph --all --decorate --oneline
并将输出以下提交树(不包括origin/master
):
(为了清晰起见,我将侧分支
留在了它所在的位置,而不是将其移动到主分支
)
所以我想要的是:
* abcdefg (HEAD, master) COPY OF commit 6
* hijklmn COPY OF commit 2
* 7c4c7a1 (origin/master) commit 6 - latest commit
* 5b0077c commit 5 - the merge
|\
| * 20a1164 (sidebranch) commit 3 - sidebranch work
* | 3a5a24f commit 4 - some more work on master
|/
* 925228b commit 2 - WANT THIS ONE
* 52af39e commit 1
注:
i) sidebranch
创建sidefile.txt
,我在恢复到commit 2时所做的所有努力最终都包含sidefile.txt
(我不希望提交2的副本包含sidefile.txt
)。我还希望避免在file1.txt
中处理合并冲突
ii)我曾尝试过重新设置基础-I
和cherry pick
,但没有成功(也许我做得不正确)-我不断遇到冲突
iii)如果我没有合并,类似于:
git revert --no-commit master...HEAD~3; git add .; git commit -m 'reverting to commit 2'
这对我来说是可行的,但合并似乎阻止了这一行的工作
iv)我花时间查看了许多关于stackoverflow的帖子,但找不到一篇能够处理这种特定场景的帖子
编辑:
(对冗长的编辑提前表示歉意,但希望澄清两次提交的状态)
为了回答@Juan的问题,并且说清楚,commit 6包含
file1.txt
:
第1行提交1第2行提交2只需要这两行
额外工作
合并后的最后工作
sidefile.txt
另一个文件-仅在侧分支中
另一方面,在提交2中,file1.txt仅包含前两行:
第1行提交1第2行提交2只需要这两行 并且提交2中没有
侧文件.txt
@Juan下面的回答对于还原/cherry pickingfile1.txt
,效果很好,但是创建的提交仍然包含sidefile.txt
(我不想要)
在玩了“他们的”、“我们的”和其他旗帜之后,提供了一个解决方案:
git checkout master~1^1~1
git checkout -b commit2branch
git merge -s ours master -m 'revert to commit2'
git checkout master
git merge commit2branch
git branch -D commit2branch
这在使文件处于正确状态方面是有效的(correctfile1.txt
,nosidefile.txt
),但提交历史记录包含一个额外的分支:
* 4236c61 (HEAD, master) revert to commit2
|\
| * 7c4c7a1 (origin/master) commit 6 - latest commit
| * 5b0077c commit 5 - the merge
| |\
| | * 20a1164 commit 3 - sidebranch work
| |/
|/|
| * 3a5a24f commit 4 - some more work on master
|/
* 925228b commit 2 - WANT THIS ONE
* 52af39e commit 1
虽然我不想要这个额外的分支
最终编辑
我有一个答案,我已经在下面发布了,它基于@Juan的第二个解决方案。但是,该解决方案使用了多个还原,而我真的想要一个单行解决方案首先,我运行了你的脚本来生成repo,我将它发布在这里,并在答案中使用我的提交来避免复制/粘贴/更改错误:
* f2cb927 (HEAD, master) commit 6 - latest commit
* 93e6ede commit 5 - the merge
|\
| * 61f0cfe (sidebranch) commit 3 - sidebranch work
* | c1d2916 commit 4 - some more work on master
|/
* 79570e8 commit 2 - WANT THIS ONE
* 5e7f2fb commit 1
然后有不同的可能性:首先:要生成第二个图形,您可以使用两个樱桃选择,首先是提交2,然后是提交6。这会有冲突,当您执行同一分支历史记录中包含的提交时,您可能希望在发生冲突时使用它们的更改,因此假设您在
master您可能希望执行以下操作:
$ git cherry-pick --strategy=recursive -X theirs 79570e8
之后,提交6的情况也一样:
$ git cherry-pick --strategy=recursive -X theirs f2cb927
这样,您将得到您想要的图形:
* f6e3ff7 (HEAD, master) commit 6 - latest commit
* 7563975 commit 2 - WANT THIS ONE
* f2cb927 commit 6 - latest commit
* 93e6ede commit 5 - the merge
|\
| * 61f0cfe (sidebranch) commit 3 - sidebranch work
* | c1d2916 commit 4 - some more work on master
|/
* 79570e8 commit 2 - WANT THIS ONE
* 5e7f2fb commit 1
但我正确理解这不是您想要的,因为回购协议将包含文件1:
第1行提交1
第2行提交2只需要这两行
额外工作
合并后的最后工作
和文件2:
另一个文件-仅在侧分支中
Git将考虑分支中包含的每个提交,优先考虑较新的提交,但cherry pick不会“撤消”分支中的提交,为此,您需要使用revert。
第二种可能性:这是一个复杂的过程,需要以某种方式处理冲突,在恢复内容时可能会很混乱。我在commit 5中创建了一个名为“new”的新分支:
$ git checkout 93e6ede
$ git branch new
$ git checkout new
我从中得出:
$ git revert c1d2916
$ git revert 61f0cfe
$ git revert -m 1 93e6ede
最后我得到了以下树(注意新建分支):
仅在“新”文件1中具有:
第1行提交1
第2行提交2只需要这两行
然后,如果您也希望提交6而不必修改历史记录,那么您需要在提交6之后添加您的工作,这样您就可以正确处理冲突,这是最后一个冲突:
在这里,除了处理冲突和手动选择所需内容之外,并没有其他解决方案
第三种可能也是最好的看到了第二种有多混乱:使用不同的分支(要查看更改),比如new2,在commit 2中签出。然后简单地执行以下操作:
$ git cherry-pick f2cb927
在这里,您可能会遇到冲突,但它们应该很容易解决,正如您在commit 6的实际内容中所希望的那样
* 9eeac5c (HEAD, new) Revert "commit 3 - sidebranch work"
* e1f3678 Revert "commit 4 - some more work on master"
| * f6e3ff7 (master) commit 6 - latest commit
| * 7563975 commit 2 - WANT THIS ONE
| * f2cb927 commit 6 - latest commit
|/
* 93e6ede commit 5 - the merge
|\
| * 61f0cfe (sidebranch) commit 3 - sidebranch work
* | c1d2916 commit 4 - some more work on master
|/
* 79570e8 commit 2 - WANT THIS ONE
* 5e7f2fb commit 1
$ git rebase f2cb927
$ git cherry-pick f2cb927
$ git add files
$ git cherry-pick --continue
* 2ded558 (HEAD, new2) commit 6 - latest commit
| * ec8ef14 (new) Revert "commit 3 - sidebranch work"
| * 9f8bb91 Revert "commit 4 - some more work on master"
| | * f6e3ff7 (master) commit 6 - latest commit
| | * 7563975 commit 2 - WANT THIS ONE
| |/
| * f2cb927 commit 6 - latest commit
| * 93e6ede commit 5 - the merge
| |\
| | * 61f0cfe (sidebranch) commit 3 - sidebranch work
| |/
|/|
| * c1d2916 commit 4 - some more work on master
|/
* 79570e8 commit 2 - WANT THIS ONE
* 5e7f2fb commit 1
git checkout master
git revert --no-commit HEAD...HEAD~1
git revert --no-commit -m 1 HEAD~1
git revert --no-commit --strategy=recursive -X theirs HEAD~1^1
git commit -m 'COPY of commit 2 using revert'
git revert --no-commit HEAD
git commit -m 'COPY of commit 6 using revert'
* a30d0b1 (HEAD, master) COPY of commit 6 using revert
* bcbd36f COPY of commit 2 using revert
* 7c4c7a1 (origin/master) commit 6 - latest commit
* 5b0077c commit 5 - the merge
|\
| * 20a1164 commit 3 - sidebranch work
* | 3a5a24f commit 4 - some more work on master
|/
* 925228b commit 2 - WANT THIS ONE
* 52af39e commit 1