Skip to content

Commit 7c7cf62

Browse files
committed
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
2 parents 6c22093 + 361cb52 commit 7c7cf62

File tree

2 files changed

+43
-2
lines changed

2 files changed

+43
-2
lines changed

builtin/pull.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,33 @@ static int get_can_ff(struct object_id *orig_head,
937937
return ret;
938938
}
939939

940+
/*
941+
* Is orig_head a descendant of _all_ merge_heads?
942+
* Unfortunately is_descendant_of() cannot be used as it asks
943+
* if orig_head is a descendant of at least one of them.
944+
*/
945+
static int already_up_to_date(struct object_id *orig_head,
946+
struct oid_array *merge_heads)
947+
{
948+
int i;
949+
struct commit *ours;
950+
951+
ours = lookup_commit_reference(the_repository, orig_head);
952+
for (i = 0; i < merge_heads->nr; i++) {
953+
struct commit_list *list = NULL;
954+
struct commit *theirs;
955+
int ok;
956+
957+
theirs = lookup_commit_reference(the_repository, &merge_heads->oid[i]);
958+
commit_list_insert(theirs, &list);
959+
ok = repo_is_descendant_of(the_repository, ours, list);
960+
free_commit_list(list);
961+
if (!ok)
962+
return 0;
963+
}
964+
return 1;
965+
}
966+
940967
static void show_advice_pull_non_ff(void)
941968
{
942969
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)
10781105

10791106
/* ff-only takes precedence over rebase */
10801107
if (opt_ff && !strcmp(opt_ff, "--ff-only")) {
1081-
if (!can_ff)
1108+
if (!can_ff && !already_up_to_date(&orig_head, &merge_heads))
10821109
die_ff_impossible();
10831110
opt_rebase = REBASE_FALSE;
10841111
}

t/t7601-merge-pull-config.sh

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
test_description='git merge
44
5-
Testing pull.* configuration parsing.'
5+
Testing pull.* configuration parsing and other things.'
66

77
. ./test-lib.sh
88

@@ -387,6 +387,20 @@ test_expect_success 'pull prevents non-fast-forward with "only" in pull.ff' '
387387
test_must_fail git pull . c3
388388
'
389389

390+
test_expect_success 'already-up-to-date pull succeeds with "only" in pull.ff' '
391+
git reset --hard c1 &&
392+
test_config pull.ff only &&
393+
git pull . c0 &&
394+
test "$(git rev-parse HEAD)" = "$(git rev-parse c1)"
395+
'
396+
397+
test_expect_success 'already-up-to-date pull/rebase succeeds with "only" in pull.ff' '
398+
git reset --hard c1 &&
399+
test_config pull.ff only &&
400+
git -c pull.rebase=true pull . c0 &&
401+
test "$(git rev-parse HEAD)" = "$(git rev-parse c1)"
402+
'
403+
390404
test_expect_success 'merge c1 with c2 (ours in pull.twohead)' '
391405
git reset --hard c1 &&
392406
git config pull.twohead ours &&

0 commit comments

Comments
 (0)