这是我的情况:
我正在尝试在我的最新提交之前放置先前提交的完全副本。但是,
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
。)
所以我想要的是:
sidebranch
注意:
i)sidefile.txt
创建sidefile.txt
,我恢复提交2 的所有努力最终都包含sidefile.txt
(我不想提交2的COPY 以包含file1.txt
)。我还想避免在rebase -i
中处理合并冲突。
ii)我尝试了cherry-pick
和git revert --no-commit master...HEAD~3; git add .; git commit -m 'reverting to commit 2'
,但没有成功(也许我做错了) - 我一直遇到冲突。
iii)如果我没有合并,那就像:
file1.txt
对我有用,但合并似乎会停止这条确切的线路。
iv)我花了很多时间在stackoverflow上查看很多帖子,但找不到处理这个特定场景的帖子......
(提前为长编辑道歉,但想澄清两次提交的状态)
在回答@Juan的问题时,为了说清楚,提交6包含
sidefile.txt
:
第1行提交1
第2行提交2只想要这两行 额外的工作
合并后的最后工作
file1.txt
另一个文件 - 仅限于sidebranch
另一方面,在提交2中sidefile.txt
仅包含前两行:
第1行提交1
第2行提交2只想要这两行
并且在提交2中没有 file1.txt
。
@ Juan的答案适用于还原/挑选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
(我不想要)。
在玩了“他们的”,“我们的”和其他旗帜后,the following post提供了一个解决方案:
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
方面有效,但提交历史记录包含额外的分支:
$dql = "SELECT p FROM MyBundle:Post p
WHERE p.from in
(SELECT u FROM MyBundle:User u JOIN u.friendsWithMe f where f = :user )";
$query = $em->createQuery($dql);
$query->setParameter(':user', $this->getUser());
虽然我不想要这个额外的分支...
我有一个答案,我在下面发布,并基于@ Juan的第二个解决方案。但是,该解决方案使用了几个恢复,而我真的很喜欢单行解决方案。
答案 0 :(得分:2)
首先,我运行你的脚本来生成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
但我理解正确这不是你想要的,因为repo将包含File1:
第1行提交1
第2行提交2只想要这两行 额外的工作
合并后的最后工作
和File2:
另一个文件 - 仅限于sidebranch
Git会考虑分支中包含的每一个提交,优先考虑更新的提交,但是一个樱桃选择不会“撤消”来自分支的提交,为此你需要使用revert。
第二种可能性:这很复杂,因为需要以某种方式处理冲突,这在回复事情时可能会很混乱。好吧,我在提交5中创建了一个名为“new”的新分支:
$ git checkout 93e6ede
$ git branch new
$ git checkout new
从那里我跑了:
$ git revert c1d2916
$ git revert 61f0cfe
$ git revert -m 1 93e6ede
我最终得到了以下树(注意新分支):
* 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
仅在'new'中使用File1:
第1行提交1
第2行提交2只想要这两行 然后,如果你想要提交6而不必修改历史记录,你需要在提交6之后添加你的工作,因为你可以正确处理冲突,这是最后一个:
$ git rebase f2cb927
除了处理冲突和手动选择你想要的东西外,没有其他解决方案。
第三种可能性,可能最好看到第二种是多么混乱:使用不同的分支(查看更改),说new2,checkout in commit 2.然后只需执行:
$ 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 push --force origin branchName。这样做之前在遥控器上做的任何事情都会丢失,并被推送的新数据取代。
答案 1 :(得分:2)
感谢@Juan - 他的第二个解决方案可以改写为:
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
但是,我希望有一种方法可以在一行中做到这一点......