Can “git pull” automatically stash and pop pending

2018-12-31 09:05发布

I know how to solve this:

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

But isn't there a way to let git pull do the stash and pop dance for me?

If this command has a different name, it's ok.

Creating a shell alias for git stash; git pull; git stash pop is a solution, but I search for a better solution.

5条回答
何处买醉
2楼-- · 2018-12-31 09:22

As you already mentioned this is the way to do it. You can use it in alias to save you typing and to use shortcut or you can use it in a single line (can be an alias as well)

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

It will do the same thing as you done but in a single line (&&) and is you set as alias it will even be shorter.

The following lines will display the incoming/outgoing changes before you pull/push

git log ^master origin/master
git log master ^origin/master
查看更多
听够珍惜
3楼-- · 2018-12-31 09:24

As the comment above stated, setting the two config values doesn't currently work with git pull, as the autostash config only applies to actual rebases. These git commands do what you want:

git fetch
git rebase --autostash FETCH_HEAD

Or set it as an alias:

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

Then do:

git pullr

Of course, this alias can be renamed as desired.

查看更多
还给你的自由
4楼-- · 2018-12-31 09:31

To save few seconds for oncoming explorers, here is a summary (thanks to @VonC):

git pull --rebase --autostash
查看更多
不流泪的眼
5楼-- · 2018-12-31 09:40

With Git 2.6+ you can use the following:

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

This --rebase makes git-pull use rebase instead of merge, so settings/options like --ff-only won't apply.

I am using an alias to pull with --ff-only by default (git pull --ff-only), and can then use gup (from above) in case a fast-forward merge is not possible or there are stashed changes.

查看更多
ら面具成の殇う
6楼-- · 2018-12-31 09:46

For Git 2.6+ (released 28 Sept 2015)

The only git config setting which would be of interest is:

rebase.autoStash

When set to true, automatically create a temporary stash before the operation begins, and apply it after the operation ends.
This means that you can run rebase on a dirty worktree.

However, use with care: the final stash application after a successful rebase might result in non-trivial conflicts. Defaults to false.

combine that with:

pull.rebase

When true, rebase branches on top of the fetched branch, instead of merging the default branch from the default remote when "git pull" is run.

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

That would be enough for a simple git pull to work even in a dirty tree.
No alias needed in that case.


See commit 53c76dc (04 Jul 2015) by Kevin Daudt (Ikke).
(Merged by Junio C Hamano -- gitster -- in commit e69b408, 17 Aug 2015)

pull: allow dirty tree when rebase.autostash enabled

rebase learned to stash changes when it encounters a dirty work tree, but git pull --rebase does not.

Only verify if the working tree is dirty when rebase.autostash is not enabled.


Note: if you want to pull without autostash (even though rebase.autoStash true is set), you have since git 2.9 (June 2016):

 pull --rebase --no-autostash

See commit 450dd1d, commit 1662297, commit 44a59ff, commit 5c82bcd, commit 6ddc97c, commit eff960b, commit efa195d (02 Apr 2016), and commit f66398e, commit c48d73b (21 Mar 2016) by Mehul Jain (mehul2029).
(Merged by Junio C Hamano -- gitster -- in commit 7c137bb, 13 Apr 2016)

Commit f66398e in particular includes:

pull --rebase: add --[no-]autostash flag

If rebase.autoStash configuration variable is set, there is no way to override it for "git pull --rebase" from the command line.

Teach "git pull --rebase" the --[no-]autostash command line flag which overrides the current value of rebase.autoStash, if set. As "git rebase" understands the --[no-]autostash option, it's just a matter of passing the option to underlying "git rebase" when "git pull --rebase" is called.


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

See commit f15e7cf (01 Jun 2017) by Tyler Brazier (tylerbrazier).
(Merged by Junio C Hamano -- gitster -- in commit 35898ea, 05 Jun 2017)

pull: ff --rebase --autostash works in dirty repo

When git pull --rebase --autostash in a dirty repository resulted in a fast-forward, nothing was being autostashed and the pull failed.
This was due to a shortcut to avoid running rebase when we can fast-forward, but autostash is ignored on that codepath.


Update: Mariusz Pawelski asks in the comments an interesting question:

So everybody is writing about autostash when you do rebase (or pull --rebase).

But no one is taking about autostashing when you do normal pull with merges.
So there is no automatic switch for that? Or I am missing something? I prefer doing git pull --rebase but OP asked about "standard" git pull

Answer:

The original thread discussing this autostash feature, it was implemented originally both for git pull (merge) and git pull --rebase.

But... Junio C Hamano (Git maintainer) noted that:

If the pull-merge were something that would induce the "annoyance" that triggered this topic, by definition, the local change overlaps with the merge, and this internal "stash pop" will touch the paths the merge touched and it is likely not result in "Dropped" but leave further conflicts to be resolved.

I suspect that pull.autostash configuration is not a good addition because it encourages a bad, pain-inducing workflow.
In simple cases it may not hurt, but when local changes are complex, it would actively hurt than not having it, and the configuration robs the incentive to choose.

The equation is somewhat different for "pull-rebase", as "rebase" insists you to start from a clean working tree, so "download and then stop" annoyance feels bigger. I have a suspicion that loosening that may be a more productive fix to the real problem.

So, regarding a classic pull-merge, it is better to:

encourage the user to think about the nature of WIP he has in the working tree before running "git pull".
Is it a too complex beast that may interfere with what others are doing, or is it a trivial change that he can stash away and pop it back?

If the former, he will be far better off doing "checkout -b", keep working until the local change gets into somewhat a better shape and "commit", before pulling into the original branch.

If the latter, he is better off doing:

  • "git pull",
  • after finding it conflicts, run
    • git stash,
    • git merge FETCH_HEAD and
    • git stash pop
查看更多
登录 后发表回答