blob: 8799b522a55f31869dcc8cbfd7229cc8db65af4c [file] [log] [blame]
Elijah Newrenb6fdc442023-04-11 00:41:54 -07001#include "git-compat-util.h"
Elijah Newren6c6ddf92023-04-11 03:00:39 +00002#include "advice.h"
Johan Herland75ef3f42010-11-09 22:49:46 +01003#include "commit.h"
Elijah Newrenf394e092023-03-21 06:25:54 +00004#include "gettext.h"
Johan Herland75ef3f42010-11-09 22:49:46 +01005#include "refs.h"
Elijah Newren87bed172023-04-11 00:41:53 -07006#include "object-file.h"
Elijah Newrendabab1d2023-04-11 00:41:49 -07007#include "object-name.h"
Elijah Newrena034e912023-05-16 06:34:06 +00008#include "object-store-ll.h"
Elijah Newrenc3399322023-05-16 06:33:59 +00009#include "path.h"
Stefan Beller2122f672018-06-28 18:21:58 -070010#include "repository.h"
Johan Herland2085b162010-11-15 00:54:11 +010011#include "diff.h"
12#include "diffcore.h"
Elijah Newren41771fa2023-02-24 00:09:27 +000013#include "hex.h"
Johan Herland809f38c2010-11-09 22:49:51 +010014#include "xdiff-interface.h"
Elijah Newren67238992023-05-16 06:34:04 +000015#include "merge-ll.h"
Johan Herland809f38c2010-11-09 22:49:51 +010016#include "dir.h"
Johan Herland56881842010-11-09 22:49:47 +010017#include "notes.h"
Johan Herland75ef3f42010-11-09 22:49:46 +010018#include "notes-merge.h"
Johan Herland443259c2010-11-09 22:49:53 +010019#include "strbuf.h"
Elijah Newren74ea5c92023-04-11 03:00:38 +000020#include "trace.h"
Johan Herlandbf9a05b2013-06-12 02:13:01 +020021#include "notes-utils.h"
Derrick Stolee64043552018-07-20 16:33:04 +000022#include "commit-reach.h"
Johan Herland75ef3f42010-11-09 22:49:46 +010023
Johan Herland2085b162010-11-15 00:54:11 +010024struct notes_merge_pair {
brian m. carlsone910bb12016-09-05 20:08:01 +000025 struct object_id obj, base, local, remote;
Johan Herland2085b162010-11-15 00:54:11 +010026};
27
Nguyễn Thái Ngọc Duy56842002018-11-10 06:48:53 +010028void init_notes_merge_options(struct repository *r,
29 struct notes_merge_options *o)
Johan Herland75ef3f42010-11-09 22:49:46 +010030{
31 memset(o, 0, sizeof(struct notes_merge_options));
Johan Herland443259c2010-11-09 22:49:53 +010032 strbuf_init(&(o->commit_msg), 0);
Johan Herland75ef3f42010-11-09 22:49:46 +010033 o->verbosity = NOTES_MERGE_VERBOSITY_DEFAULT;
Nguyễn Thái Ngọc Duy56842002018-11-10 06:48:53 +010034 o->repo = r;
Johan Herland75ef3f42010-11-09 22:49:46 +010035}
36
Brandon Williams4d778962017-05-30 10:31:01 -070037static int path_to_oid(const char *path, struct object_id *oid)
Johan Herland2085b162010-11-15 00:54:11 +010038{
brian m. carlson22350302019-02-19 00:05:00 +000039 char hex_oid[GIT_MAX_HEXSZ];
Johan Herland2085b162010-11-15 00:54:11 +010040 int i = 0;
brian m. carlson22350302019-02-19 00:05:00 +000041 while (*path && i < the_hash_algo->hexsz) {
Johan Herland2085b162010-11-15 00:54:11 +010042 if (*path != '/')
Brandon Williams4d778962017-05-30 10:31:01 -070043 hex_oid[i++] = *path;
Johan Herland2085b162010-11-15 00:54:11 +010044 path++;
45 }
brian m. carlson22350302019-02-19 00:05:00 +000046 if (*path || i != the_hash_algo->hexsz)
Johan Herland2085b162010-11-15 00:54:11 +010047 return -1;
Brandon Williams4d778962017-05-30 10:31:01 -070048 return get_oid_hex(hex_oid, oid);
Johan Herland2085b162010-11-15 00:54:11 +010049}
50
Brandon Williams4d778962017-05-30 10:31:01 -070051static int verify_notes_filepair(struct diff_filepair *p, struct object_id *oid)
Johan Herland2085b162010-11-15 00:54:11 +010052{
53 switch (p->status) {
54 case DIFF_STATUS_MODIFIED:
55 assert(p->one->mode == p->two->mode);
brian m. carlsona0d12c42016-06-24 23:09:23 +000056 assert(!is_null_oid(&p->one->oid));
57 assert(!is_null_oid(&p->two->oid));
Johan Herland2085b162010-11-15 00:54:11 +010058 break;
59 case DIFF_STATUS_ADDED:
brian m. carlsona0d12c42016-06-24 23:09:23 +000060 assert(is_null_oid(&p->one->oid));
Johan Herland2085b162010-11-15 00:54:11 +010061 break;
62 case DIFF_STATUS_DELETED:
brian m. carlsona0d12c42016-06-24 23:09:23 +000063 assert(is_null_oid(&p->two->oid));
Johan Herland2085b162010-11-15 00:54:11 +010064 break;
65 default:
66 return -1;
67 }
68 assert(!strcmp(p->one->path, p->two->path));
Brandon Williams4d778962017-05-30 10:31:01 -070069 return path_to_oid(p->one->path, oid);
Johan Herland2085b162010-11-15 00:54:11 +010070}
71
72static struct notes_merge_pair *find_notes_merge_pair_pos(
Brandon Williamsd7a7c702017-05-30 10:31:00 -070073 struct notes_merge_pair *list, int len, struct object_id *obj,
Johan Herland2085b162010-11-15 00:54:11 +010074 int insert_new, int *occupied)
75{
76 /*
77 * Both diff_tree_remote() and diff_tree_local() tend to process
78 * merge_pairs in ascending order. Therefore, cache last returned
79 * index, and search sequentially from there until the appropriate
80 * position is found.
81 *
82 * Since inserts only happen from diff_tree_remote() (which mainly
83 * _appends_), we don't care that inserting into the middle of the
84 * list is expensive (using memmove()).
85 */
86 static int last_index;
87 int i = last_index < len ? last_index : len - 1;
88 int prev_cmp = 0, cmp = -1;
89 while (i >= 0 && i < len) {
Brandon Williamsd7a7c702017-05-30 10:31:00 -070090 cmp = oidcmp(obj, &list[i].obj);
Johan Herland2085b162010-11-15 00:54:11 +010091 if (!cmp) /* obj belongs @ i */
92 break;
93 else if (cmp < 0 && prev_cmp <= 0) /* obj belongs < i */
94 i--;
95 else if (cmp < 0) /* obj belongs between i-1 and i */
96 break;
97 else if (cmp > 0 && prev_cmp >= 0) /* obj belongs > i */
98 i++;
99 else /* if (cmp > 0) */ { /* obj belongs between i and i+1 */
100 i++;
101 break;
102 }
103 prev_cmp = cmp;
104 }
105 if (i < 0)
106 i = 0;
107 /* obj belongs at, or immediately preceding, index i (0 <= i <= len) */
108
109 if (!cmp)
110 *occupied = 1;
111 else {
112 *occupied = 0;
113 if (insert_new && i < len) {
René Scharfef331ab92017-07-15 22:00:45 +0200114 MOVE_ARRAY(list + i + 1, list + i, len - i);
Johan Herland2085b162010-11-15 00:54:11 +0100115 memset(list + i, 0, sizeof(struct notes_merge_pair));
116 }
117 }
118 last_index = i;
119 return list + i;
120}
121
brian m. carlsone910bb12016-09-05 20:08:01 +0000122static struct object_id uninitialized = {
Ævar Arnfjörð Bjarmason50103642022-03-17 18:27:17 +0100123 .hash =
Johan Herland2085b162010-11-15 00:54:11 +0100124 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
brian m. carlsone910bb12016-09-05 20:08:01 +0000125 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
126};
Johan Herland2085b162010-11-15 00:54:11 +0100127
128static struct notes_merge_pair *diff_tree_remote(struct notes_merge_options *o,
Brandon Williams9d6babb2017-05-30 10:30:59 -0700129 const struct object_id *base,
130 const struct object_id *remote,
Johan Herland2085b162010-11-15 00:54:11 +0100131 int *num_changes)
132{
133 struct diff_options opt;
134 struct notes_merge_pair *changes;
135 int i, len = 0;
136
137 trace_printf("\tdiff_tree_remote(base = %.7s, remote = %.7s)\n",
Brandon Williams9d6babb2017-05-30 10:30:59 -0700138 oid_to_hex(base), oid_to_hex(remote));
Johan Herland2085b162010-11-15 00:54:11 +0100139
Nguyễn Thái Ngọc Duy56842002018-11-10 06:48:53 +0100140 repo_diff_setup(o->repo, &opt);
Brandon Williams0d1e0e72017-10-31 11:19:11 -0700141 opt.flags.recursive = 1;
Johan Herland2085b162010-11-15 00:54:11 +0100142 opt.output_format = DIFF_FORMAT_NO_OUTPUT;
Thomas Rast28452652012-08-03 14:16:24 +0200143 diff_setup_done(&opt);
Brandon Williams66f414f2017-05-30 10:31:03 -0700144 diff_tree_oid(base, remote, "", &opt);
Johan Herland2085b162010-11-15 00:54:11 +0100145 diffcore_std(&opt);
146
René Scharfeca56dad2021-03-13 17:17:22 +0100147 CALLOC_ARRAY(changes, diff_queued_diff.nr);
Johan Herland2085b162010-11-15 00:54:11 +0100148
149 for (i = 0; i < diff_queued_diff.nr; i++) {
150 struct diff_filepair *p = diff_queued_diff.queue[i];
151 struct notes_merge_pair *mp;
152 int occupied;
Brandon Williamsd7a7c702017-05-30 10:31:00 -0700153 struct object_id obj;
Johan Herland2085b162010-11-15 00:54:11 +0100154
Brandon Williams4d778962017-05-30 10:31:01 -0700155 if (verify_notes_filepair(p, &obj)) {
Johan Herland2085b162010-11-15 00:54:11 +0100156 trace_printf("\t\tCannot merge entry '%s' (%c): "
157 "%.7s -> %.7s. Skipping!\n", p->one->path,
brian m. carlsona0d12c42016-06-24 23:09:23 +0000158 p->status, oid_to_hex(&p->one->oid),
159 oid_to_hex(&p->two->oid));
Johan Herland2085b162010-11-15 00:54:11 +0100160 continue;
161 }
Brandon Williamsd7a7c702017-05-30 10:31:00 -0700162 mp = find_notes_merge_pair_pos(changes, len, &obj, 1, &occupied);
Johan Herland2085b162010-11-15 00:54:11 +0100163 if (occupied) {
164 /* We've found an addition/deletion pair */
Jeff King4a7e27e2018-08-28 17:22:40 -0400165 assert(oideq(&mp->obj, &obj));
brian m. carlsona0d12c42016-06-24 23:09:23 +0000166 if (is_null_oid(&p->one->oid)) { /* addition */
brian m. carlsone910bb12016-09-05 20:08:01 +0000167 assert(is_null_oid(&mp->remote));
168 oidcpy(&mp->remote, &p->two->oid);
brian m. carlsona0d12c42016-06-24 23:09:23 +0000169 } else if (is_null_oid(&p->two->oid)) { /* deletion */
brian m. carlsone910bb12016-09-05 20:08:01 +0000170 assert(is_null_oid(&mp->base));
171 oidcpy(&mp->base, &p->one->oid);
Johan Herland2085b162010-11-15 00:54:11 +0100172 } else
173 assert(!"Invalid existing change recorded");
174 } else {
Brandon Williamsd7a7c702017-05-30 10:31:00 -0700175 oidcpy(&mp->obj, &obj);
brian m. carlsone910bb12016-09-05 20:08:01 +0000176 oidcpy(&mp->base, &p->one->oid);
177 oidcpy(&mp->local, &uninitialized);
178 oidcpy(&mp->remote, &p->two->oid);
Johan Herland2085b162010-11-15 00:54:11 +0100179 len++;
180 }
181 trace_printf("\t\tStored remote change for %s: %.7s -> %.7s\n",
brian m. carlsone910bb12016-09-05 20:08:01 +0000182 oid_to_hex(&mp->obj), oid_to_hex(&mp->base),
183 oid_to_hex(&mp->remote));
Johan Herland2085b162010-11-15 00:54:11 +0100184 }
185 diff_flush(&opt);
Johan Herland2085b162010-11-15 00:54:11 +0100186
187 *num_changes = len;
188 return changes;
189}
190
191static void diff_tree_local(struct notes_merge_options *o,
192 struct notes_merge_pair *changes, int len,
Brandon Williams9d6babb2017-05-30 10:30:59 -0700193 const struct object_id *base,
194 const struct object_id *local)
Johan Herland2085b162010-11-15 00:54:11 +0100195{
196 struct diff_options opt;
197 int i;
198
199 trace_printf("\tdiff_tree_local(len = %i, base = %.7s, local = %.7s)\n",
Brandon Williams9d6babb2017-05-30 10:30:59 -0700200 len, oid_to_hex(base), oid_to_hex(local));
Johan Herland2085b162010-11-15 00:54:11 +0100201
Nguyễn Thái Ngọc Duy56842002018-11-10 06:48:53 +0100202 repo_diff_setup(o->repo, &opt);
Brandon Williams0d1e0e72017-10-31 11:19:11 -0700203 opt.flags.recursive = 1;
Johan Herland2085b162010-11-15 00:54:11 +0100204 opt.output_format = DIFF_FORMAT_NO_OUTPUT;
Thomas Rast28452652012-08-03 14:16:24 +0200205 diff_setup_done(&opt);
Brandon Williams66f414f2017-05-30 10:31:03 -0700206 diff_tree_oid(base, local, "", &opt);
Johan Herland2085b162010-11-15 00:54:11 +0100207 diffcore_std(&opt);
208
209 for (i = 0; i < diff_queued_diff.nr; i++) {
210 struct diff_filepair *p = diff_queued_diff.queue[i];
211 struct notes_merge_pair *mp;
212 int match;
Brandon Williamsd7a7c702017-05-30 10:31:00 -0700213 struct object_id obj;
Johan Herland2085b162010-11-15 00:54:11 +0100214
Brandon Williams4d778962017-05-30 10:31:01 -0700215 if (verify_notes_filepair(p, &obj)) {
Johan Herland2085b162010-11-15 00:54:11 +0100216 trace_printf("\t\tCannot merge entry '%s' (%c): "
217 "%.7s -> %.7s. Skipping!\n", p->one->path,
brian m. carlsona0d12c42016-06-24 23:09:23 +0000218 p->status, oid_to_hex(&p->one->oid),
219 oid_to_hex(&p->two->oid));
Johan Herland2085b162010-11-15 00:54:11 +0100220 continue;
221 }
Brandon Williamsd7a7c702017-05-30 10:31:00 -0700222 mp = find_notes_merge_pair_pos(changes, len, &obj, 0, &match);
Johan Herland2085b162010-11-15 00:54:11 +0100223 if (!match) {
224 trace_printf("\t\tIgnoring local-only change for %s: "
Brandon Williamsd7a7c702017-05-30 10:31:00 -0700225 "%.7s -> %.7s\n", oid_to_hex(&obj),
brian m. carlsona0d12c42016-06-24 23:09:23 +0000226 oid_to_hex(&p->one->oid),
227 oid_to_hex(&p->two->oid));
Johan Herland2085b162010-11-15 00:54:11 +0100228 continue;
229 }
230
Jeff King4a7e27e2018-08-28 17:22:40 -0400231 assert(oideq(&mp->obj, &obj));
brian m. carlsona0d12c42016-06-24 23:09:23 +0000232 if (is_null_oid(&p->two->oid)) { /* deletion */
Johan Herland2085b162010-11-15 00:54:11 +0100233 /*
234 * Either this is a true deletion (1), or it is part
235 * of an A/D pair (2), or D/A pair (3):
236 *
237 * (1) mp->local is uninitialized; set it to null_sha1
238 * (2) mp->local is not uninitialized; don't touch it
239 * (3) mp->local is uninitialized; set it to null_sha1
240 * (will be overwritten by following addition)
241 */
Jeff King4a7e27e2018-08-28 17:22:40 -0400242 if (oideq(&mp->local, &uninitialized))
brian m. carlsone910bb12016-09-05 20:08:01 +0000243 oidclr(&mp->local);
brian m. carlsona0d12c42016-06-24 23:09:23 +0000244 } else if (is_null_oid(&p->one->oid)) { /* addition */
Johan Herland2085b162010-11-15 00:54:11 +0100245 /*
246 * Either this is a true addition (1), or it is part
247 * of an A/D pair (2), or D/A pair (3):
248 *
249 * (1) mp->local is uninitialized; set to p->two->sha1
250 * (2) mp->local is uninitialized; set to p->two->sha1
251 * (3) mp->local is null_sha1; set to p->two->sha1
252 */
brian m. carlsone910bb12016-09-05 20:08:01 +0000253 assert(is_null_oid(&mp->local) ||
Jeff King4a7e27e2018-08-28 17:22:40 -0400254 oideq(&mp->local, &uninitialized));
brian m. carlsone910bb12016-09-05 20:08:01 +0000255 oidcpy(&mp->local, &p->two->oid);
Johan Herland2085b162010-11-15 00:54:11 +0100256 } else { /* modification */
257 /*
258 * This is a true modification. p->one->sha1 shall
259 * match mp->base, and mp->local shall be uninitialized.
260 * Set mp->local to p->two->sha1.
261 */
Jeff King4a7e27e2018-08-28 17:22:40 -0400262 assert(oideq(&p->one->oid, &mp->base));
263 assert(oideq(&mp->local, &uninitialized));
brian m. carlsone910bb12016-09-05 20:08:01 +0000264 oidcpy(&mp->local, &p->two->oid);
Johan Herland2085b162010-11-15 00:54:11 +0100265 }
266 trace_printf("\t\tStored local change for %s: %.7s -> %.7s\n",
brian m. carlsone910bb12016-09-05 20:08:01 +0000267 oid_to_hex(&mp->obj), oid_to_hex(&mp->base),
268 oid_to_hex(&mp->local));
Johan Herland2085b162010-11-15 00:54:11 +0100269 }
270 diff_flush(&opt);
Johan Herland2085b162010-11-15 00:54:11 +0100271}
272
Johan Herland809f38c2010-11-09 22:49:51 +0100273static void check_notes_merge_worktree(struct notes_merge_options *o)
274{
275 if (!o->has_worktree) {
276 /*
277 * Must establish NOTES_MERGE_WORKTREE.
278 * Abort if NOTES_MERGE_WORKTREE already exists
279 */
Johan Herlanddabba592012-03-15 15:58:56 +0100280 if (file_exists(git_path(NOTES_MERGE_WORKTREE)) &&
281 !is_empty_dir(git_path(NOTES_MERGE_WORKTREE))) {
Ben Boeckeled9bff02021-08-23 12:44:00 +0200282 if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
Vasco Almeidac041c6d2016-09-19 13:08:20 +0000283 die(_("You have not concluded your previous "
Johan Herland809f38c2010-11-09 22:49:51 +0100284 "notes merge (%s exists).\nPlease, use "
285 "'git notes merge --commit' or 'git notes "
Johan Herland6abb3652010-11-09 22:49:52 +0100286 "merge --abort' to commit/abort the "
Johan Herland809f38c2010-11-09 22:49:51 +0100287 "previous merge before you start a new "
Vasco Almeidac041c6d2016-09-19 13:08:20 +0000288 "notes merge."), git_path("NOTES_MERGE_*"));
Johan Herland809f38c2010-11-09 22:49:51 +0100289 else
Vasco Almeidac041c6d2016-09-19 13:08:20 +0000290 die(_("You have not concluded your notes merge "
291 "(%s exists)."), git_path("NOTES_MERGE_*"));
Johan Herland809f38c2010-11-09 22:49:51 +0100292 }
293
Nguyễn Thái Ngọc Duydcf69262014-11-30 15:24:27 +0700294 if (safe_create_leading_directories_const(git_path(
Johan Herland809f38c2010-11-09 22:49:51 +0100295 NOTES_MERGE_WORKTREE "/.test")))
296 die_errno("unable to create directory %s",
297 git_path(NOTES_MERGE_WORKTREE));
298 o->has_worktree = 1;
299 } else if (!file_exists(git_path(NOTES_MERGE_WORKTREE)))
300 /* NOTES_MERGE_WORKTREE should already be established */
301 die("missing '%s'. This should not happen",
302 git_path(NOTES_MERGE_WORKTREE));
303}
304
Brandon Williams9e5e0c22017-05-30 10:31:02 -0700305static void write_buf_to_worktree(const struct object_id *obj,
Johan Herland809f38c2010-11-09 22:49:51 +0100306 const char *buf, unsigned long size)
307{
308 int fd;
Brandon Williams9e5e0c22017-05-30 10:31:02 -0700309 char *path = git_pathdup(NOTES_MERGE_WORKTREE "/%s", oid_to_hex(obj));
Nguyễn Thái Ngọc Duydcf69262014-11-30 15:24:27 +0700310 if (safe_create_leading_directories_const(path))
Johan Herland809f38c2010-11-09 22:49:51 +0100311 die_errno("unable to create directory for '%s'", path);
Johan Herland809f38c2010-11-09 22:49:51 +0100312
René Scharfedeb9c152016-07-07 22:08:30 +0200313 fd = xopen(path, O_WRONLY | O_EXCL | O_CREAT, 0666);
Johan Herland809f38c2010-11-09 22:49:51 +0100314
315 while (size > 0) {
Jeff King634eb822017-09-13 13:17:44 -0400316 ssize_t ret = write_in_full(fd, buf, size);
Johan Herland809f38c2010-11-09 22:49:51 +0100317 if (ret < 0) {
318 /* Ignore epipe */
319 if (errno == EPIPE)
320 break;
321 die_errno("notes-merge");
Johan Herland809f38c2010-11-09 22:49:51 +0100322 }
323 size -= ret;
324 buf += ret;
325 }
326
327 close(fd);
Jeff Kingfcd12db2015-08-10 05:35:31 -0400328 free(path);
Johan Herland809f38c2010-11-09 22:49:51 +0100329}
330
Brandon Williams9e5e0c22017-05-30 10:31:02 -0700331static void write_note_to_worktree(const struct object_id *obj,
332 const struct object_id *note)
Johan Herland809f38c2010-11-09 22:49:51 +0100333{
334 enum object_type type;
335 unsigned long size;
Ævar Arnfjörð Bjarmasonbc726bd2023-03-28 15:58:50 +0200336 void *buf = repo_read_object_file(the_repository, note, &type, &size);
Johan Herland809f38c2010-11-09 22:49:51 +0100337
338 if (!buf)
339 die("cannot read note %s for object %s",
Brandon Williams9e5e0c22017-05-30 10:31:02 -0700340 oid_to_hex(note), oid_to_hex(obj));
Johan Herland809f38c2010-11-09 22:49:51 +0100341 if (type != OBJ_BLOB)
342 die("blob expected in note %s for object %s",
Brandon Williams9e5e0c22017-05-30 10:31:02 -0700343 oid_to_hex(note), oid_to_hex(obj));
Johan Herland809f38c2010-11-09 22:49:51 +0100344 write_buf_to_worktree(obj, buf, size);
345 free(buf);
346}
347
348static int ll_merge_in_worktree(struct notes_merge_options *o,
349 struct notes_merge_pair *p)
350{
351 mmbuffer_t result_buf;
352 mmfile_t base, local, remote;
Elijah Newren35f69672022-02-02 02:37:30 +0000353 enum ll_merge_result status;
Johan Herland809f38c2010-11-09 22:49:51 +0100354
brian m. carlsond4493472016-09-05 20:08:02 +0000355 read_mmblob(&base, &p->base);
356 read_mmblob(&local, &p->local);
357 read_mmblob(&remote, &p->remote);
Johan Herland809f38c2010-11-09 22:49:51 +0100358
brian m. carlsone910bb12016-09-05 20:08:01 +0000359 status = ll_merge(&result_buf, oid_to_hex(&p->obj), &base, NULL,
Nguyễn Thái Ngọc Duy32eaa462018-09-21 17:57:27 +0200360 &local, o->local_ref, &remote, o->remote_ref,
Nguyễn Thái Ngọc Duy56842002018-11-10 06:48:53 +0100361 o->repo->index, NULL);
Johan Herland809f38c2010-11-09 22:49:51 +0100362
363 free(base.ptr);
364 free(local.ptr);
365 free(remote.ptr);
366
Elijah Newren35f69672022-02-02 02:37:30 +0000367 if (status == LL_MERGE_BINARY_CONFLICT)
368 warning("Cannot merge binary files: %s (%s vs. %s)",
369 oid_to_hex(&p->obj), o->local_ref, o->remote_ref);
Johan Herland809f38c2010-11-09 22:49:51 +0100370 if ((status < 0) || !result_buf.ptr)
371 die("Failed to execute internal merge");
372
Brandon Williams9e5e0c22017-05-30 10:31:02 -0700373 write_buf_to_worktree(&p->obj, result_buf.ptr, result_buf.size);
Johan Herland809f38c2010-11-09 22:49:51 +0100374 free(result_buf.ptr);
375
376 return status;
377}
378
379static int merge_one_change_manual(struct notes_merge_options *o,
380 struct notes_merge_pair *p,
381 struct notes_tree *t)
382{
383 const char *lref = o->local_ref ? o->local_ref : "local version";
384 const char *rref = o->remote_ref ? o->remote_ref : "remote version";
385
386 trace_printf("\t\t\tmerge_one_change_manual(obj = %.7s, base = %.7s, "
387 "local = %.7s, remote = %.7s)\n",
brian m. carlsone910bb12016-09-05 20:08:01 +0000388 oid_to_hex(&p->obj), oid_to_hex(&p->base),
389 oid_to_hex(&p->local), oid_to_hex(&p->remote));
Johan Herland809f38c2010-11-09 22:49:51 +0100390
Johan Herland443259c2010-11-09 22:49:53 +0100391 /* add "Conflicts:" section to commit message first time through */
392 if (!o->has_worktree)
393 strbuf_addstr(&(o->commit_msg), "\n\nConflicts:\n");
394
brian m. carlsone910bb12016-09-05 20:08:01 +0000395 strbuf_addf(&(o->commit_msg), "\t%s\n", oid_to_hex(&p->obj));
Johan Herland443259c2010-11-09 22:49:53 +0100396
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600397 if (o->verbosity >= 2)
brian m. carlsone910bb12016-09-05 20:08:01 +0000398 printf("Auto-merging notes for %s\n", oid_to_hex(&p->obj));
Johan Herland809f38c2010-11-09 22:49:51 +0100399 check_notes_merge_worktree(o);
brian m. carlsone910bb12016-09-05 20:08:01 +0000400 if (is_null_oid(&p->local)) {
Johan Herland809f38c2010-11-09 22:49:51 +0100401 /* D/F conflict, checkout p->remote */
brian m. carlsone910bb12016-09-05 20:08:01 +0000402 assert(!is_null_oid(&p->remote));
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600403 if (o->verbosity >= 1)
404 printf("CONFLICT (delete/modify): Notes for object %s "
405 "deleted in %s and modified in %s. Version from %s "
406 "left in tree.\n",
brian m. carlsone910bb12016-09-05 20:08:01 +0000407 oid_to_hex(&p->obj), lref, rref, rref);
Brandon Williams9e5e0c22017-05-30 10:31:02 -0700408 write_note_to_worktree(&p->obj, &p->remote);
brian m. carlsone910bb12016-09-05 20:08:01 +0000409 } else if (is_null_oid(&p->remote)) {
Johan Herland809f38c2010-11-09 22:49:51 +0100410 /* D/F conflict, checkout p->local */
brian m. carlsone910bb12016-09-05 20:08:01 +0000411 assert(!is_null_oid(&p->local));
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600412 if (o->verbosity >= 1)
413 printf("CONFLICT (delete/modify): Notes for object %s "
414 "deleted in %s and modified in %s. Version from %s "
415 "left in tree.\n",
brian m. carlsone910bb12016-09-05 20:08:01 +0000416 oid_to_hex(&p->obj), rref, lref, lref);
Brandon Williams9e5e0c22017-05-30 10:31:02 -0700417 write_note_to_worktree(&p->obj, &p->local);
Johan Herland809f38c2010-11-09 22:49:51 +0100418 } else {
419 /* "regular" conflict, checkout result of ll_merge() */
420 const char *reason = "content";
brian m. carlsone910bb12016-09-05 20:08:01 +0000421 if (is_null_oid(&p->base))
Johan Herland809f38c2010-11-09 22:49:51 +0100422 reason = "add/add";
brian m. carlsone910bb12016-09-05 20:08:01 +0000423 assert(!is_null_oid(&p->local));
424 assert(!is_null_oid(&p->remote));
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600425 if (o->verbosity >= 1)
426 printf("CONFLICT (%s): Merge conflict in notes for "
brian m. carlsone910bb12016-09-05 20:08:01 +0000427 "object %s\n", reason,
428 oid_to_hex(&p->obj));
Johan Herland809f38c2010-11-09 22:49:51 +0100429 ll_merge_in_worktree(o, p);
430 }
431
432 trace_printf("\t\t\tremoving from partial merge result\n");
brian m. carlsone910bb12016-09-05 20:08:01 +0000433 remove_note(t, p->obj.hash);
Johan Herland809f38c2010-11-09 22:49:51 +0100434
435 return 1;
436}
437
Johan Herland3228e672010-11-15 00:55:12 +0100438static int merge_one_change(struct notes_merge_options *o,
439 struct notes_merge_pair *p, struct notes_tree *t)
440{
441 /*
Johan Herland809f38c2010-11-09 22:49:51 +0100442 * Return 0 if change is successfully resolved (stored in notes_tree).
443 * Return 1 is change results in a conflict (NOT stored in notes_tree,
444 * but instead written to NOTES_MERGE_WORKTREE with conflict markers).
Johan Herland3228e672010-11-15 00:55:12 +0100445 */
446 switch (o->strategy) {
447 case NOTES_MERGE_RESOLVE_MANUAL:
Johan Herland809f38c2010-11-09 22:49:51 +0100448 return merge_one_change_manual(o, p, t);
Johan Herland3228e672010-11-15 00:55:12 +0100449 case NOTES_MERGE_RESOLVE_OURS:
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600450 if (o->verbosity >= 2)
451 printf("Using local notes for %s\n",
brian m. carlsone910bb12016-09-05 20:08:01 +0000452 oid_to_hex(&p->obj));
Johan Herland3228e672010-11-15 00:55:12 +0100453 /* nothing to do */
454 return 0;
455 case NOTES_MERGE_RESOLVE_THEIRS:
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600456 if (o->verbosity >= 2)
457 printf("Using remote notes for %s\n",
brian m. carlsone910bb12016-09-05 20:08:01 +0000458 oid_to_hex(&p->obj));
brian m. carlson5ee8a952017-05-30 10:30:43 -0700459 if (add_note(t, &p->obj, &p->remote, combine_notes_overwrite))
Johannes Schindelin033abf92018-05-02 11:38:39 +0200460 BUG("combine_notes_overwrite failed");
Johan Herland3228e672010-11-15 00:55:12 +0100461 return 0;
462 case NOTES_MERGE_RESOLVE_UNION:
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600463 if (o->verbosity >= 2)
464 printf("Concatenating local and remote notes for %s\n",
brian m. carlsone910bb12016-09-05 20:08:01 +0000465 oid_to_hex(&p->obj));
brian m. carlson5ee8a952017-05-30 10:30:43 -0700466 if (add_note(t, &p->obj, &p->remote, combine_notes_concatenate))
Johan Herland3228e672010-11-15 00:55:12 +0100467 die("failed to concatenate notes "
468 "(combine_notes_concatenate)");
469 return 0;
Johan Herlanda6a09092010-11-15 00:57:17 +0100470 case NOTES_MERGE_RESOLVE_CAT_SORT_UNIQ:
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600471 if (o->verbosity >= 2)
472 printf("Concatenating unique lines in local and remote "
brian m. carlsone910bb12016-09-05 20:08:01 +0000473 "notes for %s\n", oid_to_hex(&p->obj));
brian m. carlson5ee8a952017-05-30 10:30:43 -0700474 if (add_note(t, &p->obj, &p->remote, combine_notes_cat_sort_uniq))
Johan Herlanda6a09092010-11-15 00:57:17 +0100475 die("failed to concatenate notes "
476 "(combine_notes_cat_sort_uniq)");
477 return 0;
Johan Herland3228e672010-11-15 00:55:12 +0100478 }
479 die("Unknown strategy (%i).", o->strategy);
480}
481
Johan Herland2085b162010-11-15 00:54:11 +0100482static int merge_changes(struct notes_merge_options *o,
483 struct notes_merge_pair *changes, int *num_changes,
484 struct notes_tree *t)
485{
486 int i, conflicts = 0;
487
488 trace_printf("\tmerge_changes(num_changes = %i)\n", *num_changes);
489 for (i = 0; i < *num_changes; i++) {
490 struct notes_merge_pair *p = changes + i;
491 trace_printf("\t\t%.7s: %.7s -> %.7s/%.7s\n",
brian m. carlsone910bb12016-09-05 20:08:01 +0000492 oid_to_hex(&p->obj), oid_to_hex(&p->base),
493 oid_to_hex(&p->local),
494 oid_to_hex(&p->remote));
Johan Herland2085b162010-11-15 00:54:11 +0100495
Jeff King4a7e27e2018-08-28 17:22:40 -0400496 if (oideq(&p->base, &p->remote)) {
Johan Herland2085b162010-11-15 00:54:11 +0100497 /* no remote change; nothing to do */
498 trace_printf("\t\t\tskipping (no remote change)\n");
Jeff King4a7e27e2018-08-28 17:22:40 -0400499 } else if (oideq(&p->local, &p->remote)) {
Johan Herland2085b162010-11-15 00:54:11 +0100500 /* same change in local and remote; nothing to do */
501 trace_printf("\t\t\tskipping (local == remote)\n");
Jeff King4a7e27e2018-08-28 17:22:40 -0400502 } else if (oideq(&p->local, &uninitialized) ||
503 oideq(&p->local, &p->base)) {
Johan Herland2085b162010-11-15 00:54:11 +0100504 /* no local change; adopt remote change */
505 trace_printf("\t\t\tno local change, adopted remote\n");
brian m. carlson5ee8a952017-05-30 10:30:43 -0700506 if (add_note(t, &p->obj, &p->remote,
Johan Herland2085b162010-11-15 00:54:11 +0100507 combine_notes_overwrite))
Johannes Schindelin033abf92018-05-02 11:38:39 +0200508 BUG("combine_notes_overwrite failed");
Johan Herland2085b162010-11-15 00:54:11 +0100509 } else {
510 /* need file-level merge between local and remote */
511 trace_printf("\t\t\tneed content-level merge\n");
Johan Herland3228e672010-11-15 00:55:12 +0100512 conflicts += merge_one_change(o, p, t);
Johan Herland2085b162010-11-15 00:54:11 +0100513 }
514 }
515
516 return conflicts;
517}
518
519static int merge_from_diffs(struct notes_merge_options *o,
Brandon Williams9d6babb2017-05-30 10:30:59 -0700520 const struct object_id *base,
521 const struct object_id *local,
522 const struct object_id *remote,
523 struct notes_tree *t)
Johan Herland2085b162010-11-15 00:54:11 +0100524{
525 struct notes_merge_pair *changes;
526 int num_changes, conflicts;
527
528 trace_printf("\tmerge_from_diffs(base = %.7s, local = %.7s, "
Brandon Williams9d6babb2017-05-30 10:30:59 -0700529 "remote = %.7s)\n", oid_to_hex(base), oid_to_hex(local),
530 oid_to_hex(remote));
Johan Herland2085b162010-11-15 00:54:11 +0100531
532 changes = diff_tree_remote(o, base, remote, &num_changes);
533 diff_tree_local(o, changes, num_changes, base, local);
534
535 conflicts = merge_changes(o, changes, &num_changes, t);
536 free(changes);
537
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600538 if (o->verbosity >= 4)
Nguyễn Thái Ngọc Duy2ca0c532012-06-07 19:05:13 +0700539 printf(t->dirty ?
540 "Merge result: %i unmerged notes and a dirty notes tree\n" :
541 "Merge result: %i unmerged notes and a clean notes tree\n",
542 conflicts);
Johan Herland2085b162010-11-15 00:54:11 +0100543
544 return conflicts ? -1 : 1;
545}
546
Johan Herland75ef3f42010-11-09 22:49:46 +0100547int notes_merge(struct notes_merge_options *o,
Johan Herland2085b162010-11-15 00:54:11 +0100548 struct notes_tree *local_tree,
Brandon Williams5237e0e2017-05-30 10:30:58 -0700549 struct object_id *result_oid)
Johan Herland75ef3f42010-11-09 22:49:46 +0100550{
brian m. carlson1e43ed92017-05-06 22:10:09 +0000551 struct object_id local_oid, remote_oid;
Johan Herland75ef3f42010-11-09 22:49:46 +0100552 struct commit *local, *remote;
553 struct commit_list *bases = NULL;
Brandon Williams5237e0e2017-05-30 10:30:58 -0700554 const struct object_id *base_oid, *base_tree_oid;
Johan Herland75ef3f42010-11-09 22:49:46 +0100555 int result = 0;
556
557 assert(o->local_ref && o->remote_ref);
Johan Herland2085b162010-11-15 00:54:11 +0100558 assert(!strcmp(o->local_ref, local_tree->ref));
Brandon Williams5237e0e2017-05-30 10:30:58 -0700559 oidclr(result_oid);
Johan Herland75ef3f42010-11-09 22:49:46 +0100560
561 trace_printf("notes_merge(o->local_ref = %s, o->remote_ref = %s)\n",
562 o->local_ref, o->remote_ref);
563
564 /* Dereference o->local_ref into local_sha1 */
brian m. carlson34c290a2017-10-15 22:06:56 +0000565 if (read_ref_full(o->local_ref, 0, &local_oid, NULL))
Johan Herland75ef3f42010-11-09 22:49:46 +0100566 die("Failed to resolve local notes ref '%s'", o->local_ref);
Michael Haggerty8d9c5012011-09-15 23:10:25 +0200567 else if (!check_refname_format(o->local_ref, 0) &&
brian m. carlson1e43ed92017-05-06 22:10:09 +0000568 is_null_oid(&local_oid))
Brandon Williams5237e0e2017-05-30 10:30:58 -0700569 local = NULL; /* local_oid == null_oid indicates unborn ref */
Nguyễn Thái Ngọc Duy878d8322018-11-10 06:48:54 +0100570 else if (!(local = lookup_commit_reference(o->repo, &local_oid)))
Johan Herland75ef3f42010-11-09 22:49:46 +0100571 die("Could not parse local commit %s (%s)",
brian m. carlson1e43ed92017-05-06 22:10:09 +0000572 oid_to_hex(&local_oid), o->local_ref);
573 trace_printf("\tlocal commit: %.7s\n", oid_to_hex(&local_oid));
Johan Herland75ef3f42010-11-09 22:49:46 +0100574
Brandon Williams5237e0e2017-05-30 10:30:58 -0700575 /* Dereference o->remote_ref into remote_oid */
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +0200576 if (repo_get_oid(the_repository, o->remote_ref, &remote_oid)) {
Johan Herland75ef3f42010-11-09 22:49:46 +0100577 /*
Brandon Williams5237e0e2017-05-30 10:30:58 -0700578 * Failed to get remote_oid. If o->remote_ref looks like an
Johan Herland75ef3f42010-11-09 22:49:46 +0100579 * unborn ref, perform the merge using an empty notes tree.
580 */
Michael Haggerty8d9c5012011-09-15 23:10:25 +0200581 if (!check_refname_format(o->remote_ref, 0)) {
brian m. carlson1e43ed92017-05-06 22:10:09 +0000582 oidclr(&remote_oid);
Johan Herland75ef3f42010-11-09 22:49:46 +0100583 remote = NULL;
584 } else {
585 die("Failed to resolve remote notes ref '%s'",
586 o->remote_ref);
587 }
Nguyễn Thái Ngọc Duy878d8322018-11-10 06:48:54 +0100588 } else if (!(remote = lookup_commit_reference(o->repo, &remote_oid))) {
Johan Herland75ef3f42010-11-09 22:49:46 +0100589 die("Could not parse remote commit %s (%s)",
brian m. carlson1e43ed92017-05-06 22:10:09 +0000590 oid_to_hex(&remote_oid), o->remote_ref);
Johan Herland75ef3f42010-11-09 22:49:46 +0100591 }
brian m. carlson1e43ed92017-05-06 22:10:09 +0000592 trace_printf("\tremote commit: %.7s\n", oid_to_hex(&remote_oid));
Johan Herland75ef3f42010-11-09 22:49:46 +0100593
594 if (!local && !remote)
595 die("Cannot merge empty notes ref (%s) into empty notes ref "
596 "(%s)", o->remote_ref, o->local_ref);
597 if (!local) {
598 /* result == remote commit */
Brandon Williams5237e0e2017-05-30 10:30:58 -0700599 oidcpy(result_oid, &remote_oid);
Johan Herland75ef3f42010-11-09 22:49:46 +0100600 goto found_result;
601 }
602 if (!remote) {
603 /* result == local commit */
Brandon Williams5237e0e2017-05-30 10:30:58 -0700604 oidcpy(result_oid, &local_oid);
Johan Herland75ef3f42010-11-09 22:49:46 +0100605 goto found_result;
606 }
607 assert(local && remote);
608
609 /* Find merge bases */
Ævar Arnfjörð Bjarmasoncb338c22023-03-28 15:58:47 +0200610 bases = repo_get_merge_bases(the_repository, local, remote);
Johan Herland75ef3f42010-11-09 22:49:46 +0100611 if (!bases) {
brian m. carlson14228442021-04-26 01:02:56 +0000612 base_oid = null_oid();
brian m. carlsoneb0ccfd2017-11-12 21:28:54 +0000613 base_tree_oid = the_hash_algo->empty_tree;
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600614 if (o->verbosity >= 4)
615 printf("No merge base found; doing history-less merge\n");
Johan Herland75ef3f42010-11-09 22:49:46 +0100616 } else if (!bases->next) {
Brandon Williams5237e0e2017-05-30 10:30:58 -0700617 base_oid = &bases->item->object.oid;
Derrick Stolee2e27bd72018-04-06 19:09:38 +0000618 base_tree_oid = get_commit_tree_oid(bases->item);
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600619 if (o->verbosity >= 4)
620 printf("One merge base found (%.7s)\n",
Brandon Williams5237e0e2017-05-30 10:30:58 -0700621 oid_to_hex(base_oid));
Johan Herland75ef3f42010-11-09 22:49:46 +0100622 } else {
623 /* TODO: How to handle multiple merge-bases? */
Brandon Williams5237e0e2017-05-30 10:30:58 -0700624 base_oid = &bases->item->object.oid;
Derrick Stolee2e27bd72018-04-06 19:09:38 +0000625 base_tree_oid = get_commit_tree_oid(bases->item);
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600626 if (o->verbosity >= 3)
627 printf("Multiple merge bases found. Using the first "
Brandon Williams5237e0e2017-05-30 10:30:58 -0700628 "(%.7s)\n", oid_to_hex(base_oid));
Johan Herland75ef3f42010-11-09 22:49:46 +0100629 }
630
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600631 if (o->verbosity >= 4)
632 printf("Merging remote commit %.7s into local commit %.7s with "
brian m. carlsonf2fd0762015-11-10 02:22:28 +0000633 "merge-base %.7s\n", oid_to_hex(&remote->object.oid),
634 oid_to_hex(&local->object.oid),
Brandon Williams5237e0e2017-05-30 10:30:58 -0700635 oid_to_hex(base_oid));
Johan Herland75ef3f42010-11-09 22:49:46 +0100636
Jeff King4a7e27e2018-08-28 17:22:40 -0400637 if (oideq(&remote->object.oid, base_oid)) {
Johan Herland75ef3f42010-11-09 22:49:46 +0100638 /* Already merged; result == local commit */
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600639 if (o->verbosity >= 2)
Eric Sunshine80cde952021-05-02 01:14:22 -0400640 printf_ln("Already up to date.");
Brandon Williams5237e0e2017-05-30 10:30:58 -0700641 oidcpy(result_oid, &local->object.oid);
Johan Herland75ef3f42010-11-09 22:49:46 +0100642 goto found_result;
643 }
Jeff King4a7e27e2018-08-28 17:22:40 -0400644 if (oideq(&local->object.oid, base_oid)) {
Johan Herland75ef3f42010-11-09 22:49:46 +0100645 /* Fast-forward; result == remote commit */
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600646 if (o->verbosity >= 2)
647 printf("Fast-forward\n");
Brandon Williams5237e0e2017-05-30 10:30:58 -0700648 oidcpy(result_oid, &remote->object.oid);
Johan Herland75ef3f42010-11-09 22:49:46 +0100649 goto found_result;
650 }
651
Derrick Stolee2e27bd72018-04-06 19:09:38 +0000652 result = merge_from_diffs(o, base_tree_oid,
653 get_commit_tree_oid(local),
654 get_commit_tree_oid(remote), local_tree);
Johan Herland2085b162010-11-15 00:54:11 +0100655
Johan Herland809f38c2010-11-09 22:49:51 +0100656 if (result != 0) { /* non-trivial merge (with or without conflicts) */
657 /* Commit (partial) result */
Johan Herland2085b162010-11-15 00:54:11 +0100658 struct commit_list *parents = NULL;
659 commit_list_insert(remote, &parents); /* LIFO order */
660 commit_list_insert(local, &parents);
Nguyễn Thái Ngọc Duy1d18d752019-01-12 09:13:23 +0700661 create_notes_commit(o->repo, local_tree, parents, o->commit_msg.buf,
Patryk Obara5078f342018-01-28 01:13:16 +0100662 o->commit_msg.len, result_oid);
Johan Herland2085b162010-11-15 00:54:11 +0100663 }
Johan Herland75ef3f42010-11-09 22:49:46 +0100664
665found_result:
666 free_commit_list(bases);
Johan Herland443259c2010-11-09 22:49:53 +0100667 strbuf_release(&(o->commit_msg));
Brandon Williams5237e0e2017-05-30 10:30:58 -0700668 trace_printf("notes_merge(): result = %i, result_oid = %.7s\n",
669 result, oid_to_hex(result_oid));
Johan Herland75ef3f42010-11-09 22:49:46 +0100670 return result;
671}
Johan Herland6abb3652010-11-09 22:49:52 +0100672
673int notes_merge_commit(struct notes_merge_options *o,
674 struct notes_tree *partial_tree,
675 struct commit *partial_commit,
Brandon Williams5237e0e2017-05-30 10:30:58 -0700676 struct object_id *result_oid)
Johan Herland6abb3652010-11-09 22:49:52 +0100677{
678 /*
679 * Iterate through files in .git/NOTES_MERGE_WORKTREE and add all
Johan Herlanda0be62c2012-03-12 15:57:13 +0100680 * found notes to 'partial_tree'. Write the updated notes tree to
Johan Herland6abb3652010-11-09 22:49:52 +0100681 * the DB, and commit the resulting tree object while reusing the
682 * commit message and parents from 'partial_commit'.
Brandon Williams5237e0e2017-05-30 10:30:58 -0700683 * Finally store the new commit object OID into 'result_oid'.
Johan Herland6abb3652010-11-09 22:49:52 +0100684 */
Johan Herlanda0be62c2012-03-12 15:57:13 +0100685 DIR *dir;
686 struct dirent *e;
687 struct strbuf path = STRBUF_INIT;
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +0200688 const char *buffer = repo_get_commit_buffer(the_repository,
689 partial_commit, NULL);
Jeff Kingbc6b8fc2014-06-10 17:41:51 -0400690 const char *msg = strstr(buffer, "\n\n");
Johan Herlanda0be62c2012-03-12 15:57:13 +0100691 int baselen;
Johan Herland6abb3652010-11-09 22:49:52 +0100692
Jeff King8c2ca3a2017-04-20 17:09:30 -0400693 git_path_buf(&path, NOTES_MERGE_WORKTREE);
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600694 if (o->verbosity >= 3)
Johan Herlanda0be62c2012-03-12 15:57:13 +0100695 printf("Committing notes in notes merge worktree at %s\n",
696 path.buf);
Johan Herland6abb3652010-11-09 22:49:52 +0100697
698 if (!msg || msg[2] == '\0')
699 die("partial notes commit has empty message");
700 msg += 2;
701
Johan Herlanda0be62c2012-03-12 15:57:13 +0100702 dir = opendir(path.buf);
703 if (!dir)
704 die_errno("could not open %s", path.buf);
705
706 strbuf_addch(&path, '/');
707 baselen = path.len;
Elijah Newrenb548f0f2021-05-12 17:28:22 +0000708 while ((e = readdir_skip_dot_and_dotdot(dir)) != NULL) {
Johan Herland6abb3652010-11-09 22:49:52 +0100709 struct stat st;
brian m. carlson5ee8a952017-05-30 10:30:43 -0700710 struct object_id obj_oid, blob_oid;
Johan Herland6abb3652010-11-09 22:49:52 +0100711
brian m. carlson5ee8a952017-05-30 10:30:43 -0700712 if (get_oid_hex(e->d_name, &obj_oid)) {
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600713 if (o->verbosity >= 3)
Johan Herlanda0be62c2012-03-12 15:57:13 +0100714 printf("Skipping non-SHA1 entry '%s%s'\n",
715 path.buf, e->d_name);
Johan Herland6abb3652010-11-09 22:49:52 +0100716 continue;
717 }
718
Johan Herlanda0be62c2012-03-12 15:57:13 +0100719 strbuf_addstr(&path, e->d_name);
Johan Herland6abb3652010-11-09 22:49:52 +0100720 /* write file as blob, and add to partial_tree */
Johan Herlanda0be62c2012-03-12 15:57:13 +0100721 if (stat(path.buf, &st))
722 die_errno("Failed to stat '%s'", path.buf);
Nguyễn Thái Ngọc Duy56842002018-11-10 06:48:53 +0100723 if (index_path(o->repo->index, &blob_oid, path.buf, &st, HASH_WRITE_OBJECT))
Johan Herlanda0be62c2012-03-12 15:57:13 +0100724 die("Failed to write blob object from '%s'", path.buf);
brian m. carlson5ee8a952017-05-30 10:30:43 -0700725 if (add_note(partial_tree, &obj_oid, &blob_oid, NULL))
Johan Herland6abb3652010-11-09 22:49:52 +0100726 die("Failed to add resolved note '%s' to notes tree",
Johan Herlanda0be62c2012-03-12 15:57:13 +0100727 path.buf);
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600728 if (o->verbosity >= 4)
729 printf("Added resolved note for object %s: %s\n",
brian m. carlson5ee8a952017-05-30 10:30:43 -0700730 oid_to_hex(&obj_oid), oid_to_hex(&blob_oid));
Johan Herlanda0be62c2012-03-12 15:57:13 +0100731 strbuf_setlen(&path, baselen);
Johan Herland6abb3652010-11-09 22:49:52 +0100732 }
733
Nguyễn Thái Ngọc Duy1d18d752019-01-12 09:13:23 +0700734 create_notes_commit(o->repo, partial_tree, partial_commit->parents, msg,
Patryk Obara5078f342018-01-28 01:13:16 +0100735 strlen(msg), result_oid);
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +0200736 repo_unuse_commit_buffer(the_repository, partial_commit, buffer);
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600737 if (o->verbosity >= 4)
738 printf("Finalized notes merge commit: %s\n",
Brandon Williams5237e0e2017-05-30 10:30:58 -0700739 oid_to_hex(result_oid));
Johan Herlanda0be62c2012-03-12 15:57:13 +0100740 strbuf_release(&path);
741 closedir(dir);
Johan Herland6abb3652010-11-09 22:49:52 +0100742 return 0;
743}
744
745int notes_merge_abort(struct notes_merge_options *o)
746{
Johan Herlanddabba592012-03-15 15:58:56 +0100747 /*
748 * Remove all files within .git/NOTES_MERGE_WORKTREE. We do not remove
749 * the .git/NOTES_MERGE_WORKTREE directory itself, since it might be
750 * the current working directory of the user.
751 */
Johan Herland6abb3652010-11-09 22:49:52 +0100752 struct strbuf buf = STRBUF_INIT;
753 int ret;
754
Jeff King8c2ca3a2017-04-20 17:09:30 -0400755 git_path_buf(&buf, NOTES_MERGE_WORKTREE);
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600756 if (o->verbosity >= 3)
Johan Herlanddabba592012-03-15 15:58:56 +0100757 printf("Removing notes merge worktree at %s/*\n", buf.buf);
758 ret = remove_dir_recursively(&buf, REMOVE_DIR_KEEP_TOPLEVEL);
Johan Herland6abb3652010-11-09 22:49:52 +0100759 strbuf_release(&buf);
760 return ret;
761}