diff --git a/builtin/commit.c b/builtin/commit.c index b2a6c7f100d82c4160c4bea6b4663af5459194cc..be370f64a995804ec6b62e03f7c6940044e08e24 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -1730,7 +1730,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) allow_fast_forward = 0; } if (allow_fast_forward) - parents = reduce_heads(parents); + reduce_heads_replace(&parents); } else { if (!reflog_msg) reflog_msg = (whence == FROM_CHERRY_PICK) diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index e99b5ddbf9a51be17bc0d976c942c29afe6563cd..27a2361e91dcd94cba4556b04b028286835f8823 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -571,7 +571,7 @@ static void find_merge_parents(struct merge_parents *result, head_commit = lookup_commit(head); if (head_commit) commit_list_insert(head_commit, &parents); - parents = reduce_heads(parents); + reduce_heads_replace(&parents); while (parents) { struct commit *cmit = pop_commit(&parents); diff --git a/builtin/merge-base.c b/builtin/merge-base.c index 6dbd167d3b0874cd966b4590951a12d01f8f6aeb..24f6c7193546b91a8644a4417bfc6d6d94da6a62 100644 --- a/builtin/merge-base.c +++ b/builtin/merge-base.c @@ -9,20 +9,20 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all) { - struct commit_list *result; + struct commit_list *result, *r; result = get_merge_bases_many_dirty(rev[0], rev_nr - 1, rev + 1); if (!result) return 1; - while (result) { - printf("%s\n", oid_to_hex(&result->item->object.oid)); + for (r = result; r; r = r->next) { + printf("%s\n", oid_to_hex(&r->item->object.oid)); if (!show_all) - return 0; - result = result->next; + break; } + free_commit_list(result); return 0; } @@ -51,45 +51,47 @@ static struct commit *get_commit_reference(const char *arg) static int handle_independent(int count, const char **args) { - struct commit_list *revs = NULL; - struct commit_list *result; + struct commit_list *revs = NULL, *rev; int i; for (i = count - 1; i >= 0; i--) commit_list_insert(get_commit_reference(args[i]), &revs); - result = reduce_heads(revs); - if (!result) + reduce_heads_replace(&revs); + + if (!revs) return 1; - while (result) { - printf("%s\n", oid_to_hex(&result->item->object.oid)); - result = result->next; - } + for (rev = revs; rev; rev = rev->next) + printf("%s\n", oid_to_hex(&rev->item->object.oid)); + + free_commit_list(revs); return 0; } static int handle_octopus(int count, const char **args, int show_all) { struct commit_list *revs = NULL; - struct commit_list *result; + struct commit_list *result, *rev; int i; for (i = count - 1; i >= 0; i--) commit_list_insert(get_commit_reference(args[i]), &revs); - result = reduce_heads(get_octopus_merge_bases(revs)); + result = get_octopus_merge_bases(revs); + free_commit_list(revs); + reduce_heads_replace(&result); if (!result) return 1; - while (result) { - printf("%s\n", oid_to_hex(&result->item->object.oid)); + for (rev = result; rev; rev = rev->next) { + printf("%s\n", oid_to_hex(&rev->item->object.oid)); if (!show_all) - return 0; - result = result->next; + break; } + free_commit_list(result); return 0; } diff --git a/builtin/merge.c b/builtin/merge.c index ab5ffe85e8f5d7a359004f2bbb52a5778d0b91b4..fbbf2a9e5eb9be47d8574ca0bab175c5a6c0d15d 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -999,6 +999,7 @@ static struct commit_list *reduce_parents(struct commit *head_commit, /* Find what parents to record by checking independent ones. */ parents = reduce_heads(remoteheads); + free_commit_list(remoteheads); remoteheads = NULL; remotes = &remoteheads; diff --git a/builtin/pull.c b/builtin/pull.c index 6f772e8a224c18238cf9a75436e8ea192765e7fe..4edab228ebe6c1d3df580689c7cf94eb989fe4bc 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -745,12 +745,15 @@ static int get_octopus_merge_base(struct object_id *merge_base, if (!is_null_oid(fork_point)) commit_list_insert(lookup_commit_reference(fork_point), &revs); - result = reduce_heads(get_octopus_merge_bases(revs)); + result = get_octopus_merge_bases(revs); free_commit_list(revs); + reduce_heads_replace(&result); + if (!result) return 1; oidcpy(merge_base, &result->item->object.oid); + free_commit_list(result); return 0; } diff --git a/commit.c b/commit.c index 1e0e633790bb834ad05ed9619e4afa0bac33ce19..cab8d4455bdbd6e4b87031613300be1112a19df5 100644 --- a/commit.c +++ b/commit.c @@ -1090,6 +1090,13 @@ struct commit_list *reduce_heads(struct commit_list *heads) return result; } +void reduce_heads_replace(struct commit_list **heads) +{ + struct commit_list *result = reduce_heads(*heads); + free_commit_list(*heads); + *heads = result; +} + static const char gpg_sig_header[] = "gpgsig"; static const int gpg_sig_header_len = sizeof(gpg_sig_header) - 1; diff --git a/commit.h b/commit.h index 6d769590f285e534d20bfd8108e8e980253f8815..99a3fea68d3f63064351ccabeaf7f11cdf8e0d04 100644 --- a/commit.h +++ b/commit.h @@ -313,7 +313,23 @@ extern int interactive_add(int argc, const char **argv, const char *prefix, int extern int run_add_interactive(const char *revision, const char *patch_mode, const struct pathspec *pathspec); -struct commit_list *reduce_heads(struct commit_list *heads); +/* + * Takes a list of commits and returns a new list where those + * have been removed that can be reached from other commits in + * the list. It is useful for, e.g., reducing the commits + * randomly thrown at the git-merge command and removing + * redundant commits that the user shouldn't have given to it. + * + * This function destroys the STALE bit of the commit objects' + * flags. + */ +extern struct commit_list *reduce_heads(struct commit_list *heads); + +/* + * Like `reduce_heads()`, except it replaces the list. Use this + * instead of `foo = reduce_heads(foo);` to avoid memory leaks. + */ +extern void reduce_heads_replace(struct commit_list **heads); struct commit_extra_header { struct commit_extra_header *next;