notes-merge.con commit git notes merge: Initial implementation handling trivial merges only (75ef3f4)
   1#include "cache.h"
   2#include "commit.h"
   3#include "refs.h"
   4#include "notes-merge.h"
   5
   6void init_notes_merge_options(struct notes_merge_options *o)
   7{
   8        memset(o, 0, sizeof(struct notes_merge_options));
   9        o->verbosity = NOTES_MERGE_VERBOSITY_DEFAULT;
  10}
  11
  12#define OUTPUT(o, v, ...) \
  13        do { \
  14                if ((o)->verbosity >= (v)) { \
  15                        printf(__VA_ARGS__); \
  16                        puts(""); \
  17                } \
  18        } while (0)
  19
  20int notes_merge(struct notes_merge_options *o,
  21                unsigned char *result_sha1)
  22{
  23        unsigned char local_sha1[20], remote_sha1[20];
  24        struct commit *local, *remote;
  25        struct commit_list *bases = NULL;
  26        const unsigned char *base_sha1;
  27        int result = 0;
  28
  29        assert(o->local_ref && o->remote_ref);
  30        hashclr(result_sha1);
  31
  32        trace_printf("notes_merge(o->local_ref = %s, o->remote_ref = %s)\n",
  33               o->local_ref, o->remote_ref);
  34
  35        /* Dereference o->local_ref into local_sha1 */
  36        if (!resolve_ref(o->local_ref, local_sha1, 0, NULL))
  37                die("Failed to resolve local notes ref '%s'", o->local_ref);
  38        else if (!check_ref_format(o->local_ref) && is_null_sha1(local_sha1))
  39                local = NULL; /* local_sha1 == null_sha1 indicates unborn ref */
  40        else if (!(local = lookup_commit_reference(local_sha1)))
  41                die("Could not parse local commit %s (%s)",
  42                    sha1_to_hex(local_sha1), o->local_ref);
  43        trace_printf("\tlocal commit: %.7s\n", sha1_to_hex(local_sha1));
  44
  45        /* Dereference o->remote_ref into remote_sha1 */
  46        if (get_sha1(o->remote_ref, remote_sha1)) {
  47                /*
  48                 * Failed to get remote_sha1. If o->remote_ref looks like an
  49                 * unborn ref, perform the merge using an empty notes tree.
  50                 */
  51                if (!check_ref_format(o->remote_ref)) {
  52                        hashclr(remote_sha1);
  53                        remote = NULL;
  54                } else {
  55                        die("Failed to resolve remote notes ref '%s'",
  56                            o->remote_ref);
  57                }
  58        } else if (!(remote = lookup_commit_reference(remote_sha1))) {
  59                die("Could not parse remote commit %s (%s)",
  60                    sha1_to_hex(remote_sha1), o->remote_ref);
  61        }
  62        trace_printf("\tremote commit: %.7s\n", sha1_to_hex(remote_sha1));
  63
  64        if (!local && !remote)
  65                die("Cannot merge empty notes ref (%s) into empty notes ref "
  66                    "(%s)", o->remote_ref, o->local_ref);
  67        if (!local) {
  68                /* result == remote commit */
  69                hashcpy(result_sha1, remote_sha1);
  70                goto found_result;
  71        }
  72        if (!remote) {
  73                /* result == local commit */
  74                hashcpy(result_sha1, local_sha1);
  75                goto found_result;
  76        }
  77        assert(local && remote);
  78
  79        /* Find merge bases */
  80        bases = get_merge_bases(local, remote, 1);
  81        if (!bases) {
  82                base_sha1 = null_sha1;
  83                OUTPUT(o, 4, "No merge base found; doing history-less merge");
  84        } else if (!bases->next) {
  85                base_sha1 = bases->item->object.sha1;
  86                OUTPUT(o, 4, "One merge base found (%.7s)",
  87                       sha1_to_hex(base_sha1));
  88        } else {
  89                /* TODO: How to handle multiple merge-bases? */
  90                base_sha1 = bases->item->object.sha1;
  91                OUTPUT(o, 3, "Multiple merge bases found. Using the first "
  92                       "(%.7s)", sha1_to_hex(base_sha1));
  93        }
  94
  95        OUTPUT(o, 4, "Merging remote commit %.7s into local commit %.7s with "
  96               "merge-base %.7s", sha1_to_hex(remote->object.sha1),
  97               sha1_to_hex(local->object.sha1), sha1_to_hex(base_sha1));
  98
  99        if (!hashcmp(remote->object.sha1, base_sha1)) {
 100                /* Already merged; result == local commit */
 101                OUTPUT(o, 2, "Already up-to-date!");
 102                hashcpy(result_sha1, local->object.sha1);
 103                goto found_result;
 104        }
 105        if (!hashcmp(local->object.sha1, base_sha1)) {
 106                /* Fast-forward; result == remote commit */
 107                OUTPUT(o, 2, "Fast-forward");
 108                hashcpy(result_sha1, remote->object.sha1);
 109                goto found_result;
 110        }
 111
 112        /* TODO: */
 113        result = error("notes_merge() cannot yet handle real merges.");
 114
 115found_result:
 116        free_commit_list(bases);
 117        trace_printf("notes_merge(): result = %i, result_sha1 = %.7s\n",
 118               result, sha1_to_hex(result_sha1));
 119        return result;
 120}