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
This commit is contained in:
Junio C Hamano
2025-08-01 11:27:13 -07:00
3 changed files with 93 additions and 3 deletions

View File

@@ -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.

View File

@@ -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."));

View File

@@ -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 &&