@matheusbsbs / matheus-bagliano / commits / 6eb1b43793
Fork 0

cherry-pick/revert: make direct internal call to merge_tree()

Refactored merge-recursive interface may still not be ideal but it already allows us to make a direct call to merge_tree(). One regression is that the status message is lost as there is no way to flush them from outside the refactored library code yet. [jc: initial version by Miklos, with moderate amount of fixup by me] Signed-off-by: Junio C Hamano <gitster@pobox.com>

Miklos Vajna committed Sep 2, 2008 at 14:11 UTC 6eb1b437933e075bd84c5cdcf5de95ed4db4820f
1 file changed +43 -40
builtin-revert.c
+43 -40
@@ -12,6 +12,7 @@
12 #include "diff.h"
13 #include "revision.h"
14 #include "rerere.h"
15 +#include "merge-recursive.h"
16
17 /*
18 * This implements the builtins revert and cherry-pick.
@@ -201,36 +202,6 @@ static void set_author_ident_env(const char *message)
202 sha1_to_hex(commit->object.sha1));
203 }
204
204 -static int merge_recursive(const char *base_sha1,
205 - const char *head_sha1, const char *head_name,
206 - const char *next_sha1, const char *next_name)
207 -{
208 - char buffer[256];
209 - const char *argv[6];
210 - int i = 0;
211 -
212 - sprintf(buffer, "GITHEAD_%s", head_sha1);
213 - setenv(buffer, head_name, 1);
214 - sprintf(buffer, "GITHEAD_%s", next_sha1);
215 - setenv(buffer, next_name, 1);
216 -
217 - /*
218 - * This three way merge is an interesting one. We are at
219 - * $head, and would want to apply the change between $commit
220 - * and $prev on top of us (when reverting), or the change between
221 - * $prev and $commit on top of us (when cherry-picking or replaying).
222 - */
223 - argv[i++] = "merge-recursive";
224 - if (base_sha1)
225 - argv[i++] = base_sha1;
226 - argv[i++] = "--";
227 - argv[i++] = head_sha1;
228 - argv[i++] = next_sha1;
229 - argv[i++] = NULL;
230 -
231 - return run_command_v_opt(argv, RUN_COMMAND_NO_STDIN | RUN_GIT_CMD);
232 -}
233 -
205 static char *help_msg(const unsigned char *sha1)
206 {
207 static char helpbuf[1024];
@@ -263,14 +234,27 @@ static int index_is_dirty(void)
234 return !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES);
235 }
236
237 +static struct tree *empty_tree(void)
238 +{
239 + struct tree *tree = xcalloc(1, sizeof(struct tree));
240 +
241 + tree->object.parsed = 1;
242 + tree->object.type = OBJ_TREE;
243 + pretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1);
244 + return tree;
245 +}
246 +
247 static int revert_or_cherry_pick(int argc, const char **argv)
248 {
249 unsigned char head[20];
250 struct commit *base, *next, *parent;
270 - int i;
251 + int i, index_fd, clean;
252 char *oneline, *reencoded_message = NULL;
253 const char *message, *encoding;
254 const char *defmsg = xstrdup(git_path("MERGE_MSG"));
255 + struct merge_options o;
256 + struct tree *result, *next_tree, *base_tree, *head_tree;
257 + static struct lock_file index_lock;
258
259 git_config(git_default_config, NULL);
260 me = action == REVERT ? "revert" : "cherry-pick";
@@ -281,6 +265,8 @@ static int revert_or_cherry_pick(int argc, const char **argv)
265 if (action == REVERT && !no_replay)
266 die("revert is incompatible with replay");
267
268 + if (read_cache() < 0)
269 + die("git %s: failed to read the index", me);
270 if (no_commit) {
271 /*
272 * We do not intend to commit immediately. We just want to
@@ -293,12 +279,12 @@ static int revert_or_cherry_pick(int argc, const char **argv)
279 } else {
280 if (get_sha1("HEAD", head))
281 die ("You do not have a valid HEAD");
296 - if (read_cache() < 0)
297 - die("could not read the index");
282 if (index_is_dirty())
283 die ("Dirty index: cannot %s", me);
300 - discard_cache();
284 }
285 + discard_cache();
286 +
287 + index_fd = hold_locked_index(&index_lock, 1);
288
289 if (!commit->parents) {
290 if (action == REVERT)
@@ -332,6 +318,10 @@ static int revert_or_cherry_pick(int argc, const char **argv)
318 die ("Cannot get commit message for %s",
319 sha1_to_hex(commit->object.sha1));
320
321 + if (parent && parse_commit(parent) < 0)
322 + die("%s: cannot parse parent commit %s",
323 + me, sha1_to_hex(parent->object.sha1));
324 +
325 /*
326 * "commit" is an existing commit. We would want to apply
327 * the difference it introduces since its first parent "prev"
@@ -374,13 +364,26 @@ static int revert_or_cherry_pick(int argc, const char **argv)
364 }
365 }
366
377 - if (merge_recursive(base == NULL ?
378 - NULL : sha1_to_hex(base->object.sha1),
379 - sha1_to_hex(head), "HEAD",
380 - sha1_to_hex(next->object.sha1), oneline) ||
381 - write_cache_as_tree(head, 0, NULL)) {
367 + read_cache();
368 + init_merge_options(&o);
369 + o.branch1 = "HEAD";
370 + o.branch2 = oneline;
371 +
372 + head_tree = parse_tree_indirect(head);
373 + next_tree = next ? next->tree : empty_tree();
374 + base_tree = base ? base->tree : empty_tree();
375 +
376 + clean = merge_trees(&o,
377 + head_tree,
378 + next_tree, base_tree, &result);
379 +
380 + if (active_cache_changed &&
381 + (write_cache(index_fd, active_cache, active_nr) ||
382 + commit_locked_index(&index_lock)))
383 + die("%s: Unable to write new index file", me);
384 +
385 + if (!clean) {
386 add_to_msg("\nConflicts:\n\n");
383 - read_cache();
387 for (i = 0; i < active_nr;) {
388 struct cache_entry *ce = active_cache[i++];
389 if (ce_stage(ce)) {