diff options
Diffstat (limited to 'commit-reach.c')
-rw-r--r-- | commit-reach.c | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/commit-reach.c b/commit-reach.c index 8ab6044414..a6bc4781a6 100644 --- a/commit-reach.c +++ b/commit-reach.c @@ -1,6 +1,10 @@ #include "cache.h" -#include "prio-queue.h" #include "commit.h" +#include "decorate.h" +#include "prio-queue.h" +#include "tree.h" +#include "revision.h" +#include "tag.h" #include "commit-reach.h" /* Remember to update object flag allocation in object.h */ @@ -358,3 +362,52 @@ void reduce_heads_replace(struct commit_list **heads) free_commit_list(*heads); *heads = result; } + +static void unmark_and_free(struct commit_list *list, unsigned int mark) +{ + while (list) { + struct commit *commit = pop_commit(&list); + commit->object.flags &= ~mark; + } +} + +int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid) +{ + struct object *o; + struct commit *old_commit, *new_commit; + struct commit_list *list, *used; + int found = 0; + + /* + * Both new_commit and old_commit must be commit-ish and new_commit is descendant of + * old_commit. Otherwise we require --force. + */ + o = deref_tag(the_repository, parse_object(the_repository, old_oid), + NULL, 0); + if (!o || o->type != OBJ_COMMIT) + return 0; + old_commit = (struct commit *) o; + + o = deref_tag(the_repository, parse_object(the_repository, new_oid), + NULL, 0); + if (!o || o->type != OBJ_COMMIT) + return 0; + new_commit = (struct commit *) o; + + if (parse_commit(new_commit) < 0) + return 0; + + used = list = NULL; + commit_list_insert(new_commit, &list); + while (list) { + new_commit = pop_most_recent_commit(&list, TMP_MARK); + commit_list_insert(new_commit, &used); + if (new_commit == old_commit) { + found = 1; + break; + } + } + unmark_and_free(list, TMP_MARK); + unmark_and_free(used, TMP_MARK); + return found; +} |