遇到错误时如何合并 "Hint: You have divergent branches and need to specify how to reconcile them."
How to Merge when you get error "Hint: You have divergent branches and need to specify how to reconcile them."
我正在与另外 1 位开发人员合作,他们创建了一个需要与 master 合并的分支。
尝试将 Visual Studio 社区(而非 Visual Studio 代码)中的 Git 拉入 Bitbucket 存储库时出现此错误
如果我尝试推送它说“无法推送,因为您的本地分支在远程分支后面”。
这是错误:
Hint: You have divergent branches and need to specify how to reconcile them.
Hint: You can do so by running one of the following commands sometime before
Hint: your next pull:
Hint:
Hint: git config pull.rebase false # merge
Hint: git config pull.rebase true # rebase
Hint: git config pull.ff only # fast-forward only
Hint:
Hint: You can replace "git config" with "git config --global" to set a default
Hint: preference for all repositories. You can also pass --rebase, --no-rebase,
Hint: or --ff-only on the command line to override the configured default per
Hint: invocation.
Git failed with a fatal error.
Git failed with a fatal error.
Need to specify how to reconcile divergent branches.
我发现了各种讨论这个的东西,例如
和
但其中 none 解释了为什么会发生这种情况以及这些操作的实际作用。
如何将其他分支中的内容合并到 master 中,为什么会出现此消息以及提示中的所有建议有什么作用?
谢谢
Git 中经常出现令人困惑的内容,其中涉及一些历史。
首先要知道的是 git pull
做的事情太多了。好吧,对于某些人(我)来说,它做的太多了;其他人喜欢它做了这么多;但实际上,它做了两项工作,每项工作都有自己独立的 Git 命令:
git pull
运行s git fetch
。大多数,但不是全部,你给 到 git pull
的参数直接传递给 git fetch
。所以 git pull
表示 运行 git fetch
而 git pull origin somebranch
表示 运行 git fetch origin somebranch
.
假设第一步成功,git pull
运行第二个 Git 命令。
进行第 2 步的原因很简单:git fetch
从其他 Git 存储库获取新提交,填充这些新提交到您自己的存储库中,您现在可以在其中访问它们。但随后 停止 。您可以访问 新提交,但是没有任何东西真正使用 新提交。要使用 新提交,您需要第二步。
最初,第二步总是 git merge
。 git merge
命令非常庞大和复杂,但它的含义很容易描述:Merge 表示 combine work. Git 将尝试获取您已完成的工作(如果您已完成)和他们已完成的工作(如果他们已完成),并使用简单而愚蠢的自动化来合并这些工作规则。这些规则没有关于你如何或为什么做这项工作的线索,或者你所做的任何更改 意味着 。它们只是基于差异中的“线”工作。
然而,这里有四种可能性:
也许你没有工作,他们也没有工作。你没有新的提交。几乎无事可做,git merge
什么也不做。
也许你做了一些工作,他们什么也没做;你没有新的提交;无事可做,git merge
又什么都不做。
也许你没有工作,他们做了一些工作。你有一些新的提交。将您的 lack-of-work 与他们的实际工作相结合很容易,如果您允许,git merge
会走捷径。
也许你和他们都工作了。你有新的提交 和 你从他们那里得到了新的提交,并且 git merge
必须使用它的 simple-and-stupid 规则来组合工作。 Git 不能在这里走捷径,你会得到一个 full-blown 合并。
Git可能可以采取的捷径是简单地检查他们最新的提交,同时向前拖动你的分支名称。 git merge
命令将其称为 fast-forward 合并 ,尽管实际上并没有涉及 合并。这种 not-really-a-merge 是微不足道的,而且通常非常安全:唯一 可以 出错的地方是他们最新的提交实际上没有正常运行。 (在那种情况下,您可以返回到旧版本。)所以“快进”合并特别友好:没有复杂的 line-by-line 合并规则可能出错。很多人喜欢这种“合并”。
有时走捷径是不可能的,有时有些人不希望 Git走捷径(原因我们不会在这里介绍以保持这个答案很简短,或者对我来说很简短)。有办法告诉git merge
不要走捷径,即使可以.
因此,仅对于 git merge
,这给了我们三种可能性:
- 无所事事(而
git merge
总是愿意无所事事);
- fast-forward是可以的,但也许Git不应该这样做;和
- fast-forward 是不可能的,这意味着这个合并不是微不足道的。
git merge
命令有选项告诉它在除了“无事可做”的情况下做什么:
- (无标志):如果可能,请执行 fast-forward,否则,请尝试真正的合并。
--ff-only
:如果可能的话做一个fast-forward。如果不行,报错说fast-forward是不可能的;不要尝试合并。
--no-ff
:即使 fast-forward 是可能的,也不要使用快捷方式:在每种情况下尝试完全合并(当然“无事可做”的情况除外)。
git pull
命令接受所有这些标志并将它们传递给 git merge
,如果您选择 git pull
运行 git merge
作为它的第 2 步。
等等,还有更多
不是每个人都希望 Git 进行合并。假设你做了一两个新的提交,我们称之为 I
和 J
,而你的 origin
的 git fetch
带来了两个新的提交 他们 自你开始以来,我们称之为 K
和 L
。这给了你一组提交,如果你要绘制它们,可能看起来像这样:
I--J <-- your-branch
/
...--G--H <-- main
\
K--L <-- origin/main
您可以 fast-forward 您的 main
来匹配他们的 origin/main
:
I--J <-- your-branch
/
...--G--H
\
K--L <-- main, origin/main
而且,无论你是否这样做,你都可以合并你的提交J
和他们的提交L
以产生一个新的合并提交 M
:
I--J
/ \
...--G--H M <-- your-branch (HEAD)
\ /
K--L <-- origin/main
但有些人更喜欢 rebase 他们的提交——在本例中是 I
和 J
——这样他们就会 在[之后] =280=] commit L
,这样图片现在是这样的:
I--J [abandoned]
/
...--G--H--K--L <-- origin/main
\
I'-J' <-- your-branch
在这里,我们复制提交I
和J
到new-and-improved提交I'
和J'
.这些提交对 L
进行了与 I-J
对 H
相同的 更改 ,但是这些提交具有不同的 big-ugly-hash-IDs 并且看起来像你在 之后 origin
人做出了 K-L
的承诺。
git pull
命令可以做这种变基:
git switch your-branch
git pull --rebase origin main
通过 运行ning git fetch
获得他们的提交,然后 运行ning git rebase
使用正确的参数使 [=385] 一次完成所有这些=] 复制 I-J
到 I'-J'
如上所示。一旦 rebase 完成——记住,像 git merge
,它可能有你必须首先解决的合并冲突——Git 会将分支名称 your-branch
移动到 select最后复制的提交:本例中的 J'
。
写完git pull
没多久,就加了这个--rebase
。由于许多人希望这种事情 自动发生 ,git pull
获得了 默认 使用 --rebase
的能力.您将分支配置为执行此操作(通过将 branch.<em>branch</em>.rebase
设置为 true
)并且 git pull
可以给你的 rebase。 (请注意,你的 rebase 现在发生的提交取决于两件事:分支的 upstream 设置,以及你可以传递给 git pull
的一些参数。我'在此示例中,我们将事情保持明确,这样我们就不必担心较小的细节,但在实践中,您会担心。)
这让我们来到了 2006 年或 2008 年左右
在 Git 的开发中,我们有:
git fetch
:从其他地方(例如“上游”或 origin
存储库)获取新提交,经常更新 origin/*
样式 remote-tracking 名称;
git merge
: 什么都不做,或者fast-forward,或者某个指定的提交或者分支的上游的真正合并;
git rebase
:使用指定的提交或分支的上游,将一些现有提交复制到 new-and-improved 提交,然后放弃原始提交以支持副本;和
git pull
:使用分支的上游或显式参数,运行 git fetch
然后 运行 git merge
或 git rebase
。
因为 git merge
可以接受 --ff-only
或 --no-ff
参数,git pull
必须能够将这些传递给 git merge
if 我们正在使用 git merge
.
随着时间的推移,更多的选项开始出现,比如auto-stashing、rebase的“fork point”等等。此外,事实证明许多人 想要 变基为 他们的默认值 git pull
,因此 Git 获得了一个新的配置选项,branch.autoSetupRebase
。当设置为 remote
或 always
时,这会满足许多人的要求(尽管今天实际上有四个设置;我不记得当时是否有四个,也懒得去检查) .
时间继续前进,我们到了 2020 年代
到现在为止——2020 年到 2022 年之间的某个时间——很明显 git pull
做了 错误的事情 对许多,甚至可能是大多数新手来说到 Git。我个人的建议是 避免 git pull
。干脆不要用了:先运行 git fetch
,再看看git fetch
说的。然后,如果 git fetch
做了很多,也许接下来使用 git log
。然后然后,一旦你确定你是否想要 git merge
与任何选项,或者 git rebase
也与任何选项,运行那个命令。 如果您使用此选项,您将拥有完全的控制权。您决定会发生什么,而不是从 Git. 那里得到一些惊喜我喜欢这个选项:它很简单!当然,您确实需要 运行 至少两个命令。但是你得到运行额外的命令在这两个之间,这可能很有用。
不过,如果 git pull
引入新的提交, 可以 合并到 git merge --ff-only
下,这通常是我想要的:做fast-forward,否则停下来让我环顾四周,然后决定我是否需要变基、合并或其他任何我可能想要的东西。1 结果通常是也成为别人想要的,现在 git pull
,运行 完全没有参数,可以告诉直接这样做:
git config --global pull.ff only
实现这个。
同时,您在问题中显示的提示中的其他两个 git config --global
命令使第二个命令成为合并或变基。所以现在,在2022年,很容易告诉git pull
去做我想要它做的事。此外,似乎 Git 维护者已经接受了我的观点: git pull
没有 一些先见之明 不好 ,新手不要用。所以他们已经设置 git pull
现在 要求 你选择这三个选项之一,如果你想 运行 它没有参数。2
因此,您需要选择一个。 旧的默认值是git config pull.rebase false
,但这是一个糟糕的默认值。我不推荐它。我做推荐git config pull.ff only
(尽管由于15年以上的习惯,我仍然没有实际使用它)。
1一个 real-world 示例:我遇到了一些对我来说很麻烦的错误。我更改了我知道是错误的代码,但让 me 完成了 my 的工作。我犯下了这个可怕的黑客行为。然后我等待上游进行更改。他们这样做了,我带来了新的承诺。如果他们修复了 错误,我想删除 我的修复,而不是合并或变基。如果他们 没有 修复错误,我想重新设置我的 hack(可能需要也可能不需要一些调整)。 “他们修复了错误”测试需要一些东西 git pull
不能单独测试。
2注意 运行ning git pull
with arguments 不应该产生这种抱怨.我仍然不 运行 太多,所以我不太确定错误是什么,但是在新功能实施的第一轮或第二轮中,有一个错误 git pull
会抱怨不当。我相信它已在 2.35 中修复并且几乎肯定它已在 2.36 中修复,现在应该随时发布。
我在使用 Visual Studio 时遇到了这个问题 - 以下命令为我解决了这个问题
git config pull.rebase false
我正在与另外 1 位开发人员合作,他们创建了一个需要与 master 合并的分支。
尝试将 Visual Studio 社区(而非 Visual Studio 代码)中的 Git 拉入 Bitbucket 存储库时出现此错误
如果我尝试推送它说“无法推送,因为您的本地分支在远程分支后面”。
这是错误:
Hint: You have divergent branches and need to specify how to reconcile them.
Hint: You can do so by running one of the following commands sometime before
Hint: your next pull:
Hint:
Hint: git config pull.rebase false # merge
Hint: git config pull.rebase true # rebase
Hint: git config pull.ff only # fast-forward only
Hint:
Hint: You can replace "git config" with "git config --global" to set a default
Hint: preference for all repositories. You can also pass --rebase, --no-rebase,
Hint: or --ff-only on the command line to override the configured default per
Hint: invocation.
Git failed with a fatal error.
Git failed with a fatal error.
Need to specify how to reconcile divergent branches.
我发现了各种讨论这个的东西,例如
和
但其中 none 解释了为什么会发生这种情况以及这些操作的实际作用。
如何将其他分支中的内容合并到 master 中,为什么会出现此消息以及提示中的所有建议有什么作用?
谢谢
Git 中经常出现令人困惑的内容,其中涉及一些历史。
首先要知道的是 git pull
做的事情太多了。好吧,对于某些人(我)来说,它做的太多了;其他人喜欢它做了这么多;但实际上,它做了两项工作,每项工作都有自己独立的 Git 命令:
git pull
运行sgit fetch
。大多数,但不是全部,你给 到git pull
的参数直接传递给git fetch
。所以git pull
表示 运行git fetch
而git pull origin somebranch
表示 运行git fetch origin somebranch
.假设第一步成功,
git pull
运行第二个 Git 命令。
进行第 2 步的原因很简单:git fetch
从其他 Git 存储库获取新提交,填充这些新提交到您自己的存储库中,您现在可以在其中访问它们。但随后 停止 。您可以访问 新提交,但是没有任何东西真正使用 新提交。要使用 新提交,您需要第二步。
最初,第二步总是 git merge
。 git merge
命令非常庞大和复杂,但它的含义很容易描述:Merge 表示 combine work. Git 将尝试获取您已完成的工作(如果您已完成)和他们已完成的工作(如果他们已完成),并使用简单而愚蠢的自动化来合并这些工作规则。这些规则没有关于你如何或为什么做这项工作的线索,或者你所做的任何更改 意味着 。它们只是基于差异中的“线”工作。
然而,这里有四种可能性:
也许你没有工作,他们也没有工作。你没有新的提交。几乎无事可做,
git merge
什么也不做。也许你做了一些工作,他们什么也没做;你没有新的提交;无事可做,
git merge
又什么都不做。也许你没有工作,他们做了一些工作。你有一些新的提交。将您的 lack-of-work 与他们的实际工作相结合很容易,如果您允许,
git merge
会走捷径。也许你和他们都工作了。你有新的提交 和 你从他们那里得到了新的提交,并且
git merge
必须使用它的 simple-and-stupid 规则来组合工作。 Git 不能在这里走捷径,你会得到一个 full-blown 合并。
Git可能可以采取的捷径是简单地检查他们最新的提交,同时向前拖动你的分支名称。 git merge
命令将其称为 fast-forward 合并 ,尽管实际上并没有涉及 合并。这种 not-really-a-merge 是微不足道的,而且通常非常安全:唯一 可以 出错的地方是他们最新的提交实际上没有正常运行。 (在那种情况下,您可以返回到旧版本。)所以“快进”合并特别友好:没有复杂的 line-by-line 合并规则可能出错。很多人喜欢这种“合并”。
有时走捷径是不可能的,有时有些人不希望 Git走捷径(原因我们不会在这里介绍以保持这个答案很简短,或者对我来说很简短)。有办法告诉git merge
不要走捷径,即使可以.
因此,仅对于 git merge
,这给了我们三种可能性:
- 无所事事(而
git merge
总是愿意无所事事); - fast-forward是可以的,但也许Git不应该这样做;和
- fast-forward 是不可能的,这意味着这个合并不是微不足道的。
git merge
命令有选项告诉它在除了“无事可做”的情况下做什么:
- (无标志):如果可能,请执行 fast-forward,否则,请尝试真正的合并。
--ff-only
:如果可能的话做一个fast-forward。如果不行,报错说fast-forward是不可能的;不要尝试合并。--no-ff
:即使 fast-forward 是可能的,也不要使用快捷方式:在每种情况下尝试完全合并(当然“无事可做”的情况除外)。
git pull
命令接受所有这些标志并将它们传递给 git merge
,如果您选择 git pull
运行 git merge
作为它的第 2 步。
等等,还有更多
不是每个人都希望 Git 进行合并。假设你做了一两个新的提交,我们称之为 I
和 J
,而你的 origin
的 git fetch
带来了两个新的提交 他们 自你开始以来,我们称之为 K
和 L
。这给了你一组提交,如果你要绘制它们,可能看起来像这样:
I--J <-- your-branch
/
...--G--H <-- main
\
K--L <-- origin/main
您可以 fast-forward 您的 main
来匹配他们的 origin/main
:
I--J <-- your-branch
/
...--G--H
\
K--L <-- main, origin/main
而且,无论你是否这样做,你都可以合并你的提交J
和他们的提交L
以产生一个新的合并提交 M
:
I--J
/ \
...--G--H M <-- your-branch (HEAD)
\ /
K--L <-- origin/main
但有些人更喜欢 rebase 他们的提交——在本例中是 I
和 J
——这样他们就会 在[之后] =280=] commit L
,这样图片现在是这样的:
I--J [abandoned]
/
...--G--H--K--L <-- origin/main
\
I'-J' <-- your-branch
在这里,我们复制提交I
和J
到new-and-improved提交I'
和J'
.这些提交对 L
进行了与 I-J
对 H
相同的 更改 ,但是这些提交具有不同的 big-ugly-hash-IDs 并且看起来像你在 之后 origin
人做出了 K-L
的承诺。
git pull
命令可以做这种变基:
git switch your-branch
git pull --rebase origin main
通过 运行ning git fetch
获得他们的提交,然后 运行ning git rebase
使用正确的参数使 [=385] 一次完成所有这些=] 复制 I-J
到 I'-J'
如上所示。一旦 rebase 完成——记住,像 git merge
,它可能有你必须首先解决的合并冲突——Git 会将分支名称 your-branch
移动到 select最后复制的提交:本例中的 J'
。
写完git pull
没多久,就加了这个--rebase
。由于许多人希望这种事情 自动发生 ,git pull
获得了 默认 使用 --rebase
的能力.您将分支配置为执行此操作(通过将 branch.<em>branch</em>.rebase
设置为 true
)并且 git pull
可以给你的 rebase。 (请注意,你的 rebase 现在发生的提交取决于两件事:分支的 upstream 设置,以及你可以传递给 git pull
的一些参数。我'在此示例中,我们将事情保持明确,这样我们就不必担心较小的细节,但在实践中,您会担心。)
这让我们来到了 2006 年或 2008 年左右
在 Git 的开发中,我们有:
git fetch
:从其他地方(例如“上游”或origin
存储库)获取新提交,经常更新origin/*
样式 remote-tracking 名称;git merge
: 什么都不做,或者fast-forward,或者某个指定的提交或者分支的上游的真正合并;git rebase
:使用指定的提交或分支的上游,将一些现有提交复制到 new-and-improved 提交,然后放弃原始提交以支持副本;和git pull
:使用分支的上游或显式参数,运行git fetch
然后 运行git merge
或git rebase
。
因为 git merge
可以接受 --ff-only
或 --no-ff
参数,git pull
必须能够将这些传递给 git merge
if 我们正在使用 git merge
.
随着时间的推移,更多的选项开始出现,比如auto-stashing、rebase的“fork point”等等。此外,事实证明许多人 想要 变基为 他们的默认值 git pull
,因此 Git 获得了一个新的配置选项,branch.autoSetupRebase
。当设置为 remote
或 always
时,这会满足许多人的要求(尽管今天实际上有四个设置;我不记得当时是否有四个,也懒得去检查) .
时间继续前进,我们到了 2020 年代
到现在为止——2020 年到 2022 年之间的某个时间——很明显 git pull
做了 错误的事情 对许多,甚至可能是大多数新手来说到 Git。我个人的建议是 避免 git pull
。干脆不要用了:先运行 git fetch
,再看看git fetch
说的。然后,如果 git fetch
做了很多,也许接下来使用 git log
。然后然后,一旦你确定你是否想要 git merge
与任何选项,或者 git rebase
也与任何选项,运行那个命令。 如果您使用此选项,您将拥有完全的控制权。您决定会发生什么,而不是从 Git. 那里得到一些惊喜我喜欢这个选项:它很简单!当然,您确实需要 运行 至少两个命令。但是你得到运行额外的命令在这两个之间,这可能很有用。
不过,如果 git pull
引入新的提交, 可以 合并到 git merge --ff-only
下,这通常是我想要的:做fast-forward,否则停下来让我环顾四周,然后决定我是否需要变基、合并或其他任何我可能想要的东西。1 结果通常是也成为别人想要的,现在 git pull
,运行 完全没有参数,可以告诉直接这样做:
git config --global pull.ff only
实现这个。
同时,您在问题中显示的提示中的其他两个 git config --global
命令使第二个命令成为合并或变基。所以现在,在2022年,很容易告诉git pull
去做我想要它做的事。此外,似乎 Git 维护者已经接受了我的观点: git pull
没有 一些先见之明 不好 ,新手不要用。所以他们已经设置 git pull
现在 要求 你选择这三个选项之一,如果你想 运行 它没有参数。2
因此,您需要选择一个。 旧的默认值是git config pull.rebase false
,但这是一个糟糕的默认值。我不推荐它。我做推荐git config pull.ff only
(尽管由于15年以上的习惯,我仍然没有实际使用它)。
1一个 real-world 示例:我遇到了一些对我来说很麻烦的错误。我更改了我知道是错误的代码,但让 me 完成了 my 的工作。我犯下了这个可怕的黑客行为。然后我等待上游进行更改。他们这样做了,我带来了新的承诺。如果他们修复了 错误,我想删除 我的修复,而不是合并或变基。如果他们 没有 修复错误,我想重新设置我的 hack(可能需要也可能不需要一些调整)。 “他们修复了错误”测试需要一些东西 git pull
不能单独测试。
2注意 运行ning git pull
with arguments 不应该产生这种抱怨.我仍然不 运行 太多,所以我不太确定错误是什么,但是在新功能实施的第一轮或第二轮中,有一个错误 git pull
会抱怨不当。我相信它已在 2.35 中修复并且几乎肯定它已在 2.36 中修复,现在应该随时发布。
我在使用 Visual Studio 时遇到了这个问题 - 以下命令为我解决了这个问题
git config pull.rebase false