git-merge 是否将 "to-be-merged" 分支中的文件添加到头部
Does git-merge add files from the "to-be-merged" branch to head or not
所以我和我的团队正在做一个敏捷开发流程下的项目。每次迭代都有几个分支离开 test
分支。每个分支充当迭代的任务。迭代完成后,所有任务分支合并到test
分支,test
分支合并到master
.
我 运行 遇到的问题是将 test
合并到 master
。在这种特定情况下,master
相当落后,test
有许多文件甚至没有包含在 master
中。因此,当我通过拉取请求比较 test
和 master
时,它的行为就像 test
中的所有新文件都不会添加到 master
.
这就是 git-merge 的工作方式吗?它只更新 master
中更改的文件而不关心添加的文件?
那么我做 git-rebase 的唯一选择是什么?如果是这样,它是如何工作的?
编辑:我可能已经找到问题的根源。如果某些任务分支在迭代开始时从 master
分支出来,然后在结束时合并到 test
会怎么样。将 test
合并到 master
时会不会导致一些问题?每当我在 Github 上查看我的 test
分支时,它会显示 "This branch is 7 commits ahead, 5 commits behind master".
git merge
合并了test
到master
的所有变化,即test
中的变化、添加和删除的文件将在[=]中更改、添加或删除13=].
您的步骤是:
git checkout master
git merge test
// if required: fix merge conflicts, shouldn't be required if `test` was in `sync` with master at the start of your sprint
git commit // if fixing merge conflicts were necessary
git push
在理想情况下,当 master
和 test
在冲刺开始时同步并且所有内容都可以合并回来,这两个分支将在冲刺结束时再次同步.您的工作流程类似于 gitflow - 只是您将分支称为 test
而不是 develop
.
我的建议:当多人在回购(分支)上工作时,尽可能避免变基。这是历史的改写,有风险。
此外,github、TFS 或 VSTS 等源代码管理工具正在合并而不是变基。
根据您的编辑,我们将其分为两部分。
首先,关于 git 操作的行为应该有何不同的直接问题:
Is this how git-merge works? It only updates the changed files in master and doesn't care about added files?
否;远程分支上的任何更改 - 包括添加新文件 - 都应通过合并合并。如果这没有发生,那就是其他事情正在发生。
So is my only option to do a git-rebase?
除了一些基于边缘情况的例外情况,您应该期望结果内容 (TREE
) 对于变基和合并是相同的。无论是什么阻碍了您的合并按预期执行,都可能 也 导致 rebase 以意外的方式运行。
变基或合并的选择(理论上)仅与如何保留历史有关。
第二个:好的...所以这里到底发生了什么?
很难确切地说 发生了什么,因为很难获得有关回购当前状态的足够信息。但我可以拟定一些场景并谈谈合并的工作原理,也许这会给你足够的继续你可以 trouble-shoot 它...
假设您像这样启动合并:
git checkout branchA
git merge branchB
现在 git
将确定三个提交:
- 我们的 - 已签出的提交(即
branchA
指向的内容)
- 他们的 - 历史被合并的提交(即 branchB` 指向的内容)
- 基础 - 我们的和他们的之间的"merge base"。通常这可以总结为 "the most recent common ancestor of ours and theirs"
所以如果你有
A -- B -- C -- D -- O <--(branchA)
\
E -- F -- T <--(branchB)
那么O
将是我们的,T
将是他们的,B
将是 base.
接下来 git 将计算 B
和 T
之间的补丁(粗略的差异) - 我们可以称之为 "their changes" - 以及 [= 之间的补丁31=] 和 O
- 我们可以称之为 "our changes".
如果提交 E
添加一个 previously-nonexistent 文件 foo.txt
,那么在我们的更改中将不会对该文件进行任何更改(因为它不存在于 [=31] =] 或 O
),但 foo.txt
将在他们的更改中成为一个新文件(因为它在 B
中不存在,但它确实存在于 T
中)。
现在 git 想要创建一个包含我们的更改和他们的更改的组合补丁。如果我们的更改和他们的更改都试图修改相同的代码块,这就是冲突可能出现的地方。但在我们的 "new file" 场景中,不会有冲突,因为我们的更改没有提及 foo.txt
。合并后的补丁应包含 "new file foo.txt
" 以及出现在 T
.
处的文件内容
所以大多数时候,如果 merge
的行为令人困惑,您可以通过了解什么被用作合并基础来开始理解它。
git merge-base branchA branchB
将打印出一个提交 ID。问题是,提交是否包含foo.txt
?如果是这样,那么您将不会得到您期望的行为;然后问题简化为“弄清楚为什么计算出的合并基数包含 foo.txt
.
现在在上面的示例中,此命令将 return B
的 ID,其中不包含 foo.txt
。那么,为什么您的情况会有所不同?
在您的编辑中,您描述了一些分支是从 master 创建并合并到 test。这不一定是个问题。假设我们有
A -- B <--(master)
你说
git checkout master
git branch test
然后一些工作发生在 test
。
A -- B <--(master)
\
C -- D <--(test)
现在有人创建了一个任务分支,但他们是从 master
.
创建的
A -- B <--(master)
|\
| E -- F <--(task1)
\
C -- D <--(test)
然后他们将task
合并成test
A -- B <--(master)
|\
| E ----- F <--(task1)
\ \
C -- D -- T <--(test)
其他一些工作继续影响 master
A -- B -- G -- H -- O <--(master)
|\
| E ----- F <--(task1)
\ \
C -- D -- T <--(test)
现在在这种情况下,task1
被创建的事实 "from master
" 并不重要。事实上,目前 git
中存储的任何内容甚至 都反映了 它是从 master
创建的事实;它也可以在提交 C
.
之前从 test
创建
意味着合并仍然可以正常工作。
但这里有一个不同的场景...如果从 master
创建 task1
的人在意识到他们需要分支之前实际上提交了对 master
的更改怎么办?所以在这种情况下我们从
重新开始
A -- B <--(master)
\
C -- D <--(test)
开发人员在 master
上开始编码 task1
。他们承诺,而你已经
A -- B -- E <--(master)
\
C -- D <--(test)
然后有人说 "hey, dude, you can't just work directly on master
",所以我们尝试解决问题。
git checkout master
git checkout -b task1
# work continues on the task1 branch
git commit
还有一些其他工作发生在 master
,所以现在你有
A -- B -- E -- G <--(master)
\ \
\ F <--(task1)
\
C -- D <--(test)
看起来不错,但是有人说"hey, we can't have the changes form E
on master
until test
gets merged back; and we can't afford the problems that a history rewrite would cause. So..."
git checkout master
git revert HEAD^
我们有
A -- B -- E -- G -- ~E <--(master)
\ \
\ F <--(task1)
\
C -- D <--(test)
每个分支上的一切看起来都正确,所以工作继续
A -- B ------- E -- G -- ~E -- H -- O <--(master)
\ \
\ F <--(task1)
\ \
C -- D -- T <--(test)
但是现在当你试图将 test
合并到 master
时,可怕的事情发生了:git
计算出合并基数是 E
,因为有共同的祖先在master
和test
之间,E
是可以到达所有其他人/无法被任何o到达的人其他人。
因此以 E
作为合并基础,它们的更改 不会影响 foo.txt
(因为它已经在 E
中创建),而 我们的更改 删除了 foo.txt
(在 ~E
中)。所以合并结果没有 foo.txt
,这不是来自分支的更改——它已经在 master
的历史中发生了更改——所以 PR 报告对此只字不提。
我知道这到底是怎么回事吗?不,我敢打赌它很像这样吗?是的。我可以详细说明修复它的程序吗?不一定,因为可能会涉及到确切的步骤,并取决于完全发生了什么。
现在我会先尝试确认问题是否与我所建议的基本一致。
所以我和我的团队正在做一个敏捷开发流程下的项目。每次迭代都有几个分支离开 test
分支。每个分支充当迭代的任务。迭代完成后,所有任务分支合并到test
分支,test
分支合并到master
.
我 运行 遇到的问题是将 test
合并到 master
。在这种特定情况下,master
相当落后,test
有许多文件甚至没有包含在 master
中。因此,当我通过拉取请求比较 test
和 master
时,它的行为就像 test
中的所有新文件都不会添加到 master
.
这就是 git-merge 的工作方式吗?它只更新 master
中更改的文件而不关心添加的文件?
那么我做 git-rebase 的唯一选择是什么?如果是这样,它是如何工作的?
编辑:我可能已经找到问题的根源。如果某些任务分支在迭代开始时从 master
分支出来,然后在结束时合并到 test
会怎么样。将 test
合并到 master
时会不会导致一些问题?每当我在 Github 上查看我的 test
分支时,它会显示 "This branch is 7 commits ahead, 5 commits behind master".
git merge
合并了test
到master
的所有变化,即test
中的变化、添加和删除的文件将在[=]中更改、添加或删除13=].
您的步骤是:
git checkout master
git merge test
// if required: fix merge conflicts, shouldn't be required if `test` was in `sync` with master at the start of your sprint
git commit // if fixing merge conflicts were necessary
git push
在理想情况下,当 master
和 test
在冲刺开始时同步并且所有内容都可以合并回来,这两个分支将在冲刺结束时再次同步.您的工作流程类似于 gitflow - 只是您将分支称为 test
而不是 develop
.
我的建议:当多人在回购(分支)上工作时,尽可能避免变基。这是历史的改写,有风险。
此外,github、TFS 或 VSTS 等源代码管理工具正在合并而不是变基。
根据您的编辑,我们将其分为两部分。
首先,关于 git 操作的行为应该有何不同的直接问题:
Is this how git-merge works? It only updates the changed files in master and doesn't care about added files?
否;远程分支上的任何更改 - 包括添加新文件 - 都应通过合并合并。如果这没有发生,那就是其他事情正在发生。
So is my only option to do a git-rebase?
除了一些基于边缘情况的例外情况,您应该期望结果内容 (TREE
) 对于变基和合并是相同的。无论是什么阻碍了您的合并按预期执行,都可能 也 导致 rebase 以意外的方式运行。
变基或合并的选择(理论上)仅与如何保留历史有关。
第二个:好的...所以这里到底发生了什么?
很难确切地说 发生了什么,因为很难获得有关回购当前状态的足够信息。但我可以拟定一些场景并谈谈合并的工作原理,也许这会给你足够的继续你可以 trouble-shoot 它...
假设您像这样启动合并:
git checkout branchA
git merge branchB
现在 git
将确定三个提交:
- 我们的 - 已签出的提交(即
branchA
指向的内容) - 他们的 - 历史被合并的提交(即 branchB` 指向的内容)
- 基础 - 我们的和他们的之间的"merge base"。通常这可以总结为 "the most recent common ancestor of ours and theirs"
所以如果你有
A -- B -- C -- D -- O <--(branchA)
\
E -- F -- T <--(branchB)
那么O
将是我们的,T
将是他们的,B
将是 base.
接下来 git 将计算 B
和 T
之间的补丁(粗略的差异) - 我们可以称之为 "their changes" - 以及 [= 之间的补丁31=] 和 O
- 我们可以称之为 "our changes".
如果提交 E
添加一个 previously-nonexistent 文件 foo.txt
,那么在我们的更改中将不会对该文件进行任何更改(因为它不存在于 [=31] =] 或 O
),但 foo.txt
将在他们的更改中成为一个新文件(因为它在 B
中不存在,但它确实存在于 T
中)。
现在 git 想要创建一个包含我们的更改和他们的更改的组合补丁。如果我们的更改和他们的更改都试图修改相同的代码块,这就是冲突可能出现的地方。但在我们的 "new file" 场景中,不会有冲突,因为我们的更改没有提及 foo.txt
。合并后的补丁应包含 "new file foo.txt
" 以及出现在 T
.
所以大多数时候,如果 merge
的行为令人困惑,您可以通过了解什么被用作合并基础来开始理解它。
git merge-base branchA branchB
将打印出一个提交 ID。问题是,提交是否包含foo.txt
?如果是这样,那么您将不会得到您期望的行为;然后问题简化为“弄清楚为什么计算出的合并基数包含 foo.txt
.
现在在上面的示例中,此命令将 return B
的 ID,其中不包含 foo.txt
。那么,为什么您的情况会有所不同?
在您的编辑中,您描述了一些分支是从 master 创建并合并到 test。这不一定是个问题。假设我们有
A -- B <--(master)
你说
git checkout master
git branch test
然后一些工作发生在 test
。
A -- B <--(master)
\
C -- D <--(test)
现在有人创建了一个任务分支,但他们是从 master
.
A -- B <--(master)
|\
| E -- F <--(task1)
\
C -- D <--(test)
然后他们将task
合并成test
A -- B <--(master)
|\
| E ----- F <--(task1)
\ \
C -- D -- T <--(test)
其他一些工作继续影响 master
A -- B -- G -- H -- O <--(master)
|\
| E ----- F <--(task1)
\ \
C -- D -- T <--(test)
现在在这种情况下,task1
被创建的事实 "from master
" 并不重要。事实上,目前 git
中存储的任何内容甚至 都反映了 它是从 master
创建的事实;它也可以在提交 C
.
test
创建
意味着合并仍然可以正常工作。
但这里有一个不同的场景...如果从 master
创建 task1
的人在意识到他们需要分支之前实际上提交了对 master
的更改怎么办?所以在这种情况下我们从
A -- B <--(master)
\
C -- D <--(test)
开发人员在 master
上开始编码 task1
。他们承诺,而你已经
A -- B -- E <--(master)
\
C -- D <--(test)
然后有人说 "hey, dude, you can't just work directly on master
",所以我们尝试解决问题。
git checkout master
git checkout -b task1
# work continues on the task1 branch
git commit
还有一些其他工作发生在 master
,所以现在你有
A -- B -- E -- G <--(master)
\ \
\ F <--(task1)
\
C -- D <--(test)
看起来不错,但是有人说"hey, we can't have the changes form E
on master
until test
gets merged back; and we can't afford the problems that a history rewrite would cause. So..."
git checkout master
git revert HEAD^
我们有
A -- B -- E -- G -- ~E <--(master)
\ \
\ F <--(task1)
\
C -- D <--(test)
每个分支上的一切看起来都正确,所以工作继续
A -- B ------- E -- G -- ~E -- H -- O <--(master)
\ \
\ F <--(task1)
\ \
C -- D -- T <--(test)
但是现在当你试图将 test
合并到 master
时,可怕的事情发生了:git
计算出合并基数是 E
,因为有共同的祖先在master
和test
之间,E
是可以到达所有其他人/无法被任何o到达的人其他人。
因此以 E
作为合并基础,它们的更改 不会影响 foo.txt
(因为它已经在 E
中创建),而 我们的更改 删除了 foo.txt
(在 ~E
中)。所以合并结果没有 foo.txt
,这不是来自分支的更改——它已经在 master
的历史中发生了更改——所以 PR 报告对此只字不提。
我知道这到底是怎么回事吗?不,我敢打赌它很像这样吗?是的。我可以详细说明修复它的程序吗?不一定,因为可能会涉及到确切的步骤,并取决于完全发生了什么。
现在我会先尝试确认问题是否与我所建议的基本一致。