为什么git pull不更新本地更改的文件?

时间:2018-07-13 18:07:14

标签: ios git macos

据我了解,“ git pull”会进行提取和合并。对于iOS项目,我使用发布设置配置了设置(证书,配置文件等)。但是,当在master分支上时,当我执行private void Grid_Loaded(object sender, RoutedEventArgs e) { //Keep it running for 5 minutes CancellationTokenSource cts = new CancellationTokenSource(new TimeSpan(hours: 0, minutes: 5, seconds: 0)); //Keep it running until user closes the app //CancellationTokenSource cts = new CancellationTokenSource(); //Go to a different thread Task.Run(() => { //Some dummy variable long millisecondsSlept = 0; //Make sure cancellation not requested while (!cts.Token.IsCancellationRequested) { //Some heavy operation here Thread.Sleep(500); millisecondsSlept += 500; //Update UI with the results of the heavy operation Application.Current.Dispatcher.Invoke(() => txtCpu.Text = millisecondsSlept.ToString()); } }, cts.Token); } git pull时,我看到git提交是最新的,而远程master分支的最新提交仍然是git log显示我的pbxproj文件是不同的(即,我在本地配置的提供配置文件字符串等)。

要明确一点,这对我来说是理想的选择,因为我只希望代码更改,而不必在每次发布正式版之前更新分支时就搞乱设置分发和配置概要文件。但我也想了解git合并的方式。我期望git将合并我在本地更改的文件和/或表明冲突。但是没有发生这样的事情。

注意:我知道一个“强制更新”,它使我的本地主服务器完全类似于远程主机,但想了解此操作与常规合并之间的区别。

2 个答案:

答案 0 :(得分:3)

git会将来自远程的更改与本地提交的更改合并。它不会尝试与您未提交的更改合并,并且如果同一文件中有远程更改,它将警告您合并将清除您的本地更改并拒绝合并。

更新-我意识到我并没有真正回答“为什么”:

在本地提交的更改与未提交的本地更改之间进行区分的原因是,您始终可以取回本地提交的更改。它们处于提交状态,您可以checkout进行提交,在此处创建一个新分支,如果需要,甚至可以reset将当前分支返回到该点。与本地提交的更改合并不会丢失任何内容。

但是您的工作树(未提交的本地更改)没有这种保护。如果git将更改合并到其中,而结果却不是您想要的,则您将无法轻易地“退回”到以前的状态。

在合并未提交的变更所涉及的内容方面,我们也可能会遇到技术差异,但是,如果需要合并未提交的变更,则可以克服那些技术原因。但是,由于这样做可能会导致数据丢失,因此最好避免将更改合并到具有本地未提交更改的任何文件中。

答案 1 :(得分:3)

  

据我了解,“ 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之类的东西。Modern Git消除了最后无益的特性。)

只要您自己不使其复杂化(通过添加refspecs或各种获取标志),就可以完成所有操作。合并部分仍然很棘手。完成提取后,git pull现在可以运行git merge,这会使事情变得有些复杂。

合并

合并的目标是最简单的部分:Git首先假设您一直在工作并进行提交,而其他人也在进行工作并进行提交。如果我们将这些提交与先前的提交朝左绘制,然后将其向右提交,给它们提供一个简单的单字母名称,而不是它们实际的难以理解的吉蒂哈希ID,我们将得到这样的结果:

          C--D--E   <-- branch (HEAD)
         /
...--A--B
         \
          F--G--H   <-- origin/branch

E是您在分支机构上的最新提交。它的父级是提交DD的父母是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将组合的更改应用于合并库中的快照以生成新快照,并与两个父级进行 merge commit

          C--D--E
         /       \
...--A--B         I   <-- branch (HEAD)
         \       /
          F--G--H   <-- origin/branch

进行新的合并提交会使分支名称branch指向新的提交,就像进行新的普通提交一样。

这是真正的合并:Git必须合并自合并基础以来的更改,这意味着它必须首先找到合并基础提交,然后进行两个比较。这是合并的动词部分,要合并(两组更改)。完成合并动词部分后,Git进行了 merge提交,以形容词形式进行合并,或更正式地以 merge 形式进行合并,后者使用merge作为名词。 >

并非所有合并都是真正的合并

假设您运行git fetch(也许通过git pull),并且什么都没有改变,那么您可以:

...--D--E   <-- branch (HEAD), origin/branch

也就是说,您在这里有两个不同的名称。您的分支名称为branch,指向您的哈希ID为E(确实有点难看的Git哈希)的提交。您还拥有远程跟踪名称origin/branch,记住 Git的分支branch,指向您的哈希ID为E的提交,因为该提交存在在两个Git中。

然后,完成 no 工作并进行 no 提交,您稍后再运行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的默认设置是不打扰。合并将其检测为快进操作,并且将改为 not 做待合并动词,而 not 进行形容词-合并提交。无需进行新的提交H,Git只会将分支名称branch向前移动:

...--D--E
         \
          F--G   <-- branch (HEAD), origin/branch

并签出提交G,以便G的快照填充索引和工作树。

Git将此称为快进合并,但是没有任何合并!快进只是对分支名称的操作。最终没有发生这种情况的踪影,这就是为什么Git允许您禁止快速前进的非合并“合并”的原因。但是,对于与远程跟踪名称相对应的本地分支,无论如何实际上实际上是您经常想要的东西,这就是为什么这是Git的默认设置。