据我了解,“ git pull”会进行获取和合并。对于iOS项目,我使用发布设置(证书,配置文件等)配置了设置。但是,当在master分支上时,当我执行git pull
和git log
时,我看到git提交与远程主分支的最新提交保持最新,但git diff
仍显示我的pbxproj文件是不同(即与我在本地配置的提供概要文件字符串等)不同。
明确地说,这对我来说是理想的,因为我只希望代码更改,而不必在每次发布分支之前(在即将发布到生产环境之前)更新分支和设置概要文件。但我也想了解git合并的方式。我期望git将合并我在本地更改的文件和/或表明冲突。但是没有发生这样的事情。
注意:我知道一个“强制更新”,它使我的本地主服务器完全类似于远程主机,但想了解此操作与常规合并之间的区别。
最佳答案
据我了解,“ git pull”会进行获取和合并。
没错更准确地说,git pull
实际上运行git fetch
,然后运行git merge
。或者更确切地说,它曾经是过去的字面意思。在过去一年左右的时间里,对Git进行了修改,以通过在内部进行获取和合并步骤来加快git pull
的速度,而不是在可能的情况下运行单独的命令-并且您还可以告诉它执行git rebase
而不是git merge
,还有其他一些极端情况。但实际上,pull =提取+合并。
棘手的部分是这两个步骤分别意味着什么。提取和合并都很复杂,也可能很复杂。
取
提取步骤更简单:您的Git调用其他Git。您的Git和他们的Git进行了一段简短的交谈,其中他们的Git告诉您的Git他们有任何新提交,而您没有。您的Git将这些新的提交加载到您的存储库中,以便您现在拥有这些提交;然后,您的Git设置您的远程跟踪名称(如origin/master
之类的名称)以记住其Git的master
等。 (当git pull
运行git fetch
时,可能会限制您的Git的获取。在非常旧的版本中,这甚至也会阻止您的Git更新您的origin/master
等。现代Git消除了最后一个无用的特性。)
只要您自己不使它复杂化(通过添加refspecs或各种获取标志),就足够了。合并部分仍然很棘手。完成提取后,git pull
现在运行git merge
,这会使事情变得有些复杂。
合并
合并的目标很简单:Git首先假设您一直在工作并进行提交,而其他人也一直在工作并进行提交。如果我们将这些提交以较早的提交向左绘制,然后将较后的提交向右绘制,给它们提供一个简单的单字母名称,而不是其实际的难以理解的吉蒂哈希ID,我们将得到如下所示:
C--D--E <-- branch (HEAD)
/
...--A--B
\
F--G--H <-- origin/branch
E
是分支上的最新提交。其父是commit D
; D
的父母是C
;等等。提交H
是他们的最新提交,您刚刚通过git fetch
引入了该提交。 H
的父级是G
,其父级是F
,其父级是B
。我们可以看到,从提交B
的共同点(合并基础)开始,这两条开发线并行发生。在这种情况下,
git merge
的作用实际上是运行两个git diff
命令。第一个找出您所做的更改:git diff --find-renames <hash-of-B> <hash-of-E>
第二个差异找出了它们的变化:
git diff --find-renames <hash-of-B> <hash-of-H>
Git可以将这两组不同的更改组合在一起,只要它们彼此不冲突即可。或者更确切地说,只要Git不认为它们发生冲突-Git不知道,它就对
git diff
的逐行差异做出了很多假设。成功(也许)组合更改后,Git将组合的更改应用于合并基础中的快照以生成新快照,并与两个父级进行合并提交: C--D--E
/ \
...--A--B I <-- branch (HEAD)
\ /
F--G--H <-- origin/branch
进行新的合并提交会使分支名称本身
branch
指向新的提交,就像进行新的普通提交一样。这是一个真正的合并:Git必须合并自合并基础以来的更改,这意味着它必须首先找到合并基础提交,然后进行两个比较。这是合并的动词部分,用于合并(两组更改)。在完成了要合并的动词部分后,Git进行了合并提交,将其合并为形容词,或者更不正式地进行了合并(使用merge作为名词)。
并非所有合并都是真实的合并
假设您运行
git fetch
(也许通过git pull
)并且什么都没有改变,那么您将:...--D--E <-- branch (HEAD), origin/branch
也就是说,您在这里有两个不同的名称。您的分支名称为
branch
,指向您的哈希ID为E
的提交(确实是一些难看的Git哈希)。您还有一个远程跟踪名称origin/branch
,记住他们的Git分支名为branch
,指向您的哈希ID为E
的提交,因为两个Git中都存在相同的提交。然后,不做任何工作也不做任何提交,您稍后再运行
git fetch
,只是这一次他们做了一些工作并进行了一些提交:...--D--E <-- branch (HEAD)
\
F--G <-- origin/branch
如果现在您要求Git将您的工作(或缺少工作)与他们的工作合并,则Git会照常找到合并基础,但是会发现合并基础本身就是
E
提交。显然,将提交E
与自身进行比较不会发现任何变化。无论如何,Git可以继续构建新的合并提交,将无更改与某些更改结合起来以得到:...--D--E------H <-- branch (HEAD)
\ /
F--G <-- origin/branch
H
中的快照与G
中的快照完全匹配。但是git merge
的默认设置是不打扰。合并将其检测为快进操作,而不是执行合并动词,也不进行形容词合并提交。 Git只会将分支名称H
向前移动,而不是进行新的提交branch
:...--D--E
\
F--G <-- branch (HEAD), origin/branch
并检出提交
G
,以便G
的快照填充索引和工作树。Git将此称为快速合并,但是没有合并!快进只是对分支名称的操作。最终没有任何痕迹发生,这就是为什么Git允许您禁止快速前进的非合并“合并”的原因。但是,对于与远程跟踪名称相对应的本地分支,无论如何实际上实际上都是这种情况,这就是Git的默认设置。
关于ios - 为什么git pull不更新本地更改的文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51330682/