notes-merge.con commit builtin/notes.c: Refactor creation of notes commits. (5688184)
   1#include "cache.h"
   2#include "commit.h"
   3#include "refs.h"
   4#include "notes.h"
   5#include "notes-merge.h"
   6
   7void init_notes_merge_options(struct notes_merge_options *o)
   8{
   9        memset(o, 0, sizeof(struct notes_merge_options));
  10        o->verbosity = NOTES_MERGE_VERBOSITY_DEFAULT;
  11}
  12
  13#define OUTPUT(o, v, ...) \
  14        do { \
  15                if ((o)->verbosity >= (v)) { \
  16                        printf(__VA_ARGS__); \
  17                        puts(""); \
  18                } \
  19        } while (0)
  20
  21void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
  22                         const char *msg, unsigned char *result_sha1)
  23{
  24        unsigned char tree_sha1[20];
  25
  26        assert(t->initialized);
  27
  28        if (write_notes_tree(t, tree_sha1))
  29                die("Failed to write notes tree to database");
  30
  31        if (!parents) {
  32                /* Deduce parent commit from t->ref */
  33                unsigned char parent_sha1[20];
  34                if (!read_ref(t->ref, parent_sha1)) {
  35                        struct commit *parent = lookup_commit(parent_sha1);
  36                        if (!parent || parse_commit(parent))
  37                                die("Failed to find/parse commit %s", t->ref);
  38                        commit_list_insert(parent, &parents);
  39                }
  40                /* else: t->ref points to nothing, assume root/orphan commit */
  41        }
  42
  43        if (commit_tree(msg, tree_sha1, parents, result_sha1, NULL))
  44                die("Failed to commit notes tree to database");
  45}
  46
  47int notes_merge(struct notes_merge_options *o,
  48                unsigned char *result_sha1)
  49{
  50        unsigned char local_sha1[20], remote_sha1[20];
  51        struct commit *local, *remote;
  52        struct commit_list *bases = NULL;
  53        const unsigned char *base_sha1;
  54        int result = 0;
  55
  56        assert(o->local_ref && o->remote_ref);
  57        hashclr(result_sha1);
  58
  59        trace_printf("notes_merge(o->local_ref = %s, o->remote_ref = %s)\n",
  60               o->local_ref, o->remote_ref);
  61
  62        /* Dereference o->local_ref into local_sha1 */
  63        if (!resolve_ref(o->local_ref, local_sha1, 0, NULL))
  64                die("Failed to resolve local notes ref '%s'", o->local_ref);
  65        else if (!check_ref_format(o->local_ref) && is_null_sha1(local_sha1))
  66                local = NULL; /* local_sha1 == null_sha1 indicates unborn ref */
  67        else if (!(local = lookup_commit_reference(local_sha1)))
  68                die("Could not parse local commit %s (%s)",
  69                    sha1_to_hex(local_sha1), o->local_ref);
  70        trace_printf("\tlocal commit: %.7s\n", sha1_to_hex(local_sha1));
  71
  72        /* Dereference o->remote_ref into remote_sha1 */
  73        if (get_sha1(o->remote_ref, remote_sha1)) {
  74                /*
  75                 * Failed to get remote_sha1. If o->remote_ref looks like an
  76                 * unborn ref, perform the merge using an empty notes tree.
  77                 */
  78                if (!check_ref_format(o->remote_ref)) {
  79                        hashclr(remote_sha1);
  80                        remote = NULL;
  81                } else {
  82                        die("Failed to resolve remote notes ref '%s'",
  83                            o->remote_ref);
  84                }
  85        } else if (!(remote = lookup_commit_reference(remote_sha1))) {
  86                die("Could not parse remote commit %s (%s)",
  87                    sha1_to_hex(remote_sha1), o->remote_ref);
  88        }
  89        trace_printf("\tremote commit: %.7s\n", sha1_to_hex(remote_sha1));
  90
  91        if (!local && !remote)
  92                die("Cannot merge empty notes ref (%s) into empty notes ref "
  93                    "(%s)", o->remote_ref, o->local_ref);
  94        if (!local) {
  95                /* result == remote commit */
  96                hashcpy(result_sha1, remote_sha1);
  97                goto found_result;
  98        }
  99        if (!remote) {
 100                /* result == local commit */
 101                hashcpy(result_sha1, local_sha1);
 102                goto found_result;
 103        }
 104        assert(local && remote);
 105
 106        /* Find merge bases */
 107        bases = get_merge_bases(local, remote, 1);
 108        if (!bases) {
 109                base_sha1 = null_sha1;
 110                OUTPUT(o, 4, "No merge base found; doing history-less merge");
 111        } else if (!bases->next) {
 112                base_sha1 = bases->item->object.sha1;
 113                OUTPUT(o, 4, "One merge base found (%.7s)",
 114                       sha1_to_hex(base_sha1));
 115        } else {
 116                /* TODO: How to handle multiple merge-bases? */
 117                base_sha1 = bases->item->object.sha1;
 118                OUTPUT(o, 3, "Multiple merge bases found. Using the first "
 119                       "(%.7s)", sha1_to_hex(base_sha1));
 120        }
 121
 122        OUTPUT(o, 4, "Merging remote commit %.7s into local commit %.7s with "
 123               "merge-base %.7s", sha1_to_hex(remote->object.sha1),
 124               sha1_to_hex(local->object.sha1), sha1_to_hex(base_sha1));
 125
 126        if (!hashcmp(remote->object.sha1, base_sha1)) {
 127                /* Already merged; result == local commit */
 128                OUTPUT(o, 2, "Already up-to-date!");
 129                hashcpy(result_sha1, local->object.sha1);
 130                goto found_result;
 131        }
 132        if (!hashcmp(local->object.sha1, base_sha1)) {
 133                /* Fast-forward; result == remote commit */
 134                OUTPUT(o, 2, "Fast-forward");
 135                hashcpy(result_sha1, remote->object.sha1);
 136                goto found_result;
 137        }
 138
 139        /* TODO: */
 140        result = error("notes_merge() cannot yet handle real merges.");
 141
 142found_result:
 143        free_commit_list(bases);
 144        trace_printf("notes_merge(): result = %i, result_sha1 = %.7s\n",
 145               result, sha1_to_hex(result_sha1));
 146        return result;
 147}