我不明白发生了什么。我将分支主服务器合并到我的功能分支中,这是我最近经常做的,并且不知何故合并提交现在存在于两个分支中,并且两个分支在提交之后处于相同的状态。我还没有找到关于如何发生这种情况的任何信息(或者它实际上可以完成)。我在Windows上使用git-gui(但在其他机器上使用git命令行,所以我理解基本的git命令)。 git-gui和GitLab都在历史图表中显示这个提交是将两个分支相互合并。有任何线索是怎么发生的?我不知道它会再发生什么,我应该摆脱git-gui吗?
然后,因为不幸的是这个提交被推送到远程,我仍然想要重置 - 硬,因为如果我做一个恢复,那么当我将来再次将master合并到功能中时,我会得到一切在功能分支中作为冲突,因为它在master中的revert中都被撤消了。关于如何最好地进行的任何意见或建议?
编辑:我以为我理解合并意味着什么,但从答案我现在更加困惑。如果我创建一个有很多新东西的功能分支,我想" import"在主人身上发生了一些变化,但是大师没有动过,这不是这样做的吗?
git checkout feature
git merge master
master A ------------ E <-- last master commit
\ \ (try to merge into feature)
feature B -- C -- D -- F <-- feature now contains "E" edits?
但我得到的是:
master A ------------ E F <-- master now contains all of feature stuff (B, C, D).
\ \ |
feature B -- C -- D --- F <-- feature now contains "E" edits.
Edit2:如果根据jszakmeister的回答,这是因为执行了2次合并操作,其中一次是快进,有没有办法恢复有关快进合并的信息,比如谁做了什么时候?如果提交消息说&#34;将master合并到feature&#34;,我想这意味着它首先在那个方向完成,然后有人快进合并功能到master,对吧?
谢谢!
答案 0 :(得分:1)
我能看到它发生的一种方式。我们假设您有一个名为&#34; feature&#34;的功能分支。你合并了#34; master&#34;进入&#34;功能&#34;。所以图表看起来像:
---o---o---o master
\
-o---o---o---* feature
如果您结帐&#34;功能&#34;并且合并master,你可能会得到一个快进合并,因为新的提交在&#34; master&#34;直接在&#34;功能&#34;的最后一次提交之前。所以图表最终看起来像这样:
---o---o---o
\
-o---o---o---* master, feature
这不是一个额外的提交,而是#34; master&#34;和&#34;功能&#34;现在指向 同样的提交。 FWIW,我的团队和我发现这种行为令人困惑,所以我已经 概述了我们在下面的工作,以帮助防止这个问题。
另外,我不确定你使用&#34; gitk&#34;是什么意思做你的提交。据我所知,gitk仅供查看。你的意思是&#34; git gui&#34;?我建议您使用&#34; gitk&#34;来查看图表。虽然。我喜欢使用以下内容:
gitk --date-order master feature
这将显示主画面和功能分支的图片,并帮助我辨别关系。如果我在同一次提交中看到master和feature分支标签,那么这是一个很好的迹象,表明我不小心将合并功能快进到我的主分支上。
如果您看到不同的内容,那么发布图片会很有帮助。但我怀疑它已经发生在功能分支上的这种快速合并。您可以使用以下步骤备份功能分支:
git checkout master
git reset --hard HEAD^
您可能需要git push --force origin master
。我建议使用这个完整的表单,因为Git的默认推送行为是推送所有本地跟踪分支,这可能导致重新分支分支。此外,强迫推动&#34;掌握&#34;与他人合作时不是一个好的答案,所以如果你愿意的话,你需要与你的团队协调。简单的答案可能就是保持原样。
根据具体情况,可能会涉及更多。
此外,如果您想要合并提交,那么您可以这样做:
git checkout master
git merge --no-ff feature
这将强制创建合并提交,即使它可以快速转发。我的团队和我非常喜欢这个,我们把它作为默认。我在下面解释一下。
编辑:我改变了感觉以匹配问题并扩展了某些部分。
顺便说一句,因为我在Subversion使用Bazaar一段时间后,我变得非常 敏感谁是历史上的主线(最左边)父母。 Git和它 快进合并使这更加困难,我发现我的团队真的 发现它也令人不快。所以我们最终做了一些事情。
首先,我们更改了配置,以便合并始终进行合并 承诺。您可以从命令行执行以下操作:
git config merge.ff false
或全球,使用:
git config --global merge.ff false
接下来的一点是,我们确实希望在引入更新时进行快速合并 从上游。所以我们有几个别名可以提供帮助:
[alias]
# Fetch the remote and update the current branch.
up = !git remote update -p && git merge --ff --ff-only @{u}
# Fast-forward pull locally
ff = !sh -c 'git merge --ff --ff-only ${1:-@\\{u\\}}' -
在大多数情况下,团队将上游分支设置为他们想要推送的位置
从中拉出来。因此,git up
将从服务器获取更新
快进当前分支。这通常在&#34; master&#34;上完成。 git ff
可以用来做类似的事情,但没有获取步骤。它也是
如果您需要,可以更轻松地快速转发您的另一个分支
这样的事情(有时会出现)。
其中一些比我关心的还要多,所以我写道
git ffwd
帮助我们git ffwd
将进行抓取,然后快进我的所有内容
在遥控器上具有等效物的本地分支。它也照顾
当分支机构被移除到服务器端时,修剪你的遥控器
更容易修饰裁判并防止它变得无序。 git ffwd
将仅进行快进合并(git up
也做同样的事情),如果失败则会失败
分支有分歧,所以它最终成为一个关于某事的好标记
有趣的事情,你需要介入并找出正确的过程
动作。
所有这一切的净效果是,现在当我们输入git merge foo
时,那里
将是合并提交。 Git会要求提供一条消息,如果你要做的话
错误的是,你可以简单地删除缓冲区的内容并保存
(导致Git中止)或者在Vim中以:cq
退出,这稍微容易一些
导致编辑器退出并显示错误。无论哪种方式,你都需要更多
控制,它已经走了很长的路,使跟踪事情变得更容易
并保持我们的历史看起来很尖锐。
另外请注意,如果我们都在努力,我们也会设置git config push.default upstream
同一个项目中的同一个项目,或git config push.default current
如果我们要进入单独的回购。如果你是Git&lt; 2.0,然后呢
设置此设置很重要,否则您可能会在主分支上执行类似git push
-f
的操作,但最终会在本地重写其他分支
跟踪远程分支。这是因为在Git&lt; 2.0,默认是
matching
并推送所有远程跟踪分支,他们就是
很少是最新的。
这有点啰嗦,但我想告诉你还有另外一种方法 工作,让你有一个更好的形状,消除一些困惑和感觉 从长远来看比较容易 - 至少对我和我的团队来说都是如此。
我有更多配置here, 如果您有兴趣。
答案 1 :(得分:1)
当我阅读这样的陈述并看到像这样的WRT git的图片时,我总是畏缩。
某种程度上,合并提交现在存在于两个分支中... git-gui和GitLab都在历史图表中显示这个提交为彼此合并两个分支。
master A ------------ E F <-- master now contains all of feature stuff (B, C, D).
\ \ |
feature B -- C -- D --- F <-- feature now contains "E" edits.
它暗示了一种非常Subversion的思维方式:即分支是桶和稳定的,提交存在于桶中,提交和合并是关于移入和移出桶的提交。
我认为对于git来说,使用不同的心智模型确实很有帮助,其中提交/提交树是稳定的,分支标签是瞬态的并且可以移动。
我要重新绘制@jszakmeister发生的图表:
$ git checkout feature
master
|
|
,----------- E
/
A
\
B -- C -- D
|
|
feature
$ git merge master
master <-- last master commit
|
|
,----------- E
/ \
A F (try to merge [master] into feature)
\ /|
B -- C -- D -/ |
|
|
feature <-- feature now contains "E" edits?
$ git checkout master
$ git merge feature # fast forwarded
master <-- master now contains all of feature stuff (B, C, D).
|
|
,----------- E |
/ \|
A F
\ /|
B -- C -- D -/ |
|
|
feature <-- feature now contains "E" edits
我会避免顶线是主分支而底线是功能分支的想法 - “分支”是移动的标签。从现在开始的一个月你不会关心主标签是否沿着A - E或B - C - D行驶并且无关紧要 - 合并后它的所有主分支。如果您查看git log --graph
/ gitk
行并开始将某些列视为固定分支(存储桶),最终该工具会误导您:“master”分支可能是第一列中的第一列树的一部分,但树的另一部分是不同的列。
请注意,它可能很容易就是另一种方式。首先可以将功能分支合并到主服务器中,即创建合并提交并将主标签移动到合并提交。然后功能被快速转发给master,即功能标签被移动到master指向的同一个提交。最终结果/图表将是相同的,并且标签到达哪个或如何到达最终位置并不重要。
另外请注意,移动分支装饰既便宜又容易。像Both git-gui and GitLab show in the history graph this commit as merging both branches with each other
这样的声明听起来很重要,但鉴于图片,这真的不是什么大问题 - 它只是意味着一个分支标签被错误地移动了,但它很容易将其移动到其他地方。
如果您对一个或两个合并不满意,请使用git log --graph --decorate
或gitk
可视化当前提交树和分支标签。然后在心理上可视化树应该看起来像你想要的样子,并移动主要和特征标签以反映它。
要将master合并到功能中,但尚未将功能合并到master中,您需要:
master
|
|
,----------- E
/ \
A F
\ /|
B -- C -- D -/ |
|
|
feature
$ git checkout master
$ git reset --hard E
$ git checkout feature # Move feature label if necessary
$ git reset --hard F
要将功能合并到主设备中,但尚未将主功能合并到功能中,您需要:
master
|
|
/----------- E |
/ \|
A F
\ /
B -- C -- D -/
|
|
feature
$ git checkout master # Move master label if necessary
$ git reset --hard F
$ git checkout feature
$ git reset --hard D
要在两次合并之前重新开始,您需要:
master
|
|
,----------- E
/
A
\
B -- C -- D
|
|
feature
$ git checkout master
$ git reset --hard E
$ git checkout feature
$ git reset --hard D
-
更多关于此类思维的信息:https://stackoverflow.com/a/23375479/11296