summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2025-08-01 11:27:13 -0700
committerJunio C Hamano <gitster@pobox.com>2025-08-01 11:27:14 -0700
commit6fe666b2cef09571aa01d9ffae179472aeaf9378 (patch)
tree67c34160a2459a37b7c08feb43dc004bc26c8b45
parentcbcde15e7316a28f9deb49b4f48e9748b5a903d2 (diff)
parente3378607c8675a2db6d997bd9781ae5500a2ec57 (diff)
Merge branch 'ly/pull-autostash'
"git pull" learned to pay attention to pull.autostash configuration variable, which overrides rebase/merge.autostash. * ly/pull-autostash: pull: add pull.autoStash config option
-rw-r--r--Documentation/config/pull.adoc16
-rw-r--r--builtin/pull.c20
-rwxr-xr-xt/t5520-pull.sh60
3 files changed, 93 insertions, 3 deletions
diff --git a/Documentation/config/pull.adoc b/Documentation/config/pull.adoc
index 9349e09261..125c930f72 100644
--- a/Documentation/config/pull.adoc
+++ b/Documentation/config/pull.adoc
@@ -29,5 +29,21 @@ pull.octopus::
The default merge strategy to use when pulling multiple branches
at once.
+pull.autoStash::
+ When set to true, automatically create a temporary stash entry
+ to record the local changes before the operation begins, and
+ restore them after the operation completes. When your "git
+ pull" rebases (instead of merges), this may be convenient, since
+ unlike merging pull that tolerates local changes that do not
+ interfere with the merge, rebasing pull refuses to work with any
+ local changes.
++
+If `pull.autostash` is set (either to true or false),
+`merge.autostash` and `rebase.autostash` are ignored. If
+`pull.autostash` is not set at all, depending on the value of
+`pull.rebase`, `merge.autostash` or `rebase.autostash` is used
+instead. Can be overridden by the `--[no-]autostash` command line
+option.
+
pull.twohead::
The default merge strategy to use when pulling a single branch.
diff --git a/builtin/pull.c b/builtin/pull.c
index c593f324fe..2a6c2e4a37 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -90,7 +90,8 @@ static char *opt_ff;
static const char *opt_verify_signatures;
static const char *opt_verify;
static int opt_autostash = -1;
-static int config_autostash;
+static int config_rebase_autostash;
+static int config_pull_autostash = -1;
static int check_trust_level = 1;
static struct strvec opt_strategies = STRVEC_INIT;
static struct strvec opt_strategy_opts = STRVEC_INIT;
@@ -367,7 +368,18 @@ static int git_pull_config(const char *var, const char *value,
const struct config_context *ctx, void *cb)
{
if (!strcmp(var, "rebase.autostash")) {
- config_autostash = git_config_bool(var, value);
+ /*
+ * run_rebase() also reads this option. The reason we handle it here is
+ * that when pull.rebase is true, a fast-forward may occur without
+ * invoking run_rebase(). We need to ensure that autostash is set even
+ * in the fast-forward case.
+ *
+ * run_merge() handles merge.autostash, so we don't handle it here.
+ */
+ config_rebase_autostash = git_config_bool(var, value);
+ return 0;
+ } else if (!strcmp(var, "pull.autostash")) {
+ config_pull_autostash = git_config_bool(var, value);
return 0;
} else if (!strcmp(var, "submodule.recurse")) {
recurse_submodules = git_config_bool(var, value) ?
@@ -1006,6 +1018,8 @@ int cmd_pull(int argc,
}
argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);
+ if (opt_autostash == -1)
+ opt_autostash = config_pull_autostash;
if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT)
recurse_submodules = recurse_submodules_cli;
@@ -1052,7 +1066,7 @@ int cmd_pull(int argc,
if (opt_rebase) {
if (opt_autostash == -1)
- opt_autostash = config_autostash;
+ opt_autostash = config_rebase_autostash;
if (is_null_oid(&orig_head) && !is_index_unborn(the_repository->index))
die(_("Updating an unborn branch with changes added to the index."));
diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh
index 63c9a8f04b..0e0019347e 100755
--- a/t/t5520-pull.sh
+++ b/t/t5520-pull.sh
@@ -472,6 +472,66 @@ test_expect_success 'pull --no-autostash & merge.autostash unset' '
test_pull_autostash_fail --no-autostash --no-rebase
'
+test_expect_success 'pull succeeds with dirty working directory and pull.autostash=true' '
+ test_config pull.autostash true &&
+ test_pull_autostash 1 --rebase &&
+ test_pull_autostash 2 --no-rebase &&
+ test_pull_autostash 1 --autostash --rebase &&
+ test_pull_autostash 2 --autostash --no-rebase
+'
+
+test_expect_success 'pull fails with dirty working directory and pull.autostash=false' '
+ test_config pull.autostash false &&
+ test_pull_autostash_fail --rebase &&
+ test_pull_autostash_fail --no-rebase &&
+ test_pull_autostash_fail --no-autostash --rebase &&
+ test_pull_autostash_fail --no-autostash --no-rebase
+'
+
+test_expect_success 'pull --autostash overrides pull.autostash=false' '
+ test_config pull.autostash false &&
+ test_pull_autostash 1 --autostash --rebase &&
+ test_pull_autostash 2 --autostash --no-rebase
+'
+
+test_expect_success 'pull --no-autostash overrides pull.autostash=true' '
+ test_config pull.autostash true &&
+ test_pull_autostash_fail --no-autostash --rebase &&
+ test_pull_autostash_fail --no-autostash --no-rebase
+'
+
+test_expect_success 'pull.autostash=true overrides rebase.autostash' '
+ test_config pull.autostash true &&
+ test_config rebase.autostash true &&
+ test_pull_autostash 1 --rebase &&
+ test_config rebase.autostash false &&
+ test_pull_autostash 1 --rebase
+'
+
+test_expect_success 'pull.autostash=false overrides rebase.autostash' '
+ test_config pull.autostash false &&
+ test_config rebase.autostash true &&
+ test_pull_autostash_fail --rebase &&
+ test_config rebase.autostash false &&
+ test_pull_autostash_fail --rebase
+'
+
+test_expect_success 'pull.autostash=true overrides merge.autostash' '
+ test_config pull.autostash true &&
+ test_config merge.autostash true &&
+ test_pull_autostash 2 --no-rebase &&
+ test_config merge.autostash false &&
+ test_pull_autostash 2 --no-rebase
+'
+
+test_expect_success 'pull.autostash=false overrides merge.autostash' '
+ test_config pull.autostash false &&
+ test_config merge.autostash true &&
+ test_pull_autostash_fail --no-rebase &&
+ test_config merge.autostash false &&
+ test_pull_autostash_fail --no-rebase
+'
+
test_expect_success 'pull.rebase' '
git reset --hard before-rebase &&
test_config pull.rebase true &&