summaryrefslogtreecommitdiff
path: root/commit-reach.c
diff options
context:
space:
mode:
Diffstat (limited to 'commit-reach.c')
-rw-r--r--commit-reach.c55
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;
+}