嗨,我刚开始使用git,但是我想知道如何解决以下假设示例:
有两个人(A和B)为一个分支(主)上的远程回购做出了贡献。我们将假设B是最新的仓库,而A不是。 A刚刚修改了新的代码行,并尝试将其推送到存储库,并被告知他需要及时更新。拉动他时遇到合并冲突,并且能够解决它。这样做后,A成功推送到存储库。现在,B意识到A的更新很重要,并决定他需要从存储库中提取信息,但是他已经在本地进行了更改,因此暂时只是藏匿。在拉动并应用存储之后,B意识到他遇到了与A先前遇到的合并冲突。现在我的问题是在这种情况下,即使另一个人之前已经这样做,从回购中撤出的人员是否总是必须再次解决合并冲突,还是有其他解决方法?
非常感谢您的协助。
答案 0 :(得分:1)
这种情况永远不会发生。原因是合并操作的输入之一已自动更改。但是,B人(我在下面称他为Bob)可以看到合并冲突。
请记住,在Git中,合并是涉及提交的操作。也就是说,当我们进行合并(动词形式要合并)时,我们会找到一些提交并进行工作。还要注意,每个提交都代表一个完整快照:所有文件,这些文件自该特定提交起就及时冻结。如果您想查看文件的昨天,去年,或其他日期,它们在当天的提交中都存在。
有三个输入可用于合并操作!作为运行Git的人,我们直接指定其中的一个 :
$ git merge origin/develop
例如。名称origin/develop
解析为某个特定的提交ID,这是一个很大的丑陋的哈希ID字符串,例如5d826e972970a784bd7a7bdf587512510097b8c7
,这是我们在存储库中拥有的一个提交,我们早些时候可能通过运行{{1} }。 (请记住,git fetch
本质上是一个便捷命令,其含义是:为我运行git pull
,然后在完成后立即为我运行第二个Git命令,通常为git fetch
< / em>。)
合并的第二个输入是无论当前提交是什么。也就是说,在我们运行git merge
(也许通过git merge
)之前,我们运行了git pull
命令:
git checkout
这将选择分支上的最新提交,因为分支名称的定义是“分支上的最新提交”。这意味着分支名称会随着时间不断更改它们的含义。要查看当前是哪个提交$ git checkout develop
或现在是哪个提交master
,可以运行develop
或git rev-parse master
,这将吐出当前的哈希ID。以后,如果有更多提交,请再次运行此命令,您将获得一个不同的哈希ID。
因此,考虑到这一点,始终值得绘制 commit图。提交图是在存储库中的历史记录,因为Git中的历史记录不过是提交。
如果您之前未绘制过提交图,则需要进行一些练习。有很多方法可以在浏览器或GUI中绘制或查看它们,尽管我对GUI非常满意,因为许多GUI都是谎言(通常是出于与性能良好相关的充分原因,但是仍然烦人)。有很多方法可以做到这一点,但是我喜欢水平地在StackOverflow帖子中做到这一点:
git rev-parse develop
在这些图中,最近的提交在右侧,时间向左移动。 分支名称指向最右边(最新)的提交,因为根据定义,名称是 last 在其分支中的提交。我们(和Git)必须从结尾开始,然后向后移到较早的提交,以查看进展情况。
从该图上,我们可以看到 o--o--o <-- develop (HEAD)
/
...--o--*
\
o--o <-- origin/develop
上有三个提交(圆形develop
节点)不在共享历史记录上,而我们的o
有两个提交提交不在共享历史记录上的内容。
共享历史记录从提交origin/develop
开始,并在时间上向后延伸。在此图中,提交*
是提交*
和develop
的合并基础。 当Git进行真正的合并时-在合并过程中执行合并部分-三个输入是合并基础,origin/develop
提交(HEAD
)和其他提交(--ours
)。
Git进行合并的方式现在实际上非常简单。因为每个提交都是完整快照,所以Git首先将合并基础快照提取到一个临时区域。然后提取我们的提交-嗯,它确实已经存在了-和他们的提交,现在运行两个单独的比较,我们可以我们自己使用--theirs
一次复制一个。我们首先找到提交git diff
的哈希ID(也许通过查看图表),然后运行:
*
git diff --find-renames <hash-of-*> HEAD # what we changed
git diff --find-renames <hash-of-*> origin/develop # what they changed
现在要做的就是结合这些更改。从基本文件开始。然后,无论我们在哪里更改了文件,如果他们没有更改该文件,请使用我们的文件。无论他们在哪里更改了文件,而我们没有更改,请使用他们的文件。无论我们都是在哪里更改了同一文件,都应合并更改。
合并冲突。在这种情况下,Git会保留文件的所有三个原始副本(隐藏在Git的 index 中),并尽最大努力将更改以及一些冲突标记组合到工作树中。
如果Git完全没有冲突,则Git进行新的提交。或者,在您手动修复了发生冲突时留下的混乱Git之后,您进行结果的最后提交。在我们的图表中,此提交看起来有些奇怪,因为它以前有两个个提交,而不是通常的提交。我给这个新提交一个字母ID(不是真实的哈希ID,只是一个替代),git merge
:
M
这种提交是 merge 或 merge作为名词:是双亲提交,两个父母都是旧的 o--o--o--M <-- develop (HEAD)
/ /
...--o--* /
\ /
o----o <-- origin/develop
(父#1)和另一个提交(#2)。
您建议Alice进行合并,然后运行HEAD
。当爱丽丝这样做时,假设她的git push
成功了,那将使另一个Git存储库调用提交git push
是其 M
的技巧。例如,也许第三个存储库位于GitHub上:
develop
我对此进行了一些不同的绘制,但这是同一组提交。这里没有 o--o--o
/ \
...--o--o M <-- develop (HEAD)
\ /
o-----L
,只有合并提交origin/develop
会导致前两次提交。我也未标记旧的共享点,并给M
表示Bob的 current 提交,因为我们很快就要讨论它了。
现在,Bob在他的存储库中运行L
,以接管Alice的工作。尽管Bob自己还没有新的提交,但他获得了新的提交。请注意,他的git fetch
已经存在,当前指向提交develop
:
L
请注意,鲍勃的 o--o--o
/ \
...--o--o M <-- origin/develop
\ /
o-----L <-- develop (HEAD)
是他分支的结尾!如果他有未提交的更改,则可以运行develop
将其保存为一次提交(实际上是两次提交,但现在仅假装一次),即位于 no 分支上:
git stash
现在,鲍勃可以运行 o--o--o
/ \
...--o--o M <-- origin/develop
\ /
o-----L <-- develop (HEAD)
\
S [stash]
(或git merge --ff-only
,这将执行另一次不执行任何操作的提取,因为没有比git pull
更新的内容,然后进行了快速转发而不是真的-a -merge“ merge”)以使 Bob 的M
指向提交develop
:
M
Bob现在可以应用并拖放(或“弹出”)存储库,以将更改添加到他的工作树中。如果可行,他们将准备添加和提交。然后Bob进行了新提交,我们可以将其绘制为 o--o--o
/ \
...--o--o M <-- develop (HEAD), origin/develop
\ /
o-----L
\
S [stash]
:
N
o--o--o
/ \
...--o--o M--N <-- develop (HEAD), origin/develop
\ /
o-----L
的内容已经包含N
的内容,因为M
接受了git stash apply
,并将其与它的父级进行比较,然后进行了相同的更改到S
中的任何内容。
Bob看到冲突的时间点不在获取和快速转发期间,而是在Bob运行M
(或git stash apply
时),该运行以运行git stash pop
开始)。实际上,这将运行另一个合并!但是它运行的合并操作不会以 merge commit 结尾。这只会执行动作的 commerging 动词部分。
此合并将提交git stash apply
作为其最后的“其他提交”输入。中间输入是S
-提交HEAD
-像往常一样是当前提交,第一个输入是两者的合并基础,即提交M
:
L
Git比较(比较) o--o--o
/ \
...--o--o M <-- develop (HEAD), origin/develop
\ /
o-----L
\
S [stash]
和L
来找出“我们”做了什么。 (当然,这实际上是 Alice 所做的,或多或少,但是Git不在乎。)它将M
与L
进行比较以查看“他们”的意思(真的,鲍勃)做到了。然后,它完全按照常规合并的方式合并或尝试合并这两个变更集。
如果一切顺利,S
会停在那里。尚无新提交。如果问题很严重,git stash
会因合并冲突而停止,由Bob来解决合并冲突。 Bob完成后,Bob进行的下一次提交将是普通提交,而不是合并提交。
如果Bob使用git stash
并且存在合并冲突,则Git在git stash pop
步骤之后停止,并且Bob仍然具有隐藏位置:他必须运行apply
才能将其修复后丢弃乱七八糟。但是如果Git认为合并进行得很好,并且Bob运行git stash drop
,那么 Git 将为Bob运行git stash pop
。因此,在使用git stash drop
时一定要格外小心:有时会同时应用和删除,但有时在应用之后会失败,并且不会执行删除部分。
(我主要建议您避免使用git stash
,但如果要使用它,请分别进行应用和删除,以免在以 Git 的方式应用时意外地删除存储空间认为很干净,但是实际上这是您的错误。即使对于Git专家,这的确确实发生了,要从中恢复是很痛苦的。)