commit-reach: move ref_newer from remote.c

There are several commit walks in the codebase. Group them together into a new commit-reach.c file and corresponding header. After we group these walks into one place, we can reduce duplicate logic by calling equivalent methods. The ref_newer() method is used by 'git push -f' to check if a force-push is necessary. By making the method public, we make it possible to test the method directly without setting up an envieronment where a 'git push' call makes sense. Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Jul 20, 2018 at 16:33 UTC 1d614d41e5fc030bc2f2799a58791aa912f78378
5 files changed +57 -51
builtin/remote.c
+1
@@ -10,6 +10,7 @@
10 #include "refspec.h"
11 #include "object-store.h"
12 #include "argv-array.h"
13 +#include "commit-reach.h"
14
15 static const char * const builtin_remote_usage[] = {
16 N_("git remote [-v | --verbose]"),
commit-reach.c
+54 -1
@@ -1,6 +1,10 @@
1 #include "cache.h"
2 -#include "prio-queue.h"
2 #include "commit.h"
3 +#include "decorate.h"
4 +#include "prio-queue.h"
5 +#include "tree.h"
6 +#include "revision.h"
7 +#include "tag.h"
8 #include "commit-reach.h"
9
10 /* Remember to update object flag allocation in object.h */
@@ -358,3 +362,52 @@ void reduce_heads_replace(struct commit_list **heads)
362 free_commit_list(*heads);
363 *heads = result;
364 }
365 +
366 +static void unmark_and_free(struct commit_list *list, unsigned int mark)
367 +{
368 + while (list) {
369 + struct commit *commit = pop_commit(&list);
370 + commit->object.flags &= ~mark;
371 + }
372 +}
373 +
374 +int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)
375 +{
376 + struct object *o;
377 + struct commit *old_commit, *new_commit;
378 + struct commit_list *list, *used;
379 + int found = 0;
380 +
381 + /*
382 + * Both new_commit and old_commit must be commit-ish and new_commit is descendant of
383 + * old_commit. Otherwise we require --force.
384 + */
385 + o = deref_tag(the_repository, parse_object(the_repository, old_oid),
386 + NULL, 0);
387 + if (!o || o->type != OBJ_COMMIT)
388 + return 0;
389 + old_commit = (struct commit *) o;
390 +
391 + o = deref_tag(the_repository, parse_object(the_repository, new_oid),
392 + NULL, 0);
393 + if (!o || o->type != OBJ_COMMIT)
394 + return 0;
395 + new_commit = (struct commit *) o;
396 +
397 + if (parse_commit(new_commit) < 0)
398 + return 0;
399 +
400 + used = list = NULL;
401 + commit_list_insert(new_commit, &list);
402 + while (list) {
403 + new_commit = pop_most_recent_commit(&list, TMP_MARK);
404 + commit_list_insert(new_commit, &used);
405 + if (new_commit == old_commit) {
406 + found = 1;
407 + break;
408 + }
409 + }
410 + unmark_and_free(list, TMP_MARK);
411 + unmark_and_free(used, TMP_MARK);
412 + return found;
413 +}
commit-reach.h
+2
@@ -39,4 +39,6 @@ struct commit_list *reduce_heads(struct commit_list *heads);
39 */
40 void reduce_heads_replace(struct commit_list **heads);
41
42 +int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);
43 +
44 #endif
remote.c
-49
@@ -1784,55 +1784,6 @@ int resolve_remote_symref(struct ref *ref, struct ref *list)
1784 return 1;
1785 }
1786
1787 -static void unmark_and_free(struct commit_list *list, unsigned int mark)
1788 -{
1789 - while (list) {
1790 - struct commit *commit = pop_commit(&list);
1791 - commit->object.flags &= ~mark;
1792 - }
1793 -}
1794 -
1795 -int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)
1796 -{
1797 - struct object *o;
1798 - struct commit *old_commit, *new_commit;
1799 - struct commit_list *list, *used;
1800 - int found = 0;
1801 -
1802 - /*
1803 - * Both new_commit and old_commit must be commit-ish and new_commit is descendant of
1804 - * old_commit. Otherwise we require --force.
1805 - */
1806 - o = deref_tag(the_repository, parse_object(the_repository, old_oid),
1807 - NULL, 0);
1808 - if (!o || o->type != OBJ_COMMIT)
1809 - return 0;
1810 - old_commit = (struct commit *) o;
1811 -
1812 - o = deref_tag(the_repository, parse_object(the_repository, new_oid),
1813 - NULL, 0);
1814 - if (!o || o->type != OBJ_COMMIT)
1815 - return 0;
1816 - new_commit = (struct commit *) o;
1817 -
1818 - if (parse_commit(new_commit) < 0)
1819 - return 0;
1820 -
1821 - used = list = NULL;
1822 - commit_list_insert(new_commit, &list);
1823 - while (list) {
1824 - new_commit = pop_most_recent_commit(&list, TMP_MARK);
1825 - commit_list_insert(new_commit, &used);
1826 - if (new_commit == old_commit) {
1827 - found = 1;
1828 - break;
1829 - }
1830 - }
1831 - unmark_and_free(list, TMP_MARK);
1832 - unmark_and_free(used, TMP_MARK);
1833 - return found;
1834 -}
1835 -
1787 /*
1788 * Lookup the upstream branch for the given branch and if present, optionally
1789 * compute the commit ahead/behind values for the pair.
remote.h
-1
@@ -149,7 +149,6 @@ extern struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
149 const struct string_list *server_options);
150
151 int resolve_remote_symref(struct ref *ref, struct ref *list);
152 -int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);
152
153 /*
154 * Remove and free all but the first of any entries in the input list