summaryrefslogtreecommitdiff
path: root/commit.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2018-11-02 02:04:55 (GMT)
committerJunio C Hamano <gitster@pobox.com>2018-11-02 02:04:55 (GMT)
commit0293121717ba66f089a38ce4d4d895db0f946e49 (patch)
tree2f9691ca131a570751e48f77b6a34c23352c352a /commit.c
parent39f73315454d2553b2d3219a58f5110a60eba5a1 (diff)
parent9dba809a69a7cd2a60e73d1ccaea0812b72b2b79 (diff)
downloadgit-0293121717ba66f089a38ce4d4d895db0f946e49.zip
git-0293121717ba66f089a38ce4d4d895db0f946e49.tar.gz
git-0293121717ba66f089a38ce4d4d895db0f946e49.tar.bz2
Merge branch 'pk/rebase-in-c-4-opts'
Rewrite "git rebase" in C. * pk/rebase-in-c-4-opts: builtin rebase: support --root builtin rebase: add support for custom merge strategies builtin rebase: support `fork-point` option merge-base --fork-point: extract libified function builtin rebase: support --rebase-merges[=[no-]rebase-cousins] builtin rebase: support `--allow-empty-message` option builtin rebase: support `--exec` builtin rebase: support `--autostash` option builtin rebase: support `-C` and `--whitespace=<type>` builtin rebase: support `--gpg-sign` option builtin rebase: support `--autosquash` builtin rebase: support `keep-empty` option builtin rebase: support `ignore-date` option builtin rebase: support `ignore-whitespace` option builtin rebase: support --committer-date-is-author-date builtin rebase: support --rerere-autoupdate builtin rebase: support --signoff builtin rebase: allow selecting the rebase "backend"
Diffstat (limited to 'commit.c')
-rw-r--r--commit.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/commit.c b/commit.c
index dc8a39d..d566d7e 100644
--- a/commit.c
+++ b/commit.c
@@ -17,6 +17,8 @@
#include "sha1-lookup.h"
#include "wt-status.h"
#include "advice.h"
+#include "refs.h"
+#include "commit-reach.h"
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
@@ -843,6 +845,86 @@ void sort_in_topological_order(struct commit_list **list, enum rev_sort_order so
clear_author_date_slab(&author_date);
}
+struct rev_collect {
+ struct commit **commit;
+ int nr;
+ int alloc;
+ unsigned int initial : 1;
+};
+
+static void add_one_commit(struct object_id *oid, struct rev_collect *revs)
+{
+ struct commit *commit;
+
+ if (is_null_oid(oid))
+ return;
+
+ commit = lookup_commit(the_repository, oid);
+ if (!commit ||
+ (commit->object.flags & TMP_MARK) ||
+ parse_commit(commit))
+ return;
+
+ ALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc);
+ revs->commit[revs->nr++] = commit;
+ commit->object.flags |= TMP_MARK;
+}
+
+static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
+ const char *ident, timestamp_t timestamp,
+ int tz, const char *message, void *cbdata)
+{
+ struct rev_collect *revs = cbdata;
+
+ if (revs->initial) {
+ revs->initial = 0;
+ add_one_commit(ooid, revs);
+ }
+ add_one_commit(noid, revs);
+ return 0;
+}
+
+struct commit *get_fork_point(const char *refname, struct commit *commit)
+{
+ struct object_id oid;
+ struct rev_collect revs;
+ struct commit_list *bases;
+ int i;
+ struct commit *ret = NULL;
+
+ memset(&revs, 0, sizeof(revs));
+ revs.initial = 1;
+ for_each_reflog_ent(refname, collect_one_reflog_ent, &revs);
+
+ if (!revs.nr && !get_oid(refname, &oid))
+ add_one_commit(&oid, &revs);
+
+ for (i = 0; i < revs.nr; i++)
+ revs.commit[i]->object.flags &= ~TMP_MARK;
+
+ bases = get_merge_bases_many(commit, revs.nr, revs.commit);
+
+ /*
+ * There should be one and only one merge base, when we found
+ * a common ancestor among reflog entries.
+ */
+ if (!bases || bases->next)
+ goto cleanup_return;
+
+ /* And the found one must be one of the reflog entries */
+ for (i = 0; i < revs.nr; i++)
+ if (&bases->item->object == &revs.commit[i]->object)
+ break; /* found */
+ if (revs.nr <= i)
+ goto cleanup_return;
+
+ ret = bases->item;
+
+cleanup_return:
+ free_commit_list(bases);
+ return ret;
+}
+
static const char gpg_sig_header[] = "gpgsig";
static const int gpg_sig_header_len = sizeof(gpg_sig_header) - 1;