🚀 OharaLumina

Can git pull automatically stash and pop pending changes

Can git pull automatically stash and pop pending changes

📅 | 📂 Category: Programming

Navigating the complexities of Git can sometimes feel like a delicate dance, especially when dealing with uncommitted local changes and the need to update your repository from a remote source. A common question among developers is, “Can git pull automatically stash and pop pending changes?” This query arises from the desire for a smoother, less interrupted workflow, where local modifications don’t block the integration of new updates. While the idea of Git intelligently managing your workspace sounds appealing, understanding its default behavior and the reasoning behind it is crucial for effective version control. This article will delve into how Git handles local changes during a pull operation, why it doesn’t automatically stash them, and the recommended best practices for managing your code with confidence and precision.

Understanding Git Pull and Local Modifications

The git pull command is fundamental for keeping your local repository synchronized with its remote counterpart. Essentially, it’s a two-step operation: first, it executes git fetch to retrieve new data from the remote repository, and then it runs git merge (or git rebase, depending on your configuration or flags) to integrate those changes into your current local branch. This process is designed to bring your local branch up to date, incorporating commits made by other developers.

However, when you have uncommitted changes in your working directory or staging area – often referred to as “pending changes” or “local modifications” – Git’s default behavior during a git pull operation is to err on the side of caution. If the incoming changes from the remote conflict with your local uncommitted work, Git will typically refuse to proceed. This protective mechanism prevents accidental loss or corruption of your ongoing work, ensuring that developers explicitly handle potential conflicts before integrating new code. This is a critical aspect of maintaining data integrity within a distributed version control system.

The rationale behind this design choice is rooted in Git’s philosophy of explicit control. Rather than making assumptions about what you intend to do with your local changes, Git prompts you to make a conscious decision. This might seem like an extra step, but it empowers developers to manage their local modifications responsibly, preventing situations where important work might be inadvertently overwritten or merged in an undesirable state. Many developers, when faced with this scenario, turn to git stash as their go-to command for temporarily saving their work.

Does Git Pull Automatically Stash and Pop?

No, by default, git pull does not automatically stash and pop pending changes. When you attempt to run git pull with uncommitted local modifications that conflict with incoming changes, Git will typically abort the operation and present an error message. This message usually indicates that your local changes would be overwritten by the merge or rebase, prompting you to either commit or stash your work before proceeding. This is a deliberate design choice to prevent accidental data loss and maintain the integrity of your codebase.

For instance, if you have modified files that are also affected by the remote changes, Git will output something similar to: “error: Your local changes to the following files would be overwritten by merge: [list of files]. Please commit your changes or stash them before you merge.” This explicit feedback from Git ensures that you, the developer, are fully aware of the potential impact of the pull operation and take appropriate action. While some developers might wish for a more automated approach, this manual step is a crucial safeguard in the developer workflow, especially in collaborative environments where merge conflicts are common.

This behavior reinforces the principle that explicit actions are preferred over implicit ones when it comes to managing code changes. While it might add an extra step to your routine, it ultimately gives you more control and prevents unexpected outcomes. According to a Git Best Practices guide from Atlassian, “Explicit actions like committing or stashing ensure that developers are always aware of their repository’s state and can make informed decisions about their changes.” This highlights the importance of understanding and utilizing Git’s manual tools rather than relying on non-existent automatic features.

Infographic here: A visual representation of the Git pull process with and without local modifications, illustrating when git stash is needed.
The Manual Workflow: Stashing and Pulling Effectively -----------------------------------------------------

Since git pull does not automatically handle local changes, the standard and recommended approach involves manually using git stash. This command temporarily saves your uncommitted modifications (both staged and unstaged) and reverts your working directory to the state of your last commit. It’s an indispensable tool for managing uncommitted changes when you need to switch branches, pull updates, or perform other Git operations without committing incomplete work.

Here’s the recommended workflow when you need to run git pull but have pending changes:

  1. Check your status: Before doing anything, always run git status to see your current changes. This helps you understand what you’re about to stash.
  2. Stash your changes: Execute git stash save "Description of my pending work". The message is optional but highly recommended for clarity, especially if you stash multiple times. This command saves your modifications onto a stack and cleans your working directory.
  3. Pull the latest changes: Now that your working directory is clean, run git pull. This will fetch and merge/rebase the remote changes into your local branch without conflicts related to your pending work.
  4. Reapply your stashed changes: Once the pull is complete, you can reapply your previously stashed changes using git stash pop. This command takes the most recent stash from the stack, applies it to your working directory, and then removes it from the stash list. If you had multiple stashes, you might use git stash apply followed by git stash drop, or specify a particular stash (e.g., git stash pop stash@{1}).
  5. Resolve any conflicts: After reapplying your stash, there might be new merge conflicts if the remote changes affected the same lines of code as your stashed modifications. You’ll need to resolve these conflicts manually, commit the resolution, and then continue your work.

This structured approach ensures that you maintain full control over your code, address conflicts explicitly, and avoid any accidental loss of work. For more advanced scenarios and further details on managing your stashes, the official Git documentation provides comprehensive guidance on git stash usage, including options for viewing multiple stashes and applying specific ones.

Exploring Alternatives and Advanced Configurations

While Git doesn’t offer a built-in “auto-stash-and-pull” command, developers often explore alternatives or custom configurations to streamline their developer workflow. One common approach is to use a specific Git configuration that automatically performs a rebase instead of a merge during a pull operation. By setting git config --global pull.rebase true, subsequent git pull commands will attempt a rebase. If you have local modifications that conflict with the rebase, Git will still stop and prompt you to handle them, but the overall rebase workflow can sometimes feel cleaner than a merge.

Another method involves creating custom Git aliases or shell scripts. For example, you could define an alias like git sap (stash and pull) that executes Question & Answer :

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.

For Git 2.6+ (released 28 Sept 2015)

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

rebase.autostash

(with Git 2.27, Q2 2020, you now also have merge.autostash, see below)

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.

In a given repository:

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

That being said, with Git 2.27 (Q2 2020), “git pull” learned to warn when no pull.rebase configuration exists, and neither --[no-]rebase nor --ff-only is given (which would result a merge).

See commit d18c950 (10 Mar 2020) by Alex Henrie (alexhenrie).
(Merged by Junio C Hamano – gitster in commit 1c56d6f, 27 Mar 2020)

pull: warn if the user didn’t say whether to rebase or to merge

Signed-off-by: Alex Henrie

Often novice Git users forget to say “pull --rebase” and end up with an unnecessary merge from upstream.

What they usually want is either “pull --rebase” in the simpler cases, or “pull --ff-only” to update the copy of main integration branches, and rebase their work separately.
The pull.rebase configuration variable exists to help them in the simpler cases, but there is no mechanism to make these users aware of it.

Issue a warning message when no --[no-]rebase option from the command line and no pull.rebase configuration variable is given.
This will inconvenience those who never want to “pull --rebase”, who haven’t had to do anything special, but the cost of the inconvenience is paid only once per user, which should be a reasonable cost to help a number of new users.


With Git 2.27 (Q2 2020), “git merge” learns the “--autostash” option, and the new merge.autostash setting.

See commit d9f15d3, commit f8a1785, commit a03b555, commit 804fe31, commit 12b6e13, commit 0dd562e, commit 0816f1d, commit 9bb3dea, commit 4d4bc15, commit b309a97, commit f213f06, commit 86ed00a, commit facca7f, commit be1bb60, commit efcf6cf, commit c20de8b, commit bfa50c2, commit 3442c3d, commit 5b2f6d9 (07 Apr 2020), commit 65c425a (04 Apr 2020), and commit fd6852c, commit 805d9ea (21 Mar 2020) by Denton Liu (Denton-L).
(Merged by Junio C Hamano – gitster in commit bf10200, 29 Apr 2020)

pull: pass –autostash to merge

Signed-off-by: Denton Liu

Before, --autostash only worked with git pull --rebase.

However, in the last patch, merge learned --autostash as well so there’s no reason why we should have this restriction anymore.
Teach pull to pass --autostash to merge, just like it did for rebase.

And:

rebase: use apply_autostash() from sequencer.c

Signed-off-by: Denton Liu

The apply_autostash() function in builtin/rebase.c is similar enough to the apply_autostash() function in sequencer.c that they are almost interchangeable, except for the type of arg they accept. Make the sequencer.c version extern and use it in rebase.

The rebase version was introduced in 6defce2b02 (“builtin rebase: support --autostash option”, 2018-09-04, Git v2.20.0-rc0 – merge listed in batch #8) as part of the shell to C conversion.
It opted to duplicate the function because, at the time, there was another in-progress project converting interactive rebase from shell to C as well and they did not want to clash with them by refactoring sequencer.c version of apply_autostash().
Since both efforts are long done, we can freely combine them together now.


With Git 2.30 (Q1 2021), the UI is improved:

See commit e01ae2a (19 Nov 2020) by Johannes Schindelin (dscho).
(Merged by Junio C Hamano – gitster in commit 290c940, 30 Nov 2020)

pull: colorize the hint about setting pull.rebase

Pointed-out-by: Ævar Arnfjörð Bjarmason
Signed-off-by: Johannes Schindelin

In d18c950a69f ("pull: warn if the user didn’t say whether to rebase or to merge", 2020-03-09, Git v2.27.0-rc0 – merge listed in batch #2), a new hint was introduced to encourage users to make a conscious decision about whether they want their pull to merge or to rebase by configuring the pull.rebase setting.

This warning was clearly intended to advise users, but as pointed out in this thread, it uses warning() instead of advise().

One consequence is that the advice is not colorized in the same manner as other, similar messages.
So let’s use advise() instead.


With Git 2.33 (Q3 2021), git pull --rebase is simplified:

See commit a7d18a1, commit a751e02, commit 3400622 (17 Jun 2021) by Felipe Contreras (felipec).
(Merged by Junio C Hamano – gitster in commit 221ec24, 08 Jul 2021)

pull: cleanup autostash check

Signed-off-by: Felipe Contreras

Currently “git pull --rebase"(man) takes a shortcut in the case a fast-forward merge is possible; run_merge() is called with –ff-only.

However, “git merge"(man) did ont have an --autostash option, so, when “git pull --rebase –autostash``"(man) was called and the fast-forward merge shortcut was taken, then the pull failed.

This was fixed in commit f15e7cf ("pull: ff --rebase –autostash works in dirty repo”, 2017-06-01, Git v2.14.0-rc0 – merge listed in batch #7) by simply skipping the fast-forward merge shortcut.

Later on “git merge” learned the --autostash option [a03b555 ("merge: teach --autostash option”, 2020-04-07, Git v2.27.0-rc0 – merge listed in batch #5)], and so did “git pull"(man) [d9f15d3 ("pull: pass --autostash to merge”, 2020-04-07, Git v2.27.0-rc0 – merge listed in batch #5)].

Therefore it’s not necessary to skip the fast-forward merge shortcut anymore when called with --rebase --autostash.

Let’s always take the fast-forward merge shortcut by essentially reverting f15e7cf.


The auto-stashed local changes created by “git merge --autostash"(man) was mixed into a conflicted state left in the working tree, which has been corrected with Git 2.38 (Q3 2022).

See commit d3a9295 (23 Aug 2022) by Elijah Newren (newren).
(Merged by Junio C Hamano – gitster in commit 3a47790, 01 Sep 2022)

merge: only apply autostash when appropriate

Signed-off-by: Elijah Newren

If a merge failed and we are leaving conflicts in the working directory for the user to resolve, we should not attempt to apply any autostash.

Further, if we fail to apply the autostash (because either the merge failed, or the user requested --no-commit), then we should instruct the user how to apply it later.

Add a testcase verifying we have corrected this behavior.

The new instructions:

When finished, apply stashed changes with git stash pop.