对于远程和本地,我都具有这样的git外观。
A---B---C---D master
现在,我希望在提交master
时恢复我的B
,但是我也不想丢失我的C
和D
提交。
是否有办法使我的git在远程和本地都看起来像这样?
C---D new branch
/
A---B master
我知道不可能回溯到上一点,也许类似的事情也可以解决这个问题:
C---D new branch
/
A---B---C---D---revertToB master
请给我一些建议。
您可以得到这个:
C--D <-- new-branch / A--B <-- master
但是要做到这一点,您必须强制all具有名为master
的分支指向现有提交D
的Git存储库,以收回其master
指向现有提交B
。这可能很困难,因为Git“喜欢” add提交,而不是“删除”它们。
要在本地获取,如果您有:
A--B--C--D <-- master (HEAD)
运行:
git branch new-branch master
git reset --hard HEAD~2
您现在拥有:
C--D <-- new-branch
/
A--B <-- master (HEAD)
本地。不幸的是,另一个位于origin
的Git存储库仍然具有its master
指向提交D
。从该其他Git存储库创建的任何克隆也具有指向提交master
的their D
。您必须使所有这些存储库都进行相同的撤消操作。如果只有一个存储库,和您有权使用git push --force
撤回它,则现在可以:
git push origin new-branch # to create new-branch on origin
git push -f origin master # to force them to retract their master
((您可能想将-u
添加到第一个git push
。]
为了获得您想要的更安全的东西-向master
添加新的提交以将其重置为提交B
时的方式-您可以使用:
git branch temp master
将其设置为可读:
A--B--C--D <-- master (HEAD), temp
然后您可以运行git revert -n HEAD~2..HEAD; git commit
或git read-tree -u HEAD~2; git commit
进行快照与E
的快照匹配的新提交B
:
A--B--C--D <-- temp
\
E <-- master (HEAD)
现有提交C-D
被卡在原处。如果希望new-branch
成为master
的后代,则现在必须创建它。请注意,如果您确定new-branch
指向现有提交D
,则可以使用名称new-branch
代替temp
,您将拥有所需的内容。但是,如果您需要一个新的提交(将其命名为F
),该提交位于E
之后且与提交D
的内容匹配,则可以立即创建新分支:
git checkout -b new-branch master
给予:
A--B--C--D <-- temp
\
E <-- master, new-branch (HEAD)
现在您可以:
E
,或git read-tree
提交D
并提交,或git cherry-pick
提交C
和D
。首先,运行git revert master
或git revert HEAD
(足够),您就可以:
A--B--C--D <-- temp
\
E <-- master
\
F <-- new-branch (HEAD)
要进行第二次,请运行git read-tree -u temp; git commit
进行新的提交F
(您需要输入新的提交消息)。
要执行第三项,请运行git cherry-pick temp~2..temp
;这将产生:
A--B--C--D <-- temp
\
E <-- master
\
C'-D' <-- new-branch (HEAD)
名称C'
和D'
分别表示它们分别是C
和D
的精选副本。 (当我们还原为E
时,我们使用git revert -n
合并了两个撤消步骤,因此E
并不完全是D
或 C
的撤消,而是两者的撤消。一次。)
现在可以安全删除名称temp
,因为我们不再需要它来方便地查找C
和D
。 (我们一直不需要它,因为无论如何我们都可以找到它们,但是为提交D
命名很方便,因此,提交C
和B
分别为temp~2
和temp~1
。 )
现在到git push --force
是安全的(并且不需要git push origin master new-branch
。
或者,您可以使名称temp
指向始终提交new-branch
,而不是创建D
。也就是说,从以下开始:
A--B--C--D <-- master (HEAD)
您可以做:
git branch new-branch master
给予:
A--B--C--D <-- master (HEAD), new-branch
然后您可以像以前一样“撤消” C-D
在master
上的提交,例如,产生:
A--B--C--D <-- new-branch
\
E <-- master (HEAD)
下一步,您可以运行:
git checkout new-branch; git merge -s ours master
使Git创建一个新的[[merge提交F
,其快照与现有提交D
的快照匹配:
A--B--C--D---F <-- new-branch
\ /
E <-- master (HEAD)
CommitF
现在是ahead of
master
一样,但是当以直线形式向后读取时,在第一个父级链接中,它永远不会访问commit E
:Git从F
走回到D
到C
等。同样,当--first-parent
或git log
从git rev-list
移回时,这是[[提供您使用F
。默认情况下,从F
返回的遍历访问both提交E
and D
(并且由于默认按提交者日期顺序进行,因此您会看到E
,我们在看到D
之前比D
做得晚。]