“ git pull”可以自动存储和弹出挂起的更改吗?

我知道怎么解决这个问题:

user@host$ git pull
Updating 9386059..6e3ffde
error: Your local changes to the following files would be overwritten by merge:
foo.bar
Please, commit your changes or stash them before you can merge.
Aborting

但是有没有办法让 git pull为我跳 stashpop舞蹈呢?

如果这个命令有一个不同的名称,没关系。

git stash; git pull; git stash pop创建 shell 别名是一种解决方案,但我正在寻找更好的解决方案。

53463 次浏览

Git 2.6 + (2015年9月28日发布)

令人感兴趣的 只有 git config设置是:

rebase.autostash

(使用 Git 2.27,Q22020,您现在还有 merge.autostash,见下文)

当设置为 true 时,在操作开始之前自动创建一个临时存储,并在操作结束后应用它。
这意味着您可以在脏的工作树上运行 rebase。

但是,使用时要小心: 在成功的 rebase 之后的最终存储应用程序可能会导致非平凡的冲突。

结合以下两点:

pull.rebase

如果为 true,则在所获取的分支上重新设置分支的基础,而不是在运行“ git pull”时从默认远程合并默认分支。

在给定的存储库中:

git config pull.rebase true
git config rebase.autoStash true

这对于一个简单的 git pull即使在肮脏的树上也足够了。
这种情况下不需要化名。


提交53c76dc(2015年7月4日) by 凯文 · 都特(Ikke)
(由 朱尼奥 · C · 哈马诺 gitster于2015年8月17日在 提交 e69b408合并)

pull: 启用 rebase.autostash时允许脏树

Rebase 学会了在遇到脏工作树时隐藏更改, 但 git pull --rebase没有。

只有在 rebase.autostash不脏时才验证工作树是否脏 启用。


注意: 如果您想要提取 没有 autostash (即使 rebase.autoStash true已经设置) ,那么从 git 2.9(2016年6月)开始:

 pull --rebase --no-autostash

犯下450天罪行提交1662297承诺44a59ff提交5c82bcd提交6ddc97c承诺960b承认错误(2016年4月2日)和 提交 f66398e提交 c48d73b(2016年3月21日) by 犯下450天罪行0。
(由 朱尼奥 · C · 哈马诺 gitster于2016年4月13日在 犯罪合并)

承诺 f66398e 特别包括:

pull --rebase: 添加 --[no-]autostash标志

如果设置了 rebase.autoStash配置变量,则无法 从命令行为“ git pull --rebase”覆盖它。

教“ git pull --rebase”的 --[no-]autostash命令行标志 覆盖 rebase.autoStash的当前值(如果设置为“ git rebase”) 了解 --[no-]autostash选项,这只是一个通过的问题 当“ git pull --rebase”被调用时,“ git rebase”底层的选项。


Warning: before Git 2.14 (Q3 2017), "git pull --rebase --autostash" didn't auto-stash when the local history fast-forwards to the upstream.

犯罪,第十五季,第7集(2017年6月1日) by 泰勒 · 布雷泽(tylerbrazier)
(由 朱尼奥 · C · 哈马诺 gitster承认35898ea合并,2017年6月5日)

F--rebase --autostash工作在肮脏的回购

当肮脏存储库中的 git pull --rebase --autostash导致 快进,没有任何东西被自动藏起来,拉取失败。
这是因为当我们可以快进时,有一个避免运行 rebase 的快捷方式, 但是在代码路径上会忽略 autostash。


更新: Mariusz Pawelski在评论中一个有趣的问题:

所以当你做 rebase (或者 pull --rebase)的时候,每个人都在写 autostash

但没有人采取关于自动存储时,你做正常的拉与 合并
所以没有自动开关吗?还是我遗漏了什么?我更喜欢做 git pull --rebase,但 OP 问了关于“ 标准”的 git 拉

回答:

讨论这个自动存储特性的 原始帖子 ,最初是为 git pull(merge)和 git pull --rebase实现的。

但是... ... Junio C Hamano (Git 维护者)指出:

如果 pull-merge是某种会引起“烦恼”的东西 触发了这个主题,根据定义,本地更改是重叠的 合并时,这个内部“隐藏弹出”将触及路径 合并触及,它可能不会导致“下降”,但离开 有待解决的进一步冲突。

我怀疑 pull.autostash配置不是一个好的补充,因为它鼓励了一个糟糕的、令人痛苦的工作流。
在简单的情况下,它可能不会造成伤害,但是当局部变化是复杂的时候,它会主动地造成伤害,而不是没有它,并且配置剥夺了选择的动力。

这个等式对于“ pull-rebase”有些不同,就像“ rebase”一样 坚持要你从一个干净的工作树开始,所以”下载和 “那就停止”的烦恼感觉更大。我有一个怀疑 放松政策可能是解决真正问题的更有效的办法。

因此,对于一个典型的拉式合并,最好是:

鼓励用户在运行“ git pull 之前考虑工作树中的在制品的性质。
它是一个过于复杂的野兽,可能会干扰别人正在做什么,或者 这是一个微不足道的改变,他可以隐藏起来,并弹回来?

如果是前者,他做“ checkout -b”会好得多,保持 一直工作到局部变化有所改善 “提交”,然后拉入原来的分支。

如果是后者,他最好这样做:

  • git pull
  • 发现有冲突后,就跑
    • git stash,
    • git merge FETCH_HEAD
    • git stash pop

也就是说,在 Git 2.27(Q22020)中,“ git pull”学会了在没有 pull.rebase配置存在时发出警告,而且既没有给出 --[no-]rebase也没有给出 --ff-only(这将导致合并)。

提交 d18c950(2020年3月10日) by 亚历克斯 · 亨利(alexhenrie)
(由 朱尼奥 · C · 哈马诺 gitster提交1c56d6f合并,2020年3月27日)

pull : 如果用户没有说是重新定基还是合并,则发出警告

签名: Alex Henrie

Git 新手经常忘记说“ pull --rebase”,最终导致不必要的上游合并。

他们通常需要的是在较简单的情况下使用“ pull --rebase”,或者使用“ pull --ff-only”来更新主集成分支的副本,并分别重新定位他们的工作。
pull.rebase配置变量的存在是为了在更简单的情况下帮助他们,但是没有机制使这些用户意识到这一点。

当命令行中没有 --[no-]rebase选项,也没有给出 pull.rebase配置变量时,发出警告消息。
这将给那些从来不想使用“ pull --rebase”的用户带来不便,他们不需要做任何特别的事情,但是每个用户只需支付一次不便的费用,这对于帮助一些新用户来说应该是一个合理的费用。


在 Git 2.27(2020年第二季度)中,“ git merge”学习了“ --autostash”选项和新的 merge.autostash设置。

参见 提交 d9f15d3提交 f8a1785承认犯罪犯下第804条第31款犯罪,第12季,第13集犯下0dd562e提交0816f1d承认错误犯罪提交 d9f15d30,提交 d9f15d31,提交 d9f15d32,提交 d9f15d33,提交 d9f15d34,提交 d9f15d35,提交 d9f15d36,提交 d9f15d37,提交 d9f15d38,提交 d9f15d39(2020年4月7日) ,提交 f8a17850(2020年4月4日)和 提交 f8a17851,提交 f8a17852(2020年3月21日)。
(由 朱尼奥 · C · 哈马诺 gitster提交 bf10200合并,2020年4月29日)

pull : 传递——自动隐藏以合并

签名: Denton Liu

以前,--autostash只能与 git pull --rebase一起工作。

然而,在最后一个补丁中,merge 也学习了 --autostash,所以我们没有理由再有这个限制了。
教拉通过 --autostash合并,就像它为重新基地。

还有:

使用 Sequencer.c 中的 apply_autostash()

签名: Denton Liu

builtin/rebase.c中的 apply_autostash()函数与 sequencer.c中的 apply_autostash()函数非常相似,除了它们接受的参数类型之外,它们几乎可以互换。使 sequencer.c版本外部化,并在 rebase 中使用它。

作为 shell 到 C 转换的一部分,在 第六季,第2集中引入了 rebase 版本(“ builtin rebase: support --autostash option”,2018-09-04,Git v2.20.0-rc0—— 第八批中列出的 合并)。
它之所以选择复制这个函数,是因为当时还有一个正在进行的项目正在将交互式 rebase 从 shell 转换为 C,他们不想因为重构 apply_autostash()sequencer.c版本而与之冲突。
由于这两种努力都是长期的,我们现在可以自由地将它们结合在一起。


通过 Git 2.30(2021年第一季度) ,UI 得到了改进:

犯罪,第一季,第2集(2020年11月19日) by 约翰内斯 · 辛德林(dscho)
(由 朱尼奥 · C · 哈马诺 gitster提交290c940合并,2020年11月30日)

pull : 将关于设置 pull.rebase的提示着色

埃瓦尔 · 阿恩菲尔 · 比亚尔马森指出
签名: Johannes Schindelin

D18c950a69f(“ pull: 警告如果用户没有说是否重新基地或合并”,2020-03-09,Git v2.27.0-rc0—— 第二批中列出的 合并)中,引入了一个新的提示,以鼓励用户做出有意识的决定,他们是否希望他们的拉合并或重新基地通过配置 pull.rebase设置。

这个警告显然是为了给用户提供建议,但是正如在 这根线中指出的,它使用 warning()而不是 advise()

其中一个后果是,通知不会以与其他类似消息相同的方式着色。
因此,让我们改用 advise()


在 Git 2.33(Q32021)中,git pull --rebase被简化了:

犯罪犯罪现场调查,第一季,第2集提交3400622(2021年6月17日) by 费利佩 · 孔特雷拉斯(felipec)
(由 朱尼奥 · C · 哈马诺 gitster于2021年7月8日在 提交221C 24合并)

pull : 清理自动存储检查

签字人: Felipe 孔特雷拉斯

目前,“ git pull --rebase(< a href = “ https://git-scm.com/docs/git-pull # Documents/git-pull.txt-- rebasefalse% 7Ctrue% 7Cmerges% 7Creserve% 7C Interactive”rel = “ noReferrer”> man )在可能进行快进合并的情况下采用快捷方式; run_merge()仅用—— ff-only 调用。

但是,“ git merge(< a href = “ https://git-scm.com/docs/git-merge”rel = “ norefrer”> man )没有 --autostash选项,因此,当“ --rebase-自动隐藏(< a href = “ https://git-scm.com/docs/git-pull # Documents/git-pull.txt-- rebasefalse% 7Ctrue% 7Cmerges% 7Creserve% 7C Interactive”rel = “ noReferrer”> man )被称为 还有时,采用了快进合并快捷方式,然后拉取失败。

这在 犯罪,第十五季,第7集(“ pull: ff --rebase—— autostash works in Dirty repo”,2017-06-01,Git v2.14.0-rc0—— 第七批中列出的 合并)中通过简单地跳过快进合并快捷方式得到了修复。

后来,“ git merge”学习了 --autostash选项[ A03b555(“ merge: each --autostash option”,2020-04-07,Git v2.27.0-rc0—— 第五批中列出的 合并)] ,“ --autostash0”--autostash1[ --autostash2(“ pull: pass --autostash to merge”,2020-04-07,Git v2.27.0-rc0—— 第五批中列出的 合并)]。

因此,在使用 --rebase --autostash调用时,不再需要跳过快进合并快捷方式。

让我们总是采取快进合并快捷方式,实质上还原 F15e7cf


由“ git merge --autostash(< a href = “ https://git-scm.com/docs/git-merge # Document/git-merge.txt--autostash”rel = “ norefrer”> man )创建的自动隐藏的本地更改被混合到工作树中留下的冲突状态中,该状态已经用 Git 2.38(Q32022)进行了纠正。

提交 d3a9295(2022年8月23日) by Elijah Newren (newren)
(由 朱尼奥 · C · 哈马诺 gitster于2022年9月1日在 提交3a47790合并)

merge : 只在适当的时候应用自动存储

由 Elijah Newren 签名

如果合并失败,我们在工作目录中留下冲突让用户解决,我们不应该尝试应用任何自动隐藏。

此外,如果我们未能应用自动隐藏(因为合并失败,或者用户请求 --no-commit) ,那么我们应该指示用户以后如何应用它。

添加一个测试用例,验证我们已经纠正了这种行为。

新的指示:

完成后,使用 git stash pop应用隐藏的更改。

正如你已经提到的,这是做到这一点的方法。您可以在别名中使用它来保存您的输入并使用快捷方式,也可以在单行中使用它(也可以是别名)

git stash && git pull --rebase && git stash pop

它将做同样的事情,但在一个单一的行(& &) ,是你设置为别名,它甚至会更短。

下面的行将显示在拉/推之前传入/传出的更改

git log ^master origin/master
git log master ^origin/master

如上所述,设置两个配置值目前不适用于 git pull,因为 autostash 配置只适用于实际的 rebase。这些 git 命令可以完成您想要的任务:

git fetch
git rebase --autostash FETCH_HEAD

或者把它设成化名:

git config alias.pullr '!git fetch; git rebase --autostash FETCH_HEAD'

然后:

git pullr

当然,这个别名可以根据需要重命名。

使用 Git 2.6 + ,你可以使用以下代码:

alias gup='git -c rebase.autoStash=true pull --rebase'

这个 --rebase使 git-pull 使用 rebase而不是 merge,所以像 --ff-only这样的设置/选项不适用。

我使用一个别名来默认使用 --ff-only(git pull --ff-only) ,然后可以使用 gup(从上面) ,以防不可能进行快进合并或存在隐藏的更改。

为了给即将到来的探索者节省几秒钟时间,下面是一个总结(感谢@VonC) :

git pull --rebase --autostash

或者,如果希望将其设置为默认值(如 接受的答案中所记录的) ,

git config pull.rebase true
git config rebase.autoStash true

然后

git pull