From: "D. Ben Knoble" <ben.knoble+github@gmail.com>
To: git@vger.kernel.org
Cc: "D. Ben Knoble" <ben.knoble+github@gmail.com>,
"Alex Henrie" <alexhenrie24@gmail.com>,
"Ævar Arnfjörð Bjarmason" <avarab@gmail.com>,
"Felipe Contreras" <felipe.contreras@gmail.com>,
"Patrick Steinhardt" <ps@pks.im>,
"Junio C Hamano" <gitster@pobox.com>,
"Elijah Newren" <newren@gmail.com>
Subject: [PATCH] pull: allow branch.<name>.rebase to override pull.ff=only
Date: Tue, 4 Feb 2025 22:06:28 -0500 [thread overview]
Message-ID: <20250205030642.95252-1-ben.knoble+github@gmail.com> (raw)
When running "git pull" with the following configuration options, we
fail to merge divergent branches:
- pull.ff=only
- pull.rebase (unset)
- branch.<current_branch>.rebase=true
Yet it seems that the user intended to make rebase the default for the
current branch while using --ff-only for non-rebase pulls. Since this
case appears uncovered by existing tests, changing the behavior here
might be safe: it makes what was an error into a successful rebase.
Add a test for the behavior and make it pass: this requires knowing from
where the rebase was requested. Previous commits (e4dc25ed49 (pull:
since --ff-only overrides, handle it first, 2021-07-22), adc27d6a93
(pull: make --rebase and --no-rebase override pull.ff=only, 2021-07-22))
took care to differentiate that --rebase overrides pull.ff=only, but
don't distinguish which config setting requests the rebase. Split
config_get_rebase into 2 parts so that we know where the rebase comes
from, since we only want to allow branch-config to override pull.ff=only
(like --rebase does); pull.rebase should still be overridden by
pull.ff=only or --ff-only.
Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>
---
Notes:
- I also looked at ea1954af77 (pull: should be noop when already-up-to-date,
2021-11-17) when trying to understand how some options override others,
but it didnt' seem germane to the final version.
- I think I've got the right test script, since it's the one that started
failing before I added the "else" branch to the new code (which also
confirms that it's necessary to preserve current behavior); the only new
behavior should be the one mentioned by the new test.
- A possible #leftoverbits: it would be good to document more clearly the
interplay of --ff[-only], --rebase, pull.ff, pull.rebase, and
branch.<name>.rebase, particularly when they override each other.
Confusingly, branch.<name>.merge has nothing to do with whether pull will
merge or rebase ;) lest you think I'd forgotten something that _looks_
parallel to pull.rebase.
builtin/pull.c | 39 ++++++++++++++++++++++++++++--------
t/t7601-merge-pull-config.sh | 8 ++++++++
2 files changed, 39 insertions(+), 8 deletions(-)
diff --git a/builtin/pull.c b/builtin/pull.c
index 9c4a00620a..c30f233dcc 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -326,13 +326,13 @@ static const char *config_get_ff(void)
}
/**
- * Returns the default configured value for --rebase. It first looks for the
+ * Returns the default configured value for --rebase. It looks for the
* value of "branch.$curr_branch.rebase", where $curr_branch is the current
* branch, and if HEAD is detached or the configuration key does not exist,
- * looks for the value of "pull.rebase". If both configuration keys do not
- * exist, returns REBASE_FALSE.
+ * considers the result unspecified. Follow up by checking
+ * config_get_rebase_pull.
*/
-static enum rebase_type config_get_rebase(int *rebase_unspecified)
+static enum rebase_type config_get_rebase_branch(int *rebase_unspecified)
{
struct branch *curr_branch = branch_get("HEAD");
const char *value;
@@ -349,11 +349,22 @@ static enum rebase_type config_get_rebase(int *rebase_unspecified)
free(key);
}
+ *rebase_unspecified = 1;
+ return REBASE_INVALID;
+}
+
+/*
+ * Looks for the value of "pull.rebase". If it does not exist, returns
+ * REBASE_FALSE.
+ */
+static enum rebase_type config_get_rebase_pull(int *rebase_unspecified)
+{
+ const char *value;
+
if (!git_config_get_value("pull.rebase", &value))
return parse_config_rebase("pull.rebase", value, 1);
*rebase_unspecified = 1;
-
return REBASE_FALSE;
}
@@ -1026,7 +1037,7 @@ int cmd_pull(int argc,
* are relying on the next if-condition happening before
* the config_get_rebase() call so that an explicit
* "--rebase" can override a config setting of
- * pull.ff=only.
+ * pull.ff=only. [continued…]
*/
if (opt_rebase >= 0 && opt_ff && !strcmp(opt_ff, "--ff-only")) {
free(opt_ff);
@@ -1034,8 +1045,20 @@ int cmd_pull(int argc,
}
}
- if (opt_rebase < 0)
- opt_rebase = config_get_rebase(&rebase_unspecified);
+ if (opt_rebase < 0) {
+ /*
+ * […continued] But, if the config requests rebase *for this
+ * branch*, override --ff-only, which otherwise takes precedence
+ * over pull.rebase=true.
+ */
+ opt_rebase = config_get_rebase_branch(&rebase_unspecified);
+ if (opt_rebase >= 0 && opt_ff && !strcmp(opt_ff, "--ff-only")) {
+ free(opt_ff);
+ opt_ff = xstrdup("--ff");
+ } else {
+ opt_rebase = config_get_rebase_pull(&rebase_unspecified);
+ }
+ }
if (repo_read_index_unmerged(the_repository))
die_resolve_conflict("pull");
diff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh
index 199a1d5db3..fd99f46aad 100755
--- a/t/t7601-merge-pull-config.sh
+++ b/t/t7601-merge-pull-config.sh
@@ -113,6 +113,14 @@
test_grep ! "You have divergent branches" err
'
+test_expect_success 'pull.rebase not set and pull.ff=only and branch.<name>.rebase=true (not-fast-forward)' '
+ git reset --hard c2 &&
+ test_config pull.ff only &&
+ git switch -c bc2 &&
+ test_config branch.bc2.rebase true &&
+ git pull . c1
+'
+
test_expect_success 'pull.rebase not set and --rebase given (not-fast-forward)' '
git reset --hard c2 &&
git pull --rebase . c1 2>err &&
--
2.47.0
next reply other threads:[~2025-02-05 3:11 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-05 3:06 D. Ben Knoble [this message]
2025-02-05 13:08 ` [PATCH] pull: allow branch.<name>.rebase to override pull.ff=only Junio C Hamano
2025-02-05 16:36 ` D. Ben Knoble
2025-02-05 17:42 ` Junio C Hamano
2025-02-05 21:14 ` D. Ben Knoble
2025-02-07 2:35 ` Alex Henrie
2025-02-10 20:26 ` D. Ben Knoble
2025-02-11 6:55 ` Alex Henrie
2025-04-22 20:03 ` D. Ben Knoble
2025-04-22 19:58 ` D. Ben Knoble
2025-04-22 20:05 ` D. Ben Knoble
2025-04-22 20:07 ` D. Ben Knoble
2025-04-22 20:30 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250205030642.95252-1-ben.knoble+github@gmail.com \
--to=ben.knoble+github@gmail.com \
--cc=alexhenrie24@gmail.com \
--cc=avarab@gmail.com \
--cc=felipe.contreras@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=newren@gmail.com \
--cc=ps@pks.im \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).