为什么 git pull autostash 需要 rebase?
Why does git pull autostash require a rebase?
如果我在本地仓库中编辑一些文件而不提交它们,并尝试 git pull
,它会失败,原因很明显 git 不知道我打算如何协调新拉取的文件使用我拥有的未提交版本更改这些文件。
我知道解决方案是 git pull --rebase --autostash
。但为什么 --rebase
是必要的?
--rebase
option is explained为:
When true, rebase the current branch on top of the upstream branch after fetching.
git-rebase - Reapply commits on top of another base tip
但在上述情况下,没有本地提交需要在拉取的内容之上重新应用,只有 未提交 更改。为什么 git 决定要求 --rebase
做 --autostash
是否有某种逻辑或者这只是偶然的?
TL;DR:这是一个历史事故。
记住 git pull
表示:
运行 git fetch
从其他 Git 存储库获取新的提交。任何人都可以随时安全地执行此操作,因此此步骤基本上始终有效(除非由于某种原因您的网络出现故障或其他原因)。
然后,假设第 1 步有效,运行 一个 second Git 命令以某种方式与当前分支混淆。
第 2 步有问题。实际命令运行通常是git merge
;另一个选项是 git rebase
.
现在,如果您有未提交的工作,则不能 运行 git merge
或 git rebase
(有一个例外,我将在稍后处理)。在这种情况下,第 1 步没问题,但第 2 步不行。
autostash 选项基本上 运行s git stash push
适合你,git stash push
意味着 提交我现在拥有的,但是 没有 分支,然后做一个 git reset --hard
(它会丢弃你所做的工作,但它现在安全地存储在一些提交中)。完成后,第 2 步现在总是可行的。如果第 2 步成功完成——尽管并非总是如此,无论你使用 哪个 第二个命令——Git 将为你 运行 git stash pop
.
您可以在这里提出几个合理的问题。一是:为什么不允许在 git merge
之前这样做?您可以存储、变基和弹出,但您也可以存储、合并和弹出;如果你可以存储、合并和弹出,为什么不把它作为一个选项呢?唯一真正的答案是:当 rebase 是一个花哨的 shell 脚本时,添加了 --autostash
选项以重新设置基准,并且在那里添加它更容易。合并命令不是花哨的 shell 脚本,很难将其添加到那里。
另一个问题是我认为你确实问过的问题:如果你没有自己的提交,并且在需要时已经完成了 git stash push
,both git merge
——在这种情况下默认执行快进操作,这意味着它实际上不合并任何东西——和 git rebase
结束做同样的事情:直接检查另一个 Git 的最新提交(并且在 pull 的第 2 步中没有失败)。同样,人们可能想知道为什么不允许 --autostash
来处理这两种情况。同样,唯一真正的答案是“因为添加到 rebase 代码路径更容易”。
我们应该注意,即使 git merge
可以 快进,它也不一定总是快进。特别是,您可以使用 git merge --no-ff
强制 Git 进行真正的合并而不是快进操作。您也可以使用 git config
将其设置为在拉取 (pull.ff
) 或始终 (merge.ff
) 时发生。所以 pull 可能会进行合并,即使它本可以进行快进。尽管如此,如果它 可以 快进,它将进行的合并将会成功,我们又回到了与以前相同的情况。
现在是时候提到一个特例了。当 git merge
可以并且确实选择进行快进操作时——本质上,git checkout
将分支名称在提交图中向前拖动——而不是真正的合并,[=94 是可能的=] 执行此操作 即使 您有未提交的工作,只要未提交的工作位于检出未更新的文件中。因此,有一个 git pull
使用 git merge
的情况 不需要 自动存储。尽管如此,实际上 做 一个 push/fast-forward/pop 序列就可以了,我们又一次回到了历史事故。
如果你对这类事情有强烈的感觉,你总是可以编写一个补丁来教 Git 如何使用自动执行 git pull
and/or git merge
藏起来。 Git 的来源可用;请参见 https://github.com/git/git.
处的仅发布克隆
如果我在本地仓库中编辑一些文件而不提交它们,并尝试 git pull
,它会失败,原因很明显 git 不知道我打算如何协调新拉取的文件使用我拥有的未提交版本更改这些文件。
我知道解决方案是 git pull --rebase --autostash
。但为什么 --rebase
是必要的?
--rebase
option is explained为:
When true, rebase the current branch on top of the upstream branch after fetching.
git-rebase - Reapply commits on top of another base tip
但在上述情况下,没有本地提交需要在拉取的内容之上重新应用,只有 未提交 更改。为什么 git 决定要求 --rebase
做 --autostash
是否有某种逻辑或者这只是偶然的?
TL;DR:这是一个历史事故。
记住 git pull
表示:
运行
git fetch
从其他 Git 存储库获取新的提交。任何人都可以随时安全地执行此操作,因此此步骤基本上始终有效(除非由于某种原因您的网络出现故障或其他原因)。然后,假设第 1 步有效,运行 一个 second Git 命令以某种方式与当前分支混淆。
第 2 步有问题。实际命令运行通常是git merge
;另一个选项是 git rebase
.
现在,如果您有未提交的工作,则不能 运行 git merge
或 git rebase
(有一个例外,我将在稍后处理)。在这种情况下,第 1 步没问题,但第 2 步不行。
autostash 选项基本上 运行s git stash push
适合你,git stash push
意味着 提交我现在拥有的,但是 没有 分支,然后做一个 git reset --hard
(它会丢弃你所做的工作,但它现在安全地存储在一些提交中)。完成后,第 2 步现在总是可行的。如果第 2 步成功完成——尽管并非总是如此,无论你使用 哪个 第二个命令——Git 将为你 运行 git stash pop
.
您可以在这里提出几个合理的问题。一是:为什么不允许在 git merge
之前这样做?您可以存储、变基和弹出,但您也可以存储、合并和弹出;如果你可以存储、合并和弹出,为什么不把它作为一个选项呢?唯一真正的答案是:当 rebase 是一个花哨的 shell 脚本时,添加了 --autostash
选项以重新设置基准,并且在那里添加它更容易。合并命令不是花哨的 shell 脚本,很难将其添加到那里。
另一个问题是我认为你确实问过的问题:如果你没有自己的提交,并且在需要时已经完成了 git stash push
,both git merge
——在这种情况下默认执行快进操作,这意味着它实际上不合并任何东西——和 git rebase
结束做同样的事情:直接检查另一个 Git 的最新提交(并且在 pull 的第 2 步中没有失败)。同样,人们可能想知道为什么不允许 --autostash
来处理这两种情况。同样,唯一真正的答案是“因为添加到 rebase 代码路径更容易”。
我们应该注意,即使 git merge
可以 快进,它也不一定总是快进。特别是,您可以使用 git merge --no-ff
强制 Git 进行真正的合并而不是快进操作。您也可以使用 git config
将其设置为在拉取 (pull.ff
) 或始终 (merge.ff
) 时发生。所以 pull 可能会进行合并,即使它本可以进行快进。尽管如此,如果它 可以 快进,它将进行的合并将会成功,我们又回到了与以前相同的情况。
现在是时候提到一个特例了。当 git merge
可以并且确实选择进行快进操作时——本质上,git checkout
将分支名称在提交图中向前拖动——而不是真正的合并,[=94 是可能的=] 执行此操作 即使 您有未提交的工作,只要未提交的工作位于检出未更新的文件中。因此,有一个 git pull
使用 git merge
的情况 不需要 自动存储。尽管如此,实际上 做 一个 push/fast-forward/pop 序列就可以了,我们又一次回到了历史事故。
如果你对这类事情有强烈的感觉,你总是可以编写一个补丁来教 Git 如何使用自动执行 git pull
and/or git merge
藏起来。 Git 的来源可用;请参见 https://github.com/git/git.