Git合并过程将忽略文件

时间:2018-08-13 15:30:12

标签: git git-extensions

有两个分支:branch A包含一些文件,branch B包含例如名为FolderB的文件夹。当我将分支B合并到分支A中时,提交的暂存文件中没有“ FolderB”。对我来说这是意外的行为。我记得几天前,在进行合并之前,我进行了另一次合并,但最终由于选择了选项keep ours而解决了冲突。也许此选项保存在某个地方,但现在确实有副作用。如果是,我在哪里可以删除这些设置?

2 个答案:

答案 0 :(得分:2)

  

我还记得几天前,在进行合并之前,我进行了另一次合并,但最终由于冲突而解决,通过选择选项keep ours解决了这一冲突。也许此选项保存在某个地方,现在它会产生副作用。

我无法与其他界面交谈(可以执行此类操作),但是命令行Git不会保存合并策略和策略选项。但是,您已经已经合并的事实意味着您并没有从您认为的起点开始。

首先,让我们做一个简单的注释:“合并”并不意味着“使相同”。如果是这样,我们根本不会理会分支机构。假设您和我都从该软件的v1.1开始,并且我对副本进行了一些更改,而您对您的副本进行了一些更改。如果然后我从您那里得到了您的提交并运行:

$ git merge yours

然后用这个替换了我所做的与您所做的一样,我对此可能并不满意!

因此,git merge所做的就是找到一些共同的起点(Git称这为合并基础提交),并找出您和他们的共同点,从那时起,无论“他们”是谁。但这意味着您必须理解 Git如何找到这个共同的起点。

合并基地

让我们看一下正常的提交过程。我们首先克隆一些现有的存​​储库:

$ git clone <url>

,我们开始工作并进行提交。 到底是什么?正如任何good Git book会告诉您的那样,提交是您制作快照时所有源的快照以及一些元数据:快照,何时,为什么以及(这对Git的内部操作至关重要)-在您制作快照之前,使您正在工作。

每个提交都有自己的唯一哈希ID,例如b7bd9486b055c3f967a870311e704e3bb0654e4f。这些十六进制数字字符串很大,很丑陋,人类无法使用。因此,我们让Git记住他们 for 。每个提交不仅具有自己唯一的哈希ID,而且每个 都会记住我们在之前签出的提交的哈希ID。我们和Git使用分支名称来记住最终提交。

当我们进行新的提交时,我们的新提交会获得一个新的丑陋的ID,但它也会记住哪个提交是分支上的最后一次提交。然后,Git将新提交的丑陋ID写入分支 name 中,以便该名称记住新的而不是旧的。

结果是我们从一些提交链开始,这些提交以这样的 tip 提交结束:

... <-F <-G <-H   <--master

其中名称 master记住提交H的ID。提交H记住提交G的ID,它记住提交F的ID,依此类推。这些内部链接可以像这样向后指向的箭头绘制,它们总是从 child commit到 parent commit向后退:commit知道他们的祖先,但不知道他们的祖先。子孙。一旦提交,就不能更改任何提交,因此无法更改提交以记住其子项,但是子项也不能忘记其父项。

因此,假设您克隆了存储库,而我也克隆了存储库,我们都有:

...--F--G--H   <-- master

现在您要进行一两次新提交:

...--F--G--H--I   <-- master

同时有其他人进行一两次提交:

...--F--G--H--I   <-- master
            \
             J--K   <-- other

(每个提交都有自己的唯一ID,这些大写字母仅代表真实的ID。在26次提交后,我们将用完所有字母。这就是Git使用更大,更丑陋的原因。)

如果我们现在(我们中的任意一个人)去合并我们的工作,那么我们将从获取另一个人的提交开始。结果是一个类似于上面的图。然后,我们git checkout一个分支,例如master,并运行一个合并命令,例如git merge other

现在,Git使用从每个分支尖端开始的向后箭头,遍历图形以查找合并基础。在这种情况下,这很清楚:它是提交H。然后,Git实际上会运行两个 git diff命令:

git diff --find-renames <hash-of-H> <hash-of-I>   # what we did on master
git diff --find-renames <hash-of-H> <hash-of-K>   # what they did on other

Git现在的工作是组合这些更改,将其应用于H中的快照,然后根据结果进行新的合并提交。如果一切顺利,Git会自行执行此操作。如果不是,则会出现合并冲突,并且必须正确解决它们。您告诉Git您已完成此操作,然后Git进行新的合并提交:

...--F--G--H--I---L   <-- master (HEAD)
            \    /
             J--K   <-- other

此合并提交L的特殊之处在于它具有两个父,而不是一个。提交L(合并提交)时,请记住,是将所有从“ HI”的内容与一切都从“ HK”。

再次合并基础

现在假设您和我俩都继续工作。我在K之后进行新的提交,而您在L之后进行新的提交:

...--F--G--H--I---L--M--N   <-- master (HEAD)
            \    /
             J--K--O--P--Q   <-- other

如果您现在再次运行git merge other ,则Git必须找到最新提交N与我最新提交Q的合并库。这次的合并基础是 not H!我们从NQ开始,然后倒退以找到最新的 shared 提交。从Q开始,只有一条向后的路径,依次经过POKJH等。

N开始,在提交L时,我们可以两种方式:NML ,然后是两者 I K 1 因此,第一个 shared 提交是现在K

这次git merge要做的是针对两个分支提示提交KN的diff commit Q。同时,提交L(我们之前的合并)是我们告诉Git处理K与我们的工作相结合的正确方法

然后,假设这些新文件是在提交JK中添加的,但不在L中,因为我们选择了“保持我们的”选项。从KN的差异表示:删除这些文件。KQ的差异可能会或可能不会修改这些新文件。文件。我们可以猜测,在这种情况下,它不会对其进行修改,因为如果这样做,则会出现新的合并冲突,而Git告诉我们我们 已删除 ,并且他们 更改了。如果他们没有更改,Git会认为我们的“删除”是正确的答案,并将其删除。


1 请记住,内部箭头始终指向后方,即我在此处绘制它们的方式。我们可以从LK,但不能从KL


该怎么办

如果这是正在发生的事情(根据我的经验,是这样),则真正的问题是您先前的合并(我们在上面L处绘制的提交)是错误的:它删除了文件。但是我们已经注意到,您不能更改任何更早的提交。

有两种解决问题的策略。第一个方法(通常是最好的方法)是确认错误并将其保留在适当的位置:将错误的合并保留在原处,但添加一个新的提交 now 来存储已纠正的 快照。我们可以通过多种方式来做到这一点。它们都涉及很多工作。在大多数情况下,我首选的方法是重新执行合并,但这次要正确执行:在错误的合并之前创建一个指向提交的新分支:

                ............<-- rework (HEAD)
               .
...--F--G--H--I---L--M--N   <-- master
            \    /
             J--K--O--P--Q   <-- other

,然后运行git merge <hash of other commit>,在这种情况下,这将是提交K的哈希。您将获得与上次相同的合并冲突,这次您可以正确解决它。

正确解决并提交后,您可以运行git diff <hash-of-original-merge> <hash-of-corrected-merge>来查看现在需要添加哪些更改以纠正问题。例如:

$ git diff <hash-of-L> <hash-of-new-merge> > /tmp/patch
$ git checkout master
$ git apply /tmp/patch

或者,如果您确定要对所有除新文件以外的所有内容都“保留我们的文件”,则只需复制多余的文件,git add,然后提交。 / p>

处理该问题的第二种策略是将其全部消除:丢弃commit L(错误合并)每一个后续的提交。显然,这使您需要重新做很多工作。如果您已经将这些提交(无论其哈希ID是什么)给了其他任何人,它也会带来另一个可怕的副作用:那些其他人仍然有这些提交。您还必须获得 them 来丢弃这些提交的他们的副本。否则他们会继续回来。

要使用第二种策略(在大多数情况下效果不佳),可以使用git reset命令。由于这通常是处理问题的错误方法,因此我将在此处停止,但请参见How to revert a Git repository to a previous commit

答案 1 :(得分:1)

通常,当一个文件被git进程忽略时,这是因为该文件与.gitignore文件的其中一行匹配。

如果您确定FolderB应该属于您的仓库,请确保分支A和分支B的.gitignore文件都不包含FolderB。另外,请确保FolderB尚未完全合并到分支A中。