summaryrefslogtreecommitdiff
path: root/builtin/pull.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2021-10-20 17:28:44 (GMT)
committerJunio C Hamano <gitster@pobox.com>2021-10-29 07:15:39 (GMT)
commit361cb52383fb986f76a34506bdec9a1dd11133f0 (patch)
treebafea74882456172c9ed5982cce4d549e31c4360 /builtin/pull.c
parentaf6d1d602a8f64164b266364339c4e936d5bbc33 (diff)
downloadgit-361cb52383fb986f76a34506bdec9a1dd11133f0.zip
git-361cb52383fb986f76a34506bdec9a1dd11133f0.tar.gz
git-361cb52383fb986f76a34506bdec9a1dd11133f0.tar.bz2
pull: --ff-only should make it a noop when already-up-to-date
Earlier, we made sure that "git pull --ff-only" (and "git -c pull.ff=only pull") errors out when our current HEAD is not an ancestor of the tip of the history we are merging, but the condition to trigger the error was implemented incorrectly. Imagine you forked from a remote branch, built your history on top of it, and then attempted to pull from them again. If they have not made any update in the meantime, our current HEAD is obviously not their ancestor, and this new error triggers. Without the --ff-only option, we just report that there is no need to pull; we did the same historically with --ff-only, too. Make sure we do not fail with the recently added check to restore the historical behaviour. Reported-by: Kenneth Arnold <ka37@calvin.edu> Helped-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'builtin/pull.c')
-rw-r--r--builtin/pull.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/builtin/pull.c b/builtin/pull.c
index b311ea6..54286b5 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -933,6 +933,33 @@ static int get_can_ff(struct object_id *orig_head,
return ret;
}
+/*
+ * Is orig_head a descendant of _all_ merge_heads?
+ * Unfortunately is_descendant_of() cannot be used as it asks
+ * if orig_head is a descendant of at least one of them.
+ */
+static int already_up_to_date(struct object_id *orig_head,
+ struct oid_array *merge_heads)
+{
+ int i;
+ struct commit *ours;
+
+ ours = lookup_commit_reference(the_repository, orig_head);
+ for (i = 0; i < merge_heads->nr; i++) {
+ struct commit_list *list = NULL;
+ struct commit *theirs;
+ int ok;
+
+ theirs = lookup_commit_reference(the_repository, &merge_heads->oid[i]);
+ commit_list_insert(theirs, &list);
+ ok = repo_is_descendant_of(the_repository, ours, list);
+ free_commit_list(list);
+ if (!ok)
+ return 0;
+ }
+ return 1;
+}
+
static void show_advice_pull_non_ff(void)
{
advise(_("You have divergent branches and need to specify how to reconcile them.\n"
@@ -1074,7 +1101,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
/* ff-only takes precedence over rebase */
if (opt_ff && !strcmp(opt_ff, "--ff-only")) {
- if (!can_ff)
+ if (!can_ff && !already_up_to_date(&orig_head, &merge_heads))
die_ff_impossible();
opt_rebase = REBASE_FALSE;
}