blob: dadbbabf86da6a3acf82c1a292700b483b5dfb5d [file] [log] [blame]
Patrick Steinhardte7da9382024-06-14 08:50:23 +02001#define USE_THE_REPOSITORY_VARIABLE
2
Elijah Newrenb6fdc442023-04-11 00:41:54 -07003#include "git-compat-util.h"
Elijah Newren6c6ddf92023-04-11 03:00:39 +00004#include "advice.h"
Johan Herland75ef3f42010-11-09 22:49:46 +01005#include "commit.h"
Elijah Newrenf394e092023-03-21 06:25:54 +00006#include "gettext.h"
Johan Herland75ef3f42010-11-09 22:49:46 +01007#include "refs.h"
Elijah Newren87bed172023-04-11 00:41:53 -07008#include "object-file.h"
Elijah Newrendabab1d2023-04-11 00:41:49 -07009#include "object-name.h"
Elijah Newrena034e912023-05-16 06:34:06 +000010#include "object-store-ll.h"
Elijah Newrenc3399322023-05-16 06:33:59 +000011#include "path.h"
Stefan Beller2122f672018-06-28 18:21:58 -070012#include "repository.h"
Johan Herland2085b162010-11-15 00:54:11 +010013#include "diff.h"
14#include "diffcore.h"
Elijah Newren41771fa2023-02-24 00:09:27 +000015#include "hex.h"
Johan Herland809f38c2010-11-09 22:49:51 +010016#include "xdiff-interface.h"
Elijah Newren67238992023-05-16 06:34:04 +000017#include "merge-ll.h"
Johan Herland809f38c2010-11-09 22:49:51 +010018#include "dir.h"
Johan Herland56881842010-11-09 22:49:47 +010019#include "notes.h"
Johan Herland75ef3f42010-11-09 22:49:46 +010020#include "notes-merge.h"
Johan Herland443259c2010-11-09 22:49:53 +010021#include "strbuf.h"
Elijah Newren74ea5c92023-04-11 03:00:38 +000022#include "trace.h"
Johan Herlandbf9a05b2013-06-12 02:13:01 +020023#include "notes-utils.h"
Derrick Stolee64043552018-07-20 16:33:04 +000024#include "commit-reach.h"
Johan Herland75ef3f42010-11-09 22:49:46 +010025
Johan Herland2085b162010-11-15 00:54:11 +010026struct notes_merge_pair {
brian m. carlsone910bb12016-09-05 20:08:01 +000027 struct object_id obj, base, local, remote;
Johan Herland2085b162010-11-15 00:54:11 +010028};
29
Nguyễn Thái Ngọc Duy56842002018-11-10 06:48:53 +010030void init_notes_merge_options(struct repository *r,
31 struct notes_merge_options *o)
Johan Herland75ef3f42010-11-09 22:49:46 +010032{
33 memset(o, 0, sizeof(struct notes_merge_options));
Johan Herland443259c2010-11-09 22:49:53 +010034 strbuf_init(&(o->commit_msg), 0);
Johan Herland75ef3f42010-11-09 22:49:46 +010035 o->verbosity = NOTES_MERGE_VERBOSITY_DEFAULT;
Nguyễn Thái Ngọc Duy56842002018-11-10 06:48:53 +010036 o->repo = r;
Johan Herland75ef3f42010-11-09 22:49:46 +010037}
38
Brandon Williams4d778962017-05-30 10:31:01 -070039static int path_to_oid(const char *path, struct object_id *oid)
Johan Herland2085b162010-11-15 00:54:11 +010040{
brian m. carlson22350302019-02-19 00:05:00 +000041 char hex_oid[GIT_MAX_HEXSZ];
Johan Herland2085b162010-11-15 00:54:11 +010042 int i = 0;
brian m. carlson22350302019-02-19 00:05:00 +000043 while (*path && i < the_hash_algo->hexsz) {
Johan Herland2085b162010-11-15 00:54:11 +010044 if (*path != '/')
Brandon Williams4d778962017-05-30 10:31:01 -070045 hex_oid[i++] = *path;
Johan Herland2085b162010-11-15 00:54:11 +010046 path++;
47 }
brian m. carlson22350302019-02-19 00:05:00 +000048 if (*path || i != the_hash_algo->hexsz)
Johan Herland2085b162010-11-15 00:54:11 +010049 return -1;
Brandon Williams4d778962017-05-30 10:31:01 -070050 return get_oid_hex(hex_oid, oid);
Johan Herland2085b162010-11-15 00:54:11 +010051}
52
Brandon Williams4d778962017-05-30 10:31:01 -070053static int verify_notes_filepair(struct diff_filepair *p, struct object_id *oid)
Johan Herland2085b162010-11-15 00:54:11 +010054{
55 switch (p->status) {
56 case DIFF_STATUS_MODIFIED:
57 assert(p->one->mode == p->two->mode);
brian m. carlsona0d12c42016-06-24 23:09:23 +000058 assert(!is_null_oid(&p->one->oid));
59 assert(!is_null_oid(&p->two->oid));
Johan Herland2085b162010-11-15 00:54:11 +010060 break;
61 case DIFF_STATUS_ADDED:
brian m. carlsona0d12c42016-06-24 23:09:23 +000062 assert(is_null_oid(&p->one->oid));
Johan Herland2085b162010-11-15 00:54:11 +010063 break;
64 case DIFF_STATUS_DELETED:
brian m. carlsona0d12c42016-06-24 23:09:23 +000065 assert(is_null_oid(&p->two->oid));
Johan Herland2085b162010-11-15 00:54:11 +010066 break;
67 default:
68 return -1;
69 }
70 assert(!strcmp(p->one->path, p->two->path));
Brandon Williams4d778962017-05-30 10:31:01 -070071 return path_to_oid(p->one->path, oid);
Johan Herland2085b162010-11-15 00:54:11 +010072}
73
74static struct notes_merge_pair *find_notes_merge_pair_pos(
Brandon Williamsd7a7c702017-05-30 10:31:00 -070075 struct notes_merge_pair *list, int len, struct object_id *obj,
Johan Herland2085b162010-11-15 00:54:11 +010076 int insert_new, int *occupied)
77{
78 /*
79 * Both diff_tree_remote() and diff_tree_local() tend to process
80 * merge_pairs in ascending order. Therefore, cache last returned
81 * index, and search sequentially from there until the appropriate
82 * position is found.
83 *
84 * Since inserts only happen from diff_tree_remote() (which mainly
85 * _appends_), we don't care that inserting into the middle of the
86 * list is expensive (using memmove()).
87 */
88 static int last_index;
89 int i = last_index < len ? last_index : len - 1;
90 int prev_cmp = 0, cmp = -1;
91 while (i >= 0 && i < len) {
Brandon Williamsd7a7c702017-05-30 10:31:00 -070092 cmp = oidcmp(obj, &list[i].obj);
Johan Herland2085b162010-11-15 00:54:11 +010093 if (!cmp) /* obj belongs @ i */
94 break;
95 else if (cmp < 0 && prev_cmp <= 0) /* obj belongs < i */
96 i--;
97 else if (cmp < 0) /* obj belongs between i-1 and i */
98 break;
99 else if (cmp > 0 && prev_cmp >= 0) /* obj belongs > i */
100 i++;
101 else /* if (cmp > 0) */ { /* obj belongs between i and i+1 */
102 i++;
103 break;
104 }
105 prev_cmp = cmp;
106 }
107 if (i < 0)
108 i = 0;
109 /* obj belongs at, or immediately preceding, index i (0 <= i <= len) */
110
111 if (!cmp)
112 *occupied = 1;
113 else {
114 *occupied = 0;
115 if (insert_new && i < len) {
René Scharfef331ab92017-07-15 22:00:45 +0200116 MOVE_ARRAY(list + i + 1, list + i, len - i);
Johan Herland2085b162010-11-15 00:54:11 +0100117 memset(list + i, 0, sizeof(struct notes_merge_pair));
118 }
119 }
120 last_index = i;
121 return list + i;
122}
123
brian m. carlsone910bb12016-09-05 20:08:01 +0000124static struct object_id uninitialized = {
Ævar Arnfjörð Bjarmason50103642022-03-17 18:27:17 +0100125 .hash =
Johan Herland2085b162010-11-15 00:54:11 +0100126 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
brian m. carlsone910bb12016-09-05 20:08:01 +0000127 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
128};
Johan Herland2085b162010-11-15 00:54:11 +0100129
130static struct notes_merge_pair *diff_tree_remote(struct notes_merge_options *o,
Brandon Williams9d6babb2017-05-30 10:30:59 -0700131 const struct object_id *base,
132 const struct object_id *remote,
Johan Herland2085b162010-11-15 00:54:11 +0100133 int *num_changes)
134{
135 struct diff_options opt;
136 struct notes_merge_pair *changes;
137 int i, len = 0;
138
139 trace_printf("\tdiff_tree_remote(base = %.7s, remote = %.7s)\n",
Brandon Williams9d6babb2017-05-30 10:30:59 -0700140 oid_to_hex(base), oid_to_hex(remote));
Johan Herland2085b162010-11-15 00:54:11 +0100141
Nguyễn Thái Ngọc Duy56842002018-11-10 06:48:53 +0100142 repo_diff_setup(o->repo, &opt);
Brandon Williams0d1e0e72017-10-31 11:19:11 -0700143 opt.flags.recursive = 1;
Johan Herland2085b162010-11-15 00:54:11 +0100144 opt.output_format = DIFF_FORMAT_NO_OUTPUT;
Thomas Rast28452652012-08-03 14:16:24 +0200145 diff_setup_done(&opt);
Brandon Williams66f414f2017-05-30 10:31:03 -0700146 diff_tree_oid(base, remote, "", &opt);
Johan Herland2085b162010-11-15 00:54:11 +0100147 diffcore_std(&opt);
148
René Scharfeca56dad2021-03-13 17:17:22 +0100149 CALLOC_ARRAY(changes, diff_queued_diff.nr);
Johan Herland2085b162010-11-15 00:54:11 +0100150
151 for (i = 0; i < diff_queued_diff.nr; i++) {
152 struct diff_filepair *p = diff_queued_diff.queue[i];
153 struct notes_merge_pair *mp;
154 int occupied;
Brandon Williamsd7a7c702017-05-30 10:31:00 -0700155 struct object_id obj;
Johan Herland2085b162010-11-15 00:54:11 +0100156
Brandon Williams4d778962017-05-30 10:31:01 -0700157 if (verify_notes_filepair(p, &obj)) {
Johan Herland2085b162010-11-15 00:54:11 +0100158 trace_printf("\t\tCannot merge entry '%s' (%c): "
159 "%.7s -> %.7s. Skipping!\n", p->one->path,
brian m. carlsona0d12c42016-06-24 23:09:23 +0000160 p->status, oid_to_hex(&p->one->oid),
161 oid_to_hex(&p->two->oid));
Johan Herland2085b162010-11-15 00:54:11 +0100162 continue;
163 }
Brandon Williamsd7a7c702017-05-30 10:31:00 -0700164 mp = find_notes_merge_pair_pos(changes, len, &obj, 1, &occupied);
Johan Herland2085b162010-11-15 00:54:11 +0100165 if (occupied) {
166 /* We've found an addition/deletion pair */
Jeff King4a7e27e2018-08-28 17:22:40 -0400167 assert(oideq(&mp->obj, &obj));
brian m. carlsona0d12c42016-06-24 23:09:23 +0000168 if (is_null_oid(&p->one->oid)) { /* addition */
brian m. carlsone910bb12016-09-05 20:08:01 +0000169 assert(is_null_oid(&mp->remote));
170 oidcpy(&mp->remote, &p->two->oid);
brian m. carlsona0d12c42016-06-24 23:09:23 +0000171 } else if (is_null_oid(&p->two->oid)) { /* deletion */
brian m. carlsone910bb12016-09-05 20:08:01 +0000172 assert(is_null_oid(&mp->base));
173 oidcpy(&mp->base, &p->one->oid);
Johan Herland2085b162010-11-15 00:54:11 +0100174 } else
175 assert(!"Invalid existing change recorded");
176 } else {
Brandon Williamsd7a7c702017-05-30 10:31:00 -0700177 oidcpy(&mp->obj, &obj);
brian m. carlsone910bb12016-09-05 20:08:01 +0000178 oidcpy(&mp->base, &p->one->oid);
179 oidcpy(&mp->local, &uninitialized);
180 oidcpy(&mp->remote, &p->two->oid);
Johan Herland2085b162010-11-15 00:54:11 +0100181 len++;
182 }
183 trace_printf("\t\tStored remote change for %s: %.7s -> %.7s\n",
brian m. carlsone910bb12016-09-05 20:08:01 +0000184 oid_to_hex(&mp->obj), oid_to_hex(&mp->base),
185 oid_to_hex(&mp->remote));
Johan Herland2085b162010-11-15 00:54:11 +0100186 }
187 diff_flush(&opt);
Johan Herland2085b162010-11-15 00:54:11 +0100188
189 *num_changes = len;
190 return changes;
191}
192
193static void diff_tree_local(struct notes_merge_options *o,
194 struct notes_merge_pair *changes, int len,
Brandon Williams9d6babb2017-05-30 10:30:59 -0700195 const struct object_id *base,
196 const struct object_id *local)
Johan Herland2085b162010-11-15 00:54:11 +0100197{
198 struct diff_options opt;
199 int i;
200
201 trace_printf("\tdiff_tree_local(len = %i, base = %.7s, local = %.7s)\n",
Brandon Williams9d6babb2017-05-30 10:30:59 -0700202 len, oid_to_hex(base), oid_to_hex(local));
Johan Herland2085b162010-11-15 00:54:11 +0100203
Nguyễn Thái Ngọc Duy56842002018-11-10 06:48:53 +0100204 repo_diff_setup(o->repo, &opt);
Brandon Williams0d1e0e72017-10-31 11:19:11 -0700205 opt.flags.recursive = 1;
Johan Herland2085b162010-11-15 00:54:11 +0100206 opt.output_format = DIFF_FORMAT_NO_OUTPUT;
Thomas Rast28452652012-08-03 14:16:24 +0200207 diff_setup_done(&opt);
Brandon Williams66f414f2017-05-30 10:31:03 -0700208 diff_tree_oid(base, local, "", &opt);
Johan Herland2085b162010-11-15 00:54:11 +0100209 diffcore_std(&opt);
210
211 for (i = 0; i < diff_queued_diff.nr; i++) {
212 struct diff_filepair *p = diff_queued_diff.queue[i];
213 struct notes_merge_pair *mp;
214 int match;
Brandon Williamsd7a7c702017-05-30 10:31:00 -0700215 struct object_id obj;
Johan Herland2085b162010-11-15 00:54:11 +0100216
Brandon Williams4d778962017-05-30 10:31:01 -0700217 if (verify_notes_filepair(p, &obj)) {
Johan Herland2085b162010-11-15 00:54:11 +0100218 trace_printf("\t\tCannot merge entry '%s' (%c): "
219 "%.7s -> %.7s. Skipping!\n", p->one->path,
brian m. carlsona0d12c42016-06-24 23:09:23 +0000220 p->status, oid_to_hex(&p->one->oid),
221 oid_to_hex(&p->two->oid));
Johan Herland2085b162010-11-15 00:54:11 +0100222 continue;
223 }
Brandon Williamsd7a7c702017-05-30 10:31:00 -0700224 mp = find_notes_merge_pair_pos(changes, len, &obj, 0, &match);
Johan Herland2085b162010-11-15 00:54:11 +0100225 if (!match) {
226 trace_printf("\t\tIgnoring local-only change for %s: "
Brandon Williamsd7a7c702017-05-30 10:31:00 -0700227 "%.7s -> %.7s\n", oid_to_hex(&obj),
brian m. carlsona0d12c42016-06-24 23:09:23 +0000228 oid_to_hex(&p->one->oid),
229 oid_to_hex(&p->two->oid));
Johan Herland2085b162010-11-15 00:54:11 +0100230 continue;
231 }
232
Jeff King4a7e27e2018-08-28 17:22:40 -0400233 assert(oideq(&mp->obj, &obj));
brian m. carlsona0d12c42016-06-24 23:09:23 +0000234 if (is_null_oid(&p->two->oid)) { /* deletion */
Johan Herland2085b162010-11-15 00:54:11 +0100235 /*
236 * Either this is a true deletion (1), or it is part
237 * of an A/D pair (2), or D/A pair (3):
238 *
239 * (1) mp->local is uninitialized; set it to null_sha1
240 * (2) mp->local is not uninitialized; don't touch it
241 * (3) mp->local is uninitialized; set it to null_sha1
242 * (will be overwritten by following addition)
243 */
Jeff King4a7e27e2018-08-28 17:22:40 -0400244 if (oideq(&mp->local, &uninitialized))
Patrick Steinhardt9da95bd2024-06-14 08:49:54 +0200245 oidclr(&mp->local, the_repository->hash_algo);
brian m. carlsona0d12c42016-06-24 23:09:23 +0000246 } else if (is_null_oid(&p->one->oid)) { /* addition */
Johan Herland2085b162010-11-15 00:54:11 +0100247 /*
248 * Either this is a true addition (1), or it is part
249 * of an A/D pair (2), or D/A pair (3):
250 *
251 * (1) mp->local is uninitialized; set to p->two->sha1
252 * (2) mp->local is uninitialized; set to p->two->sha1
253 * (3) mp->local is null_sha1; set to p->two->sha1
254 */
brian m. carlsone910bb12016-09-05 20:08:01 +0000255 assert(is_null_oid(&mp->local) ||
Jeff King4a7e27e2018-08-28 17:22:40 -0400256 oideq(&mp->local, &uninitialized));
brian m. carlsone910bb12016-09-05 20:08:01 +0000257 oidcpy(&mp->local, &p->two->oid);
Johan Herland2085b162010-11-15 00:54:11 +0100258 } else { /* modification */
259 /*
260 * This is a true modification. p->one->sha1 shall
261 * match mp->base, and mp->local shall be uninitialized.
262 * Set mp->local to p->two->sha1.
263 */
Jeff King4a7e27e2018-08-28 17:22:40 -0400264 assert(oideq(&p->one->oid, &mp->base));
265 assert(oideq(&mp->local, &uninitialized));
brian m. carlsone910bb12016-09-05 20:08:01 +0000266 oidcpy(&mp->local, &p->two->oid);
Johan Herland2085b162010-11-15 00:54:11 +0100267 }
268 trace_printf("\t\tStored local change for %s: %.7s -> %.7s\n",
brian m. carlsone910bb12016-09-05 20:08:01 +0000269 oid_to_hex(&mp->obj), oid_to_hex(&mp->base),
270 oid_to_hex(&mp->local));
Johan Herland2085b162010-11-15 00:54:11 +0100271 }
272 diff_flush(&opt);
Johan Herland2085b162010-11-15 00:54:11 +0100273}
274
Johan Herland809f38c2010-11-09 22:49:51 +0100275static void check_notes_merge_worktree(struct notes_merge_options *o)
276{
277 if (!o->has_worktree) {
278 /*
279 * Must establish NOTES_MERGE_WORKTREE.
280 * Abort if NOTES_MERGE_WORKTREE already exists
281 */
Johan Herlanddabba592012-03-15 15:58:56 +0100282 if (file_exists(git_path(NOTES_MERGE_WORKTREE)) &&
283 !is_empty_dir(git_path(NOTES_MERGE_WORKTREE))) {
Ben Boeckeled9bff02021-08-23 12:44:00 +0200284 if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
Vasco Almeidac041c6d2016-09-19 13:08:20 +0000285 die(_("You have not concluded your previous "
Johan Herland809f38c2010-11-09 22:49:51 +0100286 "notes merge (%s exists).\nPlease, use "
287 "'git notes merge --commit' or 'git notes "
Johan Herland6abb3652010-11-09 22:49:52 +0100288 "merge --abort' to commit/abort the "
Johan Herland809f38c2010-11-09 22:49:51 +0100289 "previous merge before you start a new "
Vasco Almeidac041c6d2016-09-19 13:08:20 +0000290 "notes merge."), git_path("NOTES_MERGE_*"));
Johan Herland809f38c2010-11-09 22:49:51 +0100291 else
Vasco Almeidac041c6d2016-09-19 13:08:20 +0000292 die(_("You have not concluded your notes merge "
293 "(%s exists)."), git_path("NOTES_MERGE_*"));
Johan Herland809f38c2010-11-09 22:49:51 +0100294 }
295
Nguyễn Thái Ngọc Duydcf69262014-11-30 15:24:27 +0700296 if (safe_create_leading_directories_const(git_path(
Johan Herland809f38c2010-11-09 22:49:51 +0100297 NOTES_MERGE_WORKTREE "/.test")))
298 die_errno("unable to create directory %s",
299 git_path(NOTES_MERGE_WORKTREE));
300 o->has_worktree = 1;
301 } else if (!file_exists(git_path(NOTES_MERGE_WORKTREE)))
302 /* NOTES_MERGE_WORKTREE should already be established */
303 die("missing '%s'. This should not happen",
304 git_path(NOTES_MERGE_WORKTREE));
305}
306
Brandon Williams9e5e0c22017-05-30 10:31:02 -0700307static void write_buf_to_worktree(const struct object_id *obj,
Johan Herland809f38c2010-11-09 22:49:51 +0100308 const char *buf, unsigned long size)
309{
310 int fd;
Brandon Williams9e5e0c22017-05-30 10:31:02 -0700311 char *path = git_pathdup(NOTES_MERGE_WORKTREE "/%s", oid_to_hex(obj));
Nguyễn Thái Ngọc Duydcf69262014-11-30 15:24:27 +0700312 if (safe_create_leading_directories_const(path))
Johan Herland809f38c2010-11-09 22:49:51 +0100313 die_errno("unable to create directory for '%s'", path);
Johan Herland809f38c2010-11-09 22:49:51 +0100314
René Scharfedeb9c152016-07-07 22:08:30 +0200315 fd = xopen(path, O_WRONLY | O_EXCL | O_CREAT, 0666);
Johan Herland809f38c2010-11-09 22:49:51 +0100316
317 while (size > 0) {
Jeff King634eb822017-09-13 13:17:44 -0400318 ssize_t ret = write_in_full(fd, buf, size);
Johan Herland809f38c2010-11-09 22:49:51 +0100319 if (ret < 0) {
320 /* Ignore epipe */
321 if (errno == EPIPE)
322 break;
323 die_errno("notes-merge");
Johan Herland809f38c2010-11-09 22:49:51 +0100324 }
325 size -= ret;
326 buf += ret;
327 }
328
329 close(fd);
Jeff Kingfcd12db2015-08-10 05:35:31 -0400330 free(path);
Johan Herland809f38c2010-11-09 22:49:51 +0100331}
332
Brandon Williams9e5e0c22017-05-30 10:31:02 -0700333static void write_note_to_worktree(const struct object_id *obj,
334 const struct object_id *note)
Johan Herland809f38c2010-11-09 22:49:51 +0100335{
336 enum object_type type;
337 unsigned long size;
Ævar Arnfjörð Bjarmasonbc726bd2023-03-28 15:58:50 +0200338 void *buf = repo_read_object_file(the_repository, note, &type, &size);
Johan Herland809f38c2010-11-09 22:49:51 +0100339
340 if (!buf)
341 die("cannot read note %s for object %s",
Brandon Williams9e5e0c22017-05-30 10:31:02 -0700342 oid_to_hex(note), oid_to_hex(obj));
Johan Herland809f38c2010-11-09 22:49:51 +0100343 if (type != OBJ_BLOB)
344 die("blob expected in note %s for object %s",
Brandon Williams9e5e0c22017-05-30 10:31:02 -0700345 oid_to_hex(note), oid_to_hex(obj));
Johan Herland809f38c2010-11-09 22:49:51 +0100346 write_buf_to_worktree(obj, buf, size);
347 free(buf);
348}
349
350static int ll_merge_in_worktree(struct notes_merge_options *o,
351 struct notes_merge_pair *p)
352{
353 mmbuffer_t result_buf;
354 mmfile_t base, local, remote;
Elijah Newren35f69672022-02-02 02:37:30 +0000355 enum ll_merge_result status;
Johan Herland809f38c2010-11-09 22:49:51 +0100356
brian m. carlsond4493472016-09-05 20:08:02 +0000357 read_mmblob(&base, &p->base);
358 read_mmblob(&local, &p->local);
359 read_mmblob(&remote, &p->remote);
Johan Herland809f38c2010-11-09 22:49:51 +0100360
brian m. carlsone910bb12016-09-05 20:08:01 +0000361 status = ll_merge(&result_buf, oid_to_hex(&p->obj), &base, NULL,
Nguyễn Thái Ngọc Duy32eaa462018-09-21 17:57:27 +0200362 &local, o->local_ref, &remote, o->remote_ref,
Nguyễn Thái Ngọc Duy56842002018-11-10 06:48:53 +0100363 o->repo->index, NULL);
Johan Herland809f38c2010-11-09 22:49:51 +0100364
365 free(base.ptr);
366 free(local.ptr);
367 free(remote.ptr);
368
Elijah Newren35f69672022-02-02 02:37:30 +0000369 if (status == LL_MERGE_BINARY_CONFLICT)
370 warning("Cannot merge binary files: %s (%s vs. %s)",
371 oid_to_hex(&p->obj), o->local_ref, o->remote_ref);
Johan Herland809f38c2010-11-09 22:49:51 +0100372 if ((status < 0) || !result_buf.ptr)
373 die("Failed to execute internal merge");
374
Brandon Williams9e5e0c22017-05-30 10:31:02 -0700375 write_buf_to_worktree(&p->obj, result_buf.ptr, result_buf.size);
Johan Herland809f38c2010-11-09 22:49:51 +0100376 free(result_buf.ptr);
377
378 return status;
379}
380
381static int merge_one_change_manual(struct notes_merge_options *o,
382 struct notes_merge_pair *p,
383 struct notes_tree *t)
384{
385 const char *lref = o->local_ref ? o->local_ref : "local version";
386 const char *rref = o->remote_ref ? o->remote_ref : "remote version";
387
388 trace_printf("\t\t\tmerge_one_change_manual(obj = %.7s, base = %.7s, "
389 "local = %.7s, remote = %.7s)\n",
brian m. carlsone910bb12016-09-05 20:08:01 +0000390 oid_to_hex(&p->obj), oid_to_hex(&p->base),
391 oid_to_hex(&p->local), oid_to_hex(&p->remote));
Johan Herland809f38c2010-11-09 22:49:51 +0100392
Johan Herland443259c2010-11-09 22:49:53 +0100393 /* add "Conflicts:" section to commit message first time through */
394 if (!o->has_worktree)
395 strbuf_addstr(&(o->commit_msg), "\n\nConflicts:\n");
396
brian m. carlsone910bb12016-09-05 20:08:01 +0000397 strbuf_addf(&(o->commit_msg), "\t%s\n", oid_to_hex(&p->obj));
Johan Herland443259c2010-11-09 22:49:53 +0100398
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600399 if (o->verbosity >= 2)
brian m. carlsone910bb12016-09-05 20:08:01 +0000400 printf("Auto-merging notes for %s\n", oid_to_hex(&p->obj));
Johan Herland809f38c2010-11-09 22:49:51 +0100401 check_notes_merge_worktree(o);
brian m. carlsone910bb12016-09-05 20:08:01 +0000402 if (is_null_oid(&p->local)) {
Johan Herland809f38c2010-11-09 22:49:51 +0100403 /* D/F conflict, checkout p->remote */
brian m. carlsone910bb12016-09-05 20:08:01 +0000404 assert(!is_null_oid(&p->remote));
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600405 if (o->verbosity >= 1)
406 printf("CONFLICT (delete/modify): Notes for object %s "
407 "deleted in %s and modified in %s. Version from %s "
408 "left in tree.\n",
brian m. carlsone910bb12016-09-05 20:08:01 +0000409 oid_to_hex(&p->obj), lref, rref, rref);
Brandon Williams9e5e0c22017-05-30 10:31:02 -0700410 write_note_to_worktree(&p->obj, &p->remote);
brian m. carlsone910bb12016-09-05 20:08:01 +0000411 } else if (is_null_oid(&p->remote)) {
Johan Herland809f38c2010-11-09 22:49:51 +0100412 /* D/F conflict, checkout p->local */
brian m. carlsone910bb12016-09-05 20:08:01 +0000413 assert(!is_null_oid(&p->local));
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600414 if (o->verbosity >= 1)
415 printf("CONFLICT (delete/modify): Notes for object %s "
416 "deleted in %s and modified in %s. Version from %s "
417 "left in tree.\n",
brian m. carlsone910bb12016-09-05 20:08:01 +0000418 oid_to_hex(&p->obj), rref, lref, lref);
Brandon Williams9e5e0c22017-05-30 10:31:02 -0700419 write_note_to_worktree(&p->obj, &p->local);
Johan Herland809f38c2010-11-09 22:49:51 +0100420 } else {
421 /* "regular" conflict, checkout result of ll_merge() */
422 const char *reason = "content";
brian m. carlsone910bb12016-09-05 20:08:01 +0000423 if (is_null_oid(&p->base))
Johan Herland809f38c2010-11-09 22:49:51 +0100424 reason = "add/add";
brian m. carlsone910bb12016-09-05 20:08:01 +0000425 assert(!is_null_oid(&p->local));
426 assert(!is_null_oid(&p->remote));
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600427 if (o->verbosity >= 1)
428 printf("CONFLICT (%s): Merge conflict in notes for "
brian m. carlsone910bb12016-09-05 20:08:01 +0000429 "object %s\n", reason,
430 oid_to_hex(&p->obj));
Johan Herland809f38c2010-11-09 22:49:51 +0100431 ll_merge_in_worktree(o, p);
432 }
433
434 trace_printf("\t\t\tremoving from partial merge result\n");
brian m. carlsone910bb12016-09-05 20:08:01 +0000435 remove_note(t, p->obj.hash);
Johan Herland809f38c2010-11-09 22:49:51 +0100436
437 return 1;
438}
439
Johan Herland3228e672010-11-15 00:55:12 +0100440static int merge_one_change(struct notes_merge_options *o,
441 struct notes_merge_pair *p, struct notes_tree *t)
442{
443 /*
Johan Herland809f38c2010-11-09 22:49:51 +0100444 * Return 0 if change is successfully resolved (stored in notes_tree).
445 * Return 1 is change results in a conflict (NOT stored in notes_tree,
446 * but instead written to NOTES_MERGE_WORKTREE with conflict markers).
Johan Herland3228e672010-11-15 00:55:12 +0100447 */
448 switch (o->strategy) {
449 case NOTES_MERGE_RESOLVE_MANUAL:
Johan Herland809f38c2010-11-09 22:49:51 +0100450 return merge_one_change_manual(o, p, t);
Johan Herland3228e672010-11-15 00:55:12 +0100451 case NOTES_MERGE_RESOLVE_OURS:
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600452 if (o->verbosity >= 2)
453 printf("Using local notes for %s\n",
brian m. carlsone910bb12016-09-05 20:08:01 +0000454 oid_to_hex(&p->obj));
Johan Herland3228e672010-11-15 00:55:12 +0100455 /* nothing to do */
456 return 0;
457 case NOTES_MERGE_RESOLVE_THEIRS:
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600458 if (o->verbosity >= 2)
459 printf("Using remote notes for %s\n",
brian m. carlsone910bb12016-09-05 20:08:01 +0000460 oid_to_hex(&p->obj));
brian m. carlson5ee8a952017-05-30 10:30:43 -0700461 if (add_note(t, &p->obj, &p->remote, combine_notes_overwrite))
Johannes Schindelin033abf92018-05-02 11:38:39 +0200462 BUG("combine_notes_overwrite failed");
Johan Herland3228e672010-11-15 00:55:12 +0100463 return 0;
464 case NOTES_MERGE_RESOLVE_UNION:
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600465 if (o->verbosity >= 2)
466 printf("Concatenating local and remote notes for %s\n",
brian m. carlsone910bb12016-09-05 20:08:01 +0000467 oid_to_hex(&p->obj));
brian m. carlson5ee8a952017-05-30 10:30:43 -0700468 if (add_note(t, &p->obj, &p->remote, combine_notes_concatenate))
Johan Herland3228e672010-11-15 00:55:12 +0100469 die("failed to concatenate notes "
470 "(combine_notes_concatenate)");
471 return 0;
Johan Herlanda6a09092010-11-15 00:57:17 +0100472 case NOTES_MERGE_RESOLVE_CAT_SORT_UNIQ:
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600473 if (o->verbosity >= 2)
474 printf("Concatenating unique lines in local and remote "
brian m. carlsone910bb12016-09-05 20:08:01 +0000475 "notes for %s\n", oid_to_hex(&p->obj));
brian m. carlson5ee8a952017-05-30 10:30:43 -0700476 if (add_note(t, &p->obj, &p->remote, combine_notes_cat_sort_uniq))
Johan Herlanda6a09092010-11-15 00:57:17 +0100477 die("failed to concatenate notes "
478 "(combine_notes_cat_sort_uniq)");
479 return 0;
Johan Herland3228e672010-11-15 00:55:12 +0100480 }
481 die("Unknown strategy (%i).", o->strategy);
482}
483
Johan Herland2085b162010-11-15 00:54:11 +0100484static int merge_changes(struct notes_merge_options *o,
485 struct notes_merge_pair *changes, int *num_changes,
486 struct notes_tree *t)
487{
488 int i, conflicts = 0;
489
490 trace_printf("\tmerge_changes(num_changes = %i)\n", *num_changes);
491 for (i = 0; i < *num_changes; i++) {
492 struct notes_merge_pair *p = changes + i;
493 trace_printf("\t\t%.7s: %.7s -> %.7s/%.7s\n",
brian m. carlsone910bb12016-09-05 20:08:01 +0000494 oid_to_hex(&p->obj), oid_to_hex(&p->base),
495 oid_to_hex(&p->local),
496 oid_to_hex(&p->remote));
Johan Herland2085b162010-11-15 00:54:11 +0100497
Jeff King4a7e27e2018-08-28 17:22:40 -0400498 if (oideq(&p->base, &p->remote)) {
Johan Herland2085b162010-11-15 00:54:11 +0100499 /* no remote change; nothing to do */
500 trace_printf("\t\t\tskipping (no remote change)\n");
Jeff King4a7e27e2018-08-28 17:22:40 -0400501 } else if (oideq(&p->local, &p->remote)) {
Johan Herland2085b162010-11-15 00:54:11 +0100502 /* same change in local and remote; nothing to do */
503 trace_printf("\t\t\tskipping (local == remote)\n");
Jeff King4a7e27e2018-08-28 17:22:40 -0400504 } else if (oideq(&p->local, &uninitialized) ||
505 oideq(&p->local, &p->base)) {
Johan Herland2085b162010-11-15 00:54:11 +0100506 /* no local change; adopt remote change */
507 trace_printf("\t\t\tno local change, adopted remote\n");
brian m. carlson5ee8a952017-05-30 10:30:43 -0700508 if (add_note(t, &p->obj, &p->remote,
Johan Herland2085b162010-11-15 00:54:11 +0100509 combine_notes_overwrite))
Johannes Schindelin033abf92018-05-02 11:38:39 +0200510 BUG("combine_notes_overwrite failed");
Johan Herland2085b162010-11-15 00:54:11 +0100511 } else {
512 /* need file-level merge between local and remote */
513 trace_printf("\t\t\tneed content-level merge\n");
Johan Herland3228e672010-11-15 00:55:12 +0100514 conflicts += merge_one_change(o, p, t);
Johan Herland2085b162010-11-15 00:54:11 +0100515 }
516 }
517
518 return conflicts;
519}
520
521static int merge_from_diffs(struct notes_merge_options *o,
Brandon Williams9d6babb2017-05-30 10:30:59 -0700522 const struct object_id *base,
523 const struct object_id *local,
524 const struct object_id *remote,
525 struct notes_tree *t)
Johan Herland2085b162010-11-15 00:54:11 +0100526{
527 struct notes_merge_pair *changes;
528 int num_changes, conflicts;
529
530 trace_printf("\tmerge_from_diffs(base = %.7s, local = %.7s, "
Brandon Williams9d6babb2017-05-30 10:30:59 -0700531 "remote = %.7s)\n", oid_to_hex(base), oid_to_hex(local),
532 oid_to_hex(remote));
Johan Herland2085b162010-11-15 00:54:11 +0100533
534 changes = diff_tree_remote(o, base, remote, &num_changes);
535 diff_tree_local(o, changes, num_changes, base, local);
536
537 conflicts = merge_changes(o, changes, &num_changes, t);
538 free(changes);
539
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600540 if (o->verbosity >= 4)
Nguyễn Thái Ngọc Duy2ca0c532012-06-07 19:05:13 +0700541 printf(t->dirty ?
542 "Merge result: %i unmerged notes and a dirty notes tree\n" :
543 "Merge result: %i unmerged notes and a clean notes tree\n",
544 conflicts);
Johan Herland2085b162010-11-15 00:54:11 +0100545
546 return conflicts ? -1 : 1;
547}
548
Johan Herland75ef3f42010-11-09 22:49:46 +0100549int notes_merge(struct notes_merge_options *o,
Johan Herland2085b162010-11-15 00:54:11 +0100550 struct notes_tree *local_tree,
Brandon Williams5237e0e2017-05-30 10:30:58 -0700551 struct object_id *result_oid)
Johan Herland75ef3f42010-11-09 22:49:46 +0100552{
brian m. carlson1e43ed92017-05-06 22:10:09 +0000553 struct object_id local_oid, remote_oid;
Johan Herland75ef3f42010-11-09 22:49:46 +0100554 struct commit *local, *remote;
555 struct commit_list *bases = NULL;
Brandon Williams5237e0e2017-05-30 10:30:58 -0700556 const struct object_id *base_oid, *base_tree_oid;
Johan Herland75ef3f42010-11-09 22:49:46 +0100557 int result = 0;
558
559 assert(o->local_ref && o->remote_ref);
Johan Herland2085b162010-11-15 00:54:11 +0100560 assert(!strcmp(o->local_ref, local_tree->ref));
Patrick Steinhardt9da95bd2024-06-14 08:49:54 +0200561 oidclr(result_oid, the_repository->hash_algo);
Johan Herland75ef3f42010-11-09 22:49:46 +0100562
563 trace_printf("notes_merge(o->local_ref = %s, o->remote_ref = %s)\n",
564 o->local_ref, o->remote_ref);
565
566 /* Dereference o->local_ref into local_sha1 */
Patrick Steinhardt2e5c4752024-05-07 09:11:53 +0200567 if (refs_read_ref_full(get_main_ref_store(the_repository), o->local_ref, 0, &local_oid, NULL))
Johan Herland75ef3f42010-11-09 22:49:46 +0100568 die("Failed to resolve local notes ref '%s'", o->local_ref);
Michael Haggerty8d9c5012011-09-15 23:10:25 +0200569 else if (!check_refname_format(o->local_ref, 0) &&
brian m. carlson1e43ed92017-05-06 22:10:09 +0000570 is_null_oid(&local_oid))
Brandon Williams5237e0e2017-05-30 10:30:58 -0700571 local = NULL; /* local_oid == null_oid indicates unborn ref */
Nguyễn Thái Ngọc Duy878d8322018-11-10 06:48:54 +0100572 else if (!(local = lookup_commit_reference(o->repo, &local_oid)))
Johan Herland75ef3f42010-11-09 22:49:46 +0100573 die("Could not parse local commit %s (%s)",
brian m. carlson1e43ed92017-05-06 22:10:09 +0000574 oid_to_hex(&local_oid), o->local_ref);
575 trace_printf("\tlocal commit: %.7s\n", oid_to_hex(&local_oid));
Johan Herland75ef3f42010-11-09 22:49:46 +0100576
Brandon Williams5237e0e2017-05-30 10:30:58 -0700577 /* Dereference o->remote_ref into remote_oid */
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +0200578 if (repo_get_oid(the_repository, o->remote_ref, &remote_oid)) {
Johan Herland75ef3f42010-11-09 22:49:46 +0100579 /*
Brandon Williams5237e0e2017-05-30 10:30:58 -0700580 * Failed to get remote_oid. If o->remote_ref looks like an
Johan Herland75ef3f42010-11-09 22:49:46 +0100581 * unborn ref, perform the merge using an empty notes tree.
582 */
Michael Haggerty8d9c5012011-09-15 23:10:25 +0200583 if (!check_refname_format(o->remote_ref, 0)) {
Patrick Steinhardt9da95bd2024-06-14 08:49:54 +0200584 oidclr(&remote_oid, the_repository->hash_algo);
Johan Herland75ef3f42010-11-09 22:49:46 +0100585 remote = NULL;
586 } else {
587 die("Failed to resolve remote notes ref '%s'",
588 o->remote_ref);
589 }
Nguyễn Thái Ngọc Duy878d8322018-11-10 06:48:54 +0100590 } else if (!(remote = lookup_commit_reference(o->repo, &remote_oid))) {
Johan Herland75ef3f42010-11-09 22:49:46 +0100591 die("Could not parse remote commit %s (%s)",
brian m. carlson1e43ed92017-05-06 22:10:09 +0000592 oid_to_hex(&remote_oid), o->remote_ref);
Johan Herland75ef3f42010-11-09 22:49:46 +0100593 }
brian m. carlson1e43ed92017-05-06 22:10:09 +0000594 trace_printf("\tremote commit: %.7s\n", oid_to_hex(&remote_oid));
Johan Herland75ef3f42010-11-09 22:49:46 +0100595
596 if (!local && !remote)
597 die("Cannot merge empty notes ref (%s) into empty notes ref "
598 "(%s)", o->remote_ref, o->local_ref);
599 if (!local) {
600 /* result == remote commit */
Brandon Williams5237e0e2017-05-30 10:30:58 -0700601 oidcpy(result_oid, &remote_oid);
Johan Herland75ef3f42010-11-09 22:49:46 +0100602 goto found_result;
603 }
604 if (!remote) {
605 /* result == local commit */
Brandon Williams5237e0e2017-05-30 10:30:58 -0700606 oidcpy(result_oid, &local_oid);
Johan Herland75ef3f42010-11-09 22:49:46 +0100607 goto found_result;
608 }
609 assert(local && remote);
610
611 /* Find merge bases */
Johannes Schindelin76e2a092024-02-28 09:44:14 +0000612 if (repo_get_merge_bases(the_repository, local, remote, &bases) < 0)
613 exit(128);
Johan Herland75ef3f42010-11-09 22:49:46 +0100614 if (!bases) {
brian m. carlson14228442021-04-26 01:02:56 +0000615 base_oid = null_oid();
brian m. carlsoneb0ccfd2017-11-12 21:28:54 +0000616 base_tree_oid = the_hash_algo->empty_tree;
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600617 if (o->verbosity >= 4)
618 printf("No merge base found; doing history-less merge\n");
Johan Herland75ef3f42010-11-09 22:49:46 +0100619 } else if (!bases->next) {
Brandon Williams5237e0e2017-05-30 10:30:58 -0700620 base_oid = &bases->item->object.oid;
Derrick Stolee2e27bd72018-04-06 19:09:38 +0000621 base_tree_oid = get_commit_tree_oid(bases->item);
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600622 if (o->verbosity >= 4)
623 printf("One merge base found (%.7s)\n",
Brandon Williams5237e0e2017-05-30 10:30:58 -0700624 oid_to_hex(base_oid));
Johan Herland75ef3f42010-11-09 22:49:46 +0100625 } else {
626 /* TODO: How to handle multiple merge-bases? */
Brandon Williams5237e0e2017-05-30 10:30:58 -0700627 base_oid = &bases->item->object.oid;
Derrick Stolee2e27bd72018-04-06 19:09:38 +0000628 base_tree_oid = get_commit_tree_oid(bases->item);
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600629 if (o->verbosity >= 3)
630 printf("Multiple merge bases found. Using the first "
Brandon Williams5237e0e2017-05-30 10:30:58 -0700631 "(%.7s)\n", oid_to_hex(base_oid));
Johan Herland75ef3f42010-11-09 22:49:46 +0100632 }
633
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600634 if (o->verbosity >= 4)
635 printf("Merging remote commit %.7s into local commit %.7s with "
brian m. carlsonf2fd0762015-11-10 02:22:28 +0000636 "merge-base %.7s\n", oid_to_hex(&remote->object.oid),
637 oid_to_hex(&local->object.oid),
Brandon Williams5237e0e2017-05-30 10:30:58 -0700638 oid_to_hex(base_oid));
Johan Herland75ef3f42010-11-09 22:49:46 +0100639
Jeff King4a7e27e2018-08-28 17:22:40 -0400640 if (oideq(&remote->object.oid, base_oid)) {
Johan Herland75ef3f42010-11-09 22:49:46 +0100641 /* Already merged; result == local commit */
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600642 if (o->verbosity >= 2)
Eric Sunshine80cde952021-05-02 01:14:22 -0400643 printf_ln("Already up to date.");
Brandon Williams5237e0e2017-05-30 10:30:58 -0700644 oidcpy(result_oid, &local->object.oid);
Johan Herland75ef3f42010-11-09 22:49:46 +0100645 goto found_result;
646 }
Jeff King4a7e27e2018-08-28 17:22:40 -0400647 if (oideq(&local->object.oid, base_oid)) {
Johan Herland75ef3f42010-11-09 22:49:46 +0100648 /* Fast-forward; result == remote commit */
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600649 if (o->verbosity >= 2)
650 printf("Fast-forward\n");
Brandon Williams5237e0e2017-05-30 10:30:58 -0700651 oidcpy(result_oid, &remote->object.oid);
Johan Herland75ef3f42010-11-09 22:49:46 +0100652 goto found_result;
653 }
654
Derrick Stolee2e27bd72018-04-06 19:09:38 +0000655 result = merge_from_diffs(o, base_tree_oid,
656 get_commit_tree_oid(local),
657 get_commit_tree_oid(remote), local_tree);
Johan Herland2085b162010-11-15 00:54:11 +0100658
Johan Herland809f38c2010-11-09 22:49:51 +0100659 if (result != 0) { /* non-trivial merge (with or without conflicts) */
660 /* Commit (partial) result */
Johan Herland2085b162010-11-15 00:54:11 +0100661 struct commit_list *parents = NULL;
662 commit_list_insert(remote, &parents); /* LIFO order */
663 commit_list_insert(local, &parents);
Nguyễn Thái Ngọc Duy1d18d752019-01-12 09:13:23 +0700664 create_notes_commit(o->repo, local_tree, parents, o->commit_msg.buf,
Patryk Obara5078f342018-01-28 01:13:16 +0100665 o->commit_msg.len, result_oid);
Patrick Steinhardt63c9bd32024-06-11 11:20:42 +0200666 free_commit_list(parents);
Johan Herland2085b162010-11-15 00:54:11 +0100667 }
Johan Herland75ef3f42010-11-09 22:49:46 +0100668
669found_result:
670 free_commit_list(bases);
Johan Herland443259c2010-11-09 22:49:53 +0100671 strbuf_release(&(o->commit_msg));
Brandon Williams5237e0e2017-05-30 10:30:58 -0700672 trace_printf("notes_merge(): result = %i, result_oid = %.7s\n",
673 result, oid_to_hex(result_oid));
Johan Herland75ef3f42010-11-09 22:49:46 +0100674 return result;
675}
Johan Herland6abb3652010-11-09 22:49:52 +0100676
677int notes_merge_commit(struct notes_merge_options *o,
678 struct notes_tree *partial_tree,
679 struct commit *partial_commit,
Brandon Williams5237e0e2017-05-30 10:30:58 -0700680 struct object_id *result_oid)
Johan Herland6abb3652010-11-09 22:49:52 +0100681{
682 /*
683 * Iterate through files in .git/NOTES_MERGE_WORKTREE and add all
Johan Herlanda0be62c2012-03-12 15:57:13 +0100684 * found notes to 'partial_tree'. Write the updated notes tree to
Johan Herland6abb3652010-11-09 22:49:52 +0100685 * the DB, and commit the resulting tree object while reusing the
686 * commit message and parents from 'partial_commit'.
Brandon Williams5237e0e2017-05-30 10:30:58 -0700687 * Finally store the new commit object OID into 'result_oid'.
Johan Herland6abb3652010-11-09 22:49:52 +0100688 */
Johan Herlanda0be62c2012-03-12 15:57:13 +0100689 DIR *dir;
690 struct dirent *e;
691 struct strbuf path = STRBUF_INIT;
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +0200692 const char *buffer = repo_get_commit_buffer(the_repository,
693 partial_commit, NULL);
Jeff Kingbc6b8fc2014-06-10 17:41:51 -0400694 const char *msg = strstr(buffer, "\n\n");
Johan Herlanda0be62c2012-03-12 15:57:13 +0100695 int baselen;
Johan Herland6abb3652010-11-09 22:49:52 +0100696
Jeff King8c2ca3a2017-04-20 17:09:30 -0400697 git_path_buf(&path, NOTES_MERGE_WORKTREE);
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600698 if (o->verbosity >= 3)
Johan Herlanda0be62c2012-03-12 15:57:13 +0100699 printf("Committing notes in notes merge worktree at %s\n",
700 path.buf);
Johan Herland6abb3652010-11-09 22:49:52 +0100701
702 if (!msg || msg[2] == '\0')
703 die("partial notes commit has empty message");
704 msg += 2;
705
Johan Herlanda0be62c2012-03-12 15:57:13 +0100706 dir = opendir(path.buf);
707 if (!dir)
708 die_errno("could not open %s", path.buf);
709
710 strbuf_addch(&path, '/');
711 baselen = path.len;
Elijah Newrenb548f0f2021-05-12 17:28:22 +0000712 while ((e = readdir_skip_dot_and_dotdot(dir)) != NULL) {
Johan Herland6abb3652010-11-09 22:49:52 +0100713 struct stat st;
brian m. carlson5ee8a952017-05-30 10:30:43 -0700714 struct object_id obj_oid, blob_oid;
Johan Herland6abb3652010-11-09 22:49:52 +0100715
brian m. carlson5ee8a952017-05-30 10:30:43 -0700716 if (get_oid_hex(e->d_name, &obj_oid)) {
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600717 if (o->verbosity >= 3)
Johan Herlanda0be62c2012-03-12 15:57:13 +0100718 printf("Skipping non-SHA1 entry '%s%s'\n",
719 path.buf, e->d_name);
Johan Herland6abb3652010-11-09 22:49:52 +0100720 continue;
721 }
722
Johan Herlanda0be62c2012-03-12 15:57:13 +0100723 strbuf_addstr(&path, e->d_name);
Johan Herland6abb3652010-11-09 22:49:52 +0100724 /* write file as blob, and add to partial_tree */
Johan Herlanda0be62c2012-03-12 15:57:13 +0100725 if (stat(path.buf, &st))
726 die_errno("Failed to stat '%s'", path.buf);
Nguyễn Thái Ngọc Duy56842002018-11-10 06:48:53 +0100727 if (index_path(o->repo->index, &blob_oid, path.buf, &st, HASH_WRITE_OBJECT))
Johan Herlanda0be62c2012-03-12 15:57:13 +0100728 die("Failed to write blob object from '%s'", path.buf);
brian m. carlson5ee8a952017-05-30 10:30:43 -0700729 if (add_note(partial_tree, &obj_oid, &blob_oid, NULL))
Johan Herland6abb3652010-11-09 22:49:52 +0100730 die("Failed to add resolved note '%s' to notes tree",
Johan Herlanda0be62c2012-03-12 15:57:13 +0100731 path.buf);
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600732 if (o->verbosity >= 4)
733 printf("Added resolved note for object %s: %s\n",
brian m. carlson5ee8a952017-05-30 10:30:43 -0700734 oid_to_hex(&obj_oid), oid_to_hex(&blob_oid));
Johan Herlanda0be62c2012-03-12 15:57:13 +0100735 strbuf_setlen(&path, baselen);
Johan Herland6abb3652010-11-09 22:49:52 +0100736 }
737
Nguyễn Thái Ngọc Duy1d18d752019-01-12 09:13:23 +0700738 create_notes_commit(o->repo, partial_tree, partial_commit->parents, msg,
Patryk Obara5078f342018-01-28 01:13:16 +0100739 strlen(msg), result_oid);
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +0200740 repo_unuse_commit_buffer(the_repository, partial_commit, buffer);
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600741 if (o->verbosity >= 4)
742 printf("Finalized notes merge commit: %s\n",
Brandon Williams5237e0e2017-05-30 10:30:58 -0700743 oid_to_hex(result_oid));
Johan Herlanda0be62c2012-03-12 15:57:13 +0100744 strbuf_release(&path);
745 closedir(dir);
Johan Herland6abb3652010-11-09 22:49:52 +0100746 return 0;
747}
748
749int notes_merge_abort(struct notes_merge_options *o)
750{
Johan Herlanddabba592012-03-15 15:58:56 +0100751 /*
752 * Remove all files within .git/NOTES_MERGE_WORKTREE. We do not remove
753 * the .git/NOTES_MERGE_WORKTREE directory itself, since it might be
754 * the current working directory of the user.
755 */
Johan Herland6abb3652010-11-09 22:49:52 +0100756 struct strbuf buf = STRBUF_INIT;
757 int ret;
758
Jeff King8c2ca3a2017-04-20 17:09:30 -0400759 git_path_buf(&buf, NOTES_MERGE_WORKTREE);
Jonathan Nieder5f9f8d12011-11-17 19:27:46 -0600760 if (o->verbosity >= 3)
Johan Herlanddabba592012-03-15 15:58:56 +0100761 printf("Removing notes merge worktree at %s/*\n", buf.buf);
762 ret = remove_dir_recursively(&buf, REMOVE_DIR_KEEP_TOPLEVEL);
Johan Herland6abb3652010-11-09 22:49:52 +0100763 strbuf_release(&buf);
764 return ret;
765}