summaryrefslogtreecommitdiff
path: root/sequencer.c
diff options
context:
space:
mode:
authorJohannes Schindelin <johannes.schindelin@gmx.de>2018-04-25 12:28:56 (GMT)
committerJunio C Hamano <gitster@pobox.com>2018-04-26 03:28:42 (GMT)
commitd1e8b0114bef98e8efe3f8d35430300ff9e00443 (patch)
tree9d0b6aff06162167b92a938c8a270d3ae7dd0db8 /sequencer.c
parent4c68e7ddb59457efe9d3a141dc600feda86cbe67 (diff)
downloadgit-d1e8b0114bef98e8efe3f8d35430300ff9e00443.zip
git-d1e8b0114bef98e8efe3f8d35430300ff9e00443.tar.gz
git-d1e8b0114bef98e8efe3f8d35430300ff9e00443.tar.bz2
sequencer: fast-forward `merge` commands, if possible
Just like with regular `pick` commands, if we are trying to rebase a merge commit, we now test whether the parents of said commit match HEAD and the commits to be merged, and fast-forward if possible. This is not only faster, but also avoids unnecessary proliferation of new objects. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'sequencer.c')
-rw-r--r--sequencer.c33
1 files changed, 32 insertions, 1 deletions
diff --git a/sequencer.c b/sequencer.c
index 94f4831..6722095 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2687,7 +2687,7 @@ static int do_merge(struct commit *commit, const char *arg, int arg_len,
struct commit *head_commit, *merge_commit, *i;
struct commit_list *bases, *j, *reversed = NULL;
struct merge_options o;
- int merge_arg_len, oneline_offset, ret;
+ int merge_arg_len, oneline_offset, can_fast_forward, ret;
static struct lock_file lock;
const char *p;
@@ -2772,6 +2772,37 @@ static int do_merge(struct commit *commit, const char *arg, int arg_len,
}
}
+ /*
+ * If HEAD is not identical to the first parent of the original merge
+ * commit, we cannot fast-forward.
+ */
+ can_fast_forward = opts->allow_ff && commit && commit->parents &&
+ !oidcmp(&commit->parents->item->object.oid,
+ &head_commit->object.oid);
+
+ /*
+ * If the merge head is different from the original one, we cannot
+ * fast-forward.
+ */
+ if (can_fast_forward) {
+ struct commit_list *second_parent = commit->parents->next;
+
+ if (second_parent && !second_parent->next &&
+ oidcmp(&merge_commit->object.oid,
+ &second_parent->item->object.oid))
+ can_fast_forward = 0;
+ }
+
+ if (can_fast_forward && commit->parents->next &&
+ !commit->parents->next->next &&
+ !oidcmp(&commit->parents->next->item->object.oid,
+ &merge_commit->object.oid)) {
+ rollback_lock_file(&lock);
+ ret = fast_forward_to(&commit->object.oid,
+ &head_commit->object.oid, 0, opts);
+ goto leave_merge;
+ }
+
write_message(oid_to_hex(&merge_commit->object.oid), GIT_SHA1_HEXSZ,
git_path_merge_head(), 0);
write_message("no-ff", 5, git_path_merge_mode(), 0);