rebase (autostash): store the full OID in <state-dir>/autostash
[gitweb.git] / commit.c
index add310d4231d4cc71068b64827dc041aae0bb011..a3fc77a4eb592b64e295ffee9a904c8216415c55 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -17,6 +17,7 @@
 #include "sha1-lookup.h"
 #include "wt-status.h"
 #include "advice.h"
+#include "refs.h"
 
 static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
 
@@ -342,7 +343,7 @@ struct tree *get_commit_tree(const struct commit *commit)
        if (commit->graph_pos == COMMIT_NOT_FROM_GRAPH)
                BUG("commit has NULL tree, but was not loaded from commit-graph");
 
-       return get_commit_tree_in_graph(commit);
+       return get_commit_tree_in_graph(the_repository, commit);
 }
 
 struct object_id *get_commit_tree_oid(const struct commit *commit)
@@ -438,7 +439,7 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
        item->date = parse_commit_date(bufptr, tail);
 
        if (check_graph)
-               load_commit_graph_info(item);
+               load_commit_graph_info(the_repository, item);
 
        return 0;
 }
@@ -454,7 +455,7 @@ int parse_commit_internal(struct commit *item, int quiet_on_missing, int use_com
                return -1;
        if (item->object.parsed)
                return 0;
-       if (use_commit_graph && parse_commit_in_graph(item))
+       if (use_commit_graph && parse_commit_in_graph(the_repository, item))
                return 0;
        buffer = read_object_file(&item->object.oid, &type, &size);
        if (!buffer)
@@ -958,6 +959,86 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
        return result;
 }
 
+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;
+}
+
 struct commit_list *get_octopus_merge_bases(struct commit_list *in)
 {
        struct commit_list *i, *j, *k, *ret = NULL;