Coverage Report

Created: 2024-09-08 06:23

/src/git/builtin/merge-tree.c
Line
Count
Source (jump to first uncovered line)
1
#include "builtin.h"
2
#include "tree-walk.h"
3
#include "xdiff-interface.h"
4
#include "help.h"
5
#include "gettext.h"
6
#include "hex.h"
7
#include "commit.h"
8
#include "commit-reach.h"
9
#include "merge-ort.h"
10
#include "object-name.h"
11
#include "object-store-ll.h"
12
#include "parse-options.h"
13
#include "repository.h"
14
#include "blob.h"
15
#include "merge-blobs.h"
16
#include "quote.h"
17
#include "tree.h"
18
#include "config.h"
19
#include "strvec.h"
20
21
static int line_termination = '\n';
22
23
struct merge_list {
24
  struct merge_list *next;
25
  struct merge_list *link;  /* other stages for this object */
26
27
  unsigned int stage : 2;
28
  unsigned int mode;
29
  const char *path;
30
  struct blob *blob;
31
};
32
33
static struct merge_list *merge_result, **merge_result_end = &merge_result;
34
35
static void add_merge_entry(struct merge_list *entry)
36
0
{
37
0
  *merge_result_end = entry;
38
0
  merge_result_end = &entry->next;
39
0
}
40
41
static void trivial_merge_trees(struct tree_desc t[3], const char *base);
42
43
static const char *explanation(struct merge_list *entry)
44
0
{
45
0
  switch (entry->stage) {
46
0
  case 0:
47
0
    return "merged";
48
0
  case 3:
49
0
    return "added in remote";
50
0
  case 2:
51
0
    if (entry->link)
52
0
      return "added in both";
53
0
    return "added in local";
54
0
  }
55
56
  /* Existed in base */
57
0
  entry = entry->link;
58
0
  if (!entry)
59
0
    return "removed in both";
60
61
0
  if (entry->link)
62
0
    return "changed in both";
63
64
0
  if (entry->stage == 3)
65
0
    return "removed in local";
66
0
  return "removed in remote";
67
0
}
68
69
static void *result(struct merge_list *entry, unsigned long *size)
70
0
{
71
0
  enum object_type type;
72
0
  struct blob *base, *our, *their;
73
0
  const char *path = entry->path;
74
75
0
  if (!entry->stage)
76
0
    return repo_read_object_file(the_repository,
77
0
               &entry->blob->object.oid, &type,
78
0
               size);
79
0
  base = NULL;
80
0
  if (entry->stage == 1) {
81
0
    base = entry->blob;
82
0
    entry = entry->link;
83
0
  }
84
0
  our = NULL;
85
0
  if (entry && entry->stage == 2) {
86
0
    our = entry->blob;
87
0
    entry = entry->link;
88
0
  }
89
0
  their = NULL;
90
0
  if (entry)
91
0
    their = entry->blob;
92
0
  return merge_blobs(the_repository->index, path,
93
0
         base, our, their, size);
94
0
}
95
96
static void *origin(struct merge_list *entry, unsigned long *size)
97
0
{
98
0
  enum object_type type;
99
0
  while (entry) {
100
0
    if (entry->stage == 2)
101
0
      return repo_read_object_file(the_repository,
102
0
                 &entry->blob->object.oid,
103
0
                 &type, size);
104
0
    entry = entry->link;
105
0
  }
106
0
  return NULL;
107
0
}
108
109
static int show_outf(void *priv UNUSED, mmbuffer_t *mb, int nbuf)
110
0
{
111
0
  int i;
112
0
  for (i = 0; i < nbuf; i++)
113
0
    printf("%.*s", (int) mb[i].size, mb[i].ptr);
114
0
  return 0;
115
0
}
116
117
static void show_diff(struct merge_list *entry)
118
0
{
119
0
  unsigned long size;
120
0
  mmfile_t src, dst;
121
0
  xpparam_t xpp;
122
0
  xdemitconf_t xecfg;
123
0
  xdemitcb_t ecb = { .out_line = show_outf };
124
125
0
  memset(&xpp, 0, sizeof(xpp));
126
0
  xpp.flags = 0;
127
0
  memset(&xecfg, 0, sizeof(xecfg));
128
0
  xecfg.ctxlen = 3;
129
130
0
  src.ptr = origin(entry, &size);
131
0
  if (!src.ptr)
132
0
    size = 0;
133
0
  src.size = size;
134
0
  dst.ptr = result(entry, &size);
135
0
  if (!dst.ptr)
136
0
    size = 0;
137
0
  dst.size = size;
138
0
  if (xdi_diff(&src, &dst, &xpp, &xecfg, &ecb))
139
0
    die("unable to generate diff");
140
0
  free(src.ptr);
141
0
  free(dst.ptr);
142
0
}
143
144
static void show_result_list(struct merge_list *entry)
145
0
{
146
0
  printf("%s\n", explanation(entry));
147
0
  do {
148
0
    struct merge_list *link = entry->link;
149
0
    static const char *desc[4] = { "result", "base", "our", "their" };
150
0
    printf("  %-6s %o %s %s\n", desc[entry->stage], entry->mode, oid_to_hex(&entry->blob->object.oid), entry->path);
151
0
    entry = link;
152
0
  } while (entry);
153
0
}
154
155
static void show_result(void)
156
0
{
157
0
  struct merge_list *walk;
158
159
0
  walk = merge_result;
160
0
  while (walk) {
161
0
    show_result_list(walk);
162
0
    show_diff(walk);
163
0
    walk = walk->next;
164
0
  }
165
0
}
166
167
/* An empty entry never compares same, not even to another empty entry */
168
static int same_entry(struct name_entry *a, struct name_entry *b)
169
0
{
170
0
  return  !is_null_oid(&a->oid) &&
171
0
    !is_null_oid(&b->oid) &&
172
0
    oideq(&a->oid, &b->oid) &&
173
0
    a->mode == b->mode;
174
0
}
175
176
static int both_empty(struct name_entry *a, struct name_entry *b)
177
0
{
178
0
  return is_null_oid(&a->oid) && is_null_oid(&b->oid);
179
0
}
180
181
static struct merge_list *create_entry(unsigned stage, unsigned mode, const struct object_id *oid, const char *path)
182
0
{
183
0
  struct merge_list *res = xcalloc(1, sizeof(*res));
184
185
0
  res->stage = stage;
186
0
  res->path = path;
187
0
  res->mode = mode;
188
0
  res->blob = lookup_blob(the_repository, oid);
189
0
  return res;
190
0
}
191
192
static char *traverse_path(const struct traverse_info *info, const struct name_entry *n)
193
0
{
194
0
  struct strbuf buf = STRBUF_INIT;
195
0
  strbuf_make_traverse_path(&buf, info, n->path, n->pathlen);
196
0
  return strbuf_detach(&buf, NULL);
197
0
}
198
199
static void resolve(const struct traverse_info *info, struct name_entry *ours, struct name_entry *result)
200
0
{
201
0
  struct merge_list *orig, *final;
202
0
  const char *path;
203
204
  /* If it's already ours, don't bother showing it */
205
0
  if (!ours)
206
0
    return;
207
208
0
  path = traverse_path(info, result);
209
0
  orig = create_entry(2, ours->mode, &ours->oid, path);
210
0
  final = create_entry(0, result->mode, &result->oid, path);
211
212
0
  final->link = orig;
213
214
0
  add_merge_entry(final);
215
0
}
216
217
static void unresolved_directory(const struct traverse_info *info,
218
         struct name_entry n[3])
219
0
{
220
0
  struct repository *r = the_repository;
221
0
  char *newbase;
222
0
  struct name_entry *p;
223
0
  struct tree_desc t[3];
224
0
  void *buf0, *buf1, *buf2;
225
226
0
  for (p = n; p < n + 3; p++) {
227
0
    if (p->mode && S_ISDIR(p->mode))
228
0
      break;
229
0
  }
230
0
  if (n + 3 <= p)
231
0
    return; /* there is no tree here */
232
233
0
  newbase = traverse_path(info, p);
234
235
0
#define ENTRY_OID(e) (((e)->mode && S_ISDIR((e)->mode)) ? &(e)->oid : NULL)
236
0
  buf0 = fill_tree_descriptor(r, t + 0, ENTRY_OID(n + 0));
237
0
  buf1 = fill_tree_descriptor(r, t + 1, ENTRY_OID(n + 1));
238
0
  buf2 = fill_tree_descriptor(r, t + 2, ENTRY_OID(n + 2));
239
0
#undef ENTRY_OID
240
241
0
  trivial_merge_trees(t, newbase);
242
243
0
  free(buf0);
244
0
  free(buf1);
245
0
  free(buf2);
246
0
  free(newbase);
247
0
}
248
249
250
static struct merge_list *link_entry(unsigned stage, const struct traverse_info *info, struct name_entry *n, struct merge_list *entry)
251
0
{
252
0
  const char *path;
253
0
  struct merge_list *link;
254
255
0
  if (!n->mode)
256
0
    return entry;
257
0
  if (entry)
258
0
    path = entry->path;
259
0
  else
260
0
    path = traverse_path(info, n);
261
0
  link = create_entry(stage, n->mode, &n->oid, path);
262
0
  link->link = entry;
263
0
  return link;
264
0
}
265
266
static void unresolved(const struct traverse_info *info, struct name_entry n[3])
267
0
{
268
0
  struct merge_list *entry = NULL;
269
0
  int i;
270
0
  unsigned dirmask = 0, mask = 0;
271
272
0
  for (i = 0; i < 3; i++) {
273
0
    mask |= (1 << i);
274
    /*
275
     * Treat missing entries as directories so that we return
276
     * after unresolved_directory has handled this.
277
     */
278
0
    if (!n[i].mode || S_ISDIR(n[i].mode))
279
0
      dirmask |= (1 << i);
280
0
  }
281
282
0
  unresolved_directory(info, n);
283
284
0
  if (dirmask == mask)
285
0
    return;
286
287
0
  if (n[2].mode && !S_ISDIR(n[2].mode))
288
0
    entry = link_entry(3, info, n + 2, entry);
289
0
  if (n[1].mode && !S_ISDIR(n[1].mode))
290
0
    entry = link_entry(2, info, n + 1, entry);
291
0
  if (n[0].mode && !S_ISDIR(n[0].mode))
292
0
    entry = link_entry(1, info, n + 0, entry);
293
294
0
  add_merge_entry(entry);
295
0
}
296
297
/*
298
 * Merge two trees together (t[1] and t[2]), using a common base (t[0])
299
 * as the origin.
300
 *
301
 * This walks the (sorted) trees in lock-step, checking every possible
302
 * name. Note that directories automatically sort differently from other
303
 * files (see "base_name_compare"), so you'll never see file/directory
304
 * conflicts, because they won't ever compare the same.
305
 *
306
 * IOW, if a directory changes to a filename, it will automatically be
307
 * seen as the directory going away, and the filename being created.
308
 *
309
 * Think of this as a three-way diff.
310
 *
311
 * The output will be either:
312
 *  - successful merge
313
 *   "0 mode sha1 filename"
314
 *    NOTE NOTE NOTE! FIXME! We really really need to walk the index
315
 *    in parallel with this too!
316
 *
317
 *  - conflict:
318
 *  "1 mode sha1 filename"
319
 *  "2 mode sha1 filename"
320
 *  "3 mode sha1 filename"
321
 *    where not all of the 1/2/3 lines may exist, of course.
322
 *
323
 * The successful merge rules are the same as for the three-way merge
324
 * in git-read-tree.
325
 */
326
static int threeway_callback(int n UNUSED, unsigned long mask,
327
           unsigned long dirmask UNUSED,
328
           struct name_entry *entry, struct traverse_info *info)
329
0
{
330
  /* Same in both? */
331
0
  if (same_entry(entry+1, entry+2) || both_empty(entry+1, entry+2)) {
332
    /* Modified, added or removed identically */
333
0
    resolve(info, NULL, entry+1);
334
0
    return mask;
335
0
  }
336
337
0
  if (same_entry(entry+0, entry+1)) {
338
0
    if (!is_null_oid(&entry[2].oid) && !S_ISDIR(entry[2].mode)) {
339
      /* We did not touch, they modified -- take theirs */
340
0
      resolve(info, entry+1, entry+2);
341
0
      return mask;
342
0
    }
343
    /*
344
     * If we did not touch a directory but they made it
345
     * into a file, we fall through and unresolved()
346
     * recurses down.  Likewise for the opposite case.
347
     */
348
0
  }
349
350
0
  if (same_entry(entry+0, entry+2) || both_empty(entry+0, entry+2)) {
351
    /* We added, modified or removed, they did not touch -- take ours */
352
0
    resolve(info, NULL, entry+1);
353
0
    return mask;
354
0
  }
355
356
0
  unresolved(info, entry);
357
0
  return mask;
358
0
}
359
360
static void trivial_merge_trees(struct tree_desc t[3], const char *base)
361
0
{
362
0
  struct traverse_info info;
363
364
0
  setup_traverse_info(&info, base);
365
0
  info.fn = threeway_callback;
366
0
  traverse_trees(the_repository->index, 3, t, &info);
367
0
}
368
369
static void *get_tree_descriptor(struct repository *r,
370
         struct tree_desc *desc,
371
         const char *rev)
372
0
{
373
0
  struct object_id oid;
374
0
  void *buf;
375
376
0
  if (repo_get_oid(r, rev, &oid))
377
0
    die("unknown rev %s", rev);
378
0
  buf = fill_tree_descriptor(r, desc, &oid);
379
0
  if (!buf)
380
0
    die("%s is not a tree", rev);
381
0
  return buf;
382
0
}
383
384
static int trivial_merge(const char *base,
385
       const char *branch1,
386
       const char *branch2)
387
0
{
388
0
  struct repository *r = the_repository;
389
0
  struct tree_desc t[3];
390
0
  void *buf1, *buf2, *buf3;
391
392
0
  buf1 = get_tree_descriptor(r, t+0, base);
393
0
  buf2 = get_tree_descriptor(r, t+1, branch1);
394
0
  buf3 = get_tree_descriptor(r, t+2, branch2);
395
0
  trivial_merge_trees(t, "");
396
0
  free(buf1);
397
0
  free(buf2);
398
0
  free(buf3);
399
400
0
  show_result();
401
0
  return 0;
402
0
}
403
404
enum mode {
405
  MODE_UNKNOWN,
406
  MODE_TRIVIAL,
407
  MODE_REAL,
408
};
409
410
struct merge_tree_options {
411
  int mode;
412
  int allow_unrelated_histories;
413
  int show_messages;
414
  int name_only;
415
  int use_stdin;
416
  struct merge_options merge_options;
417
};
418
419
static int real_merge(struct merge_tree_options *o,
420
          const char *merge_base,
421
          const char *branch1, const char *branch2,
422
          const char *prefix)
423
0
{
424
0
  struct commit *parent1, *parent2;
425
0
  struct commit_list *merge_bases = NULL;
426
0
  struct merge_result result = { 0 };
427
0
  int show_messages = o->show_messages;
428
0
  struct merge_options opt;
429
430
0
  copy_merge_options(&opt, &o->merge_options);
431
0
  opt.show_rename_progress = 0;
432
433
0
  opt.branch1 = branch1;
434
0
  opt.branch2 = branch2;
435
436
0
  if (merge_base) {
437
0
    struct tree *base_tree, *parent1_tree, *parent2_tree;
438
439
    /*
440
     * We actually only need the trees because we already
441
     * have a merge base.
442
     */
443
0
    struct object_id base_oid, head_oid, merge_oid;
444
445
0
    if (repo_get_oid_treeish(the_repository, merge_base, &base_oid))
446
0
      die(_("could not parse as tree '%s'"), merge_base);
447
0
    base_tree = parse_tree_indirect(&base_oid);
448
0
    if (!base_tree)
449
0
      die(_("unable to read tree (%s)"), oid_to_hex(&base_oid));
450
0
    if (repo_get_oid_treeish(the_repository, branch1, &head_oid))
451
0
      die(_("could not parse as tree '%s'"), branch1);
452
0
    parent1_tree = parse_tree_indirect(&head_oid);
453
0
    if (!parent1_tree)
454
0
      die(_("unable to read tree (%s)"), oid_to_hex(&head_oid));
455
0
    if (repo_get_oid_treeish(the_repository, branch2, &merge_oid))
456
0
      die(_("could not parse as tree '%s'"), branch2);
457
0
    parent2_tree = parse_tree_indirect(&merge_oid);
458
0
    if (!parent2_tree)
459
0
      die(_("unable to read tree (%s)"), oid_to_hex(&merge_oid));
460
461
0
    opt.ancestor = merge_base;
462
0
    merge_incore_nonrecursive(&opt, base_tree, parent1_tree, parent2_tree, &result);
463
0
  } else {
464
0
    parent1 = get_merge_parent(branch1);
465
0
    if (!parent1)
466
0
      help_unknown_ref(branch1, "merge-tree",
467
0
           _("not something we can merge"));
468
469
0
    parent2 = get_merge_parent(branch2);
470
0
    if (!parent2)
471
0
      help_unknown_ref(branch2, "merge-tree",
472
0
           _("not something we can merge"));
473
474
    /*
475
     * Get the merge bases, in reverse order; see comment above
476
     * merge_incore_recursive in merge-ort.h
477
     */
478
0
    if (repo_get_merge_bases(the_repository, parent1,
479
0
           parent2, &merge_bases) < 0)
480
0
      exit(128);
481
0
    if (!merge_bases && !o->allow_unrelated_histories)
482
0
      die(_("refusing to merge unrelated histories"));
483
0
    merge_bases = reverse_commit_list(merge_bases);
484
0
    merge_incore_recursive(&opt, merge_bases, parent1, parent2, &result);
485
0
    free_commit_list(merge_bases);
486
0
  }
487
488
0
  if (result.clean < 0)
489
0
    die(_("failure to merge"));
490
491
0
  if (show_messages == -1)
492
0
    show_messages = !result.clean;
493
494
0
  if (o->use_stdin)
495
0
    printf("%d%c", result.clean, line_termination);
496
0
  printf("%s%c", oid_to_hex(&result.tree->object.oid), line_termination);
497
0
  if (!result.clean) {
498
0
    struct string_list conflicted_files = STRING_LIST_INIT_NODUP;
499
0
    const char *last = NULL;
500
0
    int i;
501
502
0
    merge_get_conflicted_files(&result, &conflicted_files);
503
0
    for (i = 0; i < conflicted_files.nr; i++) {
504
0
      const char *name = conflicted_files.items[i].string;
505
0
      struct stage_info *c = conflicted_files.items[i].util;
506
0
      if (!o->name_only)
507
0
        printf("%06o %s %d\t",
508
0
               c->mode, oid_to_hex(&c->oid), c->stage);
509
0
      else if (last && !strcmp(last, name))
510
0
        continue;
511
0
      write_name_quoted_relative(
512
0
        name, prefix, stdout, line_termination);
513
0
      last = name;
514
0
    }
515
0
    string_list_clear(&conflicted_files, 1);
516
0
  }
517
0
  if (show_messages) {
518
0
    putchar(line_termination);
519
0
    merge_display_update_messages(&opt, line_termination == '\0',
520
0
                &result);
521
0
  }
522
0
  if (o->use_stdin)
523
0
    putchar(line_termination);
524
0
  merge_finalize(&opt, &result);
525
0
  clear_merge_options(&opt);
526
0
  return !result.clean; /* result.clean < 0 handled above */
527
0
}
528
529
int cmd_merge_tree(int argc, const char **argv, const char *prefix)
530
0
{
531
0
  struct merge_tree_options o = { .show_messages = -1 };
532
0
  struct strvec xopts = STRVEC_INIT;
533
0
  int expected_remaining_argc;
534
0
  int original_argc;
535
0
  const char *merge_base = NULL;
536
0
  int ret;
537
538
0
  const char * const merge_tree_usage[] = {
539
0
    N_("git merge-tree [--write-tree] [<options>] <branch1> <branch2>"),
540
0
    N_("git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"),
541
0
    NULL
542
0
  };
543
0
  struct option mt_options[] = {
544
0
    OPT_CMDMODE(0, "write-tree", &o.mode,
545
0
          N_("do a real merge instead of a trivial merge"),
546
0
          MODE_REAL),
547
0
    OPT_CMDMODE(0, "trivial-merge", &o.mode,
548
0
          N_("do a trivial merge only"), MODE_TRIVIAL),
549
0
    OPT_BOOL(0, "messages", &o.show_messages,
550
0
       N_("also show informational/conflict messages")),
551
0
    OPT_SET_INT('z', NULL, &line_termination,
552
0
          N_("separate paths with the NUL character"), '\0'),
553
0
    OPT_BOOL_F(0, "name-only",
554
0
         &o.name_only,
555
0
         N_("list filenames without modes/oids/stages"),
556
0
         PARSE_OPT_NONEG),
557
0
    OPT_BOOL_F(0, "allow-unrelated-histories",
558
0
         &o.allow_unrelated_histories,
559
0
         N_("allow merging unrelated histories"),
560
0
         PARSE_OPT_NONEG),
561
0
    OPT_BOOL_F(0, "stdin",
562
0
         &o.use_stdin,
563
0
         N_("perform multiple merges, one per line of input"),
564
0
         PARSE_OPT_NONEG),
565
0
    OPT_STRING(0, "merge-base",
566
0
         &merge_base,
567
0
         N_("tree-ish"),
568
0
         N_("specify a merge-base for the merge")),
569
0
    OPT_STRVEC('X', "strategy-option", &xopts, N_("option=value"),
570
0
      N_("option for selected merge strategy")),
571
0
    OPT_END()
572
0
  };
573
574
  /* Init merge options */
575
0
  init_ui_merge_options(&o.merge_options, the_repository);
576
577
  /* Parse arguments */
578
0
  original_argc = argc - 1; /* ignoring argv[0] */
579
0
  argc = parse_options(argc, argv, prefix, mt_options,
580
0
           merge_tree_usage, PARSE_OPT_STOP_AT_NON_OPTION);
581
582
0
  if (xopts.nr && o.mode == MODE_TRIVIAL)
583
0
    die(_("--trivial-merge is incompatible with all other options"));
584
0
  for (int x = 0; x < xopts.nr; x++)
585
0
    if (parse_merge_opt(&o.merge_options, xopts.v[x]))
586
0
      die(_("unknown strategy option: -X%s"), xopts.v[x]);
587
588
  /* Handle --stdin */
589
0
  if (o.use_stdin) {
590
0
    struct strbuf buf = STRBUF_INIT;
591
592
0
    if (o.mode == MODE_TRIVIAL)
593
0
      die(_("--trivial-merge is incompatible with all other options"));
594
0
    if (merge_base)
595
0
      die(_("options '%s' and '%s' cannot be used together"),
596
0
          "--merge-base", "--stdin");
597
0
    line_termination = '\0';
598
0
    while (strbuf_getline_lf(&buf, stdin) != EOF) {
599
0
      struct strbuf **split;
600
0
      int result;
601
0
      const char *input_merge_base = NULL;
602
603
0
      split = strbuf_split(&buf, ' ');
604
0
      if (!split[0] || !split[1])
605
0
        die(_("malformed input line: '%s'."), buf.buf);
606
0
      strbuf_rtrim(split[0]);
607
0
      strbuf_rtrim(split[1]);
608
609
      /* parse the merge-base */
610
0
      if (!strcmp(split[1]->buf, "--")) {
611
0
        input_merge_base = split[0]->buf;
612
0
      }
613
614
0
      if (input_merge_base && split[2] && split[3] && !split[4]) {
615
0
        strbuf_rtrim(split[2]);
616
0
        strbuf_rtrim(split[3]);
617
0
        result = real_merge(&o, input_merge_base, split[2]->buf, split[3]->buf, prefix);
618
0
      } else if (!input_merge_base && !split[2]) {
619
0
        result = real_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix);
620
0
      } else {
621
0
        die(_("malformed input line: '%s'."), buf.buf);
622
0
      }
623
624
0
      if (result < 0)
625
0
        die(_("merging cannot continue; got unclean result of %d"), result);
626
0
      strbuf_list_free(split);
627
0
    }
628
0
    strbuf_release(&buf);
629
630
0
    ret = 0;
631
0
    goto out;
632
0
  }
633
634
  /* Figure out which mode to use */
635
0
  switch (o.mode) {
636
0
  default:
637
0
    BUG("unexpected command mode %d", o.mode);
638
0
  case MODE_UNKNOWN:
639
0
    switch (argc) {
640
0
    default:
641
0
      usage_with_options(merge_tree_usage, mt_options);
642
0
    case 2:
643
0
      o.mode = MODE_REAL;
644
0
      break;
645
0
    case 3:
646
0
      o.mode = MODE_TRIVIAL;
647
0
      break;
648
0
    }
649
0
    expected_remaining_argc = argc;
650
0
    break;
651
0
  case MODE_REAL:
652
0
    expected_remaining_argc = 2;
653
0
    break;
654
0
  case MODE_TRIVIAL:
655
0
    expected_remaining_argc = 3;
656
    /* Removal of `--trivial-merge` is expected */
657
0
    original_argc--;
658
0
    break;
659
0
  }
660
0
  if (o.mode == MODE_TRIVIAL && argc < original_argc)
661
0
    die(_("--trivial-merge is incompatible with all other options"));
662
663
0
  if (argc != expected_remaining_argc)
664
0
    usage_with_options(merge_tree_usage, mt_options);
665
666
0
  git_config(git_default_config, NULL);
667
668
  /* Do the relevant type of merge */
669
0
  if (o.mode == MODE_REAL)
670
0
    ret = real_merge(&o, merge_base, argv[0], argv[1], prefix);
671
0
  else
672
0
    ret = trivial_merge(argv[0], argv[1], argv[2]);
673
674
0
out:
675
0
  strvec_clear(&xopts);
676
0
  return ret;
677
0
}