{"thread":{"id":"63795","subject":"[BUG] git pull ignores pull.autostash=true configuration when used with --git-dir and --work-tree flags on a bare repository","startedAt":"2025-07-15T03:26:47Z","lastAt":"2025-07-21T22:10:26Z","messageCount":23,"participants":["Bryan Lee","Lidong Yan","Junio C Hamano","Johannes Sixt","Eric Sunshine","Ben Knoble"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"521936","messageId":"010001980c1ee007-2797fc86-fdf3-46e9-bec9-f8da2c9ebb8d-000000@email.amazonses.com","threadId":"63795","inReplyTo":null,"subject":"[BUG] git pull ignores pull.autostash=true configuration when used with --git-dir and --work-tree flags on a bare repository","fromName":"Bryan Lee","fromEmail":"hi@looping.me","sentAt":"2025-07-15T03:26:46Z","receivedAt":"2025-07-15T03:26:47Z","isPatch":false,"sender":{"key":"hi@looping.me","avatar":null},"body":"What did you do before the bug happened? (Steps to reproduce your issue)\n\nI am using a bare Git repository to manage my dotfiles, following a\ncommon pattern where the Git directory is separate from the work tree.\nHere are the exact steps to reproduce the issue:\n\n1. Create a bare repository and set up the alias:\n   $ git init --bare $HOME/.dotfiles\n   Initialized empty Git repository in /Users/bryan/.dotfiles/\n\n   $ alias dot='git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME'\n\n2. Add a remote and create initial tracked file:\n   $ dot remote add origin git@github.com:username/dotfiles.git\n\n   $ echo \"# My dotfiles\" > $HOME/README.md\n   $ dot add $HOME/README.md\n   $ dot commit -m \"Initial commit\"\n   [main (root-commit) abc1234] Initial commit\n    1 file changed, 1 insertion(+)\n    create mode 100644 README.md\n\n   $ dot push -u origin main\n   Branch 'main' set up to track remote branch 'main' from 'origin'.\n\n3. Set global Git configuration for automatic rebasing and stashing:\n   $ git config --global pull.rebase true\n   $ git config --global pull.autostash true\n\n   Verify the configuration is set:\n   $ git config --global pull.rebase\n   true\n   $ git config --global pull.autostash\n   true\n\n4. Simulate a remote change (on another machine or via GitHub web interface):\n   - Edit README.md on remote to add a line: \"Updated from remote\"\n   - This creates a divergence between local and remote\n\n5. Make local unstaged changes:\n   $ echo \"Local change\" >> $HOME/.zshrc\n\n   Verify there are unstaged changes:\n   $ dot status\n   On branch main\n   Changes not staged for commit:\n     (use \"git add <file>...\" to update what will be committed)\n     (use \"git restore <file>...\" to discard changes in working directory)\n    modified:   .zshrc\n\n   no changes added to commit (use \"git add\" and/or \"git commit -a\")\n\n6. Attempt to pull the remote changes:\n   $ dot pull\n   error: cannot pull with rebase: You have unstaged changes.\n   error: Please commit or stash them.\n\nWhat did you expect to happen? (Expected behavior)\n\nSince I have configured pull.autostash=true globally, I expected Git to:\n\n1. Automatically create a stash of my unstaged changes (the modified\n.zshrc file)\n2. Pull the remote changes with rebase (as configured by pull.rebase=true)\n3. Apply the stash after the pull completes successfully\n4. Show output similar to:\n   Created autostash: abc2345\n   First, rewinding head to replay your work on top of it...\n   Fast-forwarded main to origin/main.\n   Applied autostash.\n\nThis is the behavior I get when using Git in a regular (non-bare)\nrepository with the same configuration.\n\nWhat happened instead? (Actual behavior)\n\nGit immediately fails with an error message:\nerror: cannot pull with rebase: You have unstaged changes.\nerror: Please commit or stash them.\n\nThe command exits with status code 1 and does not perform any stashing\nor pulling.\n\nWhat's different between what you expected and what actually happened?\n\nThe difference is that Git is not honoring the pull.autostash=true\nconfiguration when the repository is accessed using --git-dir and\n--work-tree flags. The autostash feature is completely ignored, and\nGit behaves as if pull.autostash=false.\n\nTo confirm this is specific to the --git-dir/--work-tree usage\npattern, I tested the following workarounds:\n\n1. Explicit --autostash flag works:\n   $ dot pull --rebase --autostash\n   Created autostash: def3456\n   Current branch main is up to date.\n   Applied autostash.\n\n2. The same configuration works in a regular repository:\n   $ cd /tmp/test-repo\n   $ git init\n   $ git config pull.rebase true\n   $ git config pull.autostash true\n   $ echo \"test\" > file.txt\n   $ git add file.txt\n   $ git commit -m \"test\"\n   $ echo \"change\" >> file.txt\n   $ git pull origin main  # This would autostash as expected\n\nAdditional diagnostic information:\n\n1. The configuration is properly loaded by Git:\n   $ dot config --show-origin pull.autostash\n   file:/Users/bryan/.config/git/config true\n\n   $ dot config --show-origin pull.rebase\n   file:/Users/bryan/.config/git/config true\n\n2. Even setting the configuration directly in the bare repository doesn't help:\n   $ dot config pull.autostash true\n   $ dot config pull.rebase true\n   $ cat $HOME/.dotfiles/config | grep -A2 \"\\[pull\\]\"\n   [pull]\n    rebase = true\n    autostash = true\n\n   $ dot pull\n   error: cannot pull with rebase: You have unstaged changes.\n   error: Please commit or stash them.\n\n3. Using -c flag to override configuration inline also fails:\n   $ git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME -c\npull.autostash=true pull\n   error: cannot pull with rebase: You have unstaged changes.\n   error: Please commit or stash them.\n\n4. GIT_TRACE output shows the pull command is executed but autostash\nis not attempted:\n   $ GIT_TRACE=1 dot pull 2>&1 | head -5\n   11:09:57.474770 git.c:476               trace: built-in: git pull\n   error: cannot pull with rebase: You have unstaged changes.\n   error: Please commit or stash them.\n\nThis appears to be a bug where the autostash functionality is bypassed\nwhen Git is invoked with --git-dir and --work-tree flags, possibly\nbecause the work tree context is not properly established when the\nautostash check occurs.\n\n[System Info]\ngit version:\ngit version 2.50.1\ncpu: arm64\nno commit associated with this build\nsizeof-long: 8\nsizeof-size_t: 8\nshell-path: /bin/sh\nfeature: fsmonitor--daemon\nlibcurl: 8.7.1\nzlib: 1.2.12\nSHA-1: SHA1_DC\nSHA-256: SHA256_BLK\nuname: Darwin 24.5.0 Darwin Kernel Version 24.5.0: Tue Apr 22 19:54:29\nPDT 2025; root:xnu-11417.121.6~2/RELEASE_ARM64_T6030 arm64\ncompiler info: clang: 17.0.0 (clang-1700.0.13.3)\nlibc info: no libc information available\n$SHELL (typically, interactive shell): /bin/zsh\n"},{"id":"521937","messageId":"BCD357B1-39B1-4B00-BEB2-EF2C20A0E4AF@gmail.com","threadId":"63795","inReplyTo":"010001980c1ee007-2797fc86-fdf3-46e9-bec9-f8da2c9ebb8d-000000@email.amazonses.com","subject":"Re: [BUG] git pull ignores pull.autostash=true configuration when used with --git-dir and --work-tree flags on a bare repository","fromName":"Lidong Yan","fromEmail":"yldhome2d2@gmail.com","sentAt":"2025-07-15T04:09:21Z","receivedAt":"2025-07-15T04:09:36Z","isPatch":false,"sender":{"key":"yldhome2d2@gmail.com","avatar":"https://avatars.githubusercontent.com/u/77328395?v=4"},"body":"Bryan Lee <hi@looping.me> wrote:\n> \n> 3. Set global Git configuration for automatic rebasing and stashing:\n>   $ git config --global pull.rebase true\n>   $ git config --global pull.autostash true\n> \n>   Verify the configuration is set:\n>   $ git config --global pull.rebase\n>   true\n>   $ git config --global pull.autostash\n>   true\n\nMaybe you can try `git config rebase.autostash true` instead.\n\n> The difference is that Git is not honoring the pull.autostash=true\n> configuration when the repository is accessed using --git-dir and\n> --work-tree flags. The autostash feature is completely ignored, and\n> Git behaves as if pull.autostash=false.\n\nI’m not sure why this difference happens either.\n\n- Lidong"},{"id":"521939","messageId":"010001980c90be52-f49c4b4b-36b2-4826-86b8-bd524604be30-000000@email.amazonses.com","threadId":"63795","inReplyTo":"BCD357B1-39B1-4B00-BEB2-EF2C20A0E4AF@gmail.com","subject":"Re: [BUG] git pull ignores pull.autostash=true configuration when used with --git-dir and --work-tree flags on a bare repository","fromName":"Bryan Lee","fromEmail":"hi@looping.me","sentAt":"2025-07-15T05:31:09Z","receivedAt":"2025-07-15T05:31:10Z","isPatch":false,"sender":{"key":"hi@looping.me","avatar":null},"body":"Lidong Yan <yldhome2d2@gmail.com> wrote:\n> Maybe you can try `git config rebase.autostash true` instead.\n\nThank you! You're absolutely right. After testing, I can confirm that:\n\n1. `pull.autostash` is not a real Git configuration option - it has no\neffect whatsoever\n2. The correct configuration is `rebase.autoStash=true` (for rebase operations)\n3. This issue is not specific to bare repositories - it happens in\nregular repos too\n\nHere's my test in a regular (non-bare) repository that proves this:\n\n```\n$ git config --global pull.autostash true\n$ git config --global pull.rebase true\n$ echo \"test\" >> README.md  # create unstaged changes\n$ git pull\nerror: cannot pull with rebase: You have unstaged changes.\nerror: Please commit or stash them.\n\n$ git config --global rebase.autostash true\n$ git pull\nUpdating 9571176..5125236\nCreated autostash: 9ad0490\nFast-forward\n[... changes ...]\nApplied autostash.\n```\n\nThis raises an important issue: Git silently accepts invalid\nconfiguration keys without any warning. Users can waste significant\ntime debugging \"why isn't my configuration working?\" when the\nconfiguration key doesn't even exist.\n\nWould it be worthwhile to:\n1. Add a warning when users set non-existent configuration keys?\n2. Or at least document common misconceptions like `pull.autostash` in\nthe git-config man page?\n\nThanks again for pointing me in the right direction!\n\nOn Tue, Jul 15, 2025 at 12:09 PM Lidong Yan <yldhome2d2@gmail.com> wrote:\n>\n> Bryan Lee <hi@looping.me> wrote:\n> >\n> > 3. Set global Git configuration for automatic rebasing and stashing:\n> >   $ git config --global pull.rebase true\n> >   $ git config --global pull.autostash true\n> >\n> >   Verify the configuration is set:\n> >   $ git config --global pull.rebase\n> >   true\n> >   $ git config --global pull.autostash\n> >   true\n>\n> Maybe you can try `git config rebase.autostash true` instead.\n>\n> > The difference is that Git is not honoring the pull.autostash=true\n> > configuration when the repository is accessed using --git-dir and\n> > --work-tree flags. The autostash feature is completely ignored, and\n> > Git behaves as if pull.autostash=false.\n>\n> I’m not sure why this difference happens either.\n>\n> - Lidong\n"},{"id":"521940","messageId":"010001980c90be66-2401a0b0-5c86-4135-90e2-c325852ef168-000000@email.amazonses.com","threadId":"63795","inReplyTo":"BCD357B1-39B1-4B00-BEB2-EF2C20A0E4AF@gmail.com","subject":"Re: [BUG] git pull ignores pull.autostash=true configuration when used with --git-dir and --work-tree flags on a bare repository","fromName":"Bryan Lee","fromEmail":"hi@looping.me","sentAt":"2025-07-15T05:31:09Z","receivedAt":"2025-07-15T05:31:10Z","isPatch":false,"sender":{"key":"hi@looping.me","avatar":null},"body":"Lidong Yan <yldhome2d2@gmail.com> wrote:\n> Maybe you can try `git config rebase.autostash true` instead.\n\nThank you! You're absolutely right. After testing, I can confirm that:\n\n1. `pull.autostash` is not a real Git configuration option - it has no\neffect whatsoever\n2. The correct configuration is `rebase.autoStash=true` (for rebase operations)\n3. This issue is not specific to bare repositories - it happens in\nregular repos too\n\nHere's my test in a regular (non-bare) repository that proves this:\n\n```\n$ git config --global pull.autostash true\n$ git config --global pull.rebase true\n$ echo \"test\" >> README.md  # create unstaged changes\n$ git pull\nerror: cannot pull with rebase: You have unstaged changes.\nerror: Please commit or stash them.\n\n$ git config --global rebase.autostash true\n$ git pull\nUpdating 9571176..5125236\nCreated autostash: 9ad0490\nFast-forward\n[... changes ...]\nApplied autostash.\n```\n\nThis raises an important issue: Git silently accepts invalid\nconfiguration keys without any warning. Users can waste significant\ntime debugging \"why isn't my configuration working?\" when the\nconfiguration key doesn't even exist.\n\nWould it be worthwhile to:\n1. Add a warning when users set non-existent configuration keys?\n2. Or at least document common misconceptions like `pull.autostash` in\nthe git-config man page?\n\nThanks again for pointing me in the right direction!\n\nOn Tue, Jul 15, 2025 at 12:09 PM Lidong Yan <yldhome2d2@gmail.com> wrote:\n>\n> Bryan Lee <hi@looping.me> wrote:\n> >\n> > 3. Set global Git configuration for automatic rebasing and stashing:\n> >   $ git config --global pull.rebase true\n> >   $ git config --global pull.autostash true\n> >\n> >   Verify the configuration is set:\n> >   $ git config --global pull.rebase\n> >   true\n> >   $ git config --global pull.autostash\n> >   true\n>\n> Maybe you can try `git config rebase.autostash true` instead.\n>\n> > The difference is that Git is not honoring the pull.autostash=true\n> > configuration when the repository is accessed using --git-dir and\n> > --work-tree flags. The autostash feature is completely ignored, and\n> > Git behaves as if pull.autostash=false.\n>\n> I’m not sure why this difference happens either.\n>\n> - Lidong\n"},{"id":"522005","messageId":"1AD9A170-8E17-411D-A13B-EA7780CF4D39@gmail.com","threadId":"63795","inReplyTo":"010001980c90be66-2401a0b0-5c86-4135-90e2-c325852ef168-000000@email.amazonses.com","subject":"Re: [BUG] git pull ignores pull.autostash=true configuration when used with --git-dir and --work-tree flags on a bare repository","fromName":"Lidong Yan","fromEmail":"yldhome2d2@gmail.com","sentAt":"2025-07-15T15:02:36Z","receivedAt":"2025-07-15T15:02:49Z","isPatch":false,"sender":{"key":"yldhome2d2@gmail.com","avatar":"https://avatars.githubusercontent.com/u/77328395?v=4"},"body":"Bryan Lee <hi@looping.me> wrote:\n> \n> Would it be worthwhile to:\n> 1. Add a warning when users set non-existent configuration keys?\n> 2. Or at least document common misconceptions like `pull.autostash` in\n> the git-config man page?\n\nI think adding a subcommand like ‘git config verify’ might be a way to\nsolve this problem.\n\n- Lidong\n\n"},{"id":"522042","messageId":"xmqqa555gp1i.fsf@gitster.g","threadId":"63795","inReplyTo":"1AD9A170-8E17-411D-A13B-EA7780CF4D39@gmail.com","subject":"Re: [BUG] git pull ignores pull.autostash=true configuration when used with --git-dir and --work-tree flags on a bare repository","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-07-15T20:46:49Z","receivedAt":"2025-07-15T20:46:53Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Lidong Yan <yldhome2d2@gmail.com> writes:\n\n> Bryan Lee <hi@looping.me> wrote:\n>> \n>> Would it be worthwhile to:\n>> 1. Add a warning when users set non-existent configuration keys?\n>> 2. Or at least document common misconceptions like `pull.autostash` in\n>> the git-config man page?\n>\n> I think adding a subcommand like ‘git config verify’ might be a way to\n> solve this problem.\n\nYes, but I do not know if it is feasible.\n\nThere always are end-user or third-party defined keys that are not\nknown to us, and we cannot tell if an unknown variable is such a\nend-user defined one or a typo of a known one.\n\n"},{"id":"522061","messageId":"6AEC3113-D687-42E0-B6D0-DF62FA1A9A8B@gmail.com","threadId":"63795","inReplyTo":"xmqqa555gp1i.fsf@gitster.g","subject":"Re: [BUG] git pull ignores pull.autostash=true configuration when used with --git-dir and --work-tree flags on a bare repository","fromName":"Lidong Yan","fromEmail":"yldhome2d2@gmail.com","sentAt":"2025-07-16T01:39:53Z","receivedAt":"2025-07-16T01:40:06Z","isPatch":false,"sender":{"key":"yldhome2d2@gmail.com","avatar":"https://avatars.githubusercontent.com/u/77328395?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n> \n> Lidong Yan <yldhome2d2@gmail.com> writes:\n> \n>> Bryan Lee <hi@looping.me> wrote:\n>>> \n>>> Would it be worthwhile to:\n>>> 1. Add a warning when users set non-existent configuration keys?\n>>> 2. Or at least document common misconceptions like `pull.autostash` in\n>>> the git-config man page?\n>> \n>> I think adding a subcommand like ‘git config verify’ might be a way to\n>> solve this problem.\n> \n> Yes, but I do not know if it is feasible.\n> \n> There always are end-user or third-party defined keys that are not\n> known to us, and we cannot tell if an unknown variable is such a\n> end-user defined one or a typo of a known one.\n\nFor every git_xxx_config(), we could add a register function like\ngit_xxx_config_register(), which looks like:\n\n  int git_xxx_config_register()\n  {\n    struct key_ent ent;\n\n    register_bool_key(\"key1\");\n    register_int_key(\"key2”);\n    register_date_key(\"key3”);\n\n    ent.key = “key4”;\n    ent.desp = “key4_desp\";\n    ent.verify_fn = &verify_key4_value;\n    register_key(ent);\n  }\n\n\nAnd then end-user could define their own register function as well\nso that they could also use `git config verify` to verify their own config\n<key, value>.\n\nOr end-user could provide a .gitconfigspec and `git config verify` will\nload .gitconfigspec to verify whether there exists some invalid config\n<k, v> pair.\n\n- Lidong"},{"id":"522073","messageId":"26cef1b9-1f17-447e-b647-3d32a3984997@kdbg.org","threadId":"63795","inReplyTo":"6AEC3113-D687-42E0-B6D0-DF62FA1A9A8B@gmail.com","subject":"Re: [BUG] git pull ignores pull.autostash=true configuration when used with --git-dir and --work-tree flags on a bare repository","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2025-07-16T05:55:34Z","receivedAt":"2025-07-16T05:55:46Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 16.07.25 um 03:39 schrieb Lidong Yan:\n> Junio C Hamano <gitster@pobox.com> writes:\n>> Lidong Yan <yldhome2d2@gmail.com> writes:\n>>> Bryan Lee <hi@looping.me> wrote:\n>>>> 2. Or at least document common misconceptions like `pull.autostash` in\n>>>> the git-config man page?\n\n>> There always are end-user or third-party defined keys that are not\n>> known to us, and we cannot tell if an unknown variable is such a\n>> end-user defined one or a typo of a known one.\n> \n> For every git_xxx_config(), we could add a register function like\n> git_xxx_config_register(), which looks like:\n\nInstead of this complexity, it is most likely a lot easier to fix the\norigin of the misconception that `pull.autostash` is the correct\nconfiguration. After all, it isn't even mentioned in the git-config nor\nthe git-pull man page.\n\n-- Hannes\n\n"},{"id":"522093","messageId":"ECF947E6-06DE-425D-B1FE-A4DA67F60834@gmail.com","threadId":"63795","inReplyTo":"26cef1b9-1f17-447e-b647-3d32a3984997@kdbg.org","subject":"Re: [BUG] git pull ignores pull.autostash=true configuration when used with --git-dir and --work-tree flags on a bare repository","fromName":"Lidong Yan","fromEmail":"yldhome2d2@gmail.com","sentAt":"2025-07-16T11:20:53Z","receivedAt":"2025-07-16T11:21:08Z","isPatch":false,"sender":{"key":"yldhome2d2@gmail.com","avatar":"https://avatars.githubusercontent.com/u/77328395?v=4"},"body":"Johannes Sixt <j6t@kdbg.org> write:\n> \n> Instead of this complexity, it is most likely a lot easier to fix the\n> origin of the misconception that `pull.autostash` is the correct\n> configuration. After all, it isn't even mentioned in the git-config nor\n> the git-pull man page.\n\nYes, update the document is the more important thing.\n\n- Lidong\n"},{"id":"522113","messageId":"xmqq5xfsdv3w.fsf@gitster.g","threadId":"63795","inReplyTo":"26cef1b9-1f17-447e-b647-3d32a3984997@kdbg.org","subject":"Re: [BUG] git pull ignores pull.autostash=true configuration when used with --git-dir and --work-tree flags on a bare repository","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-07-16T15:16:19Z","receivedAt":"2025-07-16T15:16:22Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j6t@kdbg.org> writes:\n\n> Instead of this complexity, it is most likely a lot easier to fix the\n> origin of the misconception that `pull.autostash` is the correct\n> configuration. After all, it isn't even mentioned in the git-config nor\n> the git-pull man page.\n\ngit_pull_config() does pay attention to \"rebase.autostash\".  \n\nEither it is a bug for the code to do so, or it is a bug that the\ndocumentation does not talk about it.  \n\nThe reason why I think \"git pull\" that pays attention to\nrebase.autostash is a bug is because the user is more likely to be\nmuch more familiar with both branches involved and more likely to be\nprepared to deal with conflicts potentially created by autostashing\nbehaviour when making a private merge or rebase of local branches,\nthan when pulling from other repositories.  So those who show\nwillingness to accept the responsibility of having to resolve\nconflicts that arise when popping autostashed changes by setting\nrebase.autostash may not want to be cavalier to the same degree when\nrunning \"git pull\".  git_pull_config() that pays attention to\n\"rebase.autostash\" breaks that expectation.\n\nThere is another curiosity.  git_pull_config() does not pay\nattention to \"merge.autostash\", which seems inconsistent.\n\nIf I did not have any existing users, I would actually vote to teach\ngit_pull_config() stop paying attention to \"rebase.autostash\", but\nwe do not live in an ideal world.  Perhaps rectify this at Git 3.0?\n\nWe could give a convenience feature in the opposite direction as\nwell.\n\nIt is not inconceivable for the git_pull_config() function to\npretend as if rebase.autostash (when pull.rebase is true) or\nmerge.autostash (otherwise) is set to true when pull.autostash is\nset to true.  It would have prevented this discussion thread from\nhappening.\n\nI personally think that such an arrangement is backwards, though,\nfor the same reason why I think git_pull_config() should not pay\nattention to \"rebase.autostash\".  So I am not sure if a new\n\"pull.autostash\" variable is such a good idea to begin with.\n\n\n"},{"id":"522146","messageId":"20250717030732.75106-1-yldhome2d2@gmail.com","threadId":"63795","inReplyTo":"xmqq5xfsdv3w.fsf@gitster.g","subject":"[PATCH] pull: add pull.autoStash config option","fromName":"Lidong Yan","fromEmail":"yldhome2d2@gmail.com","sentAt":"2025-07-17T03:07:32Z","receivedAt":"2025-07-17T03:07:47Z","isPatch":true,"sender":{"key":"yldhome2d2@gmail.com","avatar":"https://avatars.githubusercontent.com/u/77328395?v=4"},"body":"Git uses the `rebase.autoStash` option to decide if git-pull is allowed\nwhen the working tree has uncommitted changes. However, since the\ndocumentation does not explicitly state this, users may find it difficult\nto associate `rebase.autoStash` with the git-pull command. Add\n`pull.autoStash` option along with its documentation.\n\n`pull.autoStash` provides the same functionality as `rebase.autoStash`\nbut is more user-friendly because its prefix clearly associates it\nwith git-pull commands. Additionally, when both options are set,\n`pull.autoStash` takes precedence and overrides the value of\n`rebase.autoStash`.\n\nSigned-off-by: Lidong Yan <yldhome2d2@gmail.com>\n---\n Documentation/config/pull.adoc |  9 +++++++++\n builtin/pull.c                 | 10 +++++++---\n 2 files changed, 16 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/config/pull.adoc b/Documentation/config/pull.adoc\nindex 9349e09261..da9686dbd2 100644\n--- a/Documentation/config/pull.adoc\n+++ b/Documentation/config/pull.adoc\n@@ -13,6 +13,15 @@ pull.rebase::\n \tof merging the default branch from the default remote when \"git\n \tpull\" is run. See \"branch.<name>.rebase\" for setting this on a\n \tper-branch basis.\n+\n+pull.autoStash::\n+\tWhen true, Git will automatically perform a `git stash` before the\n+\toperation and then restore the local changes with `git stash pop`\n+\tafter the merge or rebase is complete. This means that you can run\n+\tpull on a dirty worktree. Noticed that `rebase.autoStash` provides\n+\tthe same functionality, but `pull.autoStash` overrides its behavior\n+\twhen both are set. This option can be overridden by the `--no-autostash`\n+\tand `--autostash` options of linkgit:git-pull[1]. Defaults to false.\n +\n When `merges` (or just 'm'), pass the `--rebase-merges` option to 'git rebase'\n so that the local merge commits are included in the rebase (see\ndiff --git a/builtin/pull.c b/builtin/pull.c\nindex c593f324fe..dfc3d4656b 100644\n--- a/builtin/pull.c\n+++ b/builtin/pull.c\n@@ -90,7 +90,8 @@ static char *opt_ff;\n static const char *opt_verify_signatures;\n static const char *opt_verify;\n static int opt_autostash = -1;\n-static int config_autostash;\n+static int config_rebase_autostash;\n+static int config_pull_autostash = -1;\n static int check_trust_level = 1;\n static struct strvec opt_strategies = STRVEC_INIT;\n static struct strvec opt_strategy_opts = STRVEC_INIT;\n@@ -367,7 +368,10 @@ static int git_pull_config(const char *var, const char *value,\n \t\t\t   const struct config_context *ctx, void *cb)\n {\n \tif (!strcmp(var, \"rebase.autostash\")) {\n-\t\tconfig_autostash = git_config_bool(var, value);\n+\t\tconfig_rebase_autostash = git_config_bool(var, value);\n+\t\treturn 0;\n+\t} else if (!strcmp(var, \"pull.autostash\")) {\n+\t\tconfig_pull_autostash = git_config_bool(var, value);\n \t\treturn 0;\n \t} else if (!strcmp(var, \"submodule.recurse\")) {\n \t\trecurse_submodules = git_config_bool(var, value) ?\n@@ -1052,7 +1056,7 @@ int cmd_pull(int argc,\n \n \tif (opt_rebase) {\n \t\tif (opt_autostash == -1)\n-\t\t\topt_autostash = config_autostash;\n+\t\t\topt_autostash = config_pull_autostash == -1 ? config_rebase_autostash : config_pull_autostash;\n \n \t\tif (is_null_oid(&orig_head) && !is_index_unborn(the_repository->index))\n \t\t\tdie(_(\"Updating an unborn branch with changes added to the index.\"));\n-- \n2.39.5 (Apple Git-154)\n\n"},{"id":"522147","messageId":"CAPig+cTQ017qGK_Qx04+R_0rCXEOirW+oLEjeaDoCFJiQbnsGw@mail.gmail.com","threadId":"63795","inReplyTo":"20250717030732.75106-1-yldhome2d2@gmail.com","subject":"Re: [PATCH] pull: add pull.autoStash config option","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2025-07-17T03:27:57Z","receivedAt":"2025-07-17T03:28:10Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Jul 16, 2025 at 11:07 PM Lidong Yan <yldhome2d2@gmail.com> wrote:\n> Git uses the `rebase.autoStash` option to decide if git-pull is allowed\n> when the working tree has uncommitted changes. However, since the\n> documentation does not explicitly state this, users may find it difficult\n> to associate `rebase.autoStash` with the git-pull command. Add\n> `pull.autoStash` option along with its documentation.\n\nI have no opinion as to whether this is a good path forward.\n\n> `pull.autoStash` provides the same functionality as `rebase.autoStash`\n> but is more user-friendly because its prefix clearly associates it\n> with git-pull commands.\n\nRather than \"user-friendly\", perhaps a better way to phrase it would\nbe to say that `pull.autoStash` is more *discoverable*.\n\n> Additionally, when both options are set,\n> `pull.autoStash` takes precedence and overrides the value of\n> `rebase.autoStash`.\n\nThis was a question which immediately popped into my head, so it's\nnice to see that you considered it and discussed it in the commit\nmessage.\n\n> Signed-off-by: Lidong Yan <yldhome2d2@gmail.com>\n> ---\n>  Documentation/config/pull.adoc |  9 +++++++++\n>  builtin/pull.c                 | 10 +++++++---\n>  2 files changed, 16 insertions(+), 3 deletions(-)\n\nYou will want to add one or more new tests to a test script to verify\nthat this new configuration works as expected, and probably also to\nverify that `pull.autoStash` takes precedence over `rebase.autoStash`.\n\n> diff --git a/Documentation/config/pull.adoc b/Documentation/config/pull.adoc\n> @@ -13,6 +13,15 @@ pull.rebase::\n> +pull.autoStash::\n> +       When true, Git will automatically perform a `git stash` before the\n> +       operation and then restore the local changes with `git stash pop`\n> +       after the merge or rebase is complete. This means that you can run\n\nI wonder if you meant \"pull\" instead of \"merge or rebase\".\n\n> +       pull on a dirty worktree. Noticed that `rebase.autoStash` provides\n\ns/Noticed/Notice/\n\n> +       the same functionality, but `pull.autoStash` overrides its behavior\n\nRather: \"...same functionality as `pull.autoStash` but overrides the\nlatter when...\"\n\n> +       when both are set. This option can be overridden by the `--no-autostash`\n> +       and `--autostash` options of linkgit:git-pull[1]. Defaults to false.\n> diff --git a/builtin/pull.c b/builtin/pull.c\n> @@ -1052,7 +1056,7 @@ int cmd_pull(int argc,\n>         if (opt_rebase) {\n>                 if (opt_autostash == -1)\n> -                       opt_autostash = config_autostash;\n> +                       opt_autostash = config_pull_autostash == -1 ? config_rebase_autostash : config_pull_autostash;\n\nYou may want to wrap this over-long line. Perhaps:\n\n    opt_autostash = config_pull_autostash == -1 ?\n        config_rebase_autostash : config_pull_autostash;\n"},{"id":"522148","messageId":"78DFE806-5DAC-4A90-893B-77F32E393E07@gmail.com","threadId":"63795","inReplyTo":"CAPig+cTQ017qGK_Qx04+R_0rCXEOirW+oLEjeaDoCFJiQbnsGw@mail.gmail.com","subject":"Re: [PATCH] pull: add pull.autoStash config option","fromName":"Lidong Yan","fromEmail":"yldhome2d2@gmail.com","sentAt":"2025-07-17T04:09:48Z","receivedAt":"2025-07-17T04:10:02Z","isPatch":true,"sender":{"key":"yldhome2d2@gmail.com","avatar":"https://avatars.githubusercontent.com/u/77328395?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> write:\n> You will want to add one or more new tests to a test script to verify\n> that this new configuration works as expected, and probably also to\n> verify that `pull.autoStash` takes precedence over `rebase.autoStash`.\n\nGot it. Always make sure to add tests when introducing new features.\n\n>> diff --git a/Documentation/config/pull.adoc b/Documentation/config/pull.adoc\n>> @@ -13,6 +13,15 @@ pull.rebase::\n>> +pull.autoStash::\n>> +       When true, Git will automatically perform a `git stash` before the\n>> +       operation and then restore the local changes with `git stash pop`\n>> +       after the merge or rebase is complete. This means that you can run\n> \n> I wonder if you meant \"pull\" instead of \"merge or rebase\".\n\nYes, I think I should also say that pull.autoStash only works if we set pull.rebase.\n\n> \n>> +       pull on a dirty worktree. Noticed that `rebase.autoStash` provides\n> \n> s/Noticed/Notice/\n> \n>> +       the same functionality, but `pull.autoStash` overrides its behavior\n> \n> Rather: \"...same functionality as `pull.autoStash` but overrides the\n> latter when...\"\n\nGot it.\n\n> \n>> +       when both are set. This option can be overridden by the `--no-autostash`\n>> +       and `--autostash` options of linkgit:git-pull[1]. Defaults to false.\n>> diff --git a/builtin/pull.c b/builtin/pull.c\n>> @@ -1052,7 +1056,7 @@ int cmd_pull(int argc,\n>>        if (opt_rebase) {\n>>                if (opt_autostash == -1)\n>> -                       opt_autostash = config_autostash;\n>> +                       opt_autostash = config_pull_autostash == -1 ? config_rebase_autostash : config_pull_autostash;\n> \n> You may want to wrap this over-long line. Perhaps:\n> \n>    opt_autostash = config_pull_autostash == -1 ?\n>        config_rebase_autostash : config_pull_autostash;\n\nHere's something completely unrelated: the output of clang-format can\nsometimes be confusing.\n\n- opt_autostash = config_pull_autostash == -1 ?\n-       config_rebase_autostash :\n-       config_pull_autostash;\n+ opt_autostash = config_pull_autostash == -1 ? config_rebase_autostash : config_pull_autostash;\n\nThis made me mistakenly think that Git had set a large line length limit,\nSo I didn’t break this line here.\n\nThanks,\nLidong\n\n"},{"id":"522149","messageId":"xmqqms938mbq.fsf@gitster.g","threadId":"63795","inReplyTo":"78DFE806-5DAC-4A90-893B-77F32E393E07@gmail.com","subject":"Re: [PATCH] pull: add pull.autoStash config option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-07-17T04:37:13Z","receivedAt":"2025-07-17T04:37:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Lidong Yan <yldhome2d2@gmail.com> writes:\n\n>>> +pull.autoStash::\n>>> +       When true, Git will automatically perform a `git stash` before the\n>>> +       operation and then restore the local changes with `git stash pop`\n>>> +       after the merge or rebase is complete. This means that you can run\n>> \n>> I wonder if you meant \"pull\" instead of \"merge or rebase\".\n>\n> Yes, I think I should also say that pull.autoStash only works if we set pull.rebase.\n\nIs that wise, though?  When pull.rebase is false, shouldn't pull.autostash\npass --autostash to underlying \"git merge\" instead?\n\nI've written about the interaction among three commands and\nautostash in another message several hours ago, so I won't repeat\nit.\n\nhttps://lore.kernel.org/git/xmqq5xfsdv3w.fsf@gitster.g/\n\n"},{"id":"522151","messageId":"xmqqfrev8m0d.fsf@gitster.g","threadId":"63795","inReplyTo":"CAPig+cTQ017qGK_Qx04+R_0rCXEOirW+oLEjeaDoCFJiQbnsGw@mail.gmail.com","subject":"Re: [PATCH] pull: add pull.autoStash config option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-07-17T04:44:02Z","receivedAt":"2025-07-17T04:44:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n>>                 if (opt_autostash == -1)\n>> -                       opt_autostash = config_autostash;\n>> +                       opt_autostash = config_pull_autostash == -1 ? config_rebase_autostash : config_pull_autostash;\n>\n> You may want to wrap this over-long line. Perhaps:\n>\n>     opt_autostash = config_pull_autostash == -1 ?\n>         config_rebase_autostash : config_pull_autostash;\n\nAlternatively\n\n\topt_autostash = (config_pull_autostash == -1\n\t\t\t ? config_rebase_autostash\n\t\t\t : config_pull_autostash);\n\n"},{"id":"522169","messageId":"174669ED-8E02-49BB-BD61-277DBCA4D890@gmail.com","threadId":"63795","inReplyTo":"xmqqms938mbq.fsf@gitster.g","subject":"Re: [PATCH] pull: add pull.autoStash config option","fromName":"Lidong Yan","fromEmail":"yldhome2d2@gmail.com","sentAt":"2025-07-17T05:01:42Z","receivedAt":"2025-07-17T05:01:54Z","isPatch":true,"sender":{"key":"yldhome2d2@gmail.com","avatar":"https://avatars.githubusercontent.com/u/77328395?v=4"},"body":"Junio C Hamano <gitster@pobox.com> write:\n> \n> Lidong Yan <yldhome2d2@gmail.com> writes:\n> \n>>>> +pull.autoStash::\n>>>> +       When true, Git will automatically perform a `git stash` before the\n>>>> +       operation and then restore the local changes with `git stash pop`\n>>>> +       after the merge or rebase is complete. This means that you can run\n>>> \n>>> I wonder if you meant \"pull\" instead of \"merge or rebase\".\n>> \n>> Yes, I think I should also say that pull.autoStash only works if we set pull.rebase.\n> \n> Is that wise, though?  When pull.rebase is false, shouldn't pull.autostash\n> pass --autostash to underlying \"git merge\" instead?\n\nHere set pull.rebase means either set pull.rebase to true or false. And\nmy patch will autostash if pull.rebase = false. \n\n> I've written about the interaction among three commands and\n> autostash in another message several hours ago, so I won't repeat\n> it.\n> \n> https://lore.kernel.org/git/xmqq5xfsdv3w.fsf@gitster.g/\n\nYeah. Though I considered that when pull.rebase = false, checking\nmerge.autoStash instead of rebase.autoStashmight confuse users\nwho rely on setting rebase.autoStash for their merge operations."},{"id":"522170","messageId":"xmqq5xfr8j0r.fsf@gitster.g","threadId":"63795","inReplyTo":"174669ED-8E02-49BB-BD61-277DBCA4D890@gmail.com","subject":"Re: [PATCH] pull: add pull.autoStash config option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-07-17T05:48:36Z","receivedAt":"2025-07-17T05:48:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Lidong Yan <yldhome2d2@gmail.com> writes:\n\n> Yeah. Though I considered that when pull.rebase = false, checking\n> merge.autoStash instead of rebase.autoStashmight confuse users\n> who rely on setting rebase.autoStash for their merge operations.\n\nYes, that would be a behaviour change, but it is just one time\nthing.  You notice your \"git pull\" do not autostash and instead\nstops, you scratch your head and go read the documentation, and set\npull.autostash to true (which as I said I would not necessarily\nrecommend) or merge.autostash to true (which may not be as bad) and\nmove on.\n\nI didn't consider it when I wrote my earlier message, but I like\nyour idea of defeating rebase.autostash and merge.autostash when\npull.autostash is explicitly set to false very much.  With it, users\ncan set {rebase,merge}.autostash to true so that their local rebases\nand merges, for which they are familiar with what both sides did,\nwould autostash (and autounstash), and set pull.autostash to false\nso their \"git pull\" would be stopped when they have local changes\nthat would interfere with the operation, if they wanted to.\n\nThanks.\n\n\n"},{"id":"522228","messageId":"66D1F0CE-3DBC-45BE-A777-606D50E84094@gmail.com","threadId":"63795","inReplyTo":"xmqq5xfsdv3w.fsf@gitster.g","subject":"Re: [BUG] git pull ignores pull.autostash=true configuration when used with --git-dir and --work-tree flags on a bare repository","fromName":"Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2025-07-17T19:32:03Z","receivedAt":"2025-07-17T19:32:15Z","isPatch":false,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"\n> Le 16 juil. 2025 à 11:17, Junio C Hamano <gitster@pobox.com> a écrit :\n> \n> ﻿Johannes Sixt <j6t@kdbg.org> writes:\n> \n>> Instead of this complexity, it is most likely a lot easier to fix the\n>> origin of the misconception that `pull.autostash` is the correct\n>> configuration. After all, it isn't even mentioned in the git-config nor\n>> the git-pull man page.\n> \n> git_pull_config() does pay attention to \"rebase.autostash\".  \n> \n> Either it is a bug for the code to do so, or it is a bug that the\n> documentation does not talk about it.  \n> \n> The reason why I think \"git pull\" that pays attention to\n> rebase.autostash is a bug is because the user is more likely to be\n> much more familiar with both branches involved and more likely to be\n> prepared to deal with conflicts potentially created by autostashing\n> behaviour when making a private merge or rebase of local branches,\n> than when pulling from other repositories.  So those who show\n> willingness to accept the responsibility of having to resolve\n> conflicts that arise when popping autostashed changes by setting\n> rebase.autostash may not want to be cavalier to the same degree when\n> running \"git pull\".  git_pull_config() that pays attention to\n> \"rebase.autostash\" breaks that expectation.\n\nOn the other hand, a pull that rebases is (conceptually) a fetch followed by a rebase, and there is a lot of description and teaching of pull as fetch+merge. Breaking that expectation is also unnatural.\n\nI would consider it far more inconsistent if pulls that rebase don’t honor rebase configuration. So put me in the camp that pull should probably respect merge.autostash, too. (I don’t have any opinion about pull.autostash, which seems reasonable on the surface.)\n\n> \n> There is another curiosity.  git_pull_config() does not pay\n> attention to \"merge.autostash\", which seems inconsistent.\n> \n> If I did not have any existing users, I would actually vote to teach\n> git_pull_config() stop paying attention to \"rebase.autostash\", but\n> we do not live in an ideal world.  Perhaps rectify this at Git 3.0?\n"},{"id":"522270","messageId":"20250718035221.2293-1-yldhome2d2@gmail.com","threadId":"63795","inReplyTo":"20250717030732.75106-1-yldhome2d2@gmail.com","subject":"[PATCH] pull: add pull.autoStash config option","fromName":"Lidong Yan","fromEmail":"yldhome2d2@gmail.com","sentAt":"2025-07-18T03:52:21Z","receivedAt":"2025-07-18T03:52:36Z","isPatch":true,"sender":{"key":"yldhome2d2@gmail.com","avatar":"https://avatars.githubusercontent.com/u/77328395?v=4"},"body":"Git uses `rebase.autostash` or `merge.autostash` to determine whether a\ndirty worktree is allowed during pull. However, this behavior is not\nclearly documented, making it difficult for users to discover how to\nenable autostash, or causing them to unknowingly enable it. Add new\nconfig option `pull.autostash` along with its documentation and test\ncases.\n\n`pull.autostash` provides the same functionality as `rebase.autostash`\nand `merge.autostash`, but overrides them when set. If `pull.autostash`\nis not set, it falls back to `rebase.autostash` or `merge.autostash`,\ndepending on the value of `pull.rebase`.\n\nSigned-off-by: Lidong Yan <yldhome2d2@gmail.com>\n---\n Documentation/config/pull.adoc | 11 +++++\n builtin/pull.c                 | 20 ++++++--\n t/t5520-pull.sh                | 90 ++++++++++++++++++++++++++++++++++\n 3 files changed, 118 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/config/pull.adoc b/Documentation/config/pull.adoc\nindex 9349e09261..3aa1e67923 100644\n--- a/Documentation/config/pull.adoc\n+++ b/Documentation/config/pull.adoc\n@@ -13,6 +13,17 @@ pull.rebase::\n \tof merging the default branch from the default remote when \"git\n \tpull\" is run. See \"branch.<name>.rebase\" for setting this on a\n \tper-branch basis.\n+\n+pull.autoStash::\n+\tWhen true, Git will automatically perform a `git stash` before the\n+\toperation and then restore the local changes with `git stash pop`\n+\tafter the pull is complete. This means that you can run pull on a\n+\tdirty worktree. If `pull.autostash` is set, it takes precedence over\n+\t`rebase.autostash` and `merge.autostash`. If `pull.autostash` is not\n+\tset, it falls back to `rebase.autostash` or `merge.autostash`,\n+\tdepending on the value of `pull.rebase`. This option can be\n+\toverridden by the `--no-autostash` and `--autostash` options of\n+\tlinkgit:git-pull[1]. Defaults to false.\n +\n When `merges` (or just 'm'), pass the `--rebase-merges` option to 'git rebase'\n so that the local merge commits are included in the rebase (see\ndiff --git a/builtin/pull.c b/builtin/pull.c\nindex c593f324fe..2a6c2e4a37 100644\n--- a/builtin/pull.c\n+++ b/builtin/pull.c\n@@ -90,7 +90,8 @@ static char *opt_ff;\n static const char *opt_verify_signatures;\n static const char *opt_verify;\n static int opt_autostash = -1;\n-static int config_autostash;\n+static int config_rebase_autostash;\n+static int config_pull_autostash = -1;\n static int check_trust_level = 1;\n static struct strvec opt_strategies = STRVEC_INIT;\n static struct strvec opt_strategy_opts = STRVEC_INIT;\n@@ -367,7 +368,18 @@ static int git_pull_config(const char *var, const char *value,\n \t\t\t   const struct config_context *ctx, void *cb)\n {\n \tif (!strcmp(var, \"rebase.autostash\")) {\n-\t\tconfig_autostash = git_config_bool(var, value);\n+\t\t/*\n+\t\t * run_rebase() also reads this option. The reason we handle it here is\n+\t\t * that when pull.rebase is true, a fast-forward may occur without\n+\t\t * invoking run_rebase(). We need to ensure that autostash is set even\n+\t\t * in the fast-forward case.\n+\t\t *\n+\t\t * run_merge() handles merge.autostash, so we don't handle it here.\n+\t\t */\n+\t\tconfig_rebase_autostash = git_config_bool(var, value);\n+\t\treturn 0;\n+\t} else if (!strcmp(var, \"pull.autostash\")) {\n+\t\tconfig_pull_autostash = git_config_bool(var, value);\n \t\treturn 0;\n \t} else if (!strcmp(var, \"submodule.recurse\")) {\n \t\trecurse_submodules = git_config_bool(var, value) ?\n@@ -1006,6 +1018,8 @@ int cmd_pull(int argc,\n \t}\n \n \targc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);\n+\tif (opt_autostash == -1)\n+\t\topt_autostash = config_pull_autostash;\n \n \tif (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT)\n \t\trecurse_submodules = recurse_submodules_cli;\n@@ -1052,7 +1066,7 @@ int cmd_pull(int argc,\n \n \tif (opt_rebase) {\n \t\tif (opt_autostash == -1)\n-\t\t\topt_autostash = config_autostash;\n+\t\t\topt_autostash = config_rebase_autostash;\n \n \t\tif (is_null_oid(&orig_head) && !is_index_unborn(the_repository->index))\n \t\t\tdie(_(\"Updating an unborn branch with changes added to the index.\"));\ndiff --git a/t/t5520-pull.sh b/t/t5520-pull.sh\nindex 63c9a8f04b..134da2185c 100755\n--- a/t/t5520-pull.sh\n+++ b/t/t5520-pull.sh\n@@ -472,6 +472,96 @@ test_expect_success 'pull --no-autostash & merge.autostash unset' '\n \ttest_pull_autostash_fail --no-autostash --no-rebase\n '\n \n+test_expect_success 'pull succeeds with dirty working directory and pull.autostash set' '\n+\ttest_config pull.autostash true &&\n+\ttest_pull_autostash 1 --rebase &&\n+\ttest_pull_autostash 2 --no-rebase\n+'\n+\n+test_expect_success 'pull --autostash & pull.autostash=true' '\n+\ttest_config pull.autostash true &&\n+\ttest_pull_autostash 1 --autostash --rebase &&\n+\ttest_pull_autostash 2 --autostash --no-rebase\n+'\n+\n+test_expect_success 'pull --autostash & pull.autostash=false' '\n+\ttest_config pull.autostash false &&\n+\ttest_pull_autostash 1 --autostash --rebase &&\n+\ttest_pull_autostash 2 --autostash --no-rebase\n+'\n+\n+test_expect_success 'pull --autostash & pull.autostash unset' '\n+\ttest_unconfig pull.autostash &&\n+\ttest_pull_autostash 1 --autostash --rebase &&\n+\ttest_pull_autostash 2 --autostash --no-rebase\n+'\n+\n+test_expect_success 'pull --no-autostash & pull.autostash=true' '\n+\ttest_config pull.autostash true &&\n+\ttest_pull_autostash_fail --no-autostash --rebase &&\n+\ttest_pull_autostash_fail --no-autostash --no-rebase\n+'\n+\n+test_expect_success 'pull --no-autostash & pull.autostash=false' '\n+\ttest_config pull.autostash false &&\n+\ttest_pull_autostash_fail --no-autostash --rebase &&\n+\ttest_pull_autostash_fail --no-autostash --no-rebase\n+'\n+\n+test_expect_success 'pull --no-autostash & pull.autostash unset' '\n+\ttest_unconfig pull.autostash &&\n+\ttest_pull_autostash_fail --no-autostash --rebase &&\n+\ttest_pull_autostash_fail --no-autostash --no-rebase\n+'\n+\n+test_expect_success 'pull.autostash=true & rebase.autostash=true' '\n+\ttest_config pull.autostash true &&\n+\ttest_config rebase.autostash true &&\n+\ttest_pull_autostash 1 --rebase\n+'\n+\n+test_expect_success 'pull.autostash=true & rebase.autostash=false' '\n+\ttest_config pull.autostash true &&\n+\ttest_config rebase.autostash false &&\n+\ttest_pull_autostash 1 --rebase\n+'\n+\n+test_expect_success 'pull.autostash=false & rebase.autostash=true' '\n+\ttest_config pull.autostash false &&\n+\ttest_config rebase.autostash true &&\n+\ttest_pull_autostash_fail --rebase\n+'\n+\n+test_expect_success 'pull.autostash=false & rebase.autostash=false' '\n+\ttest_config pull.autostash false &&\n+\ttest_config rebase.autostash false &&\n+\ttest_pull_autostash_fail --rebase\n+'\n+\n+test_expect_success 'pull.autostash=true & merge.autostash=true' '\n+\ttest_config pull.autostash true &&\n+\ttest_config merge.autostash true &&\n+\ttest_pull_autostash 2 --no-rebase\n+'\n+\n+test_expect_success 'pull.autostash=true & merge.autostash=false' '\n+\ttest_config pull.autostash true &&\n+\ttest_config merge.autostash false &&\n+\ttest_pull_autostash 2 --no-rebase\n+'\n+\n+test_expect_success 'pull.autostash=false & merge.autostash=true' '\n+\ttest_config pull.autostash false &&\n+\ttest_config merge.autostash true &&\n+\ttest_pull_autostash_fail --no-rebase\n+'\n+\n+test_expect_success 'pull.autostash=false & merge.autostash=false' '\n+\ttest_config pull.autostash false &&\n+\ttest_config merge.autostash false &&\n+\ttest_pull_autostash_fail --no-rebase\n+'\n+\n test_expect_success 'pull.rebase' '\n \tgit reset --hard before-rebase &&\n \ttest_config pull.rebase true &&\n-- \n2.39.5 (Apple Git-154)\n\n"},{"id":"522291","messageId":"xmqqjz45172n.fsf@gitster.g","threadId":"63795","inReplyTo":"20250718035221.2293-1-yldhome2d2@gmail.com","subject":"Re: [PATCH] pull: add pull.autoStash config option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-07-18T22:13:04Z","receivedAt":"2025-07-18T22:13:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Lidong Yan <yldhome2d2@gmail.com> writes:\n\n> Git uses `rebase.autostash` or `merge.autostash` to determine whether a\n> dirty worktree is allowed during pull. However, this behavior is not\n> clearly documented, making it difficult for users to discover how to\n> enable autostash, or causing them to unknowingly enable it. Add new\n> config option `pull.autostash` along with its documentation and test\n> cases.\n>\n> `pull.autostash` provides the same functionality as `rebase.autostash`\n> and `merge.autostash`, but overrides them when set. If `pull.autostash`\n> is not set, it falls back to `rebase.autostash` or `merge.autostash`,\n> depending on the value of `pull.rebase`.\n\nVery well reasoned and described.\n\n> diff --git a/Documentation/config/pull.adoc b/Documentation/config/pull.adoc\n> index 9349e09261..3aa1e67923 100644\n> --- a/Documentation/config/pull.adoc\n> +++ b/Documentation/config/pull.adoc\n> @@ -13,6 +13,17 @@ pull.rebase::\n>  \tof merging the default branch from the default remote when \"git\n>  \tpull\" is run. See \"branch.<name>.rebase\" for setting this on a\n>  \tper-branch basis.\n> +\n> +pull.autoStash::\n> +\tWhen true, Git will automatically perform a `git stash` before the\n> +\toperation and then restore the local changes with `git stash pop`\n> +\tafter the pull is complete. This means that you can run pull on a\n> +\tdirty worktree. If `pull.autostash` is set, it takes precedence over\n> +\t`rebase.autostash` and `merge.autostash`. If `pull.autostash` is not\n> +\tset, it falls back to `rebase.autostash` or `merge.autostash`,\n> +\tdepending on the value of `pull.rebase`. This option can be\n> +\toverridden by the `--no-autostash` and `--autostash` options of\n> +\tlinkgit:git-pull[1]. Defaults to false.\n>  +\n>  When `merges` (or just 'm'), pass the `--rebase-merges` option to 'git rebase'\n>  so that the local merge commits are included in the rebase (see\n\nThe new text is inserted at a wrong spot.  This \"+\\nWhen `merges`\"\nis a continuation of the text that describes `pull.rebase`.  If that\nis set to `true`, one thing happens.  If that is set to `merges`,\nsomething else happens.\n\nInsert the text for `pull.autoStash` immediately before the\ndescription of the `pull.octopus` configuration variable.\n\nAs to the text itself, \"you can run pull on a dirty worktree\" may\nnot be what you want to say here, for a few reasons.\n\n * (pedantic) Even without the configuration variable set, you can\n   run \"git pull\" in a dirty working tree; it just will refuse to do\n   any damage until you stash the local changes away yourself.\n\n * If your \"git pull\" merges, it would work even in a dirty working\n   tree as long as your local change doesn't overlap with what the\n   merge would bring in.  This is quite useful for a maintainer with\n   \"upcoming\" change to GIT-VERSION-GEN always updated locally in\n   the working tree and not having to worry about pulling from\n   contributors and submaintainers who won't usually be touching\n   that file, for example.\n\n * Not limited to this instance, when you have to say \"(This|It)\n   means <<B>>\" immediately after making a statement <<A>, I would\n   like us to think if we can just say <<B>> without saying <<A> at\n   all.  In this case, it is not so, which makes me suspect that\n   perhaps we do not even want to say <<B>>, as it may not mean\n   <<B>> after all.\n\nHere is my attempt.\n\n    When set to true, automatically create a temporary stash entry\n    to record the local changes before the operation begins, and\n    restore them after the operation completes.  When your \"git\n    pull\" rebases (instead of merges), this may be convenient, since\n    unlike merging pull that tolerates local changes that do not\n    interfere with the merge, rebasing pull refuses to work with any\n    local changes.\n+\nIf `pull.autostash` is set (either to true or false),\n`merge.autostash` and `rebase.autostash` are ignored.  If\n`pull.autostash` is not set at all, depending on the value of\n`pull.rebase`, `merge.autostash` or `rebase.autostash` is used\ninstead.  Can be overridden by the `--[no-]autostash` command line\noption.\n\n> diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh\n> index 63c9a8f04b..134da2185c 100755\n> --- a/t/t5520-pull.sh\n> +++ b/t/t5520-pull.sh\n> @@ -472,6 +472,96 @@ test_expect_success 'pull --no-autostash & merge.autostash unset' '\n>  \ttest_pull_autostash_fail --no-autostash --no-rebase\n>  '\n>  \n> +test_expect_success 'pull succeeds with dirty working directory and pull.autostash set' '\n> +\ttest_config pull.autostash true &&\n> +\ttest_pull_autostash 1 --rebase &&\n> +\ttest_pull_autostash 2 --no-rebase\n> +'\n\nMost trivial case.  No command line override.\n\n> +test_expect_success 'pull --autostash & pull.autostash=true' '\n> +\ttest_config pull.autostash true &&\n> +\ttest_pull_autostash 1 --autostash --rebase &&\n> +\ttest_pull_autostash 2 --autostash --no-rebase\n> +'\n\nCommand line override specifies the same behaviour as the\nconfiguration, so we cannot learn much from this test.  It still\nshould keep working, so the test is worth having [*], but I wonder\nif makes sense to combine the above two into one test, i.e. set the\nconfiguration variable to true once, and then try --rebase and\n--no-rebase with and without --autostash (four combinations).\n\n    [*] In this review, unless I explicitly say \"this test is wrong\n    and expects an incorrect result\", they are not wrong, even\n    though what they test may not be as interesting as others, and I\n    am not suggesting its removal.  This is one of these tests.\n\n> +test_expect_success 'pull --autostash & pull.autostash=false' '\n> +\ttest_config pull.autostash false &&\n> +\ttest_pull_autostash 1 --autostash --rebase &&\n> +\ttest_pull_autostash 2 --autostash --no-rebase\n> +'\n\nConfiguration should be overridden by the command line option, which\nis a good thing to test.\n\n> +test_expect_success 'pull --autostash & pull.autostash unset' '\n> +\ttest_unconfig pull.autostash &&\n> +\ttest_pull_autostash 1 --autostash --rebase &&\n> +\ttest_pull_autostash 2 --autostash --no-rebase\n> +'\n\nAnother most trivial case.  Shouldn't we already have an existing\ntest for this, back from the days before pull.autostash got\nintroduced, since the command line option has been there all along?\n\n> +test_expect_success 'pull --no-autostash & pull.autostash=true' '\n> +\ttest_config pull.autostash true &&\n> +\ttest_pull_autostash_fail --no-autostash --rebase &&\n> +\ttest_pull_autostash_fail --no-autostash --no-rebase\n> +'\n\nConfiguration overridden by the option, opposite of what we saw\nearlier, which is another good thing to test.\n\n> +test_expect_success 'pull --no-autostash & pull.autostash=false' '\n> +\ttest_config pull.autostash false &&\n> +\ttest_pull_autostash_fail --no-autostash --rebase &&\n> +\ttest_pull_autostash_fail --no-autostash --no-rebase\n> +'\n\nUninteresting test that does not tell us much; we cannot tell which\nbetween the configuration and the command line option caused us not\nto auto stash with this test.\n\nTwo cases that may be worth adding to this test immediately after\nsetting pull.autostash to false are:\n\n\ttest_pull_autostash_fail --rebase &&\n\ttest_pull_autostash_fail --no-rebase &&\n\n> +test_expect_success 'pull --no-autostash & pull.autostash unset' '\n> +\ttest_unconfig pull.autostash &&\n> +\ttest_pull_autostash_fail --no-autostash --rebase &&\n> +\ttest_pull_autostash_fail --no-autostash --no-rebase\n> +'\n\nAnother uninteresting case that probably should be already covered\nby existing test, since this tests \"what happens when autostash is\nexplicitly declined from the command line when there is no\nconfiguration variable to intervene?\".\n\n> +test_expect_success 'pull.autostash=true & rebase.autostash=true' '\n> +\ttest_config pull.autostash true &&\n> +\ttest_config rebase.autostash true &&\n> +\ttest_pull_autostash 1 --rebase\n> +'\n\nOK.  Perhaps make sure \"--no-autostash --rebase\" would fail while at\nit in the same test?\n\n> +test_expect_success 'pull.autostash=true & rebase.autostash=false' '\n> +\ttest_config pull.autostash true &&\n> +\ttest_config rebase.autostash false &&\n> +\ttest_pull_autostash 1 --rebase\n> +'\n\nThis is more interesting than the previous one, as we make sure that\npull.* trumps rebase.* with this test.  Perhaps throw --no-autostash\nspecified on the command line into the mix?\n\n> +test_expect_success 'pull.autostash=false & rebase.autostash=true' '\n> +\ttest_config pull.autostash false &&\n> +\ttest_config rebase.autostash true &&\n> +\ttest_pull_autostash_fail --rebase\n> +'\n\nAnother good one.  It might be intereseting to test --no-rebase and\nmake sure it also fails?  I dunno.\n\n> +test_expect_success 'pull.autostash=false & rebase.autostash=false' '\n> +\ttest_config pull.autostash false &&\n> +\ttest_config rebase.autostash false &&\n> +\ttest_pull_autostash_fail --rebase\n> +'\n\nNot as interesting as others.\n\n> +test_expect_success 'pull.autostash=true & merge.autostash=true' '\n> +\ttest_config pull.autostash true &&\n> +\ttest_config merge.autostash true &&\n> +\ttest_pull_autostash 2 --no-rebase\n> +'\n\nNot as interesting as others.  Throw --no-autostash given on the\ncommand line into the mix as well?\n\n> +test_expect_success 'pull.autostash=true & merge.autostash=false' '\n> +\ttest_config pull.autostash true &&\n> +\ttest_config merge.autostash false &&\n> +\ttest_pull_autostash 2 --no-rebase\n> +'\n\nOK.  pull.*=true trumps merge.*=false.  We test the other way around\nnext.  Good.\n\n> +test_expect_success 'pull.autostash=false & merge.autostash=true' '\n> +\ttest_config pull.autostash false &&\n> +\ttest_config merge.autostash true &&\n> +\ttest_pull_autostash_fail --no-rebase\n> +'\n> +\n> +test_expect_success 'pull.autostash=false & merge.autostash=false' '\n> +\ttest_config pull.autostash false &&\n> +\ttest_config merge.autostash false &&\n> +\ttest_pull_autostash_fail --no-rebase\n> +'\n\nNot very interesting.  Throw anothre that gives --autostash from the\ncommand line in the mix, perhaps?\n\n>  test_expect_success 'pull.rebase' '\n>  \tgit reset --hard before-rebase &&\n>  \ttest_config pull.rebase true &&\n\n\nWhew.\n\nI did not spot anything majory broken (except for the location to\nwhich the new documentation paragraph goes) in the patch.  Nicely\ndone.\n\nThanks.\n"},{"id":"522304","messageId":"3CABAF88-B343-4996-B968-3736FC24917B@gmail.com","threadId":"63795","inReplyTo":"xmqqjz45172n.fsf@gitster.g","subject":"Re: [PATCH] pull: add pull.autoStash config option","fromName":"Lidong Yan","fromEmail":"yldhome2d2@gmail.com","sentAt":"2025-07-19T03:14:48Z","receivedAt":"2025-07-19T03:14:54Z","isPatch":true,"sender":{"key":"yldhome2d2@gmail.com","avatar":"https://avatars.githubusercontent.com/u/77328395?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n> \n> Lidong Yan <yldhome2d2@gmail.com> writes:\n> \n>> Git uses `rebase.autostash` or `merge.autostash` to determine whether a\n>> dirty worktree is allowed during pull. However, this behavior is not\n>> clearly documented, making it difficult for users to discover how to\n>> enable autostash, or causing them to unknowingly enable it. Add new\n>> config option `pull.autostash` along with its documentation and test\n>> cases.\n>> \n>> `pull.autostash` provides the same functionality as `rebase.autostash`\n>> and `merge.autostash`, but overrides them when set. If `pull.autostash`\n>> is not set, it falls back to `rebase.autostash` or `merge.autostash`,\n>> depending on the value of `pull.rebase`.\n> \n> Very well reasoned and described.\n> \n>> diff --git a/Documentation/config/pull.adoc b/Documentation/config/pull.adoc\n>> index 9349e09261..3aa1e67923 100644\n>> --- a/Documentation/config/pull.adoc\n>> +++ b/Documentation/config/pull.adoc\n>> @@ -13,6 +13,17 @@ pull.rebase::\n>> of merging the default branch from the default remote when \"git\n>> pull\" is run. See \"branch.<name>.rebase\" for setting this on a\n>> per-branch basis.\n>> +\n>> +pull.autoStash::\n>> + When true, Git will automatically perform a `git stash` before the\n>> + operation and then restore the local changes with `git stash pop`\n>> + after the pull is complete. This means that you can run pull on a\n>> + dirty worktree. If `pull.autostash` is set, it takes precedence over\n>> + `rebase.autostash` and `merge.autostash`. If `pull.autostash` is not\n>> + set, it falls back to `rebase.autostash` or `merge.autostash`,\n>> + depending on the value of `pull.rebase`. This option can be\n>> + overridden by the `--no-autostash` and `--autostash` options of\n>> + linkgit:git-pull[1]. Defaults to false.\n>> +\n>> When `merges` (or just 'm'), pass the `--rebase-merges` option to 'git rebase'\n>> so that the local merge commits are included in the rebase (see\n> \n> The new text is inserted at a wrong spot.  This \"+\\nWhen `merges`\"\n> is a continuation of the text that describes `pull.rebase`.  If that\n> is set to `true`, one thing happens.  If that is set to `merges`,\n> something else happens.\n> \n> Insert the text for `pull.autoStash` immediately before the\n> description of the `pull.octopus` configuration variable.\n> \n> As to the text itself, \"you can run pull on a dirty worktree\" may\n> not be what you want to say here, for a few reasons.\n> \n> * (pedantic) Even without the configuration variable set, you can\n>   run \"git pull\" in a dirty working tree; it just will refuse to do\n>   any damage until you stash the local changes away yourself.\n> \n> * If your \"git pull\" merges, it would work even in a dirty working\n>   tree as long as your local change doesn't overlap with what the\n>   merge would bring in.  This is quite useful for a maintainer with\n>   \"upcoming\" change to GIT-VERSION-GEN always updated locally in\n>   the working tree and not having to worry about pulling from\n>   contributors and submaintainers who won't usually be touching\n>   that file, for example.\n> \n> * Not limited to this instance, when you have to say \"(This|It)\n>   means <<B>>\" immediately after making a statement <<A>, I would\n>   like us to think if we can just say <<B>> without saying <<A> at\n>   all.  In this case, it is not so, which makes me suspect that\n>   perhaps we do not even want to say <<B>>, as it may not mean\n>   <<B>> after all.\n> \n> Here is my attempt.\n> \n>    When set to true, automatically create a temporary stash entry\n>    to record the local changes before the operation begins, and\n>    restore them after the operation completes.  When your \"git\n>    pull\" rebases (instead of merges), this may be convenient, since\n>    unlike merging pull that tolerates local changes that do not\n>    interfere with the merge, rebasing pull refuses to work with any\n>    local changes.\n> +\n> If `pull.autostash` is set (either to true or false),\n> `merge.autostash` and `rebase.autostash` are ignored.  If\n> `pull.autostash` is not set at all, depending on the value of\n> `pull.rebase`, `merge.autostash` or `rebase.autostash` is used\n> instead.  Can be overridden by the `--[no-]autostash` command line\n> option.\n> \n>> diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh\n>> index 63c9a8f04b..134da2185c 100755\n>> --- a/t/t5520-pull.sh\n>> +++ b/t/t5520-pull.sh\n>> @@ -472,6 +472,96 @@ test_expect_success 'pull --no-autostash & merge.autostash unset' '\n>> test_pull_autostash_fail --no-autostash --no-rebase\n>> '\n>> \n>> +test_expect_success 'pull succeeds with dirty working directory and pull.autostash set' '\n>> + test_config pull.autostash true &&\n>> + test_pull_autostash 1 --rebase &&\n>> + test_pull_autostash 2 --no-rebase\n>> +'\n> \n> Most trivial case.  No command line override.\n> \n>> +test_expect_success 'pull --autostash & pull.autostash=true' '\n>> + test_config pull.autostash true &&\n>> + test_pull_autostash 1 --autostash --rebase &&\n>> + test_pull_autostash 2 --autostash --no-rebase\n>> +'\n> \n> Command line override specifies the same behaviour as the\n> configuration, so we cannot learn much from this test.  It still\n> should keep working, so the test is worth having [*], but I wonder\n> if makes sense to combine the above two into one test, i.e. set the\n> configuration variable to true once, and then try --rebase and\n> --no-rebase with and without --autostash (four combinations).\n> \n>    [*] In this review, unless I explicitly say \"this test is wrong\n>    and expects an incorrect result\", they are not wrong, even\n>    though what they test may not be as interesting as others, and I\n>    am not suggesting its removal.  This is one of these tests.\n> \n>> +test_expect_success 'pull --autostash & pull.autostash=false' '\n>> + test_config pull.autostash false &&\n>> + test_pull_autostash 1 --autostash --rebase &&\n>> + test_pull_autostash 2 --autostash --no-rebase\n>> +'\n> \n> Configuration should be overridden by the command line option, which\n> is a good thing to test.\n> \n>> +test_expect_success 'pull --autostash & pull.autostash unset' '\n>> + test_unconfig pull.autostash &&\n>> + test_pull_autostash 1 --autostash --rebase &&\n>> + test_pull_autostash 2 --autostash --no-rebase\n>> +'\n> \n> Another most trivial case.  Shouldn't we already have an existing\n> test for this, back from the days before pull.autostash got\n> introduced, since the command line option has been there all along?\n> \n>> +test_expect_success 'pull --no-autostash & pull.autostash=true' '\n>> + test_config pull.autostash true &&\n>> + test_pull_autostash_fail --no-autostash --rebase &&\n>> + test_pull_autostash_fail --no-autostash --no-rebase\n>> +'\n> \n> Configuration overridden by the option, opposite of what we saw\n> earlier, which is another good thing to test.\n> \n>> +test_expect_success 'pull --no-autostash & pull.autostash=false' '\n>> + test_config pull.autostash false &&\n>> + test_pull_autostash_fail --no-autostash --rebase &&\n>> + test_pull_autostash_fail --no-autostash --no-rebase\n>> +'\n> \n> Uninteresting test that does not tell us much; we cannot tell which\n> between the configuration and the command line option caused us not\n> to auto stash with this test.\n> \n> Two cases that may be worth adding to this test immediately after\n> setting pull.autostash to false are:\n> \n> test_pull_autostash_fail --rebase &&\n> test_pull_autostash_fail --no-rebase &&\n> \n>> +test_expect_success 'pull --no-autostash & pull.autostash unset' '\n>> + test_unconfig pull.autostash &&\n>> + test_pull_autostash_fail --no-autostash --rebase &&\n>> + test_pull_autostash_fail --no-autostash --no-rebase\n>> +'\n> \n> Another uninteresting case that probably should be already covered\n> by existing test, since this tests \"what happens when autostash is\n> explicitly declined from the command line when there is no\n> configuration variable to intervene?\".\n> \n>> +test_expect_success 'pull.autostash=true & rebase.autostash=true' '\n>> + test_config pull.autostash true &&\n>> + test_config rebase.autostash true &&\n>> + test_pull_autostash 1 --rebase\n>> +'\n> \n> OK.  Perhaps make sure \"--no-autostash --rebase\" would fail while at\n> it in the same test?\n> \n>> +test_expect_success 'pull.autostash=true & rebase.autostash=false' '\n>> + test_config pull.autostash true &&\n>> + test_config rebase.autostash false &&\n>> + test_pull_autostash 1 --rebase\n>> +'\n> \n> This is more interesting than the previous one, as we make sure that\n> pull.* trumps rebase.* with this test.  Perhaps throw --no-autostash\n> specified on the command line into the mix?\n> \n>> +test_expect_success 'pull.autostash=false & rebase.autostash=true' '\n>> + test_config pull.autostash false &&\n>> + test_config rebase.autostash true &&\n>> + test_pull_autostash_fail --rebase\n>> +'\n> \n> Another good one.  It might be intereseting to test --no-rebase and\n> make sure it also fails?  I dunno.\n> \n>> +test_expect_success 'pull.autostash=false & rebase.autostash=false' '\n>> + test_config pull.autostash false &&\n>> + test_config rebase.autostash false &&\n>> + test_pull_autostash_fail --rebase\n>> +'\n> \n> Not as interesting as others.\n> \n>> +test_expect_success 'pull.autostash=true & merge.autostash=true' '\n>> + test_config pull.autostash true &&\n>> + test_config merge.autostash true &&\n>> + test_pull_autostash 2 --no-rebase\n>> +'\n> \n> Not as interesting as others.  Throw --no-autostash given on the\n> command line into the mix as well?\n> \n>> +test_expect_success 'pull.autostash=true & merge.autostash=false' '\n>> + test_config pull.autostash true &&\n>> + test_config merge.autostash false &&\n>> + test_pull_autostash 2 --no-rebase\n>> +'\n> \n> OK.  pull.*=true trumps merge.*=false.  We test the other way around\n> next.  Good.\n> \n>> +test_expect_success 'pull.autostash=false & merge.autostash=true' '\n>> + test_config pull.autostash false &&\n>> + test_config merge.autostash true &&\n>> + test_pull_autostash_fail --no-rebase\n>> +'\n>> +\n>> +test_expect_success 'pull.autostash=false & merge.autostash=false' '\n>> + test_config pull.autostash false &&\n>> + test_config merge.autostash false &&\n>> + test_pull_autostash_fail --no-rebase\n>> +'\n> \n> Not very interesting.  Throw anothre that gives --autostash from the\n> command line in the mix, perhaps?\n> \n>> test_expect_success 'pull.rebase' '\n>> git reset --hard before-rebase &&\n>> test_config pull.rebase true &&\n\n\nThank you very much for your thorough review. I will reorganize the\ndocumentation and test cases in v2.\n\n- Lidong"},{"id":"522341","messageId":"20250720124334.12045-1-yldhome2d2@gmail.com","threadId":"63795","inReplyTo":"20250718035221.2293-1-yldhome2d2@gmail.com","subject":"[PATCH v2] pull: add pull.autoStash config option","fromName":"Lidong Yan","fromEmail":"yldhome2d2@gmail.com","sentAt":"2025-07-20T12:43:34Z","receivedAt":"2025-07-20T12:43:57Z","isPatch":true,"sender":{"key":"yldhome2d2@gmail.com","avatar":"https://avatars.githubusercontent.com/u/77328395?v=4"},"body":"Git uses `rebase.autostash` or `merge.autostash` to determine whether a\ndirty worktree is allowed during pull. However, this behavior is not\nclearly documented, making it difficult for users to discover how to\nenable autostash, or causing them to unknowingly enable it. Add new\nconfig option `pull.autostash` along with its documentation and test\ncases.\n\n`pull.autostash` provides the same functionality as `rebase.autostash`\nand `merge.autostash`, but overrides them when set. If `pull.autostash`\nis not set, it falls back to `rebase.autostash` or `merge.autostash`,\ndepending on the value of `pull.rebase`.\n\nSigned-off-by: Lidong Yan <yldhome2d2@gmail.com>\n---\nRange-diff against v1:\n1:  5b7d10d7e9 ! 1:  51a7c66783 pull: add pull.autoStash config option\n    @@ Commit message\n         Signed-off-by: Lidong Yan <yldhome2d2@gmail.com>\n     \n      ## Documentation/config/pull.adoc ##\n    -@@ Documentation/config/pull.adoc: pull.rebase::\n    - \tof merging the default branch from the default remote when \"git\n    - \tpull\" is run. See \"branch.<name>.rebase\" for setting this on a\n    - \tper-branch basis.\n    -+\n    +@@ Documentation/config/pull.adoc: pull.octopus::\n    + \tThe default merge strategy to use when pulling multiple branches\n    + \tat once.\n    + \n     +pull.autoStash::\n    -+\tWhen true, Git will automatically perform a `git stash` before the\n    -+\toperation and then restore the local changes with `git stash pop`\n    -+\tafter the pull is complete. This means that you can run pull on a\n    -+\tdirty worktree. If `pull.autostash` is set, it takes precedence over\n    -+\t`rebase.autostash` and `merge.autostash`. If `pull.autostash` is not\n    -+\tset, it falls back to `rebase.autostash` or `merge.autostash`,\n    -+\tdepending on the value of `pull.rebase`. This option can be\n    -+\toverridden by the `--no-autostash` and `--autostash` options of\n    -+\tlinkgit:git-pull[1]. Defaults to false.\n    - +\n    - When `merges` (or just 'm'), pass the `--rebase-merges` option to 'git rebase'\n    - so that the local merge commits are included in the rebase (see\n    ++\tWhen set to true, automatically create a temporary stash entry\n    ++\tto record the local changes before the operation begins, and\n    ++\trestore them after the operation completes.  When your \"git\n    ++\tpull\" rebases (instead of merges), this may be convenient, since\n    ++\tunlike merging pull that tolerates local changes that do not\n    ++\tinterfere with the merge, rebasing pull refuses to work with any\n    ++\tlocal changes.\n    +++\n    ++If `pull.autostash` is set (either to true or false),\n    ++`merge.autostash` and `rebase.autostash` are ignored.  If\n    ++`pull.autostash` is not set at all, depending on the value of\n    ++`pull.rebase`, `merge.autostash` or `rebase.autostash` is used\n    ++instead.  Can be overridden by the `--[no-]autostash` command line\n    ++option.\n    ++\n    + pull.twohead::\n    + \tThe default merge strategy to use when pulling a single branch.\n     \n      ## builtin/pull.c ##\n     @@ builtin/pull.c: static char *opt_ff;\n    @@ t/t5520-pull.sh: test_expect_success 'pull --no-autostash & merge.autostash unse\n      \ttest_pull_autostash_fail --no-autostash --no-rebase\n      '\n      \n    -+test_expect_success 'pull succeeds with dirty working directory and pull.autostash set' '\n    ++test_expect_success 'pull succeeds with dirty working directory and pull.autostash=true' '\n     +\ttest_config pull.autostash true &&\n     +\ttest_pull_autostash 1 --rebase &&\n    -+\ttest_pull_autostash 2 --no-rebase\n    -+'\n    -+\n    -+test_expect_success 'pull --autostash & pull.autostash=true' '\n    -+\ttest_config pull.autostash true &&\n    ++\ttest_pull_autostash 2 --no-rebase &&\n     +\ttest_pull_autostash 1 --autostash --rebase &&\n     +\ttest_pull_autostash 2 --autostash --no-rebase\n     +'\n     +\n    -+test_expect_success 'pull --autostash & pull.autostash=false' '\n    ++test_expect_success 'pull fails with dirty working directory and pull.autostash=false' '\n     +\ttest_config pull.autostash false &&\n    -+\ttest_pull_autostash 1 --autostash --rebase &&\n    -+\ttest_pull_autostash 2 --autostash --no-rebase\n    -+'\n    -+\n    -+test_expect_success 'pull --autostash & pull.autostash unset' '\n    -+\ttest_unconfig pull.autostash &&\n    -+\ttest_pull_autostash 1 --autostash --rebase &&\n    -+\ttest_pull_autostash 2 --autostash --no-rebase\n    -+'\n    -+\n    -+test_expect_success 'pull --no-autostash & pull.autostash=true' '\n    -+\ttest_config pull.autostash true &&\n    ++\ttest_pull_autostash_fail --rebase &&\n    ++\ttest_pull_autostash_fail --no-rebase &&\n     +\ttest_pull_autostash_fail --no-autostash --rebase &&\n     +\ttest_pull_autostash_fail --no-autostash --no-rebase\n     +'\n     +\n    -+test_expect_success 'pull --no-autostash & pull.autostash=false' '\n    ++test_expect_success 'pull --autostash overrides pull.autostash=false' '\n     +\ttest_config pull.autostash false &&\n    -+\ttest_pull_autostash_fail --no-autostash --rebase &&\n    -+\ttest_pull_autostash_fail --no-autostash --no-rebase\n    ++\ttest_pull_autostash 1 --autostash --rebase &&\n    ++\ttest_pull_autostash 2 --autostash --no-rebase\n     +'\n     +\n    -+test_expect_success 'pull --no-autostash & pull.autostash unset' '\n    -+\ttest_unconfig pull.autostash &&\n    ++test_expect_success 'pull --no-autostash overrides pull.autostash=true' '\n    ++\ttest_config pull.autostash true &&\n     +\ttest_pull_autostash_fail --no-autostash --rebase &&\n     +\ttest_pull_autostash_fail --no-autostash --no-rebase\n     +'\n     +\n    -+test_expect_success 'pull.autostash=true & rebase.autostash=true' '\n    ++test_expect_success 'pull.autostash=true overrides rebase.autostash' '\n     +\ttest_config pull.autostash true &&\n     +\ttest_config rebase.autostash true &&\n    -+\ttest_pull_autostash 1 --rebase\n    -+'\n    -+\n    -+test_expect_success 'pull.autostash=true & rebase.autostash=false' '\n    -+\ttest_config pull.autostash true &&\n    ++\ttest_pull_autostash 1 --rebase &&\n     +\ttest_config rebase.autostash false &&\n     +\ttest_pull_autostash 1 --rebase\n     +'\n     +\n    -+test_expect_success 'pull.autostash=false & rebase.autostash=true' '\n    ++test_expect_success 'pull.autostash=false overrides rebase.autostash' '\n     +\ttest_config pull.autostash false &&\n     +\ttest_config rebase.autostash true &&\n    -+\ttest_pull_autostash_fail --rebase\n    -+'\n    -+\n    -+test_expect_success 'pull.autostash=false & rebase.autostash=false' '\n    -+\ttest_config pull.autostash false &&\n    ++\ttest_pull_autostash_fail --rebase &&\n     +\ttest_config rebase.autostash false &&\n     +\ttest_pull_autostash_fail --rebase\n     +'\n     +\n    -+test_expect_success 'pull.autostash=true & merge.autostash=true' '\n    ++test_expect_success 'pull.autostash=true overrides merge.autostash' '\n     +\ttest_config pull.autostash true &&\n     +\ttest_config merge.autostash true &&\n    -+\ttest_pull_autostash 2 --no-rebase\n    -+'\n    -+\n    -+test_expect_success 'pull.autostash=true & merge.autostash=false' '\n    -+\ttest_config pull.autostash true &&\n    ++\ttest_pull_autostash 2 --no-rebase &&\n     +\ttest_config merge.autostash false &&\n     +\ttest_pull_autostash 2 --no-rebase\n     +'\n     +\n    -+test_expect_success 'pull.autostash=false & merge.autostash=true' '\n    ++test_expect_success 'pull.autostash=false overrides merge.autostash' '\n     +\ttest_config pull.autostash false &&\n     +\ttest_config merge.autostash true &&\n    -+\ttest_pull_autostash_fail --no-rebase\n    -+'\n    -+\n    -+test_expect_success 'pull.autostash=false & merge.autostash=false' '\n    -+\ttest_config pull.autostash false &&\n    ++\ttest_pull_autostash_fail --no-rebase &&\n     +\ttest_config merge.autostash false &&\n     +\ttest_pull_autostash_fail --no-rebase\n     +'\n\n Documentation/config/pull.adoc | 16 +++++++++\n builtin/pull.c                 | 20 ++++++++++--\n t/t5520-pull.sh                | 60 ++++++++++++++++++++++++++++++++++\n 3 files changed, 93 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/config/pull.adoc b/Documentation/config/pull.adoc\nindex 9349e09261..125c930f72 100644\n--- a/Documentation/config/pull.adoc\n+++ b/Documentation/config/pull.adoc\n@@ -29,5 +29,21 @@ pull.octopus::\n \tThe default merge strategy to use when pulling multiple branches\n \tat once.\n \n+pull.autoStash::\n+\tWhen set to true, automatically create a temporary stash entry\n+\tto record the local changes before the operation begins, and\n+\trestore them after the operation completes.  When your \"git\n+\tpull\" rebases (instead of merges), this may be convenient, since\n+\tunlike merging pull that tolerates local changes that do not\n+\tinterfere with the merge, rebasing pull refuses to work with any\n+\tlocal changes.\n++\n+If `pull.autostash` is set (either to true or false),\n+`merge.autostash` and `rebase.autostash` are ignored.  If\n+`pull.autostash` is not set at all, depending on the value of\n+`pull.rebase`, `merge.autostash` or `rebase.autostash` is used\n+instead.  Can be overridden by the `--[no-]autostash` command line\n+option.\n+\n pull.twohead::\n \tThe default merge strategy to use when pulling a single branch.\ndiff --git a/builtin/pull.c b/builtin/pull.c\nindex c593f324fe..2a6c2e4a37 100644\n--- a/builtin/pull.c\n+++ b/builtin/pull.c\n@@ -90,7 +90,8 @@ static char *opt_ff;\n static const char *opt_verify_signatures;\n static const char *opt_verify;\n static int opt_autostash = -1;\n-static int config_autostash;\n+static int config_rebase_autostash;\n+static int config_pull_autostash = -1;\n static int check_trust_level = 1;\n static struct strvec opt_strategies = STRVEC_INIT;\n static struct strvec opt_strategy_opts = STRVEC_INIT;\n@@ -367,7 +368,18 @@ static int git_pull_config(const char *var, const char *value,\n \t\t\t   const struct config_context *ctx, void *cb)\n {\n \tif (!strcmp(var, \"rebase.autostash\")) {\n-\t\tconfig_autostash = git_config_bool(var, value);\n+\t\t/*\n+\t\t * run_rebase() also reads this option. The reason we handle it here is\n+\t\t * that when pull.rebase is true, a fast-forward may occur without\n+\t\t * invoking run_rebase(). We need to ensure that autostash is set even\n+\t\t * in the fast-forward case.\n+\t\t *\n+\t\t * run_merge() handles merge.autostash, so we don't handle it here.\n+\t\t */\n+\t\tconfig_rebase_autostash = git_config_bool(var, value);\n+\t\treturn 0;\n+\t} else if (!strcmp(var, \"pull.autostash\")) {\n+\t\tconfig_pull_autostash = git_config_bool(var, value);\n \t\treturn 0;\n \t} else if (!strcmp(var, \"submodule.recurse\")) {\n \t\trecurse_submodules = git_config_bool(var, value) ?\n@@ -1006,6 +1018,8 @@ int cmd_pull(int argc,\n \t}\n \n \targc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);\n+\tif (opt_autostash == -1)\n+\t\topt_autostash = config_pull_autostash;\n \n \tif (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT)\n \t\trecurse_submodules = recurse_submodules_cli;\n@@ -1052,7 +1066,7 @@ int cmd_pull(int argc,\n \n \tif (opt_rebase) {\n \t\tif (opt_autostash == -1)\n-\t\t\topt_autostash = config_autostash;\n+\t\t\topt_autostash = config_rebase_autostash;\n \n \t\tif (is_null_oid(&orig_head) && !is_index_unborn(the_repository->index))\n \t\t\tdie(_(\"Updating an unborn branch with changes added to the index.\"));\ndiff --git a/t/t5520-pull.sh b/t/t5520-pull.sh\nindex 63c9a8f04b..0e0019347e 100755\n--- a/t/t5520-pull.sh\n+++ b/t/t5520-pull.sh\n@@ -472,6 +472,66 @@ test_expect_success 'pull --no-autostash & merge.autostash unset' '\n \ttest_pull_autostash_fail --no-autostash --no-rebase\n '\n \n+test_expect_success 'pull succeeds with dirty working directory and pull.autostash=true' '\n+\ttest_config pull.autostash true &&\n+\ttest_pull_autostash 1 --rebase &&\n+\ttest_pull_autostash 2 --no-rebase &&\n+\ttest_pull_autostash 1 --autostash --rebase &&\n+\ttest_pull_autostash 2 --autostash --no-rebase\n+'\n+\n+test_expect_success 'pull fails with dirty working directory and pull.autostash=false' '\n+\ttest_config pull.autostash false &&\n+\ttest_pull_autostash_fail --rebase &&\n+\ttest_pull_autostash_fail --no-rebase &&\n+\ttest_pull_autostash_fail --no-autostash --rebase &&\n+\ttest_pull_autostash_fail --no-autostash --no-rebase\n+'\n+\n+test_expect_success 'pull --autostash overrides pull.autostash=false' '\n+\ttest_config pull.autostash false &&\n+\ttest_pull_autostash 1 --autostash --rebase &&\n+\ttest_pull_autostash 2 --autostash --no-rebase\n+'\n+\n+test_expect_success 'pull --no-autostash overrides pull.autostash=true' '\n+\ttest_config pull.autostash true &&\n+\ttest_pull_autostash_fail --no-autostash --rebase &&\n+\ttest_pull_autostash_fail --no-autostash --no-rebase\n+'\n+\n+test_expect_success 'pull.autostash=true overrides rebase.autostash' '\n+\ttest_config pull.autostash true &&\n+\ttest_config rebase.autostash true &&\n+\ttest_pull_autostash 1 --rebase &&\n+\ttest_config rebase.autostash false &&\n+\ttest_pull_autostash 1 --rebase\n+'\n+\n+test_expect_success 'pull.autostash=false overrides rebase.autostash' '\n+\ttest_config pull.autostash false &&\n+\ttest_config rebase.autostash true &&\n+\ttest_pull_autostash_fail --rebase &&\n+\ttest_config rebase.autostash false &&\n+\ttest_pull_autostash_fail --rebase\n+'\n+\n+test_expect_success 'pull.autostash=true overrides merge.autostash' '\n+\ttest_config pull.autostash true &&\n+\ttest_config merge.autostash true &&\n+\ttest_pull_autostash 2 --no-rebase &&\n+\ttest_config merge.autostash false &&\n+\ttest_pull_autostash 2 --no-rebase\n+'\n+\n+test_expect_success 'pull.autostash=false overrides merge.autostash' '\n+\ttest_config pull.autostash false &&\n+\ttest_config merge.autostash true &&\n+\ttest_pull_autostash_fail --no-rebase &&\n+\ttest_config merge.autostash false &&\n+\ttest_pull_autostash_fail --no-rebase\n+'\n+\n test_expect_success 'pull.rebase' '\n \tgit reset --hard before-rebase &&\n \ttest_config pull.rebase true &&\n-- \n2.39.5 (Apple Git-154)\n\n"},{"id":"522376","messageId":"xmqqjz41w5yp.fsf@gitster.g","threadId":"63795","inReplyTo":"20250720124334.12045-1-yldhome2d2@gmail.com","subject":"Re: [PATCH v2] pull: add pull.autoStash config option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-07-21T22:10:22Z","receivedAt":"2025-07-21T22:10:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Lidong Yan <yldhome2d2@gmail.com> writes:\n\n>  Documentation/config/pull.adoc | 16 +++++++++\n>  builtin/pull.c                 | 20 ++++++++++--\n>  t/t5520-pull.sh                | 60 ++++++++++++++++++++++++++++++++++\n>  3 files changed, 93 insertions(+), 3 deletions(-)\n\nThanks, will replace.\n\nShall we mark it for 'next' now?\n"}]}