source src/rebase.c
Line | Flow | Count | Block(s) | Source |
---|---|---|---|---|
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 | - | |||
10 | - | #include "buffer.h" | ||
11 | - | #include "repository.h" | ||
12 | - | #include "posix.h" | ||
13 | - | #include "filebuf.h" | ||
14 | - | #include "merge.h" | ||
15 | - | #include "array.h" | ||
16 | - | #include "config.h" | ||
17 | - | #include "annotated_commit.h" | ||
18 | - | #include "index.h" | ||
19 | - | |||
20 | - | #include <git2/types.h> | ||
21 | - | #include <git2/annotated_commit.h> | ||
22 | - | #include <git2/rebase.h> | ||
23 | - | #include <git2/commit.h> | ||
24 | - | #include <git2/reset.h> | ||
25 | - | #include <git2/revwalk.h> | ||
26 | - | #include <git2/notes.h> | ||
27 | - | |||
28 | - | #define REBASE_APPLY_DIR "rebase-apply" | ||
29 | - | #define REBASE_MERGE_DIR "rebase-merge" | ||
30 | - | |||
31 | - | #define HEAD_NAME_FILE "head-name" | ||
32 | - | #define ORIG_HEAD_FILE "orig-head" | ||
33 | - | #define HEAD_FILE "head" | ||
34 | - | #define ONTO_FILE "onto" | ||
35 | - | #define ONTO_NAME_FILE "onto_name" | ||
36 | - | #define QUIET_FILE "quiet" | ||
37 | - | |||
38 | - | #define MSGNUM_FILE "msgnum" | ||
39 | - | #define END_FILE "end" | ||
40 | - | #define CMT_FILE_FMT "cmt.%" PRIuZ | ||
41 | - | #define CURRENT_FILE "current" | ||
42 | - | #define REWRITTEN_FILE "rewritten" | ||
43 | - | |||
44 | - | #define ORIG_DETACHED_HEAD "detached HEAD" | ||
45 | - | |||
46 | - | #define NOTES_DEFAULT_REF NULL | ||
47 | - | |||
48 | - | #define REBASE_DIR_MODE 0777 | ||
49 | - | #define REBASE_FILE_MODE 0666 | ||
50 | - | |||
51 | - | typedef enum { | ||
52 | - | GIT_REBASE_NONE = 0, | ||
53 | - | GIT_REBASE_APPLY = 1, | ||
54 | - | GIT_REBASE_MERGE = 2, | ||
55 | - | GIT_REBASE_INTERACTIVE = 3, | ||
56 | - | } git_rebase_t; | ||
57 | - | |||
58 | - | struct git_rebase { | ||
59 | - | git_repository *repo; | ||
60 | - | |||
61 | - | git_rebase_options options; | ||
62 | - | |||
63 | - | git_rebase_t type; | ||
64 | - | char *state_path; | ||
65 | - | |||
66 | - | int head_detached : 1, | ||
67 | - | inmemory : 1, | ||
68 | - | quiet : 1, | ||
69 | - | started : 1; | ||
70 | - | |||
71 | - | git_array_t(git_rebase_operation) operations; | ||
72 | - | size_t current; | ||
73 | - | |||
74 | - | /* Used by in-memory rebase */ | ||
75 | - | git_index *index; | ||
76 | - | git_commit *last_commit; | ||
77 | - | |||
78 | - | /* Used by regular (not in-memory) merge-style rebase */ | ||
79 | - | git_oid orig_head_id; | ||
80 | - | char *orig_head_name; | ||
81 | - | |||
82 | - | git_oid onto_id; | ||
83 | - | char *onto_name; | ||
84 | - | }; | ||
85 | - | |||
86 | - | #define GIT_REBASE_STATE_INIT {0} | ||
87 | - | |||
88 | 53 | 2 | static int rebase_state_type( | |
89 | - | git_rebase_t *type_out, | ||
90 | - | char **path_out, | ||
91 | - | git_repository *repo) | ||
92 | - | { | ||
93 | 53 | 2 | git_buf path = GIT_BUF_INIT; | |
94 | 53 | 2 | git_rebase_t type = GIT_REBASE_NONE; | |
95 | - | |||
96 | 53 | 2,3 | if (git_buf_joinpath(&path, repo->gitdir, REBASE_APPLY_DIR) < 0) | |
97 | ##### | 4 | return -1; | |
98 | - | |||
99 | 53 | 5-7 | if (git_path_isdir(git_buf_cstr(&path))) { | |
100 | ##### | 8 | type = GIT_REBASE_APPLY; | |
101 | ##### | 8 | goto done; | |
102 | - | } | ||
103 | - | |||
104 | 53 | 9 | git_buf_clear(&path); | |
105 | 53 | 10,11 | if (git_buf_joinpath(&path, repo->gitdir, REBASE_MERGE_DIR) < 0) | |
106 | ##### | 12 | return -1; | |
107 | - | |||
108 | 53 | 13-15 | if (git_path_isdir(git_buf_cstr(&path))) { | |
109 | 8 | 16 | type = GIT_REBASE_MERGE; | |
110 | 8 | 16 | goto done; | |
111 | - | } | ||
112 | - | |||
113 | - | done: | ||
114 | 53 | 17 | *type_out = type; | |
115 | - | |||
116 | 53 | 17,18 | if (type != GIT_REBASE_NONE && path_out) | |
117 | 7 | 19,20 | *path_out = git_buf_detach(&path); | |
118 | - | |||
119 | 53 | 21 | git_buf_dispose(&path); | |
120 | - | |||
121 | 53 | 22 | return 0; | |
122 | - | } | ||
123 | - | |||
124 | 63 | 2 | GIT_INLINE(int) rebase_readfile( | |
125 | - | git_buf *out, | ||
126 | - | git_buf *state_path, | ||
127 | - | const char *filename) | ||
128 | - | { | ||
129 | 63 | 2 | size_t state_path_len = state_path->size; | |
130 | - | int error; | ||
131 | - | |||
132 | 63 | 2 | git_buf_clear(out); | |
133 | - | |||
134 | 63 | 3-6 | if ((error = git_buf_joinpath(state_path, state_path->ptr, filename)) < 0 || | |
135 | 63 | 5 | (error = git_futils_readbuffer(out, state_path->ptr)) < 0) | |
136 | - | goto done; | ||
137 | - | |||
138 | 51 | 7 | git_buf_rtrim(out); | |
139 | - | |||
140 | - | done: | ||
141 | 63 | 8 | git_buf_truncate(state_path, state_path_len); | |
142 | 63 | 9 | return error; | |
143 | - | } | ||
144 | - | |||
145 | 14 | 2 | GIT_INLINE(int) rebase_readint( | |
146 | - | size_t *out, git_buf *asc_out, git_buf *state_path, const char *filename) | ||
147 | - | { | ||
148 | - | int32_t num; | ||
149 | - | const char *eol; | ||
150 | 14 | 2 | int error = 0; | |
151 | - | |||
152 | 14 | 2,3 | if ((error = rebase_readfile(asc_out, state_path, filename)) < 0) | |
153 | 6 | 4 | return error; | |
154 | - | |||
155 | 8 | 5-8 | if (git__strntol32(&num, asc_out->ptr, asc_out->size, &eol, 10) < 0 || num < 0 || *eol) { | |
156 | ##### | 9 | git_error_set(GIT_ERROR_REBASE, "the file '%s' contains an invalid numeric value", filename); | |
157 | ##### | 10 | return -1; | |
158 | - | } | ||
159 | - | |||
160 | 8 | 11 | *out = (size_t) num; | |
161 | - | |||
162 | 8 | 11 | return 0; | |
163 | - | } | ||
164 | - | |||
165 | 42 | 2 | GIT_INLINE(int) rebase_readoid( | |
166 | - | git_oid *out, git_buf *str_out, git_buf *state_path, const char *filename) | ||
167 | - | { | ||
168 | - | int error; | ||
169 | - | |||
170 | 42 | 2,3 | if ((error = rebase_readfile(str_out, state_path, filename)) < 0) | |
171 | 6 | 4 | return error; | |
172 | - | |||
173 | 36 | 5-7 | if (str_out->size != GIT_OID_HEXSZ || git_oid_fromstr(out, str_out->ptr) < 0) { | |
174 | ##### | 8 | git_error_set(GIT_ERROR_REBASE, "the file '%s' contains an invalid object ID", filename); | |
175 | ##### | 9 | return -1; | |
176 | - | } | ||
177 | - | |||
178 | 36 | 10 | return 0; | |
179 | - | } | ||
180 | - | |||
181 | 212 | 2 | static git_rebase_operation *rebase_operation_alloc( | |
182 | - | git_rebase *rebase, | ||
183 | - | git_rebase_operation_t type, | ||
184 | - | git_oid *id, | ||
185 | - | const char *exec) | ||
186 | - | { | ||
187 | - | git_rebase_operation *operation; | ||
188 | - | |||
189 | 212 | 2,3 | assert((type == GIT_REBASE_OPERATION_EXEC) == !id); | |
190 | 212 | 4,5 | assert((type == GIT_REBASE_OPERATION_EXEC) == !!exec); | |
191 | - | |||
192 | 212 | 6-12 | if ((operation = git_array_alloc(rebase->operations)) == NULL) | |
193 | ##### | 13 | return NULL; | |
194 | - | |||
195 | 212 | 14 | operation->type = type; | |
196 | 212 | 14 | git_oid_cpy((git_oid *)&operation->id, id); | |
197 | 212 | 15 | operation->exec = exec; | |
198 | - | |||
199 | 212 | 15 | return operation; | |
200 | - | } | ||
201 | - | |||
202 | 7 | 2 | static int rebase_open_merge(git_rebase *rebase) | |
203 | - | { | ||
204 | 7 | 2 | git_buf state_path = GIT_BUF_INIT, buf = GIT_BUF_INIT, cmt = GIT_BUF_INIT; | |
205 | - | git_oid id; | ||
206 | - | git_rebase_operation *operation; | ||
207 | 7 | 2 | size_t i, msgnum = 0, end; | |
208 | - | int error; | ||
209 | - | |||
210 | 7 | 2,3 | if ((error = git_buf_puts(&state_path, rebase->state_path)) < 0) | |
211 | ##### | 4 | goto done; | |
212 | - | |||
213 | - | /* Read 'msgnum' if it exists (otherwise, let msgnum = 0) */ | ||
214 | 7 | 5-7 | if ((error = rebase_readint(&msgnum, &buf, &state_path, MSGNUM_FILE)) < 0 && | |
215 | - | error != GIT_ENOTFOUND) | ||
216 | ##### | 8 | goto done; | |
217 | - | |||
218 | 7 | 9 | if (msgnum) { | |
219 | 1 | 10 | rebase->started = 1; | |
220 | 1 | 10 | rebase->current = msgnum - 1; | |
221 | - | } | ||
222 | - | |||
223 | - | /* Read 'end' */ | ||
224 | 7 | 11,12 | if ((error = rebase_readint(&end, &buf, &state_path, END_FILE)) < 0) | |
225 | ##### | 13 | goto done; | |
226 | - | |||
227 | - | /* Read 'current' if it exists */ | ||
228 | 7 | 14-16 | if ((error = rebase_readoid(&id, &buf, &state_path, CURRENT_FILE)) < 0 && | |
229 | - | error != GIT_ENOTFOUND) | ||
230 | ##### | 17 | goto done; | |
231 | - | |||
232 | - | /* Read cmt.* */ | ||
233 | 7 | 18 | git_array_init_to_size(rebase->operations, end); | |
234 | 7 | 19,20 | GIT_ERROR_CHECK_ARRAY(rebase->operations); | |
235 | - | |||
236 | 42 | 21,30,31 | for (i = 0; i < end; i++) { | |
237 | 35 | 22 | git_buf_clear(&cmt); | |
238 | - | |||
239 | 35 | 23-26 | if ((error = git_buf_printf(&cmt, "cmt.%" PRIuZ, (i+1))) < 0 || | |
240 | 35 | 25 | (error = rebase_readoid(&id, &buf, &state_path, cmt.ptr)) < 0) | |
241 | - | goto done; | ||
242 | - | |||
243 | 35 | 27 | operation = rebase_operation_alloc(rebase, GIT_REBASE_OPERATION_PICK, &id, NULL); | |
244 | 35 | 28,29 | GIT_ERROR_CHECK_ALLOC(operation); | |
245 | - | } | ||
246 | - | |||
247 | - | /* Read 'onto_name' */ | ||
248 | 7 | 32,33 | if ((error = rebase_readfile(&buf, &state_path, ONTO_NAME_FILE)) < 0) | |
249 | ##### | 34 | goto done; | |
250 | - | |||
251 | 7 | 35,36 | rebase->onto_name = git_buf_detach(&buf); | |
252 | - | |||
253 | - | done: | ||
254 | 7 | 37 | git_buf_dispose(&cmt); | |
255 | 7 | 38 | git_buf_dispose(&state_path); | |
256 | 7 | 39 | git_buf_dispose(&buf); | |
257 | - | |||
258 | 7 | 40 | return error; | |
259 | - | } | ||
260 | - | |||
261 | 55 | 2 | static int rebase_alloc(git_rebase **out, const git_rebase_options *rebase_opts) | |
262 | - | { | ||
263 | 55 | 2 | git_rebase *rebase = git__calloc(1, sizeof(git_rebase)); | |
264 | 55 | 3,4 | GIT_ERROR_CHECK_ALLOC(rebase); | |
265 | - | |||
266 | 55 | 5 | *out = NULL; | |
267 | - | |||
268 | 55 | 5 | if (rebase_opts) | |
269 | 12 | 6 | memcpy(&rebase->options, rebase_opts, sizeof(git_rebase_options)); | |
270 | - | else | ||
271 | 43 | 7 | git_rebase_options_init(&rebase->options, GIT_REBASE_OPTIONS_VERSION); | |
272 | - | |||
273 | 55 | 8,9 | if (rebase_opts && rebase_opts->rewrite_notes_ref) { | |
274 | 1 | 10 | rebase->options.rewrite_notes_ref = git__strdup(rebase_opts->rewrite_notes_ref); | |
275 | 1 | 11,12 | GIT_ERROR_CHECK_ALLOC(rebase->options.rewrite_notes_ref); | |
276 | - | } | ||
277 | - | |||
278 | 55 | 13 | *out = rebase; | |
279 | - | |||
280 | 55 | 13 | return 0; | |
281 | - | } | ||
282 | - | |||
283 | 58 | 2 | static int rebase_check_versions(const git_rebase_options *given_opts) | |
284 | - | { | ||
285 | 58 | 2-4 | GIT_ERROR_CHECK_VERSION(given_opts, GIT_REBASE_OPTIONS_VERSION, "git_rebase_options"); | |
286 | - | |||
287 | 58 | 5 | if (given_opts) | |
288 | 12 | 6-8 | GIT_ERROR_CHECK_VERSION(&given_opts->checkout_options, GIT_CHECKOUT_OPTIONS_VERSION, "git_checkout_options"); | |
289 | - | |||
290 | 58 | 9 | return 0; | |
291 | - | } | ||
292 | - | |||
293 | 7 | 2 | int git_rebase_open( | |
294 | - | git_rebase **out, | ||
295 | - | git_repository *repo, | ||
296 | - | const git_rebase_options *given_opts) | ||
297 | - | { | ||
298 | - | git_rebase *rebase; | ||
299 | 7 | 2 | git_buf path = GIT_BUF_INIT, orig_head_name = GIT_BUF_INIT, | |
300 | 7 | 2 | orig_head_id = GIT_BUF_INIT, onto_id = GIT_BUF_INIT; | |
301 | - | size_t state_path_len; | ||
302 | - | int error; | ||
303 | - | |||
304 | 7 | 2,3 | assert(repo); | |
305 | - | |||
306 | 7 | 4,5 | if ((error = rebase_check_versions(given_opts)) < 0) | |
307 | ##### | 6 | return error; | |
308 | - | |||
309 | 7 | 7,8 | if (rebase_alloc(&rebase, given_opts) < 0) | |
310 | ##### | 9 | return -1; | |
311 | - | |||
312 | 7 | 10 | rebase->repo = repo; | |
313 | - | |||
314 | 7 | 10,11 | if ((error = rebase_state_type(&rebase->type, &rebase->state_path, repo)) < 0) | |
315 | ##### | 12 | goto done; | |
316 | - | |||
317 | 7 | 13 | if (rebase->type == GIT_REBASE_NONE) { | |
318 | ##### | 14 | git_error_set(GIT_ERROR_REBASE, "there is no rebase in progress"); | |
319 | ##### | 15 | error = GIT_ENOTFOUND; | |
320 | ##### | 15 | goto done; | |
321 | - | } | ||
322 | - | |||
323 | 7 | 16,17 | if ((error = git_buf_puts(&path, rebase->state_path)) < 0) | |
324 | ##### | 18 | goto done; | |
325 | - | |||
326 | 7 | 19 | state_path_len = git_buf_len(&path); | |
327 | - | |||
328 | 7 | 20-23 | if ((error = git_buf_joinpath(&path, path.ptr, HEAD_NAME_FILE)) < 0 || | |
329 | 7 | 22 | (error = git_futils_readbuffer(&orig_head_name, path.ptr)) < 0) | |
330 | - | goto done; | ||
331 | - | |||
332 | 7 | 24 | git_buf_rtrim(&orig_head_name); | |
333 | - | |||
334 | 7 | 25 | if (strcmp(ORIG_DETACHED_HEAD, orig_head_name.ptr) == 0) | |
335 | 3 | 26 | rebase->head_detached = 1; | |
336 | - | |||
337 | 7 | 27 | git_buf_truncate(&path, state_path_len); | |
338 | - | |||
339 | 7 | 28,29 | if ((error = git_buf_joinpath(&path, path.ptr, ORIG_HEAD_FILE)) < 0) | |
340 | ##### | 30 | goto done; | |
341 | - | |||
342 | 7 | 31,32 | if (!git_path_isfile(path.ptr)) { | |
343 | - | /* Previous versions of git.git used 'head' here; support that. */ | ||
344 | ##### | 33 | git_buf_truncate(&path, state_path_len); | |
345 | - | |||
346 | ##### | 34,35 | if ((error = git_buf_joinpath(&path, path.ptr, HEAD_FILE)) < 0) | |
347 | ##### | 36 | goto done; | |
348 | - | } | ||
349 | - | |||
350 | 7 | 37,38 | if ((error = git_futils_readbuffer(&orig_head_id, path.ptr)) < 0) | |
351 | ##### | 39 | goto done; | |
352 | - | |||
353 | 7 | 40 | git_buf_rtrim(&orig_head_id); | |
354 | - | |||
355 | 7 | 41,42 | if ((error = git_oid_fromstr(&rebase->orig_head_id, orig_head_id.ptr)) < 0) | |
356 | ##### | 43 | goto done; | |
357 | - | |||
358 | 7 | 44 | git_buf_truncate(&path, state_path_len); | |
359 | - | |||
360 | 7 | 45-48 | if ((error = git_buf_joinpath(&path, path.ptr, ONTO_FILE)) < 0 || | |
361 | 7 | 47 | (error = git_futils_readbuffer(&onto_id, path.ptr)) < 0) | |
362 | - | goto done; | ||
363 | - | |||
364 | 7 | 49 | git_buf_rtrim(&onto_id); | |
365 | - | |||
366 | 7 | 50,51 | if ((error = git_oid_fromstr(&rebase->onto_id, onto_id.ptr)) < 0) | |
367 | ##### | 52 | goto done; | |
368 | - | |||
369 | 7 | 53 | if (!rebase->head_detached) | |
370 | 4 | 54,55 | rebase->orig_head_name = git_buf_detach(&orig_head_name); | |
371 | - | |||
372 | 7 | 56 | switch (rebase->type) { | |
373 | - | case GIT_REBASE_INTERACTIVE: | ||
374 | ##### | 57 | git_error_set(GIT_ERROR_REBASE, "interactive rebase is not supported"); | |
375 | ##### | 58 | error = -1; | |
376 | ##### | 58 | break; | |
377 | - | case GIT_REBASE_MERGE: | ||
378 | 7 | 59 | error = rebase_open_merge(rebase); | |
379 | 7 | 63 | break; | |
380 | - | case GIT_REBASE_APPLY: | ||
381 | ##### | 60 | git_error_set(GIT_ERROR_REBASE, "patch application rebase is not supported"); | |
382 | ##### | 61 | error = -1; | |
383 | ##### | 61 | break; | |
384 | - | default: | ||
385 | - | 62 | abort(); | |
386 | - | } | ||
387 | - | |||
388 | - | done: | ||
389 | 7 | 64 | if (error == 0) | |
390 | 7 | 65 | *out = rebase; | |
391 | - | else | ||
392 | ##### | 66 | git_rebase_free(rebase); | |
393 | - | |||
394 | 7 | 67 | git_buf_dispose(&path); | |
395 | 7 | 68 | git_buf_dispose(&orig_head_name); | |
396 | 7 | 69 | git_buf_dispose(&orig_head_id); | |
397 | 7 | 70 | git_buf_dispose(&onto_id); | |
398 | 7 | 71 | return error; | |
399 | - | } | ||
400 | - | |||
401 | 19 | 2 | static int rebase_cleanup(git_rebase *rebase) | |
402 | - | { | ||
403 | 19 | 2,3 | if (!rebase || rebase->inmemory) | |
404 | 3 | 4 | return 0; | |
405 | - | |||
406 | 16 | 5 | return git_path_isdir(rebase->state_path) ? | |
407 | 16 | 6-8 | git_futils_rmdir_r(rebase->state_path, NULL, GIT_RMDIR_REMOVE_FILES) : | |
408 | - | 0; | ||
409 | - | } | ||
410 | - | |||
411 | 525 | 2 | static int rebase_setupfile(git_rebase *rebase, const char *filename, int flags, const char *fmt, ...) | |
412 | - | { | ||
413 | 525 | 2 | git_buf path = GIT_BUF_INIT, | |
414 | 525 | 2 | contents = GIT_BUF_INIT; | |
415 | - | va_list ap; | ||
416 | - | int error; | ||
417 | - | |||
418 | 525 | 2 | va_start(ap, fmt); | |
419 | 525 | 2 | git_buf_vprintf(&contents, fmt, ap); | |
420 | 525 | 3 | va_end(ap); | |
421 | - | |||
422 | 525 | 3,4 | if ((error = git_buf_joinpath(&path, rebase->state_path, filename)) == 0) | |
423 | 525 | 5 | error = git_futils_writebuffer(&contents, path.ptr, flags, REBASE_FILE_MODE); | |
424 | - | |||
425 | 525 | 6 | git_buf_dispose(&path); | |
426 | 525 | 7 | git_buf_dispose(&contents); | |
427 | - | |||
428 | 525 | 8 | return error; | |
429 | - | } | ||
430 | - | |||
431 | 86 | 2 | static const char *rebase_onto_name(const git_annotated_commit *onto) | |
432 | - | { | ||
433 | 86 | 2,3 | if (onto->ref_name && git__strncmp(onto->ref_name, "refs/heads/", 11) == 0) | |
434 | 70 | 4 | return onto->ref_name + 11; | |
435 | 16 | 5 | else if (onto->ref_name) | |
436 | ##### | 6 | return onto->ref_name; | |
437 | - | else | ||
438 | 16 | 7 | return onto->id_str; | |
439 | - | } | ||
440 | - | |||
441 | 43 | 2 | static int rebase_setupfiles_merge(git_rebase *rebase) | |
442 | - | { | ||
443 | 43 | 2 | git_buf commit_filename = GIT_BUF_INIT; | |
444 | - | char id_str[GIT_OID_HEXSZ]; | ||
445 | - | git_rebase_operation *operation; | ||
446 | - | size_t i; | ||
447 | 43 | 2 | int error = 0; | |
448 | - | |||
449 | 43 | 2-5 | if ((error = rebase_setupfile(rebase, END_FILE, 0, "%" PRIuZ "\n", git_array_size(rebase->operations))) < 0 || | |
450 | 43 | 4 | (error = rebase_setupfile(rebase, ONTO_NAME_FILE, 0, "%s\n", rebase->onto_name)) < 0) | |
451 | - | goto done; | ||
452 | - | |||
453 | 199 | 6,16,17 | for (i = 0; i < git_array_size(rebase->operations); i++) { | |
454 | 156 | 7-9 | operation = git_array_get(rebase->operations, i); | |
455 | - | |||
456 | 156 | 10 | git_buf_clear(&commit_filename); | |
457 | 156 | 11 | git_buf_printf(&commit_filename, CMT_FILE_FMT, i+1); | |
458 | - | |||
459 | 156 | 12 | git_oid_fmt(id_str, &operation->id); | |
460 | - | |||
461 | 156 | 13,14 | if ((error = rebase_setupfile(rebase, commit_filename.ptr, 0, | |
462 | - | "%.*s\n", GIT_OID_HEXSZ, id_str)) < 0) | ||
463 | ##### | 15 | goto done; | |
464 | - | } | ||
465 | - | |||
466 | - | done: | ||
467 | 43 | 18 | git_buf_dispose(&commit_filename); | |
468 | 43 | 19 | return error; | |
469 | - | } | ||
470 | - | |||
471 | 43 | 2 | static int rebase_setupfiles(git_rebase *rebase) | |
472 | - | { | ||
473 | - | char onto[GIT_OID_HEXSZ], orig_head[GIT_OID_HEXSZ]; | ||
474 | - | const char *orig_head_name; | ||
475 | - | |||
476 | 43 | 2 | git_oid_fmt(onto, &rebase->onto_id); | |
477 | 43 | 3 | git_oid_fmt(orig_head, &rebase->orig_head_id); | |
478 | - | |||
479 | 43 | 4,5 | if (p_mkdir(rebase->state_path, REBASE_DIR_MODE) < 0) { | |
480 | ##### | 6 | git_error_set(GIT_ERROR_OS, "failed to create rebase directory '%s'", rebase->state_path); | |
481 | ##### | 7 | return -1; | |
482 | - | } | ||
483 | - | |||
484 | 43 | 8-10 | orig_head_name = rebase->head_detached ? ORIG_DETACHED_HEAD : | |
485 | - | rebase->orig_head_name; | ||
486 | - | |||
487 | 43 | 11,12,14 | if (git_repository__set_orig_head(rebase->repo, &rebase->orig_head_id) < 0 || | |
488 | 43 | 13,16 | rebase_setupfile(rebase, HEAD_NAME_FILE, 0, "%s\n", orig_head_name) < 0 || | |
489 | 43 | 15,18 | rebase_setupfile(rebase, ONTO_FILE, 0, "%.*s\n", GIT_OID_HEXSZ, onto) < 0 || | |
490 | 43 | 17,23 | rebase_setupfile(rebase, ORIG_HEAD_FILE, 0, "%.*s\n", GIT_OID_HEXSZ, orig_head) < 0 || | |
491 | 43 | 19-22 | rebase_setupfile(rebase, QUIET_FILE, 0, rebase->quiet ? "t\n" : "\n") < 0) | |
492 | ##### | 24 | return -1; | |
493 | - | |||
494 | 43 | 25 | return rebase_setupfiles_merge(rebase); | |
495 | - | } | ||
496 | - | |||
497 | 43 | 2 | int git_rebase_options_init(git_rebase_options *opts, unsigned int version) | |
498 | - | { | ||
499 | 43 | 2-4 | GIT_INIT_STRUCTURE_FROM_TEMPLATE( | |
500 | - | opts, version, git_rebase_options, GIT_REBASE_OPTIONS_INIT); | ||
501 | 43 | 5 | return 0; | |
502 | - | } | ||
503 | - | |||
504 | - | #ifndef GIT_DEPRECATE_HARD | ||
505 | ##### | 2 | int git_rebase_init_options(git_rebase_options *opts, unsigned int version) | |
506 | - | { | ||
507 | ##### | 2 | return git_rebase_options_init(opts, version); | |
508 | - | } | ||
509 | - | #endif | ||
510 | - | |||
511 | 46 | 2 | static int rebase_ensure_not_in_progress(git_repository *repo) | |
512 | - | { | ||
513 | - | int error; | ||
514 | - | git_rebase_t type; | ||
515 | - | |||
516 | 46 | 2,3 | if ((error = rebase_state_type(&type, NULL, repo)) < 0) | |
517 | ##### | 4 | return error; | |
518 | - | |||
519 | 46 | 5 | if (type != GIT_REBASE_NONE) { | |
520 | 1 | 6 | git_error_set(GIT_ERROR_REBASE, "there is an existing rebase in progress"); | |
521 | 1 | 7 | return -1; | |
522 | - | } | ||
523 | - | |||
524 | 45 | 8 | return 0; | |
525 | - | } | ||
526 | - | |||
527 | 81 | 2 | static int rebase_ensure_not_dirty( | |
528 | - | git_repository *repo, | ||
529 | - | bool check_index, | ||
530 | - | bool check_workdir, | ||
531 | - | int fail_with) | ||
532 | - | { | ||
533 | 81 | 2 | git_tree *head = NULL; | |
534 | 81 | 2 | git_index *index = NULL; | |
535 | 81 | 2 | git_diff *diff = NULL; | |
536 | 81 | 2 | int error = 0; | |
537 | - | |||
538 | 81 | 2 | if (check_index) { | |
539 | 45 | 3-6 | if ((error = git_repository_head_tree(&head, repo)) < 0 || | |
540 | 45 | 7,8 | (error = git_repository_index(&index, repo)) < 0 || | |
541 | 45 | 7 | (error = git_diff_tree_to_index(&diff, repo, head, index, NULL)) < 0) | |
542 | - | goto done; | ||
543 | - | |||
544 | 45 | 9,10 | if (git_diff_num_deltas(diff) > 0) { | |
545 | 1 | 11 | git_error_set(GIT_ERROR_REBASE, "uncommitted changes exist in index"); | |
546 | 1 | 12 | error = fail_with; | |
547 | 1 | 12 | goto done; | |
548 | - | } | ||
549 | - | |||
550 | 44 | 13 | git_diff_free(diff); | |
551 | 44 | 14 | diff = NULL; | |
552 | - | } | ||
553 | - | |||
554 | 80 | 15 | if (check_workdir) { | |
555 | 80 | 16 | git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; | |
556 | 80 | 16 | diff_opts.ignore_submodules = GIT_SUBMODULE_IGNORE_UNTRACKED; | |
557 | 80 | 16,17 | if ((error = git_diff_index_to_workdir(&diff, repo, index, &diff_opts)) < 0) | |
558 | 3 | 18,24 | goto done; | |
559 | - | |||
560 | 80 | 19,20 | if (git_diff_num_deltas(diff) > 0) { | |
561 | 3 | 21 | git_error_set(GIT_ERROR_REBASE, "unstaged changes exist in workdir"); | |
562 | 3 | 22 | error = fail_with; | |
563 | 77 | 22,23 | goto done; | |
564 | - | } | ||
565 | - | } | ||
566 | - | |||
567 | - | done: | ||
568 | 81 | 25 | git_diff_free(diff); | |
569 | 81 | 26 | git_index_free(index); | |
570 | 81 | 27 | git_tree_free(head); | |
571 | - | |||
572 | 81 | 28 | return error; | |
573 | - | } | ||
574 | - | |||
575 | 48 | 2 | static int rebase_init_operations( | |
576 | - | git_rebase *rebase, | ||
577 | - | git_repository *repo, | ||
578 | - | const git_annotated_commit *branch, | ||
579 | - | const git_annotated_commit *upstream, | ||
580 | - | const git_annotated_commit *onto) | ||
581 | - | { | ||
582 | 48 | 2 | git_revwalk *revwalk = NULL; | |
583 | - | git_commit *commit; | ||
584 | - | git_oid id; | ||
585 | - | bool merge; | ||
586 | - | git_rebase_operation *operation; | ||
587 | - | int error; | ||
588 | - | |||
589 | 48 | 2 | if (!upstream) | |
590 | 8 | 3 | upstream = onto; | |
591 | - | |||
592 | 48 | 4,5,7,8 | if ((error = git_revwalk_new(&revwalk, rebase->repo)) < 0 || | |
593 | 48 | 6,10,11 | (error = git_revwalk_push(revwalk, git_annotated_commit_id(branch))) < 0 || | |
594 | 48 | 9 | (error = git_revwalk_hide(revwalk, git_annotated_commit_id(upstream))) < 0) | |
595 | - | goto done; | ||
596 | - | |||
597 | 48 | 12 | git_revwalk_sorting(revwalk, GIT_SORT_REVERSE); | |
598 | - | |||
599 | 227 | 23-25 | while ((error = git_revwalk_next(&id, revwalk)) == 0) { | |
600 | 179 | 13,14 | if ((error = git_commit_lookup(&commit, repo, &id)) < 0) | |
601 | ##### | 15 | goto done; | |
602 | - | |||
603 | 179 | 16 | merge = (git_commit_parentcount(commit) > 1); | |
604 | 179 | 17 | git_commit_free(commit); | |
605 | - | |||
606 | 179 | 18 | if (merge) | |
607 | 2 | 19 | continue; | |
608 | - | |||
609 | 177 | 20 | operation = rebase_operation_alloc(rebase, GIT_REBASE_OPERATION_PICK, &id, NULL); | |
610 | 177 | 21,22 | GIT_ERROR_CHECK_ALLOC(operation); | |
611 | - | } | ||
612 | - | |||
613 | 48 | 26 | error = 0; | |
614 | - | |||
615 | - | done: | ||
616 | 48 | 27 | git_revwalk_free(revwalk); | |
617 | 48 | 28 | return error; | |
618 | - | } | ||
619 | - | |||
620 | 43 | 2 | static int rebase_init_merge( | |
621 | - | git_rebase *rebase, | ||
622 | - | git_repository *repo, | ||
623 | - | const git_annotated_commit *branch, | ||
624 | - | const git_annotated_commit *upstream, | ||
625 | - | const git_annotated_commit *onto) | ||
626 | - | { | ||
627 | 43 | 2 | git_reference *head_ref = NULL; | |
628 | 43 | 2 | git_commit *onto_commit = NULL; | |
629 | 43 | 2 | git_buf reflog = GIT_BUF_INIT; | |
630 | 43 | 2 | git_buf state_path = GIT_BUF_INIT; | |
631 | - | int error; | ||
632 | - | |||
633 | - | GIT_UNUSED(upstream); | ||
634 | - | |||
635 | 43 | 2,3 | if ((error = git_buf_joinpath(&state_path, repo->gitdir, REBASE_MERGE_DIR)) < 0) | |
636 | ##### | 4 | goto done; | |
637 | - | |||
638 | 43 | 5 | rebase->state_path = git_buf_detach(&state_path); | |
639 | 43 | 6,7 | GIT_ERROR_CHECK_ALLOC(rebase->state_path); | |
640 | - | |||
641 | 43 | 8,9 | if (branch->ref_name && strcmp(branch->ref_name, "HEAD")) { | |
642 | 34 | 10 | rebase->orig_head_name = git__strdup(branch->ref_name); | |
643 | 34 | 11-13 | GIT_ERROR_CHECK_ALLOC(rebase->orig_head_name); | |
644 | - | } else { | ||
645 | 9 | 14 | rebase->head_detached = 1; | |
646 | - | } | ||
647 | - | |||
648 | 43 | 15,16 | rebase->onto_name = git__strdup(rebase_onto_name(onto)); | |
649 | 43 | 17,18 | GIT_ERROR_CHECK_ALLOC(rebase->onto_name); | |
650 | - | |||
651 | 43 | 19 | rebase->quiet = rebase->options.quiet; | |
652 | - | |||
653 | 43 | 19,20 | git_oid_cpy(&rebase->orig_head_id, git_annotated_commit_id(branch)); | |
654 | 43 | 21,22 | git_oid_cpy(&rebase->onto_id, git_annotated_commit_id(onto)); | |
655 | - | |||
656 | 43 | 23,24,26,27 | if ((error = rebase_setupfiles(rebase)) < 0 || | |
657 | 43 | 25 | (error = git_buf_printf(&reflog, | |
658 | 43 | 29,30 | "rebase: checkout %s", rebase_onto_name(onto))) < 0 || | |
659 | 43 | 28 | (error = git_commit_lookup( | |
660 | 43 | 31,32 | &onto_commit, repo, git_annotated_commit_id(onto))) < 0 || | |
661 | 43 | 31 | (error = git_checkout_tree(repo, | |
662 | 43 | 31,34 | (git_object *)onto_commit, &rebase->options.checkout_options)) < 0 || | |
663 | 43 | 33 | (error = git_reference_create(&head_ref, repo, GIT_HEAD_FILE, | |
664 | 43 | 33 | git_annotated_commit_id(onto), 1, reflog.ptr)) < 0) | |
665 | - | goto done; | ||
666 | - | |||
667 | - | done: | ||
668 | 43 | 35 | git_reference_free(head_ref); | |
669 | 43 | 36 | git_commit_free(onto_commit); | |
670 | 43 | 37 | git_buf_dispose(&reflog); | |
671 | 43 | 38 | git_buf_dispose(&state_path); | |
672 | - | |||
673 | 43 | 39 | return error; | |
674 | - | } | ||
675 | - | |||
676 | 5 | 2 | static int rebase_init_inmemory( | |
677 | - | git_rebase *rebase, | ||
678 | - | git_repository *repo, | ||
679 | - | const git_annotated_commit *branch, | ||
680 | - | const git_annotated_commit *upstream, | ||
681 | - | const git_annotated_commit *onto) | ||
682 | - | { | ||
683 | - | GIT_UNUSED(branch); | ||
684 | - | GIT_UNUSED(upstream); | ||
685 | - | |||
686 | 5 | 2 | return git_commit_lookup( | |
687 | - | &rebase->last_commit, repo, git_annotated_commit_id(onto)); | ||
688 | - | } | ||
689 | - | |||
690 | 51 | 2 | int git_rebase_init( | |
691 | - | git_rebase **out, | ||
692 | - | git_repository *repo, | ||
693 | - | const git_annotated_commit *branch, | ||
694 | - | const git_annotated_commit *upstream, | ||
695 | - | const git_annotated_commit *onto, | ||
696 | - | const git_rebase_options *given_opts) | ||
697 | - | { | ||
698 | 51 | 2 | git_rebase *rebase = NULL; | |
699 | 51 | 2 | git_annotated_commit *head_branch = NULL; | |
700 | 51 | 2 | git_reference *head_ref = NULL; | |
701 | 51 | 2-5 | bool inmemory = (given_opts && given_opts->inmemory); | |
702 | - | int error; | ||
703 | - | |||
704 | 51 | 6-9 | assert(repo && (upstream || onto)); | |
705 | - | |||
706 | 51 | 10 | *out = NULL; | |
707 | - | |||
708 | 51 | 10 | if (!onto) | |
709 | 40 | 11 | onto = upstream; | |
710 | - | |||
711 | 51 | 12,13 | if ((error = rebase_check_versions(given_opts)) < 0) | |
712 | ##### | 14 | goto done; | |
713 | - | |||
714 | 51 | 15 | if (!inmemory) { | |
715 | 46 | 16-19 | if ((error = git_repository__ensure_not_bare(repo, "rebase")) < 0 || | |
716 | 45 | 20,21 | (error = rebase_ensure_not_in_progress(repo)) < 0 || | |
717 | - | (error = rebase_ensure_not_dirty(repo, true, true, GIT_ERROR)) < 0) | ||
718 | - | goto done; | ||
719 | - | } | ||
720 | - | |||
721 | 48 | 22 | if (!branch) { | |
722 | 2 | 23-26 | if ((error = git_repository_head(&head_ref, repo)) < 0 || | |
723 | 2 | 25 | (error = git_annotated_commit_from_ref(&head_branch, repo, head_ref)) < 0) | |
724 | - | goto done; | ||
725 | - | |||
726 | 2 | 27 | branch = head_branch; | |
727 | - | } | ||
728 | - | |||
729 | 48 | 28,29 | if (rebase_alloc(&rebase, given_opts) < 0) | |
730 | ##### | 30 | return -1; | |
731 | - | |||
732 | 48 | 31 | rebase->repo = repo; | |
733 | 48 | 31 | rebase->inmemory = inmemory; | |
734 | 48 | 31 | rebase->type = GIT_REBASE_MERGE; | |
735 | - | |||
736 | 48 | 31,32 | if ((error = rebase_init_operations(rebase, repo, branch, upstream, onto)) < 0) | |
737 | ##### | 33 | goto done; | |
738 | - | |||
739 | 48 | 34 | if (inmemory) | |
740 | 5 | 35 | error = rebase_init_inmemory(rebase, repo, branch, upstream, onto); | |
741 | - | else | ||
742 | 43 | 36 | error = rebase_init_merge(rebase, repo, branch ,upstream, onto); | |
743 | - | |||
744 | 48 | 37 | if (error == 0) | |
745 | 48 | 38 | *out = rebase; | |
746 | - | |||
747 | - | done: | ||
748 | 51 | 39 | git_reference_free(head_ref); | |
749 | 51 | 40 | git_annotated_commit_free(head_branch); | |
750 | - | |||
751 | 51 | 41 | if (error < 0) { | |
752 | 3 | 42 | rebase_cleanup(rebase); | |
753 | 3 | 43 | git_rebase_free(rebase); | |
754 | - | } | ||
755 | - | |||
756 | 51 | 44 | return error; | |
757 | - | } | ||
758 | - | |||
759 | 39 | 2 | static void normalize_checkout_options_for_apply( | |
760 | - | git_checkout_options *checkout_opts, | ||
761 | - | git_rebase *rebase, | ||
762 | - | git_commit *current_commit) | ||
763 | - | { | ||
764 | 39 | 2 | memcpy(checkout_opts, &rebase->options.checkout_options, sizeof(git_checkout_options)); | |
765 | - | |||
766 | 39 | 2 | if (!checkout_opts->ancestor_label) | |
767 | 39 | 3 | checkout_opts->ancestor_label = "ancestor"; | |
768 | - | |||
769 | 39 | 4 | if (rebase->type == GIT_REBASE_MERGE) { | |
770 | 39 | 5 | if (!checkout_opts->our_label) | |
771 | 39 | 6 | checkout_opts->our_label = rebase->onto_name; | |
772 | - | |||
773 | 39 | 7 | if (!checkout_opts->their_label) | |
774 | 39 | 8-10 | checkout_opts->their_label = git_commit_summary(current_commit); | |
775 | - | } else { | ||
776 | - | 11 | abort(); | |
777 | - | } | ||
778 | 39 | 12 | } | |
779 | - | |||
780 | 63 | 2 | GIT_INLINE(int) rebase_movenext(git_rebase *rebase) | |
781 | - | { | ||
782 | 63 | 2-4 | size_t next = rebase->started ? rebase->current + 1 : 0; | |
783 | - | |||
784 | 63 | 5 | if (next == git_array_size(rebase->operations)) | |
785 | 11 | 6 | return GIT_ITEROVER; | |
786 | - | |||
787 | 52 | 7 | rebase->started = 1; | |
788 | 52 | 7 | rebase->current = next; | |
789 | - | |||
790 | 52 | 7 | return 0; | |
791 | - | } | ||
792 | - | |||
793 | 39 | 2 | static int rebase_next_merge( | |
794 | - | git_rebase_operation **out, | ||
795 | - | git_rebase *rebase) | ||
796 | - | { | ||
797 | 39 | 2 | git_buf path = GIT_BUF_INIT; | |
798 | 39 | 2 | git_commit *current_commit = NULL, *parent_commit = NULL; | |
799 | 39 | 2 | git_tree *current_tree = NULL, *head_tree = NULL, *parent_tree = NULL; | |
800 | 39 | 2 | git_index *index = NULL; | |
801 | 39 | 2 | git_indexwriter indexwriter = GIT_INDEXWRITER_INIT; | |
802 | - | git_rebase_operation *operation; | ||
803 | - | git_checkout_options checkout_opts; | ||
804 | - | char current_idstr[GIT_OID_HEXSZ]; | ||
805 | - | unsigned int parent_count; | ||
806 | - | int error; | ||
807 | - | |||
808 | 39 | 2 | *out = NULL; | |
809 | - | |||
810 | 39 | 2-4 | operation = git_array_get(rebase->operations, rebase->current); | |
811 | - | |||
812 | 39 | 5-8 | if ((error = git_commit_lookup(¤t_commit, rebase->repo, &operation->id)) < 0 || | |
813 | 39 | 7,9,10 | (error = git_commit_tree(¤t_tree, current_commit)) < 0 || | |
814 | 39 | 9 | (error = git_repository_head_tree(&head_tree, rebase->repo)) < 0) | |
815 | - | goto done; | ||
816 | - | |||
817 | 39 | 11,12 | if ((parent_count = git_commit_parentcount(current_commit)) > 1) { | |
818 | ##### | 13 | git_error_set(GIT_ERROR_REBASE, "cannot rebase a merge commit"); | |
819 | ##### | 14 | error = -1; | |
820 | ##### | 14 | goto done; | |
821 | 39 | 15 | } else if (parent_count) { | |
822 | 38 | 16-19 | if ((error = git_commit_parent(&parent_commit, current_commit, 0)) < 0 || | |
823 | 38 | 18 | (error = git_commit_tree(&parent_tree, parent_commit)) < 0) | |
824 | - | goto done; | ||
825 | - | } | ||
826 | - | |||
827 | 39 | 20 | git_oid_fmt(current_idstr, &operation->id); | |
828 | - | |||
829 | 39 | 21 | normalize_checkout_options_for_apply(&checkout_opts, rebase, current_commit); | |
830 | - | |||
831 | 39 | 22-25 | if ((error = git_indexwriter_init_for_operation(&indexwriter, rebase->repo, &checkout_opts.checkout_strategy)) < 0 || | |
832 | 39 | 24,26,27 | (error = rebase_setupfile(rebase, MSGNUM_FILE, 0, "%" PRIuZ "\n", rebase->current+1)) < 0 || | |
833 | 39 | 28,29 | (error = rebase_setupfile(rebase, CURRENT_FILE, 0, "%.*s\n", GIT_OID_HEXSZ, current_idstr)) < 0 || | |
834 | 39 | 28,30,31 | (error = git_merge_trees(&index, rebase->repo, parent_tree, head_tree, current_tree, &rebase->options.merge_options)) < 0 || | |
835 | 38 | 30,32,33 | (error = git_merge__check_result(rebase->repo, index)) < 0 || | |
836 | 38 | 32,34,35 | (error = git_checkout_index(rebase->repo, index, &checkout_opts)) < 0 || | |
837 | - | (error = git_indexwriter_commit(&indexwriter)) < 0) | ||
838 | - | goto done; | ||
839 | - | |||
840 | 38 | 36 | *out = operation; | |
841 | - | |||
842 | - | done: | ||
843 | 39 | 37 | git_indexwriter_cleanup(&indexwriter); | |
844 | 39 | 38 | git_index_free(index); | |
845 | 39 | 39 | git_tree_free(current_tree); | |
846 | 39 | 40 | git_tree_free(head_tree); | |
847 | 39 | 41 | git_tree_free(parent_tree); | |
848 | 39 | 42 | git_commit_free(parent_commit); | |
849 | 39 | 43 | git_commit_free(current_commit); | |
850 | 39 | 44 | git_buf_dispose(&path); | |
851 | - | |||
852 | 39 | 45 | return error; | |
853 | - | } | ||
854 | - | |||
855 | 13 | 2 | static int rebase_next_inmemory( | |
856 | - | git_rebase_operation **out, | ||
857 | - | git_rebase *rebase) | ||
858 | - | { | ||
859 | 13 | 2 | git_commit *current_commit = NULL, *parent_commit = NULL; | |
860 | 13 | 2 | git_tree *current_tree = NULL, *head_tree = NULL, *parent_tree = NULL; | |
861 | - | git_rebase_operation *operation; | ||
862 | 13 | 2 | git_index *index = NULL; | |
863 | - | unsigned int parent_count; | ||
864 | - | int error; | ||
865 | - | |||
866 | 13 | 2 | *out = NULL; | |
867 | - | |||
868 | 13 | 2-4 | operation = git_array_get(rebase->operations, rebase->current); | |
869 | - | |||
870 | 13 | 5-8 | if ((error = git_commit_lookup(¤t_commit, rebase->repo, &operation->id)) < 0 || | |
871 | 13 | 7 | (error = git_commit_tree(¤t_tree, current_commit)) < 0) | |
872 | - | goto done; | ||
873 | - | |||
874 | 13 | 9,10 | if ((parent_count = git_commit_parentcount(current_commit)) > 1) { | |
875 | ##### | 11 | git_error_set(GIT_ERROR_REBASE, "cannot rebase a merge commit"); | |
876 | ##### | 12 | error = -1; | |
877 | ##### | 12 | goto done; | |
878 | 13 | 13 | } else if (parent_count) { | |
879 | 12 | 14-17 | if ((error = git_commit_parent(&parent_commit, current_commit, 0)) < 0 || | |
880 | 12 | 16 | (error = git_commit_tree(&parent_tree, parent_commit)) < 0) | |
881 | - | goto done; | ||
882 | - | } | ||
883 | - | |||
884 | 13 | 18-21 | if ((error = git_commit_tree(&head_tree, rebase->last_commit)) < 0 || | |
885 | 13 | 20 | (error = git_merge_trees(&index, rebase->repo, parent_tree, head_tree, current_tree, &rebase->options.merge_options)) < 0) | |
886 | - | goto done; | ||
887 | - | |||
888 | 13 | 22 | if (!rebase->index) { | |
889 | 4 | 23 | rebase->index = index; | |
890 | 4 | 23 | index = NULL; | |
891 | - | } else { | ||
892 | 9 | 24,25 | if ((error = git_index_read_index(rebase->index, index)) < 0) | |
893 | ##### | 26 | goto done; | |
894 | - | } | ||
895 | - | |||
896 | 13 | 27 | *out = operation; | |
897 | - | |||
898 | - | done: | ||
899 | 13 | 28 | git_commit_free(current_commit); | |
900 | 13 | 29 | git_commit_free(parent_commit); | |
901 | 13 | 30 | git_tree_free(current_tree); | |
902 | 13 | 31 | git_tree_free(head_tree); | |
903 | 13 | 32 | git_tree_free(parent_tree); | |
904 | 13 | 33 | git_index_free(index); | |
905 | - | |||
906 | 13 | 34 | return error; | |
907 | - | } | ||
908 | - | |||
909 | 63 | 2 | int git_rebase_next( | |
910 | - | git_rebase_operation **out, | ||
911 | - | git_rebase *rebase) | ||
912 | - | { | ||
913 | - | int error; | ||
914 | - | |||
915 | 63 | 2-4 | assert(out && rebase); | |
916 | - | |||
917 | 63 | 5,6 | if ((error = rebase_movenext(rebase)) < 0) | |
918 | 11 | 7 | return error; | |
919 | - | |||
920 | 52 | 8 | if (rebase->inmemory) | |
921 | 13 | 9 | error = rebase_next_inmemory(out, rebase); | |
922 | 39 | 10 | else if (rebase->type == GIT_REBASE_MERGE) | |
923 | 39 | 11 | error = rebase_next_merge(out, rebase); | |
924 | - | else | ||
925 | - | 12 | abort(); | |
926 | - | |||
927 | 52 | 13 | return error; | |
928 | - | } | ||
929 | - | |||
930 | 1 | 2 | int git_rebase_inmemory_index( | |
931 | - | git_index **out, | ||
932 | - | git_rebase *rebase) | ||
933 | - | { | ||
934 | 1 | 2-5 | assert(out && rebase && rebase->index); | |
935 | - | |||
936 | 1 | 6 | GIT_REFCOUNT_INC(rebase->index); | |
937 | 1 | 7 | *out = rebase->index; | |
938 | - | |||
939 | 1 | 7 | return 0; | |
940 | - | } | ||
941 | - | |||
942 | 48 | 2 | static int rebase_commit__create( | |
943 | - | git_commit **out, | ||
944 | - | git_rebase *rebase, | ||
945 | - | git_index *index, | ||
946 | - | git_commit *parent_commit, | ||
947 | - | const git_signature *author, | ||
948 | - | const git_signature *committer, | ||
949 | - | const char *message_encoding, | ||
950 | - | const char *message) | ||
951 | - | { | ||
952 | - | git_rebase_operation *operation; | ||
953 | 48 | 2 | git_commit *current_commit = NULL, *commit = NULL; | |
954 | 48 | 2 | git_tree *parent_tree = NULL, *tree = NULL; | |
955 | - | git_oid tree_id, commit_id; | ||
956 | 48 | 2 | git_buf commit_content = GIT_BUF_INIT, commit_signature = GIT_BUF_INIT, | |
957 | 48 | 2 | signature_field = GIT_BUF_INIT; | |
958 | 48 | 2 | const char *signature_field_string = NULL, | |
959 | 48 | 2 | *commit_signature_string = NULL; | |
960 | - | int error; | ||
961 | - | |||
962 | 48 | 2-4 | operation = git_array_get(rebase->operations, rebase->current); | |
963 | - | |||
964 | 48 | 5,6 | if (git_index_has_conflicts(index)) { | |
965 | 1 | 7 | git_error_set(GIT_ERROR_REBASE, "conflicts have not been resolved"); | |
966 | 1 | 8 | error = GIT_EUNMERGED; | |
967 | 1 | 8 | goto done; | |
968 | - | } | ||
969 | - | |||
970 | 47 | 9-12 | if ((error = git_commit_lookup(¤t_commit, rebase->repo, &operation->id)) < 0 || | |
971 | 47 | 11,13,14 | (error = git_commit_tree(&parent_tree, parent_commit)) < 0 || | |
972 | 47 | 13,15,16 | (error = git_index_write_tree_to(&tree_id, index, rebase->repo)) < 0 || | |
973 | 47 | 15 | (error = git_tree_lookup(&tree, rebase->repo, &tree_id)) < 0) | |
974 | - | goto done; | ||
975 | - | |||
976 | 47 | 17-19 | if (git_oid_equal(&tree_id, git_tree_id(parent_tree))) { | |
977 | 1 | 20 | git_error_set(GIT_ERROR_REBASE, "this patch has already been applied"); | |
978 | 1 | 21 | error = GIT_EAPPLIED; | |
979 | 1 | 21 | goto done; | |
980 | - | } | ||
981 | - | |||
982 | 46 | 22 | if (!author) | |
983 | 46 | 23 | author = git_commit_author(current_commit); | |
984 | - | |||
985 | 46 | 24 | if (!message) { | |
986 | 46 | 25 | message_encoding = git_commit_message_encoding(current_commit); | |
987 | 46 | 26 | message = git_commit_message(current_commit); | |
988 | - | } | ||
989 | - | |||
990 | 46 | 27,28 | if ((error = git_commit_create_buffer(&commit_content, rebase->repo, author, committer, | |
991 | - | message_encoding, message, tree, 1, (const git_commit **)&parent_commit)) < 0) | ||
992 | ##### | 29 | goto done; | |
993 | - | |||
994 | 46 | 30 | if (rebase->options.signing_cb) { | |
995 | 3 | 31 | git_error_clear(); | |
996 | 3 | 32-34 | error = git_error_set_after_callback_function(rebase->options.signing_cb( | |
997 | - | &commit_signature, &signature_field, git_buf_cstr(&commit_content), | ||
998 | - | rebase->options.payload), "commit signing_cb failed"); | ||
999 | 3 | 35 | if (error == GIT_PASSTHROUGH) { | |
1000 | 1 | 36 | git_buf_dispose(&commit_signature); | |
1001 | 1 | 37 | git_buf_dispose(&signature_field); | |
1002 | 1 | 38 | git_error_clear(); | |
1003 | 1 | 39 | error = GIT_OK; | |
1004 | 2 | 40 | } else if (error < 0) | |
1005 | ##### | 41 | goto done; | |
1006 | - | } | ||
1007 | - | |||
1008 | 46 | 42,43 | if (git_buf_is_allocated(&commit_signature)) { | |
1009 | 2 | 44-46 | assert(git_buf_contains_nul(&commit_signature)); | |
1010 | 2 | 47 | commit_signature_string = git_buf_cstr(&commit_signature); | |
1011 | - | } | ||
1012 | - | |||
1013 | 46 | 48,49 | if (git_buf_is_allocated(&signature_field)) { | |
1014 | 1 | 50-52 | assert(git_buf_contains_nul(&signature_field)); | |
1015 | 1 | 53 | signature_field_string = git_buf_cstr(&signature_field); | |
1016 | - | } | ||
1017 | - | |||
1018 | 46 | 54-56 | if ((error = git_commit_create_with_signature(&commit_id, rebase->repo, | |
1019 | - | git_buf_cstr(&commit_content), commit_signature_string, | ||
1020 | - | signature_field_string))) | ||
1021 | ##### | 57 | goto done; | |
1022 | - | |||
1023 | 46 | 58,59 | if ((error = git_commit_lookup(&commit, rebase->repo, &commit_id)) < 0) | |
1024 | ##### | 60 | goto done; | |
1025 | - | |||
1026 | 46 | 61 | *out = commit; | |
1027 | - | |||
1028 | - | done: | ||
1029 | 48 | 62 | if (error < 0) | |
1030 | 2 | 63 | git_commit_free(commit); | |
1031 | - | |||
1032 | 48 | 64 | git_buf_dispose(&commit_signature); | |
1033 | 48 | 65 | git_buf_dispose(&signature_field); | |
1034 | 48 | 66 | git_buf_dispose(&commit_content); | |
1035 | 48 | 67 | git_commit_free(current_commit); | |
1036 | 48 | 68 | git_tree_free(parent_tree); | |
1037 | 48 | 69 | git_tree_free(tree); | |
1038 | - | |||
1039 | 48 | 70 | return error; | |
1040 | - | } | ||
1041 | - | |||
1042 | 36 | 2 | static int rebase_commit_merge( | |
1043 | - | git_oid *commit_id, | ||
1044 | - | git_rebase *rebase, | ||
1045 | - | const git_signature *author, | ||
1046 | - | const git_signature *committer, | ||
1047 | - | const char *message_encoding, | ||
1048 | - | const char *message) | ||
1049 | - | { | ||
1050 | - | git_rebase_operation *operation; | ||
1051 | 36 | 2 | git_reference *head = NULL; | |
1052 | 36 | 2 | git_commit *head_commit = NULL, *commit = NULL; | |
1053 | 36 | 2 | git_index *index = NULL; | |
1054 | - | char old_idstr[GIT_OID_HEXSZ], new_idstr[GIT_OID_HEXSZ]; | ||
1055 | - | int error; | ||
1056 | - | |||
1057 | 36 | 2-4 | operation = git_array_get(rebase->operations, rebase->current); | |
1058 | 36 | 5,6 | assert(operation); | |
1059 | - | |||
1060 | 36 | 7-10 | if ((error = rebase_ensure_not_dirty(rebase->repo, false, true, GIT_EUNMERGED)) < 0 || | |
1061 | 34 | 9,11,12 | (error = git_repository_head(&head, rebase->repo)) < 0 || | |
1062 | 34 | 11,13,14 | (error = git_reference_peel((git_object **)&head_commit, head, GIT_OBJECT_COMMIT)) < 0 || | |
1063 | 34 | 13,15,16 | (error = git_repository_index(&index, rebase->repo)) < 0 || | |
1064 | 34 | 15 | (error = rebase_commit__create(&commit, rebase, index, head_commit, | |
1065 | 33 | 18,19 | author, committer, message_encoding, message)) < 0 || | |
1066 | 33 | 17 | (error = git_reference__update_for_commit( | |
1067 | - | rebase->repo, NULL, "HEAD", git_commit_id(commit), "rebase")) < 0) | ||
1068 | - | goto done; | ||
1069 | - | |||
1070 | 33 | 20 | git_oid_fmt(old_idstr, &operation->id); | |
1071 | 33 | 21,22 | git_oid_fmt(new_idstr, git_commit_id(commit)); | |
1072 | - | |||
1073 | 33 | 23,24 | if ((error = rebase_setupfile(rebase, REWRITTEN_FILE, O_CREAT|O_WRONLY|O_APPEND, | |
1074 | - | "%.*s %.*s\n", GIT_OID_HEXSZ, old_idstr, GIT_OID_HEXSZ, new_idstr)) < 0) | ||
1075 | ##### | 25 | goto done; | |
1076 | - | |||
1077 | 33 | 26,27 | git_oid_cpy(commit_id, git_commit_id(commit)); | |
1078 | - | |||
1079 | - | done: | ||
1080 | 36 | 28 | git_index_free(index); | |
1081 | 36 | 29 | git_reference_free(head); | |
1082 | 36 | 30 | git_commit_free(head_commit); | |
1083 | 36 | 31 | git_commit_free(commit); | |
1084 | 36 | 32 | return error; | |
1085 | - | } | ||
1086 | - | |||
1087 | 14 | 2 | static int rebase_commit_inmemory( | |
1088 | - | git_oid *commit_id, | ||
1089 | - | git_rebase *rebase, | ||
1090 | - | const git_signature *author, | ||
1091 | - | const git_signature *committer, | ||
1092 | - | const char *message_encoding, | ||
1093 | - | const char *message) | ||
1094 | - | { | ||
1095 | 14 | 2 | git_commit *commit = NULL; | |
1096 | 14 | 2 | int error = 0; | |
1097 | - | |||
1098 | 14 | 2,3 | assert(rebase->index); | |
1099 | 14 | 4,5 | assert(rebase->last_commit); | |
1100 | 14 | 6,7 | assert(rebase->current < rebase->operations.size); | |
1101 | - | |||
1102 | 14 | 8,9 | if ((error = rebase_commit__create(&commit, rebase, rebase->index, | |
1103 | - | rebase->last_commit, author, committer, message_encoding, message)) < 0) | ||
1104 | 1 | 10 | goto done; | |
1105 | - | |||
1106 | 13 | 11 | git_commit_free(rebase->last_commit); | |
1107 | 13 | 12 | rebase->last_commit = commit; | |
1108 | - | |||
1109 | 13 | 12,13 | git_oid_cpy(commit_id, git_commit_id(commit)); | |
1110 | - | |||
1111 | - | done: | ||
1112 | 14 | 14 | if (error < 0) | |
1113 | 1 | 15 | git_commit_free(commit); | |
1114 | - | |||
1115 | 14 | 16 | return error; | |
1116 | - | } | ||
1117 | - | |||
1118 | 50 | 2 | int git_rebase_commit( | |
1119 | - | git_oid *id, | ||
1120 | - | git_rebase *rebase, | ||
1121 | - | const git_signature *author, | ||
1122 | - | const git_signature *committer, | ||
1123 | - | const char *message_encoding, | ||
1124 | - | const char *message) | ||
1125 | - | { | ||
1126 | - | int error; | ||
1127 | - | |||
1128 | 50 | 2-4 | assert(rebase && committer); | |
1129 | - | |||
1130 | 50 | 5 | if (rebase->inmemory) | |
1131 | 14 | 6 | error = rebase_commit_inmemory( | |
1132 | - | id, rebase, author, committer, message_encoding, message); | ||
1133 | 36 | 7 | else if (rebase->type == GIT_REBASE_MERGE) | |
1134 | 36 | 8 | error = rebase_commit_merge( | |
1135 | - | id, rebase, author, committer, message_encoding, message); | ||
1136 | - | else | ||
1137 | - | 9 | abort(); | |
1138 | - | |||
1139 | 50 | 10 | return error; | |
1140 | - | } | ||
1141 | - | |||
1142 | 8 | 2 | int git_rebase_abort(git_rebase *rebase) | |
1143 | - | { | ||
1144 | 8 | 2 | git_reference *orig_head_ref = NULL; | |
1145 | 8 | 2 | git_commit *orig_head_commit = NULL; | |
1146 | - | int error; | ||
1147 | - | |||
1148 | 8 | 2,3 | assert(rebase); | |
1149 | - | |||
1150 | 8 | 4 | if (rebase->inmemory) | |
1151 | ##### | 5 | return 0; | |
1152 | - | |||
1153 | 8 | 6,9 | error = rebase->head_detached ? | |
1154 | 4 | 7 | git_reference_create(&orig_head_ref, rebase->repo, GIT_HEAD_FILE, | |
1155 | 8 | 6-8 | &rebase->orig_head_id, 1, "rebase: aborting") : | |
1156 | 4 | 8 | git_reference_symbolic_create( | |
1157 | 4 | 8 | &orig_head_ref, rebase->repo, GIT_HEAD_FILE, rebase->orig_head_name, 1, | |
1158 | - | "rebase: aborting"); | ||
1159 | - | |||
1160 | 8 | 9 | if (error < 0) | |
1161 | ##### | 10 | goto done; | |
1162 | - | |||
1163 | 8 | 11,12 | if ((error = git_commit_lookup( | |
1164 | 8 | 11,13,14 | &orig_head_commit, rebase->repo, &rebase->orig_head_id)) < 0 || | |
1165 | 8 | 13 | (error = git_reset(rebase->repo, (git_object *)orig_head_commit, | |
1166 | 8 | 13 | GIT_RESET_HARD, &rebase->options.checkout_options)) < 0) | |
1167 | - | goto done; | ||
1168 | - | |||
1169 | 8 | 15 | error = rebase_cleanup(rebase); | |
1170 | - | |||
1171 | - | done: | ||
1172 | 8 | 16 | git_commit_free(orig_head_commit); | |
1173 | 8 | 17 | git_reference_free(orig_head_ref); | |
1174 | - | |||
1175 | 8 | 18 | return error; | |
1176 | - | } | ||
1177 | - | |||
1178 | 8 | 2 | static int notes_ref_lookup(git_buf *out, git_rebase *rebase) | |
1179 | - | { | ||
1180 | 8 | 2 | git_config *config = NULL; | |
1181 | - | int do_rewrite, error; | ||
1182 | - | |||
1183 | 8 | 2 | if (rebase->options.rewrite_notes_ref) { | |
1184 | 1 | 3 | git_buf_attach_notowned(out, | |
1185 | - | rebase->options.rewrite_notes_ref, | ||
1186 | - | strlen(rebase->options.rewrite_notes_ref)); | ||
1187 | 1 | 4 | return 0; | |
1188 | - | } | ||
1189 | - | |||
1190 | 7 | 5-8 | if ((error = git_repository_config(&config, rebase->repo)) < 0 || | |
1191 | 7 | 7 | (error = git_config_get_bool(&do_rewrite, config, "notes.rewrite.rebase")) < 0) { | |
1192 | - | |||
1193 | 6 | 9 | if (error != GIT_ENOTFOUND) | |
1194 | ##### | 10 | goto done; | |
1195 | - | |||
1196 | 6 | 11 | git_error_clear(); | |
1197 | 6 | 12 | do_rewrite = 1; | |
1198 | - | } | ||
1199 | - | |||
1200 | 7 | 13,16 | error = do_rewrite ? | |
1201 | 7 | 13-15 | git_config_get_string_buf(out, config, "notes.rewriteref") : | |
1202 | - | GIT_ENOTFOUND; | ||
1203 | - | |||
1204 | - | done: | ||
1205 | 7 | 17 | git_config_free(config); | |
1206 | 7 | 18 | return error; | |
1207 | - | } | ||
1208 | - | |||
1209 | 2 | 2 | static int rebase_copy_note( | |
1210 | - | git_rebase *rebase, | ||
1211 | - | const char *notes_ref, | ||
1212 | - | git_oid *from, | ||
1213 | - | git_oid *to, | ||
1214 | - | const git_signature *committer) | ||
1215 | - | { | ||
1216 | 2 | 2 | git_note *note = NULL; | |
1217 | - | git_oid note_id; | ||
1218 | 2 | 2 | git_signature *who = NULL; | |
1219 | - | int error; | ||
1220 | - | |||
1221 | 2 | 2,3 | if ((error = git_note_read(¬e, rebase->repo, notes_ref, from)) < 0) { | |
1222 | ##### | 4 | if (error == GIT_ENOTFOUND) { | |
1223 | ##### | 5 | git_error_clear(); | |
1224 | ##### | 6 | error = 0; | |
1225 | - | } | ||
1226 | - | |||
1227 | ##### | 7 | goto done; | |
1228 | - | } | ||
1229 | - | |||
1230 | 2 | 8 | if (!committer) { | |
1231 | ##### | 9,10 | if((error = git_signature_default(&who, rebase->repo)) < 0) { | |
1232 | ##### | 11-13 | if (error != GIT_ENOTFOUND || | |
1233 | - | (error = git_signature_now(&who, "unknown", "unknown")) < 0) | ||
1234 | - | goto done; | ||
1235 | - | |||
1236 | ##### | 14 | git_error_clear(); | |
1237 | - | } | ||
1238 | - | |||
1239 | ##### | 15 | committer = who; | |
1240 | - | } | ||
1241 | - | |||
1242 | 2 | 16-18 | error = git_note_create(¬e_id, rebase->repo, notes_ref, | |
1243 | - | git_note_author(note), committer, to, git_note_message(note), 0); | ||
1244 | - | |||
1245 | - | done: | ||
1246 | 2 | 19 | git_note_free(note); | |
1247 | 2 | 20 | git_signature_free(who); | |
1248 | - | |||
1249 | 2 | 21 | return error; | |
1250 | - | } | ||
1251 | - | |||
1252 | 8 | 2 | static int rebase_copy_notes( | |
1253 | - | git_rebase *rebase, | ||
1254 | - | const git_signature *committer) | ||
1255 | - | { | ||
1256 | 8 | 2 | git_buf path = GIT_BUF_INIT, rewritten = GIT_BUF_INIT, notes_ref = GIT_BUF_INIT; | |
1257 | - | char *pair_list, *fromstr, *tostr, *end; | ||
1258 | - | git_oid from, to; | ||
1259 | 8 | 2 | unsigned int linenum = 1; | |
1260 | 8 | 2 | int error = 0; | |
1261 | - | |||
1262 | 8 | 2,3 | if ((error = notes_ref_lookup(¬es_ref, rebase)) < 0) { | |
1263 | 6 | 4 | if (error == GIT_ENOTFOUND) { | |
1264 | 6 | 5 | git_error_clear(); | |
1265 | 6 | 6 | error = 0; | |
1266 | - | } | ||
1267 | - | |||
1268 | 6 | 7 | goto done; | |
1269 | - | } | ||
1270 | - | |||
1271 | 2 | 8-11 | if ((error = git_buf_joinpath(&path, rebase->state_path, REWRITTEN_FILE)) < 0 || | |
1272 | 2 | 10 | (error = git_futils_readbuffer(&rewritten, path.ptr)) < 0) | |
1273 | - | goto done; | ||
1274 | - | |||
1275 | 2 | 12 | pair_list = rewritten.ptr; | |
1276 | - | |||
1277 | 4 | 12,27 | while (*pair_list) { | |
1278 | 2 | 13 | fromstr = pair_list; | |
1279 | - | |||
1280 | 2 | 13 | if ((end = strchr(fromstr, '\n')) == NULL) | |
1281 | ##### | 14 | goto on_error; | |
1282 | - | |||
1283 | 2 | 15 | pair_list = end+1; | |
1284 | 2 | 15 | *end = '\0'; | |
1285 | - | |||
1286 | 2 | 15 | if ((end = strchr(fromstr, ' ')) == NULL) | |
1287 | ##### | 16 | goto on_error; | |
1288 | - | |||
1289 | 2 | 17 | tostr = end+1; | |
1290 | 2 | 17 | *end = '\0'; | |
1291 | - | |||
1292 | 2 | 17,18 | if (strlen(fromstr) != GIT_OID_HEXSZ || | |
1293 | 2 | 18,20 | strlen(tostr) != GIT_OID_HEXSZ || | |
1294 | 2 | 19,22 | git_oid_fromstr(&from, fromstr) < 0 || | |
1295 | 2 | 21 | git_oid_fromstr(&to, tostr) < 0) | |
1296 | - | goto on_error; | ||
1297 | - | |||
1298 | 2 | 23,24 | if ((error = rebase_copy_note(rebase, notes_ref.ptr, &from, &to, committer)) < 0) | |
1299 | ##### | 25 | goto done; | |
1300 | - | |||
1301 | 2 | 26 | linenum++; | |
1302 | - | } | ||
1303 | - | |||
1304 | 2 | 28 | goto done; | |
1305 | - | |||
1306 | - | on_error: | ||
1307 | ##### | 29 | git_error_set(GIT_ERROR_REBASE, "invalid rewritten file at line %d", linenum); | |
1308 | ##### | 30 | error = -1; | |
1309 | - | |||
1310 | - | done: | ||
1311 | 8 | 31 | git_buf_dispose(&rewritten); | |
1312 | 8 | 32 | git_buf_dispose(&path); | |
1313 | 8 | 33 | git_buf_dispose(¬es_ref); | |
1314 | - | |||
1315 | 8 | 34 | return error; | |
1316 | - | } | ||
1317 | - | |||
1318 | 6 | 2 | static int return_to_orig_head(git_rebase *rebase) | |
1319 | - | { | ||
1320 | 6 | 2 | git_reference *terminal_ref = NULL, *branch_ref = NULL, *head_ref = NULL; | |
1321 | 6 | 2 | git_commit *terminal_commit = NULL; | |
1322 | 6 | 2 | git_buf branch_msg = GIT_BUF_INIT, head_msg = GIT_BUF_INIT; | |
1323 | - | char onto[GIT_OID_HEXSZ]; | ||
1324 | 6 | 2 | int error = 0; | |
1325 | - | |||
1326 | 6 | 2 | git_oid_fmt(onto, &rebase->onto_id); | |
1327 | - | |||
1328 | 6 | 3,4 | if ((error = git_buf_printf(&branch_msg, | |
1329 | - | "rebase finished: %s onto %.*s", | ||
1330 | 6 | 5,6 | rebase->orig_head_name, GIT_OID_HEXSZ, onto)) == 0 && | |
1331 | 6 | 5 | (error = git_buf_printf(&head_msg, | |
1332 | - | "rebase finished: returning to %s", | ||
1333 | 6 | 7,8 | rebase->orig_head_name)) == 0 && | |
1334 | 6 | 7,9,10 | (error = git_repository_head(&terminal_ref, rebase->repo)) == 0 && | |
1335 | 6 | 9 | (error = git_reference_peel((git_object **)&terminal_commit, | |
1336 | 6 | 12,13 | terminal_ref, GIT_OBJECT_COMMIT)) == 0 && | |
1337 | 6 | 11,12 | (error = git_reference_create_matching(&branch_ref, | |
1338 | 6 | 12 | rebase->repo, rebase->orig_head_name, | |
1339 | - | git_commit_id(terminal_commit), 1, | ||
1340 | 6 | 11 | &rebase->orig_head_id, branch_msg.ptr)) == 0) | |
1341 | 6 | 14 | error = git_reference_symbolic_create(&head_ref, | |
1342 | 6 | 14 | rebase->repo, GIT_HEAD_FILE, rebase->orig_head_name, 1, | |
1343 | 6 | 14 | head_msg.ptr); | |
1344 | - | |||
1345 | 6 | 15 | git_buf_dispose(&head_msg); | |
1346 | 6 | 16 | git_buf_dispose(&branch_msg); | |
1347 | 6 | 17 | git_commit_free(terminal_commit); | |
1348 | 6 | 18 | git_reference_free(head_ref); | |
1349 | 6 | 19 | git_reference_free(branch_ref); | |
1350 | 6 | 20 | git_reference_free(terminal_ref); | |
1351 | - | |||
1352 | 6 | 21 | return error; | |
1353 | - | } | ||
1354 | - | |||
1355 | 9 | 2 | int git_rebase_finish( | |
1356 | - | git_rebase *rebase, | ||
1357 | - | const git_signature *signature) | ||
1358 | - | { | ||
1359 | 9 | 2 | int error = 0; | |
1360 | - | |||
1361 | 9 | 2,3 | assert(rebase); | |
1362 | - | |||
1363 | 9 | 4 | if (rebase->inmemory) | |
1364 | 1 | 5 | return 0; | |
1365 | - | |||
1366 | 8 | 6 | if (!rebase->head_detached) | |
1367 | 6 | 7 | error = return_to_orig_head(rebase); | |
1368 | - | |||
1369 | 8 | 8-10 | if (error == 0 && (error = rebase_copy_notes(rebase, signature)) == 0) | |
1370 | 8 | 11 | error = rebase_cleanup(rebase); | |
1371 | - | |||
1372 | 8 | 12 | return error; | |
1373 | - | } | ||
1374 | - | |||
1375 | 1 | 2 | const char *git_rebase_orig_head_name(git_rebase *rebase) { | |
1376 | 1 | 2 | return rebase->orig_head_name; | |
1377 | - | } | ||
1378 | - | |||
1379 | 1 | 2 | const git_oid *git_rebase_orig_head_id(git_rebase *rebase) { | |
1380 | 1 | 2 | return &rebase->orig_head_id; | |
1381 | - | } | ||
1382 | - | |||
1383 | 1 | 2 | const char *git_rebase_onto_name(git_rebase *rebase) { | |
1384 | 1 | 2 | return rebase->onto_name; | |
1385 | - | } | ||
1386 | - | |||
1387 | 1 | 2 | const git_oid *git_rebase_onto_id(git_rebase *rebase) { | |
1388 | 1 | 2 | return &rebase->onto_id; | |
1389 | - | } | ||
1390 | - | |||
1391 | 14 | 2 | size_t git_rebase_operation_entrycount(git_rebase *rebase) | |
1392 | - | { | ||
1393 | 14 | 2,3 | assert(rebase); | |
1394 | - | |||
1395 | 14 | 4 | return git_array_size(rebase->operations); | |
1396 | - | } | ||
1397 | - | |||
1398 | 14 | 2 | size_t git_rebase_operation_current(git_rebase *rebase) | |
1399 | - | { | ||
1400 | 14 | 2,3 | assert(rebase); | |
1401 | - | |||
1402 | 14 | 4 | return rebase->started ? rebase->current : GIT_REBASE_NO_OPERATION; | |
1403 | - | } | ||
1404 | - | |||
1405 | 70 | 2 | git_rebase_operation *git_rebase_operation_byindex(git_rebase *rebase, size_t idx) | |
1406 | - | { | ||
1407 | 70 | 2,3 | assert(rebase); | |
1408 | - | |||
1409 | 70 | 4 | return git_array_get(rebase->operations, idx); | |
1410 | - | } | ||
1411 | - | |||
1412 | 60 | 2 | void git_rebase_free(git_rebase *rebase) | |
1413 | - | { | ||
1414 | 60 | 2 | if (rebase == NULL) | |
1415 | 60 | 3,12 | return; | |
1416 | - | |||
1417 | 55 | 4 | git_index_free(rebase->index); | |
1418 | 55 | 5 | git_commit_free(rebase->last_commit); | |
1419 | 55 | 6 | git__free(rebase->onto_name); | |
1420 | 55 | 7 | git__free(rebase->orig_head_name); | |
1421 | 55 | 8 | git__free(rebase->state_path); | |
1422 | 55 | 9 | git_array_clear(rebase->operations); | |
1423 | 55 | 10 | git__free((char *)rebase->options.rewrite_notes_ref); | |
1424 | 55 | 11 | git__free(rebase); | |
1425 | - | } |