summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2021-11-10 23:01:19 (GMT)
committerJunio C Hamano <gitster@pobox.com>2021-11-10 23:01:19 (GMT)
commit7c7cf62c485f527bee6d3eb7e37dcfbf8064cab2 (patch)
tree1ae588b26347be9651758ca0c3137245f07b0fef
parent6c220937e2b26d85920bf2d38ff2464a0d57fd6b (diff)
parent361cb52383fb986f76a34506bdec9a1dd11133f0 (diff)
downloadgit-7c7cf62c485f527bee6d3eb7e37dcfbf8064cab2.zip
git-7c7cf62c485f527bee6d3eb7e37dcfbf8064cab2.tar.gz
git-7c7cf62c485f527bee6d3eb7e37dcfbf8064cab2.tar.bz2
Merge branch 'jc/fix-pull-ff-only-when-already-up-to-date'
"git pull --ff-only" and "git pull --rebase --ff-only" should make it a no-op to attempt pulling from a remote that is behind us, but instead the command errored out by saying it was impossible to fast-forward, which may technically be true, but not a useful thing to diagnose as an error. This has been corrected. * jc/fix-pull-ff-only-when-already-up-to-date: pull: --ff-only should make it a noop when already-up-to-date
-rw-r--r--builtin/pull.c29
-rwxr-xr-xt/t7601-merge-pull-config.sh16
2 files changed, 43 insertions, 2 deletions
diff --git a/builtin/pull.c b/builtin/pull.c
index efe4f4a..127798b 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -937,6 +937,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"
@@ -1078,7 +1105,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;
}
diff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh
index 1f652f4..6275641 100755
--- a/t/t7601-merge-pull-config.sh
+++ b/t/t7601-merge-pull-config.sh
@@ -2,7 +2,7 @@
test_description='git merge
-Testing pull.* configuration parsing.'
+Testing pull.* configuration parsing and other things.'
. ./test-lib.sh
@@ -387,6 +387,20 @@ test_expect_success 'pull prevents non-fast-forward with "only" in pull.ff' '
test_must_fail git pull . c3
'
+test_expect_success 'already-up-to-date pull succeeds with "only" in pull.ff' '
+ git reset --hard c1 &&
+ test_config pull.ff only &&
+ git pull . c0 &&
+ test "$(git rev-parse HEAD)" = "$(git rev-parse c1)"
+'
+
+test_expect_success 'already-up-to-date pull/rebase succeeds with "only" in pull.ff' '
+ git reset --hard c1 &&
+ test_config pull.ff only &&
+ git -c pull.rebase=true pull . c0 &&
+ test "$(git rev-parse HEAD)" = "$(git rev-parse c1)"
+'
+
test_expect_success 'merge c1 with c2 (ours in pull.twohead)' '
git reset --hard c1 &&
git config pull.twohead ours &&