我已经检查了我的主分支上的先前提交(让我处于分离的HEAD状态)并修改了代码。现在我想推动这个 版本到origin / master,这样这个版本现在成为最新的提交。 在视觉上,这就是我所做的
这就是我的开始:
commits: A -> B -> C -> D (HEAD)
我git checkout
到C
:
commits: A -> B -> C (detached HEAD) -> D
修改了C
处的代码,导致C'
:
commits: A -> B -> C' (detached HEAD) -> D
然后我add
编辑了commit
我的修改。现在我想在origin / master上进行C'
最新的提交,以便它在D
之前提交:
commits: A -> B -> C'-> D -> C' (HEAD)
如果C'
之前的D
恢复为C
或保持为C'
,我并不特别在意。
我不清楚为了达到这个目的我需要发出什么命令,有人知道吗?
更新:我也不关心保留D
。因此,也许可以删除D
,这会使C'
成为最新的?
更新:我最终git rebase
提交C
,从而删除D
,然后重新添加修改以获取C'
,然后推送{{1} }}。我相信有更好的方法可以做到这一点......
答案 0 :(得分:1)
嗯,你的提交图表并不完全准确(并且可以使用一点澄清)。进入这个的原因是,当我们达到这一点时,它将有助于理解解决方案。所以:
这就是我的开始:
commits: A -> B -> C -> D (HEAD)
现在,如果你要在提交之间绘制箭头,它们应该及时指向“向后”,因为git存储父指针而不是子指针。 (我只画线而不是箭头。)
我认为master
分支(以及origin/master
参考号)位于D
。此外,由于您没有显示分离的HEAD
状态,我假设您已master
已签出。我通常会画出像
commits: A -- B -- C -- D <--(master)(origin/master)
^(HEAD)
显示引用指向的位置,并反映HEAD
是指向master
的符号引用。
我把结账给C:
所以现在我们已经
了commits: A -- B -- C -- D <--(master)(origin/master)
^(HEAD)
(这显示了以这种方式绘制HEAD
的优势;只需移动它以使其指向提交,并且我们知道我们处于分离状态。)
在C处修改代码,导致C':
这就是上面的图表变得不准确的地方。这个新提交不会像您绘制的那样替换 C
,而是C
的新子项。所以这更像是
commits: A -- B -- C -- D <--(master)(origin/master)
\
C'
^(HEAD)
(显示了绘制线而不是箭头的优点;更容易描绘不同的提交行)。但即使这样也不太正确,因为按照约定C'
将意味着“一个新的/重写的提交应用与C
的父级相同的更改适用于C
的父级”;所以我们应该把它称之为别的。
commits: A -- B -- C -- D <--(master)(origin/master)
\
E
^(HEAD)
现在我们可以解决你想要做的事情了。
现在,当你在更新中说你不关心保留D
时,你可能没有考虑到保留它的所有理由。如果你说“我真的想把D
扔出历史,这就是为什么......”这将是一回事,但如果它只是“我不关心这种或那种方式”,那么你应该考虑保留它。这就是原因:
删除D
是历史记录重写。推送分支后,在该分支上执行历史记录重写可能会导致问题,尤其是当repo与其他用户共享时。请参阅“从上游rebase恢复”下的git rebase
文档。
现在,如果你理解了这个问题 - 即如果你得到了它,你需要与拥有ref副本的任何其他人协调,并且如果没有这样做可能会导致你的重写被意外撤消 - 仍然想要丢弃D
,那么你可以这样做:
重写方法
从原始问题停止的地方开始,您将master
分支移动到新创建的提交。
git branch -f master
git checkout master
会给你
commits: A -- B -- C -- D <--(origin/master)
\
E <--(master)
^(HEAD)
(事实上,在开始时将master
重置为HEAD^
更容易,而不是检查分离的HEAD
状态;假设,这是,你知道你当时要重写一次。)
然后你可以推翻master
的重写,但你必须“强制”推动。这是你将导致上游反弹的“红旗”
git push --force-with-lease
如果其他人向origin/master
添加了更多提交,则会失败。这是因为完成重写会冒失去工作的风险,至少应采取额外措施来解决这个问题。如果您仍想覆盖该安全检查,可以说
git push -f
请注意,此方法或任何其他方法实际上都不会删除提交D
。它会从D
历史记录中删除master
,这意味着它最终可能会被gc
删除。
commits: A -- B -- C -- D
\
E <--(master)(origin/master)
^(HEAD)
无重写方法
另一方面,如果你认为重写比它的价值更麻烦,你会做这样的事情:
再次找到原始问题所在的位置,您可能希望保留所做的更改,这样您就不必重新开始。
git branch temp
git checkout master
现在还原D
git revert HEAD
产生
~D <--(master)
/ ^(HEAD)
commits: A -- B -- C -- D <--(origin/master)
\
E <--(temp)
TREE
的内容(~D
)将与C
的内容相匹配,现在您可以说
git rebase master temp
git checkout master
git merge --ff-only temp
git branch -d temp
所以我们终于有了
~D -- E' <--(master)
/ ^(HEAD)
commits: A -- B -- C -- D <--(origin/master)
\
E
最初的E
提交不再有意义; D
(~D
)的撤销以及E
(E'
)的更改都在master
上,可以正常推送。
答案 1 :(得分:0)
如果您只是想在C'
处使用修改过的代码重写git历史记录,则可以创建一个新分支:
git checkout -b <name_of_new_branch>
然后强制将您的新分支推送到遥控器:
git push origin <your_branch_name> -f