Git merge - 将没有冲突的文件添加到下一次提交

时间:2018-06-07 16:11:33

标签: git

我试图提取最新的提交,我们会说有3个不同的文件: FILE1.TXT FILE2.TXT file3.txt

我跑:

git pull origin master

这会删除上面的3个文件并告诉我file1.txt中存在冲突,我使用

识别
git diff --name-only --diff-filter=U

我解决了这个冲突并致电

git add file1.txt

但是当我打电话时

git status -uno

它说

On branch master
Your branch and 'origin/master' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)

All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)

Changes to be committed:
modified:   text1.txt
modified:   text2.txt
new file:   text3.txt

Etc. Etc.

为什么要将text2.txt和text3.txt添加到我的提交中?我刚刚从原点拉出这些?

(仅供参考我为所有这些编写脚本并为了示例而简化它)。 感谢

1 个答案:

答案 0 :(得分:1)

TL; DR

真正简短的回答是"是"。但是有一些误解,这个简单的"是的,他们是因为你拉了"留下了。

首先,您需要停止考虑单个文件,因为git pull不会提取文件。实际上,它只是运行两个Git命令的包装器。如果您是Git新手,我建议避免 git pull:使用两个单独的命令,因为它可以让您更好地了解正在发生的事情,以及当其中一个命令失败时该怎么办。

(这在脚本中尤为重要:避免面向用户的高级命令,支持面向机器或管道命令。它们是专为此用途而设计的,并且不需要根据每个用户的个人配置偏好来改变他们的行为。git pull命令是一个管道命令,但是git fetch是,或者可以。{第二个命令我们看看不是,但解决这个问题更难。)

git fetch

git pull运行的两个命令中的第一个是git fetch:例如,git pull origin master运行git fetch origin master。如果你自己运行,你可以完全放弃origin master:默认情况下,你的Git将使用名称origin下存储的网址从另一个Git中获取。

此步骤将带来提交。虽然提交包含文件是真的(因此这会带来文件),但最好将它们视为它们的提交。每一个都是每个文件的快照,就像有人提交时一样。

提交实际上是通过其哈希ID(例如,commit b9c30a8...)来标识的,并且每个提交都存储其提交的哈希ID。这让Git将链中的提交串起来,总是向后看。 分支名称只包含分支上最新提交的ID:

... <-commit1  <-commit2  <-commit3   <--branch-name

当您第一个git clone某个Git存储库时,您会指示您的Git创建一个新的存储库,并从其他一些现有的Git存储库中的所有提交中填充它。您的提交与提交相同(具有相同的ID)。与此同时,你的Git会记住他们的分支名称使用origin/master等名称指向的位置,并使自己的分支名称master指向相同的 commit:

...--I--J   <-- master (HEAD), origin/master

(你的一个分支名称附加HEAD,以便你的Git知道你所在的分支。)

当您进行新的提交时,origin/master - 正在记住他们的origin,主要留下来,但是您的master移动,以便记住您的最新提交。您的新提交会记住先前提交的ID:

          K   <-- master (HEAD)
         /
...--I--J   <-- origin/master

当您运行git fetchgit fetch origin时,您的Git会再次调用另一个Git,并找出它所提交的内容,即您不会提交给您的新内容。你的Git让他们的Git发送这些提交,然后更新你的origin/*名称以记住他们最新的分支指针:

          K   <-- master (HEAD)
         /
...--I--J--L   <-- origin/master

这是第二个命令的来源。

在我们到达之前,让我添加一个术语旁注。当您进行新的提交时,您将处理工作树中的文件,但随后运行git add somefile.ext。此文件从工作树复制到Git称之为 index staging-area 的文件中。该索引可能最好描述为,您将在其中构建您将要进行的下一次提交。它开始包含当前提交中每个文件的副本。您将新版本复制到索引中以使其准备好进入下一次提交,并且您不会覆盖的文件保留在索引中,进入下次提交。所以这就是为什么每次提交都是每个文件的快照,以及当时索引中的每个文件。

索引在合并期间占据了扩展的角色,我们即将看到。

git merge

git pull运行的第二个命令通常是git mergegit rebase - 它使用哪个命令取决于用户配置设置等。在您的特定情况下,它显然使用git merge。特别是它运行git merge -m "Merge branch 'master' of <url>" <hash-id>,但是当你自己执行此操作时,通常可以只运行git merge而没有参数。

merge命令有许多不同的操作模式。但是,默认情况下,它会查看当前的提交/分支(由附加的HEAD记住),以及您提供的其他提交或分支名称,或当前的上游科。此操作的目标是将您所做的任何工作与他们所做的任何工作相结合。为此,Git需要找到您和他们共享的第一个提交

看一下我们绘制的图表,显而易见的是你们两个都提到了:

          K   <-- master (HEAD)
         /
...--I--J--L   <-- origin/master

在您和他们以不同的方式进行之前,您分享的提交是提交J。所以现在,你的Git实际上运行了两个git diff命令:

git diff --find-renames <hash-of-J> <hash-of-K>
git diff --find-renames <hash-of-J> <hash-of-L>

这个差异发现您修改了file1.txttext1.txt(无论哪个 - 我将在这里跟text1.txt一起使用),并且他们还修改了text1.txt 。也许你没有修改text2.txt,但他们确实如此;并且没有创建新文件text3.txt,但他们确实如此。

您的Git现在尝试合并所有这些更改,从合并库本身的所有文件开始作为起点。您和他们都修改了text1.txt,因此您的Git会尝试将对该文件的更改与对该文件的更改进行组合。 此尝试失败,因此Git很快会因合并冲突而停止;但与此同时,它继续将对text2.txt的更改与text2.txt的不足更改结合起来。这真的很容易!它只需要text2.txt。然后它继续将他们新创建的text3.txt与你text3.txt的缺乏创作结合起来,这也很容易。

现在你的Git因冲突而停止。它会在您的索引/登台区/缓存中留下 text1.txt的所有三个版本。合并命令还会在您的工作树中留下自己尝试将所有三个版本组合在一起的<<<<<<< ... >>>>>>>标记,以便它是第四个版本的文件。

此时,您的工作是弄清楚正确的组合是什么。您可以从索引中提取所有三个更高阶段(基数,--ours--theirs)版本 - 例如git mergetool所做的事情 - 和/或使用Git试图将Git留在工作树中的那些组合起来。但是,当你完成组合时,你应该:

  1. 将合并后的版本保留在工作树中,名称为text1.txt
  2. 运行git add text1.txt。这会将工作树中的版本复制到索引中,从索引中移除三个更高级版本。
  3. 现在索引中只有一个版本,即正确合并的版本,它已准备好提交。同时,text2.txttext3.txt在索引中也是 ,在正常(阶段0)&#34;准备提交&#34;州。但每个其他文件也是如此。

    您会看到这三个文件,但不会看到其他文件,因为对于这三个文件,索引中的版本已经构建并准备好进行下一次提交,中的内容不同当前的提交。对于索引中的每个其他文件,索引中的内容当前提交中的内容相同,因此git status不会报告&#34;将在提交但是相同的#34;。