【发布时间】:2016-01-08 23:41:09
【问题描述】:
这是我的情况:
我正在尝试在我最近的提交之上放置一个较早提交的精确副本。不过,
- 我已经推送到远程,所以不想简单地
git reset --hard(或者,如果我能以某种方式将较早的提交添加回最新提交的顶部,我很乐意这样做) - 在我的最新提交和所需提交之间,我创建并合并了一个分支,这似乎给我带来了问题/冲突(否则会进行还原)
- 我尝试过的任何解决方案似乎都保留了来自其他分支的额外更改,这是我不想要的(我希望我的副本看起来与之前提交的签出完全一样)
我知道这可能是一个简单的问题,但经过多次搜索/反复试验,我仍然找不到解决方案。任何帮助将不胜感激。
如果您想知道我为什么要做这样的事情,最初的动机是为了方便地使用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):
* 7c4c7a1 (HEAD, origin/master, 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
(为了清楚起见,我将 sidebranch 留在原处,而不是将其移至 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(我不希望 COPY of commit 2 包含sidefile.txt)。我还想避免在file1.txt 中处理合并冲突。
ii) 我尝试了rebase -i 和cherry-pick,但没有成功(也许我做错了) - 我一直遇到冲突。
iii) 如果我没有合并,类似于:
git revert --no-commit master...HEAD~3; git add .; git commit -m 'reverting to commit 2'
对我有用,但合并似乎阻止了这条确切的行。
iv) 我在 stackoverflow 上查看了很多帖子,但找不到处理这种特定场景的帖子...
编辑:
(提前为长时间的编辑道歉,但想澄清两次提交的状态)
为了回答@Juan 的问题,为了清楚起见,提交 6 包含
file1.txt:
第 1 行提交 1
第 2 行提交 2 只想要这两行
额外的工作
合并后的最后工作
sidefile.txt
另一个文件 - 仅在侧分支中
另一方面,在提交 2 中,file1.txt 仅包含前两行:
第 1 行提交 1
line 2 commit 2 只想要这两行
在提交 2 中没有sidefile.txt。
@Juan 下面的回答非常适合恢复/采摘file1.txt,但创建的提交仍然包含sidefile.txt(我不想要)。
在玩弄了“他们的”、“我们的”和其他标志之后,the following post 提供了一个解决方案:
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
在使文件处于正确状态方面有效(正确的file1.txt,没有sidefile.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 的第二个解决方案。但是,该解决方案使用了多个还原,而 我真的想要一个单行解决方案。
【问题讨论】:
标签: git merge revert cherry-pick