Coverage Report

Created: 2026-11-12 06:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/git/merge.c
Line
Count
Source
1
#define USE_THE_REPOSITORY_VARIABLE
2
3
#include "git-compat-util.h"
4
#include "gettext.h"
5
#include "hash.h"
6
#include "hex.h"
7
#include "lockfile.h"
8
#include "merge.h"
9
#include "commit.h"
10
#include "repository.h"
11
#include "path.h"
12
#include "run-command.h"
13
#include "resolve-undo.h"
14
#include "tree.h"
15
#include "tree-walk.h"
16
#include "unpack-trees.h"
17
18
static const char *merge_argument(struct commit *commit)
19
0
{
20
0
  return oid_to_hex(commit ? &commit->object.oid : the_hash_algo->empty_tree);
21
0
}
22
23
int try_merge_command(struct repository *r,
24
          const char *strategy, size_t xopts_nr,
25
          const char **xopts, struct commit_list *common,
26
          const char *head_arg, struct commit_list *remotes)
27
0
{
28
0
  struct child_process cmd = CHILD_PROCESS_INIT;
29
0
  int ret;
30
0
  struct commit_list *j;
31
32
0
  strvec_pushf(&cmd.args, "merge-%s", strategy);
33
0
  for (size_t i = 0; i < xopts_nr; i++)
34
0
    strvec_pushf(&cmd.args, "--%s", xopts[i]);
35
0
  for (j = common; j; j = j->next)
36
0
    strvec_push(&cmd.args, merge_argument(j->item));
37
0
  strvec_push(&cmd.args, "--");
38
0
  strvec_push(&cmd.args, head_arg);
39
0
  for (j = remotes; j; j = j->next)
40
0
    strvec_push(&cmd.args, merge_argument(j->item));
41
42
0
  cmd.git_cmd = 1;
43
0
  ret = run_command(&cmd);
44
45
0
  discard_index(r->index);
46
0
  if (repo_read_index(r) < 0)
47
0
    die(_("failed to read the cache"));
48
0
  resolve_undo_clear_index(r->index);
49
50
0
  return ret;
51
0
}
52
53
int checkout_fast_forward(struct repository *r,
54
        const struct object_id *head,
55
        const struct object_id *remote,
56
        int overwrite_ignore)
57
0
{
58
0
  struct tree *trees[MAX_UNPACK_TREES];
59
0
  struct unpack_trees_options opts;
60
0
  struct tree_desc t[MAX_UNPACK_TREES];
61
0
  int i, nr_trees = 0;
62
0
  struct lock_file lock_file = LOCK_INIT;
63
64
0
  refresh_index(r->index, REFRESH_QUIET, NULL, NULL, NULL);
65
66
0
  if (repo_hold_locked_index(r, &lock_file, LOCK_REPORT_ON_ERROR) < 0)
67
0
    return -1;
68
69
0
  memset(&trees, 0, sizeof(trees));
70
0
  memset(&t, 0, sizeof(t));
71
72
0
  trees[nr_trees] = repo_parse_tree_indirect(the_repository, head);
73
0
  if (!trees[nr_trees++]) {
74
0
    rollback_lock_file(&lock_file);
75
0
    return -1;
76
0
  }
77
0
  trees[nr_trees] = repo_parse_tree_indirect(the_repository, remote);
78
0
  if (!trees[nr_trees++]) {
79
0
    rollback_lock_file(&lock_file);
80
0
    return -1;
81
0
  }
82
0
  for (i = 0; i < nr_trees; i++) {
83
0
    if (repo_parse_tree(the_repository, trees[i]) < 0) {
84
0
      rollback_lock_file(&lock_file);
85
0
      return -1;
86
0
    }
87
0
    init_tree_desc(t+i, &trees[i]->object.oid,
88
0
             trees[i]->buffer, trees[i]->size);
89
0
  }
90
91
0
  memset(&opts, 0, sizeof(opts));
92
0
  opts.preserve_ignored = !overwrite_ignore;
93
94
0
  opts.head_idx = 1;
95
0
  opts.src_index = r->index;
96
0
  opts.dst_index = r->index;
97
0
  opts.update = 1;
98
0
  opts.verbose_update = 1;
99
0
  opts.merge = 1;
100
0
  opts.fn = twoway_merge;
101
0
  init_checkout_metadata(&opts.meta, NULL, remote, NULL);
102
0
  setup_unpack_trees_porcelain(&opts, "merge");
103
104
0
  if (unpack_trees(nr_trees, t, &opts)) {
105
0
    rollback_lock_file(&lock_file);
106
0
    clear_unpack_trees_porcelain(&opts);
107
0
    return -1;
108
0
  }
109
0
  clear_unpack_trees_porcelain(&opts);
110
111
0
  if (write_locked_index(r->index, &lock_file, COMMIT_LOCK))
112
0
    return error(_("unable to write new index file"));
113
0
  return 0;
114
0
}
115
116
int write_merge_labels(struct repository *r, const char *labels[3])
117
0
{
118
0
  FILE *f = fopen_or_warn(git_path_merge_labels(r), "w");
119
120
0
  if (!f)
121
0
    return -1;
122
123
0
  fprintf(f, "%s\n%s\n%s\n", labels[0], labels[1], labels[2]);
124
0
  if (fclose(f))
125
0
    return error_errno("could not write '%s'",
126
0
           git_path_merge_labels(r));
127
128
0
  return 0;
129
0
}
130
131
static char *parse_merge_label_line(FILE *fp)
132
0
{
133
0
  struct strbuf buf = STRBUF_INIT;
134
135
0
  if (strbuf_getline(&buf, fp) == EOF) {
136
0
    strbuf_release(&buf);
137
0
    return NULL;
138
0
  }
139
140
0
  return strbuf_detach(&buf, NULL);
141
0
}
142
143
int read_merge_labels(struct repository *r,
144
          char **pbase, char **pours, char **ptheirs)
145
0
{
146
0
  char *base = NULL, *ours = NULL, *theirs = NULL;
147
0
  int ret = -1;
148
0
  FILE *fp = fopen(git_path_merge_labels(r), "r");
149
150
0
  if (!fp)
151
0
    return -1;
152
153
0
  base = parse_merge_label_line(fp);
154
0
  if (!base)
155
0
    goto out;
156
157
0
  ours = parse_merge_label_line(fp);
158
0
  if (!ours)
159
0
    goto out;
160
161
0
  theirs = parse_merge_label_line(fp);
162
0
  if (!theirs)
163
0
    goto out;
164
  /* We ignore any trailing lines */
165
166
0
  ret = 0;
167
0
  *pbase = base;
168
0
  *pours = ours;
169
0
  *ptheirs = theirs;
170
0
out:
171
0
  if (ret) {
172
0
    free(base);
173
0
    free(ours);
174
0
    free(theirs);
175
0
  }
176
0
  fclose(fp);
177
178
0
  return ret;
179
0
}