]> git.proxmox.com Git - libgit2.git/blame - src/rebase.c
rebase: preload all operations
[libgit2.git] / src / rebase.c
CommitLineData
867a36f3
ET
1/*
2 * Copyright (C) the libgit2 contributors. All rights reserved.
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7
8#include "common.h"
9#include "buffer.h"
10#include "repository.h"
11#include "posix.h"
12#include "filebuf.h"
13#include "merge.h"
14#include "array.h"
5ae9d296 15#include "config.h"
867a36f3
ET
16
17#include <git2/types.h>
18#include <git2/rebase.h>
19#include <git2/commit.h>
20#include <git2/reset.h>
21#include <git2/revwalk.h>
5ae9d296 22#include <git2/notes.h>
867a36f3
ET
23
24#define REBASE_APPLY_DIR "rebase-apply"
25#define REBASE_MERGE_DIR "rebase-merge"
26
27#define HEAD_NAME_FILE "head-name"
28#define ORIG_HEAD_FILE "orig-head"
29#define HEAD_FILE "head"
30#define ONTO_FILE "onto"
31#define ONTO_NAME_FILE "onto_name"
32#define QUIET_FILE "quiet"
33
34#define MSGNUM_FILE "msgnum"
35#define END_FILE "end"
36#define CMT_FILE_FMT "cmt.%d"
950a7091 37#define CURRENT_FILE "current"
a35a9890 38#define REWRITTEN_FILE "rewritten"
867a36f3
ET
39
40#define ORIG_DETACHED_HEAD "detached HEAD"
41
5ae9d296
ET
42#define NOTES_DEFAULT_REF NULL
43
867a36f3
ET
44#define REBASE_DIR_MODE 0777
45#define REBASE_FILE_MODE 0666
46
47typedef enum {
48 GIT_REBASE_TYPE_NONE = 0,
49 GIT_REBASE_TYPE_APPLY = 1,
50 GIT_REBASE_TYPE_MERGE = 2,
950a7091 51 GIT_REBASE_TYPE_INTERACTIVE = 3,
867a36f3
ET
52} git_rebase_type_t;
53
b6b636a7
ET
54struct git_rebase {
55 git_repository *repo;
56
4fe84d62
ET
57 git_rebase_type_t type;
58 char *state_path;
59
b6b636a7 60 int head_detached : 1,
f152f8ac
ET
61 quiet : 1,
62 started : 1;
4fe84d62
ET
63
64 char *orig_head_name;
65 git_oid orig_head_id;
950a7091 66
517644cc 67 git_oid onto_id;
f152f8ac 68 char *onto_name;
517644cc 69
b6b636a7 70 git_array_t(git_rebase_operation) operations;
f152f8ac 71 size_t current;
b6b636a7 72};
4fe84d62
ET
73
74#define GIT_REBASE_STATE_INIT {0}
75
867a36f3
ET
76static int rebase_state_type(
77 git_rebase_type_t *type_out,
78 char **path_out,
79 git_repository *repo)
80{
81 git_buf path = GIT_BUF_INIT;
82 git_rebase_type_t type = GIT_REBASE_TYPE_NONE;
83
84 if (git_buf_joinpath(&path, repo->path_repository, REBASE_APPLY_DIR) < 0)
85 return -1;
86
87 if (git_path_isdir(git_buf_cstr(&path))) {
88 type = GIT_REBASE_TYPE_APPLY;
89 goto done;
90 }
91
92 git_buf_clear(&path);
93 if (git_buf_joinpath(&path, repo->path_repository, REBASE_MERGE_DIR) < 0)
94 return -1;
95
96 if (git_path_isdir(git_buf_cstr(&path))) {
97 type = GIT_REBASE_TYPE_MERGE;
98 goto done;
99 }
100
101done:
102 *type_out = type;
103
104 if (type != GIT_REBASE_TYPE_NONE && path_out)
105 *path_out = git_buf_detach(&path);
106
107 git_buf_free(&path);
108
109 return 0;
110}
111
f152f8ac 112GIT_INLINE(int) rebase_readfile(git_buf *out, git_buf *state_path, const char *filename)
950a7091 113{
f152f8ac
ET
114 size_t state_path_len = state_path->size;
115 int error;
950a7091 116
f152f8ac
ET
117 git_buf_clear(out);
118
119 if ((error = git_buf_joinpath(state_path, state_path->ptr, filename)) < 0 ||
120 (error = git_futils_readbuffer(out, state_path->ptr)) < 0)
950a7091
ET
121 goto done;
122
f152f8ac 123 git_buf_rtrim(out);
950a7091 124
f152f8ac
ET
125done:
126 git_buf_truncate(state_path, state_path_len);
127 return error;
128}
443d5674 129
f152f8ac
ET
130GIT_INLINE(int) rebase_readint(
131 size_t *out, git_buf *asc_out, git_buf *state_path, const char *filename)
132{
133 int32_t num;
134 char *eol;
135 int error = 0;
443d5674 136
f152f8ac
ET
137 if ((error = rebase_readfile(asc_out, state_path, filename)) < 0)
138 return error;
443d5674 139
f152f8ac
ET
140 if (git__strtol32(&num, asc_out->ptr, &eol, 10) < 0 || num < 0 || *eol) {
141 giterr_set(GITERR_REBASE, "The file '%s' contains an invalid numeric value", filename);
142 return -1;
143 }
443d5674 144
f152f8ac 145 *out = (size_t) num;
443d5674 146
f152f8ac
ET
147 return 0;
148}
443d5674 149
f152f8ac
ET
150GIT_INLINE(int) rebase_readoid(
151 git_oid *out, git_buf *str_out, git_buf *state_path, const char *filename)
152{
153 int error;
443d5674 154
f152f8ac
ET
155 if ((error = rebase_readfile(str_out, state_path, filename)) < 0)
156 return error;
443d5674 157
f152f8ac
ET
158 if (str_out->size != GIT_OID_HEXSZ || git_oid_fromstr(out, str_out->ptr) < 0) {
159 giterr_set(GITERR_REBASE, "The file '%s' contains an invalid object ID", filename);
160 return -1;
161 }
950a7091 162
f152f8ac
ET
163 return 0;
164}
950a7091 165
f152f8ac
ET
166static int rebase_open_merge(git_rebase *rebase)
167{
168 git_buf state_path = GIT_BUF_INIT, buf = GIT_BUF_INIT, cmt = GIT_BUF_INIT;
169 git_oid current_id = {0};
170 git_rebase_operation *operation;
171 size_t i, msgnum = 0, end;
172 int error;
950a7091 173
f152f8ac
ET
174 if ((error = git_buf_puts(&state_path, rebase->state_path)) < 0)
175 goto done;
950a7091 176
f152f8ac
ET
177 /* Read 'msgnum' if it exists (otherwise, let msgnum = 0) */
178 if ((error = rebase_readint(&msgnum, &buf, &state_path, MSGNUM_FILE)) < 0 &&
179 error != GIT_ENOTFOUND)
180 goto done;
443d5674 181
f152f8ac
ET
182 if (msgnum) {
183 rebase->started = 1;
184 rebase->current = msgnum - 1;
185 }
950a7091 186
f152f8ac
ET
187 /* Read 'end' */
188 if ((error = rebase_readint(&end, &buf, &state_path, END_FILE)) < 0)
950a7091
ET
189 goto done;
190
f152f8ac
ET
191 /* Read 'current' if it exists */
192 if ((error = rebase_readoid(&current_id, &buf, &state_path, CURRENT_FILE)) < 0 &&
193 error != GIT_ENOTFOUND)
194 goto done;
195
196 /* Read cmt.* */
197 git_array_init_to_size(rebase->operations, end);
198 GITERR_CHECK_ARRAY(rebase->operations);
950a7091 199
f152f8ac
ET
200 for (i = 0; i < end; i++) {
201 operation = git_array_alloc(rebase->operations);
202 GITERR_CHECK_ALLOC(operation);
443d5674 203
f152f8ac
ET
204 git_buf_clear(&cmt);
205
206 if ((error = git_buf_printf(&cmt, "cmt.%" PRIuZ, (i+1))) < 0 ||
207 (error = rebase_readoid(&operation->id, &buf, &state_path, cmt.ptr)) < 0)
443d5674
ET
208 goto done;
209 }
950a7091 210
f152f8ac
ET
211 /* Read 'onto_name' */
212 if ((error = rebase_readfile(&buf, &state_path, ONTO_NAME_FILE)) < 0)
213 goto done;
214
215 rebase->onto_name = git_buf_detach(&buf);
216
950a7091 217done:
f152f8ac
ET
218 git_buf_free(&cmt);
219 git_buf_free(&state_path);
220 git_buf_free(&buf);
950a7091
ET
221
222 return error;
223}
224
b6b636a7 225int git_rebase_open(git_rebase **out, git_repository *repo)
4fe84d62 226{
b6b636a7 227 git_rebase *rebase;
4fe84d62 228 git_buf path = GIT_BUF_INIT, orig_head_name = GIT_BUF_INIT,
517644cc 229 orig_head_id = GIT_BUF_INIT, onto_id = GIT_BUF_INIT;
4fe84d62
ET
230 int state_path_len, error;
231
b6b636a7
ET
232 assert(repo);
233
234 rebase = git__calloc(1, sizeof(git_rebase));
235 GITERR_CHECK_ALLOC(rebase);
4fe84d62 236
b6b636a7
ET
237 rebase->repo = repo;
238
239 if ((error = rebase_state_type(&rebase->type, &rebase->state_path, repo)) < 0)
4fe84d62
ET
240 goto done;
241
b6b636a7 242 if (rebase->type == GIT_REBASE_TYPE_NONE) {
4fe84d62
ET
243 giterr_set(GITERR_REBASE, "There is no rebase in progress");
244 return GIT_ENOTFOUND;
245 }
246
b6b636a7 247 if ((error = git_buf_puts(&path, rebase->state_path)) < 0)
4fe84d62
ET
248 goto done;
249
250 state_path_len = git_buf_len(&path);
251
252 if ((error = git_buf_joinpath(&path, path.ptr, HEAD_NAME_FILE)) < 0 ||
253 (error = git_futils_readbuffer(&orig_head_name, path.ptr)) < 0)
254 goto done;
255
256 git_buf_rtrim(&orig_head_name);
257
258 if (strcmp(ORIG_DETACHED_HEAD, orig_head_name.ptr) == 0)
b6b636a7 259 rebase->head_detached = 1;
4fe84d62
ET
260
261 git_buf_truncate(&path, state_path_len);
262
263 if ((error = git_buf_joinpath(&path, path.ptr, ORIG_HEAD_FILE)) < 0)
264 goto done;
265
266 if (!git_path_isfile(path.ptr)) {
267 /* Previous versions of git.git used 'head' here; support that. */
268 git_buf_truncate(&path, state_path_len);
269
270 if ((error = git_buf_joinpath(&path, path.ptr, HEAD_FILE)) < 0)
271 goto done;
272 }
273
274 if ((error = git_futils_readbuffer(&orig_head_id, path.ptr)) < 0)
275 goto done;
276
277 git_buf_rtrim(&orig_head_id);
278
b6b636a7 279 if ((error = git_oid_fromstr(&rebase->orig_head_id, orig_head_id.ptr)) < 0)
4fe84d62
ET
280 goto done;
281
517644cc
ET
282 git_buf_truncate(&path, state_path_len);
283
284 if ((error = git_buf_joinpath(&path, path.ptr, ONTO_FILE)) < 0 ||
285 (error = git_futils_readbuffer(&onto_id, path.ptr)) < 0)
286 goto done;
287
288 git_buf_rtrim(&onto_id);
289
b6b636a7 290 if ((error = git_oid_fromstr(&rebase->onto_id, onto_id.ptr)) < 0)
517644cc
ET
291 goto done;
292
b6b636a7
ET
293 if (!rebase->head_detached)
294 rebase->orig_head_name = git_buf_detach(&orig_head_name);
4fe84d62 295
b6b636a7 296 switch (rebase->type) {
950a7091
ET
297 case GIT_REBASE_TYPE_INTERACTIVE:
298 giterr_set(GITERR_REBASE, "Interactive rebase is not supported");
299 error = -1;
300 break;
301 case GIT_REBASE_TYPE_MERGE:
b6b636a7 302 error = rebase_open_merge(rebase);
950a7091
ET
303 break;
304 case GIT_REBASE_TYPE_APPLY:
305 giterr_set(GITERR_REBASE, "Patch application rebase is not supported");
306 error = -1;
307 break;
308 default:
309 abort();
310 }
311
4fe84d62 312done:
b6b636a7
ET
313 if (error == 0)
314 *out = rebase;
315 else
316 git_rebase_free(rebase);
317
4fe84d62
ET
318 git_buf_free(&path);
319 git_buf_free(&orig_head_name);
320 git_buf_free(&orig_head_id);
321 git_buf_free(&onto_id);
322 return error;
323}
324
b6b636a7 325static int rebase_cleanup(git_rebase *rebase)
4fe84d62 326{
b6b636a7
ET
327 return git_path_isdir(rebase->state_path) ?
328 git_futils_rmdir_r(rebase->state_path, NULL, GIT_RMDIR_REMOVE_FILES) :
4fe84d62
ET
329 0;
330}
331
b6b636a7 332static int rebase_setupfile(git_rebase *rebase, const char *filename, int flags, const char *fmt, ...)
867a36f3
ET
333{
334 git_buf path = GIT_BUF_INIT,
335 contents = GIT_BUF_INIT;
336 va_list ap;
337 int error;
338
339 va_start(ap, fmt);
340 git_buf_vprintf(&contents, fmt, ap);
341 va_end(ap);
342
b6b636a7 343 if ((error = git_buf_joinpath(&path, rebase->state_path, filename)) == 0)
a35a9890 344 error = git_futils_writebuffer(&contents, path.ptr, flags, REBASE_FILE_MODE);
867a36f3
ET
345
346 git_buf_free(&path);
347 git_buf_free(&contents);
348
349 return error;
350}
351
867a36f3
ET
352static const char *rebase_onto_name(const git_merge_head *onto)
353{
354 if (onto->ref_name && git__strncmp(onto->ref_name, "refs/heads/", 11) == 0)
355 return onto->ref_name + 11;
356 else if (onto->ref_name)
357 return onto->ref_name;
358 else
359 return onto->oid_str;
360}
361
b6b636a7 362static int rebase_setupfiles_merge(git_rebase *rebase)
867a36f3 363{
867a36f3 364 git_buf commit_filename = GIT_BUF_INIT;
867a36f3 365 char id_str[GIT_OID_HEXSZ];
b6b636a7
ET
366 git_rebase_operation *operation;
367 size_t i;
368 int error = 0;
867a36f3 369
b6b636a7 370 if ((error = rebase_setupfile(rebase, END_FILE, -1, "%d\n", git_array_size(rebase->operations))) < 0 ||
f152f8ac 371 (error = rebase_setupfile(rebase, ONTO_NAME_FILE, -1, "%s\n", rebase->onto_name)) < 0)
867a36f3
ET
372 goto done;
373
b6b636a7
ET
374 for (i = 0; i < git_array_size(rebase->operations); i++) {
375 operation = git_array_get(rebase->operations, i);
867a36f3
ET
376
377 git_buf_clear(&commit_filename);
b6b636a7
ET
378 git_buf_printf(&commit_filename, CMT_FILE_FMT, i+1);
379
380 git_oid_fmt(id_str, &operation->id);
867a36f3 381
b6b636a7 382 if ((error = rebase_setupfile(rebase, commit_filename.ptr, -1,
867a36f3
ET
383 "%.*s\n", GIT_OID_HEXSZ, id_str)) < 0)
384 goto done;
385 }
386
867a36f3 387done:
867a36f3 388 git_buf_free(&commit_filename);
867a36f3
ET
389 return error;
390}
391
b6b636a7 392static int rebase_setupfiles(git_rebase *rebase)
867a36f3 393{
b6b636a7 394 char onto[GIT_OID_HEXSZ], orig_head[GIT_OID_HEXSZ];
867a36f3 395
b6b636a7
ET
396 git_oid_fmt(onto, &rebase->onto_id);
397 git_oid_fmt(orig_head, &rebase->orig_head_id);
867a36f3 398
b6b636a7
ET
399 if (p_mkdir(rebase->state_path, REBASE_DIR_MODE) < 0) {
400 giterr_set(GITERR_OS, "Failed to create rebase directory '%s'", rebase->state_path);
401 return -1;
867a36f3
ET
402 }
403
b6b636a7
ET
404 if (git_repository__set_orig_head(rebase->repo, &rebase->orig_head_id) < 0 ||
405 rebase_setupfile(rebase, HEAD_NAME_FILE, -1, "%s\n", rebase->orig_head_name) < 0 ||
406 rebase_setupfile(rebase, ONTO_FILE, -1, "%.*s\n", GIT_OID_HEXSZ, onto) < 0 ||
407 rebase_setupfile(rebase, ORIG_HEAD_FILE, -1, "%.*s\n", GIT_OID_HEXSZ, orig_head) < 0 ||
408 rebase_setupfile(rebase, QUIET_FILE, -1, rebase->quiet ? "t\n" : "\n") < 0)
409 return -1;
867a36f3 410
b6b636a7 411 return rebase_setupfiles_merge(rebase);
867a36f3
ET
412}
413
414int git_rebase_init_options(git_rebase_options *opts, unsigned int version)
415{
416 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
417 opts, version, git_rebase_options, GIT_REBASE_OPTIONS_INIT);
418 return 0;
419}
420
5ae9d296
ET
421static int rebase_normalize_opts(
422 git_repository *repo,
867a36f3
ET
423 git_rebase_options *opts,
424 const git_rebase_options *given_opts)
425{
5ae9d296
ET
426 git_rebase_options default_opts = GIT_REBASE_OPTIONS_INIT;
427 git_config *config;
428
867a36f3 429 if (given_opts)
5ae9d296
ET
430 memcpy(opts, given_opts, sizeof(git_rebase_options));
431 else
432 memcpy(opts, &default_opts, sizeof(git_rebase_options));
433
434 if (git_repository_config(&config, repo) < 0)
435 return -1;
436
437 if (given_opts && given_opts->rewrite_notes_ref) {
438 opts->rewrite_notes_ref = git__strdup(given_opts->rewrite_notes_ref);
439 GITERR_CHECK_ALLOC(opts->rewrite_notes_ref);
440 } else if (git_config__get_bool_force(config, "notes.rewrite.rebase", 1)) {
441 const char *rewrite_ref = git_config__get_string_force(
442 config, "notes.rewriteref", NOTES_DEFAULT_REF);
443
444 if (rewrite_ref) {
445 opts->rewrite_notes_ref = git__strdup(rewrite_ref);
446 GITERR_CHECK_ALLOC(opts->rewrite_notes_ref);
447 }
448 }
449
450 git_config_free(config);
451
452 return 0;
453}
454
455static void rebase_opts_free(git_rebase_options *opts)
456{
457 if (!opts)
458 return;
459
460 git__free((char *)opts->rewrite_notes_ref);
867a36f3
ET
461}
462
463static int rebase_ensure_not_in_progress(git_repository *repo)
464{
465 int error;
466 git_rebase_type_t type;
467
468 if ((error = rebase_state_type(&type, NULL, repo)) < 0)
469 return error;
470
471 if (type != GIT_REBASE_TYPE_NONE) {
472 giterr_set(GITERR_REBASE, "There is an existing rebase in progress");
473 return -1;
474 }
475
476 return 0;
477}
478
479static int rebase_ensure_not_dirty(git_repository *repo)
480{
481 git_tree *head = NULL;
482 git_index *index = NULL;
483 git_diff *diff = NULL;
484 int error;
485
486 if ((error = git_repository_head_tree(&head, repo)) < 0 ||
487 (error = git_repository_index(&index, repo)) < 0 ||
488 (error = git_diff_tree_to_index(&diff, repo, head, index, NULL)) < 0)
489 goto done;
490
491 if (git_diff_num_deltas(diff) > 0) {
492 giterr_set(GITERR_REBASE, "Uncommitted changes exist in index");
493 error = -1;
494 goto done;
495 }
496
497 git_diff_free(diff);
498 diff = NULL;
499
500 if ((error = git_diff_index_to_workdir(&diff, repo, index, NULL)) < 0)
501 goto done;
502
503 if (git_diff_num_deltas(diff) > 0) {
504 giterr_set(GITERR_REBASE, "Unstaged changes exist in workdir");
505 error = -1;
506 }
507
508done:
509 git_diff_free(diff);
510 git_index_free(index);
511 git_tree_free(head);
512
513 return error;
514}
515
b6b636a7
ET
516static int rebase_init_operations(
517 git_rebase *rebase,
518 git_repository *repo,
519 const git_merge_head *branch,
520 const git_merge_head *upstream,
521 const git_merge_head *onto)
522{
523 git_revwalk *revwalk = NULL;
524 git_commit *commit;
525 git_oid id;
526 bool merge;
527 git_rebase_operation *operation;
528 int error;
529
530 if (!upstream)
531 upstream = onto;
532
533 if ((error = git_revwalk_new(&revwalk, rebase->repo)) < 0 ||
534 (error = git_revwalk_push(revwalk, &branch->oid)) < 0 ||
535 (error = git_revwalk_hide(revwalk, &upstream->oid)) < 0)
536 goto done;
537
538 git_revwalk_sorting(revwalk, GIT_SORT_REVERSE | GIT_SORT_TIME);
539
540 while ((error = git_revwalk_next(&id, revwalk)) == 0) {
541 if ((error = git_commit_lookup(&commit, repo, &id)) < 0)
542 goto done;
543
544 merge = (git_commit_parentcount(commit) > 1);
545 git_commit_free(commit);
546
547 if (merge)
548 continue;
549
550 operation = git_array_alloc(rebase->operations);
551 operation->type = GIT_REBASE_OPERATION_PICK;
552 git_oid_cpy(&operation->id, &id);
553 }
554
555 error = 0;
556
557done:
558 git_revwalk_free(revwalk);
559 return error;
560}
561
562static int rebase_init_merge(
563 git_rebase *rebase,
564 git_repository *repo,
565 const git_merge_head *branch,
566 const git_merge_head *upstream,
567 const git_merge_head *onto)
568{
569 if (rebase_init_operations(rebase, repo, branch, upstream, onto) < 0)
570 return -1;
571
f152f8ac
ET
572 rebase->onto_name = git__strdup(rebase_onto_name(onto));
573 GITERR_CHECK_ALLOC(rebase->onto_name);
b6b636a7
ET
574
575 return 0;
576}
577
578static int rebase_init(
579 git_rebase *rebase,
580 git_repository *repo,
581 const git_merge_head *branch,
582 const git_merge_head *upstream,
583 const git_merge_head *onto,
584 const git_rebase_options *opts)
585{
586 git_buf state_path = GIT_BUF_INIT;
587 int error;
588
589 git_buf_joinpath(&state_path, repo->path_repository, REBASE_MERGE_DIR);
590
591 rebase->repo = repo;
592 rebase->type = GIT_REBASE_TYPE_MERGE;
593 rebase->state_path = git_buf_detach(&state_path);
594 rebase->orig_head_name = git__strdup(branch->ref_name ? branch->ref_name : ORIG_DETACHED_HEAD);
595 rebase->quiet = opts->quiet;
596
597 git_oid_cpy(&rebase->orig_head_id, &branch->oid);
598 git_oid_cpy(&rebase->onto_id, &onto->oid);
599
600 if (!rebase->orig_head_name || !rebase->state_path)
601 return -1;
602
603 error = rebase_init_merge(rebase, repo, branch, upstream, onto);
604
605 git_buf_free(&state_path);
606
607 return error;
608}
609
610int git_rebase_init(
611 git_rebase **out,
867a36f3
ET
612 git_repository *repo,
613 const git_merge_head *branch,
614 const git_merge_head *upstream,
615 const git_merge_head *onto,
616 const git_signature *signature,
617 const git_rebase_options *given_opts)
618{
b6b636a7 619 git_rebase *rebase = NULL;
5ae9d296 620 git_rebase_options opts;
867a36f3
ET
621 git_reference *head_ref = NULL;
622 git_buf reflog = GIT_BUF_INIT;
623 git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
624 int error;
625
626 assert(repo && branch && (upstream || onto));
627
b6b636a7
ET
628 *out = NULL;
629
867a36f3 630 GITERR_CHECK_VERSION(given_opts, GIT_MERGE_OPTIONS_VERSION, "git_merge_options");
867a36f3 631
b6b636a7
ET
632 if (!onto)
633 onto = upstream;
634
635 checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
636
5ae9d296
ET
637 if ((error = rebase_normalize_opts(repo, &opts, given_opts)) < 0 ||
638 (error = git_repository__ensure_not_bare(repo, "rebase")) < 0 ||
867a36f3
ET
639 (error = rebase_ensure_not_in_progress(repo)) < 0 ||
640 (error = rebase_ensure_not_dirty(repo)) < 0)
b6b636a7 641 return error;
867a36f3 642
b6b636a7
ET
643 rebase = git__calloc(1, sizeof(git_rebase));
644 GITERR_CHECK_ALLOC(rebase);
867a36f3 645
b6b636a7
ET
646 if ((error = rebase_init(rebase, repo, branch, upstream, onto, &opts)) < 0 ||
647 (error = rebase_setupfiles(rebase)) < 0 ||
648 (error = git_buf_printf(&reflog,
867a36f3
ET
649 "rebase: checkout %s", rebase_onto_name(onto))) < 0 ||
650 (error = git_reference_create(&head_ref, repo, GIT_HEAD_FILE,
b6b636a7
ET
651 &onto->oid, 1, signature, reflog.ptr)) < 0 ||
652 (error = git_checkout_head(repo, &checkout_opts)) < 0)
867a36f3
ET
653 goto done;
654
b6b636a7 655 *out = rebase;
867a36f3
ET
656
657done:
b6b636a7
ET
658 if (error < 0) {
659 rebase_cleanup(rebase);
660 git_rebase_free(rebase);
661 }
662
867a36f3
ET
663 git_reference_free(head_ref);
664 git_buf_free(&reflog);
5ae9d296 665 rebase_opts_free(&opts);
b6b636a7 666
867a36f3
ET
667 return error;
668}
4fe84d62 669
443d5674 670static int normalize_checkout_opts(
b6b636a7 671 git_rebase *rebase,
443d5674 672 git_checkout_options *checkout_opts,
b6b636a7 673 const git_checkout_options *given_checkout_opts)
443d5674 674{
f152f8ac 675 git_commit *current_commit = NULL;
443d5674
ET
676 int error = 0;
677
443d5674
ET
678 if (given_checkout_opts != NULL)
679 memcpy(checkout_opts, given_checkout_opts, sizeof(git_checkout_options));
680 else {
681 git_checkout_options default_checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
682 default_checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
683
684 memcpy(checkout_opts, &default_checkout_opts, sizeof(git_checkout_options));
685 }
686
687 if (!checkout_opts->ancestor_label)
688 checkout_opts->ancestor_label = "ancestor";
689
b6b636a7 690 if (rebase->type == GIT_REBASE_TYPE_MERGE) {
443d5674 691 if (!checkout_opts->our_label)
f152f8ac 692 checkout_opts->our_label = rebase->onto_name;
443d5674 693
f152f8ac
ET
694 if (!checkout_opts->their_label) {
695 git_rebase_operation *operation =
696 git_array_get(rebase->operations, rebase->current);
697
698 if ((error = git_commit_lookup(
699 &current_commit, rebase->repo, &operation->id)) < 0)
700 goto done;
701
702 checkout_opts->their_label =
703 git__strdup(git_commit_summary(current_commit));
704 GITERR_CHECK_ALLOC(checkout_opts->their_label);
705 }
443d5674
ET
706 } else {
707 abort();
708 }
709
f152f8ac
ET
710done:
711 git_commit_free(current_commit);
443d5674
ET
712 return error;
713}
714
f152f8ac
ET
715GIT_INLINE(int) rebase_movenext(git_rebase *rebase)
716{
717 size_t next = rebase->started ? rebase->current + 1 : 0;
718
719 if (next == git_array_size(rebase->operations))
720 return GIT_ITEROVER;
721
722 rebase->started = 1;
723 rebase->current = next;
724
725 return 0;
726}
727
950a7091 728static int rebase_next_merge(
f152f8ac 729 git_rebase_operation **out,
b6b636a7 730 git_rebase *rebase,
443d5674 731 git_checkout_options *given_checkout_opts)
950a7091 732{
f152f8ac 733 git_buf path = GIT_BUF_INIT;
443d5674 734 git_checkout_options checkout_opts = {0};
f152f8ac 735 git_commit *current_commit = NULL, *parent_commit = NULL;
950a7091
ET
736 git_tree *current_tree = NULL, *head_tree = NULL, *parent_tree = NULL;
737 git_index *index = NULL;
f152f8ac
ET
738 git_rebase_operation *operation;
739 char current_idstr[GIT_OID_HEXSZ];
950a7091
ET
740 unsigned int parent_count;
741 int error;
742
f152f8ac 743 *out = NULL;
950a7091 744
f152f8ac 745 if ((error = rebase_movenext(rebase)) < 0)
950a7091
ET
746 goto done;
747
f152f8ac 748 operation = git_array_get(rebase->operations, rebase->current);
443d5674 749
f152f8ac
ET
750 if ((error = git_commit_lookup(&current_commit, rebase->repo, &operation->id)) < 0 ||
751 (error = git_commit_tree(&current_tree, current_commit)) < 0 ||
b6b636a7 752 (error = git_repository_head_tree(&head_tree, rebase->repo)) < 0)
950a7091
ET
753 goto done;
754
f152f8ac 755 if ((parent_count = git_commit_parentcount(current_commit)) > 1) {
950a7091
ET
756 giterr_set(GITERR_REBASE, "Cannot rebase a merge commit");
757 error = -1;
758 goto done;
759 } else if (parent_count) {
f152f8ac 760 if ((error = git_commit_parent(&parent_commit, current_commit, 0)) < 0 ||
950a7091
ET
761 (error = git_commit_tree(&parent_tree, parent_commit)) < 0)
762 goto done;
763 }
764
f152f8ac
ET
765 git_oid_fmt(current_idstr, &operation->id);
766
767 if ((error = rebase_setupfile(rebase, MSGNUM_FILE, -1, "%d\n", rebase->current+1)) < 0 ||
768 (error = rebase_setupfile(rebase, CURRENT_FILE, -1, "%.*s\n", GIT_OID_HEXSZ, current_idstr)) < 0)
950a7091
ET
769 goto done;
770
b6b636a7
ET
771 if ((error = normalize_checkout_opts(rebase, &checkout_opts, given_checkout_opts)) < 0 ||
772 (error = git_merge_trees(&index, rebase->repo, parent_tree, head_tree, current_tree, NULL)) < 0 ||
773 (error = git_merge__check_result(rebase->repo, index)) < 0 ||
774 (error = git_checkout_index(rebase->repo, index, &checkout_opts)) < 0)
950a7091
ET
775 goto done;
776
f152f8ac 777 *out = operation;
18b439b9 778
950a7091
ET
779done:
780 git_index_free(index);
781 git_tree_free(current_tree);
782 git_tree_free(head_tree);
783 git_tree_free(parent_tree);
950a7091 784 git_commit_free(parent_commit);
f152f8ac 785 git_commit_free(current_commit);
950a7091 786 git_buf_free(&path);
950a7091
ET
787
788 return error;
789}
790
443d5674 791int git_rebase_next(
f152f8ac 792 git_rebase_operation **out,
b6b636a7 793 git_rebase *rebase,
443d5674 794 git_checkout_options *checkout_opts)
950a7091 795{
950a7091
ET
796 int error;
797
b6b636a7 798 assert(out && rebase);
18b439b9 799
b6b636a7 800 switch (rebase->type) {
950a7091 801 case GIT_REBASE_TYPE_MERGE:
b6b636a7 802 error = rebase_next_merge(out, rebase, checkout_opts);
950a7091
ET
803 break;
804 default:
805 abort();
806 }
807
a35a9890
ET
808 return error;
809}
810
811static int rebase_commit_merge(
812 git_oid *commit_id,
b6b636a7 813 git_rebase *rebase,
a35a9890
ET
814 const git_signature *author,
815 const git_signature *committer,
816 const char *message_encoding,
817 const char *message)
818{
819 git_index *index = NULL;
820 git_reference *head = NULL;
f152f8ac
ET
821 git_commit *current_commit = NULL, *head_commit = NULL, *commit = NULL;
822 git_rebase_operation *operation;
93a7004c
ET
823 git_tree *head_tree = NULL, *tree = NULL;
824 git_diff *diff = NULL;
a35a9890 825 git_oid tree_id;
a612a25f 826 git_buf reflog_msg = GIT_BUF_INIT;
a35a9890
ET
827 char old_idstr[GIT_OID_HEXSZ], new_idstr[GIT_OID_HEXSZ];
828 int error;
829
f152f8ac
ET
830 operation = git_array_get(rebase->operations, rebase->current);
831 assert(operation);
a35a9890 832
b6b636a7 833 if ((error = git_repository_index(&index, rebase->repo)) < 0)
a35a9890
ET
834 goto done;
835
836 if (git_index_has_conflicts(index)) {
837 giterr_set(GITERR_REBASE, "Conflicts have not been resolved");
838 error = GIT_EMERGECONFLICT;
839 goto done;
840 }
841
f152f8ac
ET
842 if ((error = git_commit_lookup(&current_commit, rebase->repo, &operation->id)) < 0 ||
843 (error = git_repository_head(&head, rebase->repo)) < 0 ||
a35a9890 844 (error = git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT)) < 0 ||
93a7004c 845 (error = git_commit_tree(&head_tree, head_commit)) < 0 ||
b6b636a7 846 (error = git_diff_tree_to_index(&diff, rebase->repo, head_tree, index, NULL)) < 0)
93a7004c
ET
847 goto done;
848
849 if (git_diff_num_deltas(diff) == 0) {
850 giterr_set(GITERR_REBASE, "This patch has already been applied");
851 error = GIT_EAPPLIED;
852 goto done;
853 }
854
855 if ((error = git_index_write_tree(&tree_id, index)) < 0 ||
b6b636a7 856 (error = git_tree_lookup(&tree, rebase->repo, &tree_id)) < 0)
a35a9890
ET
857 goto done;
858
859 if (!author)
f152f8ac 860 author = git_commit_author(current_commit);
a35a9890
ET
861
862 if (!message) {
f152f8ac
ET
863 message_encoding = git_commit_message_encoding(current_commit);
864 message = git_commit_message(current_commit);
a35a9890
ET
865 }
866
b6b636a7 867 if ((error = git_commit_create(commit_id, rebase->repo, NULL, author,
a35a9890 868 committer, message_encoding, message, tree, 1,
a612a25f 869 (const git_commit **)&head_commit)) < 0 ||
b6b636a7 870 (error = git_commit_lookup(&commit, rebase->repo, commit_id)) < 0 ||
a612a25f 871 (error = git_reference__update_for_commit(
b6b636a7 872 rebase->repo, NULL, "HEAD", commit_id, committer, "rebase")) < 0)
a35a9890
ET
873 goto done;
874
f152f8ac 875 git_oid_fmt(old_idstr, git_commit_id(current_commit));
a35a9890
ET
876 git_oid_fmt(new_idstr, commit_id);
877
b6b636a7 878 error = rebase_setupfile(rebase, REWRITTEN_FILE, O_CREAT|O_WRONLY|O_APPEND,
a35a9890
ET
879 "%.*s %.*s\n", GIT_OID_HEXSZ, old_idstr, GIT_OID_HEXSZ, new_idstr);
880
881done:
a612a25f
ET
882 git_buf_free(&reflog_msg);
883 git_commit_free(commit);
93a7004c 884 git_diff_free(diff);
a35a9890 885 git_tree_free(tree);
93a7004c 886 git_tree_free(head_tree);
a35a9890 887 git_commit_free(head_commit);
f152f8ac 888 git_commit_free(current_commit);
a35a9890
ET
889 git_reference_free(head);
890 git_index_free(index);
891
892 return error;
893}
894
895int git_rebase_commit(
896 git_oid *id,
b6b636a7 897 git_rebase *rebase,
a35a9890
ET
898 const git_signature *author,
899 const git_signature *committer,
900 const char *message_encoding,
901 const char *message)
902{
a35a9890
ET
903 int error;
904
b6b636a7 905 assert(rebase && committer);
a35a9890 906
b6b636a7 907 switch (rebase->type) {
a35a9890
ET
908 case GIT_REBASE_TYPE_MERGE:
909 error = rebase_commit_merge(
b6b636a7 910 id, rebase, author, committer, message_encoding, message);
a35a9890
ET
911 break;
912 default:
913 abort();
914 }
915
950a7091
ET
916 return error;
917}
918
b6b636a7 919int git_rebase_abort(git_rebase *rebase, const git_signature *signature)
4fe84d62 920{
4fe84d62
ET
921 git_reference *orig_head_ref = NULL;
922 git_commit *orig_head_commit = NULL;
923 int error;
924
b6b636a7 925 assert(rebase && signature);
4fe84d62 926
b6b636a7
ET
927 error = rebase->head_detached ?
928 git_reference_create(&orig_head_ref, rebase->repo, GIT_HEAD_FILE,
929 &rebase->orig_head_id, 1, signature, "rebase: aborting") :
4fe84d62 930 git_reference_symbolic_create(
b6b636a7 931 &orig_head_ref, rebase->repo, GIT_HEAD_FILE, rebase->orig_head_name, 1,
4fe84d62
ET
932 signature, "rebase: aborting");
933
934 if (error < 0)
935 goto done;
936
937 if ((error = git_commit_lookup(
b6b636a7
ET
938 &orig_head_commit, rebase->repo, &rebase->orig_head_id)) < 0 ||
939 (error = git_reset(rebase->repo, (git_object *)orig_head_commit,
4fe84d62
ET
940 GIT_RESET_HARD, NULL, signature, NULL)) < 0)
941 goto done;
942
b6b636a7 943 error = rebase_cleanup(rebase);
4fe84d62
ET
944
945done:
946 git_commit_free(orig_head_commit);
947 git_reference_free(orig_head_ref);
4fe84d62
ET
948
949 return error;
950}
517644cc 951
5ae9d296 952static int rebase_copy_note(
b6b636a7 953 git_rebase *rebase,
5ae9d296
ET
954 git_oid *from,
955 git_oid *to,
956 const git_signature *committer,
957 const git_rebase_options *opts)
517644cc 958{
5ae9d296
ET
959 git_note *note = NULL;
960 git_oid note_id;
961 int error;
962
b6b636a7 963 if ((error = git_note_read(&note, rebase->repo, opts->rewrite_notes_ref, from)) < 0) {
5ae9d296
ET
964 if (error == GIT_ENOTFOUND) {
965 giterr_clear();
966 error = 0;
967 }
968
969 goto done;
970 }
971
b6b636a7 972 error = git_note_create(&note_id, rebase->repo, git_note_author(note),
5ae9d296
ET
973 committer, opts->rewrite_notes_ref, to, git_note_message(note), 0);
974
975done:
976 git_note_free(note);
977
978 return error;
979}
980
981static int rebase_copy_notes(
b6b636a7 982 git_rebase *rebase,
5ae9d296
ET
983 const git_signature *committer,
984 const git_rebase_options *opts)
985{
986 git_buf path = GIT_BUF_INIT, rewritten = GIT_BUF_INIT;
987 char *pair_list, *fromstr, *tostr, *end;
988 git_oid from, to;
989 unsigned int linenum = 1;
990 int error = 0;
991
992 if (!opts->rewrite_notes_ref)
993 goto done;
994
b6b636a7 995 if ((error = git_buf_joinpath(&path, rebase->state_path, REWRITTEN_FILE)) < 0 ||
5ae9d296
ET
996 (error = git_futils_readbuffer(&rewritten, path.ptr)) < 0)
997 goto done;
998
999 pair_list = rewritten.ptr;
1000
1001 while (*pair_list) {
1002 fromstr = pair_list;
1003
1004 if ((end = strchr(fromstr, '\n')) == NULL)
1005 goto on_error;
1006
1007 pair_list = end+1;
1008 *end = '\0';
1009
1010 if ((end = strchr(fromstr, ' ')) == NULL)
1011 goto on_error;
1012
1013 tostr = end+1;
1014 *end = '\0';
1015
1016 if (strlen(fromstr) != GIT_OID_HEXSZ ||
1017 strlen(tostr) != GIT_OID_HEXSZ ||
1018 git_oid_fromstr(&from, fromstr) < 0 ||
1019 git_oid_fromstr(&to, tostr) < 0)
1020 goto on_error;
1021
b6b636a7 1022 if ((error = rebase_copy_note(rebase, &from, &to, committer, opts)) < 0)
5ae9d296
ET
1023 goto done;
1024
1025 linenum++;
1026 }
1027
1028 goto done;
1029
1030on_error:
1031 giterr_set(GITERR_REBASE, "Invalid rewritten file at line %d", linenum);
1032 error = -1;
1033
1034done:
1035 git_buf_free(&rewritten);
1036 git_buf_free(&path);
1037
1038 return error;
1039}
1040
1041int git_rebase_finish(
b6b636a7 1042 git_rebase *rebase,
5ae9d296
ET
1043 const git_signature *signature,
1044 const git_rebase_options *given_opts)
1045{
1046 git_rebase_options opts;
517644cc
ET
1047 git_reference *terminal_ref = NULL, *branch_ref = NULL, *head_ref = NULL;
1048 git_commit *terminal_commit = NULL;
1049 git_buf branch_msg = GIT_BUF_INIT, head_msg = GIT_BUF_INIT;
1050 char onto[GIT_OID_HEXSZ];
1051 int error;
1052
b6b636a7 1053 assert(rebase);
517644cc 1054
b6b636a7 1055 if ((error = rebase_normalize_opts(rebase->repo, &opts, given_opts)) < 0)
517644cc
ET
1056 goto done;
1057
b6b636a7 1058 git_oid_fmt(onto, &rebase->onto_id);
517644cc
ET
1059
1060 if ((error = git_buf_printf(&branch_msg, "rebase finished: %s onto %.*s",
b6b636a7 1061 rebase->orig_head_name, GIT_OID_HEXSZ, onto)) < 0 ||
517644cc 1062 (error = git_buf_printf(&head_msg, "rebase finished: returning to %s",
b6b636a7
ET
1063 rebase->orig_head_name)) < 0 ||
1064 (error = git_repository_head(&terminal_ref, rebase->repo)) < 0 ||
517644cc 1065 (error = git_reference_peel((git_object **)&terminal_commit,
5ae9d296
ET
1066 terminal_ref, GIT_OBJ_COMMIT)) < 0 ||
1067 (error = git_reference_create_matching(&branch_ref,
b6b636a7
ET
1068 rebase->repo, rebase->orig_head_name, git_commit_id(terminal_commit), 1,
1069 &rebase->orig_head_id, signature, branch_msg.ptr)) < 0 ||
517644cc 1070 (error = git_reference_symbolic_create(&head_ref,
b6b636a7 1071 rebase->repo, GIT_HEAD_FILE, rebase->orig_head_name, 1,
5ae9d296 1072 signature, head_msg.ptr)) < 0 ||
b6b636a7 1073 (error = rebase_copy_notes(rebase, signature, &opts)) < 0)
517644cc 1074 goto done;
5ae9d296 1075
b6b636a7 1076 error = rebase_cleanup(rebase);
517644cc
ET
1077
1078done:
1079 git_buf_free(&head_msg);
1080 git_buf_free(&branch_msg);
1081 git_commit_free(terminal_commit);
1082 git_reference_free(head_ref);
1083 git_reference_free(branch_ref);
1084 git_reference_free(terminal_ref);
5ae9d296 1085 rebase_opts_free(&opts);
517644cc
ET
1086
1087 return error;
1088}
1089
b6b636a7
ET
1090void git_rebase_free(git_rebase *rebase)
1091{
1092 if (rebase == NULL)
1093 return;
1094
f152f8ac 1095 git__free(rebase->onto_name);
b6b636a7
ET
1096 git__free(rebase->orig_head_name);
1097 git__free(rebase->state_path);
f152f8ac
ET
1098 git_array_clear(rebase->operations);
1099 git__free(rebase);
b6b636a7 1100}