From: Junio C Hamano Date: Sat, 3 Apr 2010 19:28:41 +0000 (-0700) Subject: Merge branch 'jn/merge-diff3-label' X-Git-Tag: v1.7.1-rc0~15 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/16b8a3e4b94dc7f6e05b624eae3cf1eed7b358a5?ds=inline;hp=-c Merge branch 'jn/merge-diff3-label' * jn/merge-diff3-label: merge-recursive: add a label for ancestor cherry-pick, revert: add a label for ancestor revert: clarify label on conflict hunks compat: add mempcpy() checkout -m --conflict=diff3: add a label for ancestor merge_trees(): add ancestor label parameter for diff3-style output merge_file(): add comment explaining behavior wrt conflict style checkout --conflict=diff3: add a label for ancestor ll_merge(): add ancestor label parameter for diff3-style output merge-file --diff3: add a label for ancestor xdl_merge(): move file1 and file2 labels to xmparam structure xdl_merge(): add optional ancestor label to diff3-style output tests: document cherry-pick behavior in face of conflicts tests: document format of conflicts from checkout -m Conflicts: builtin/revert.c --- 16b8a3e4b94dc7f6e05b624eae3cf1eed7b358a5 diff --combined builtin/revert.c index 9a3c14c329,1ddfac15b5..778a56eb51 --- a/builtin/revert.c +++ b/builtin/revert.c @@@ -13,7 -13,6 +13,7 @@@ #include "revision.h" #include "rerere.h" #include "merge-recursive.h" +#include "refs.h" /* * This implements the builtins revert and cherry-pick. @@@ -36,7 -35,7 +36,7 @@@ static const char * const cherry_pick_u NULL }; -static int edit, no_replay, no_commit, mainline, signoff; +static int edit, no_replay, no_commit, mainline, signoff, allow_ff; static enum { REVERT, CHERRY_PICK } action; static struct commit *commit; static const char *commit_name; @@@ -46,6 -45,8 +46,8 @@@ static const char *me #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION" + static char *get_encoding(const char *message); + static void parse_args(int argc, const char **argv) { const char * const * usage_str = @@@ -61,19 -62,8 +63,19 @@@ OPT_INTEGER('m', "mainline", &mainline, "parent number"), OPT_RERERE_AUTOUPDATE(&allow_rerere_auto), OPT_END(), + OPT_END(), + OPT_END(), }; + if (action == CHERRY_PICK) { + struct option cp_extra[] = { + OPT_BOOLEAN(0, "ff", &allow_ff, "allow fast-forward"), + OPT_END(), + }; + if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra)) + die("program error"); + } + if (parse_options(argc, argv, NULL, options, usage_str, 0) != 1) usage_with_options(usage_str, options); @@@ -85,33 -75,64 +87,64 @@@ exit(1); } - static char *get_oneline(const char *message) + struct commit_message { + char *parent_label; + const char *label; + const char *subject; + char *reencoded_message; + const char *message; + }; + + static int get_message(const char *raw_message, struct commit_message *out) { - char *result; - const char *p = message, *abbrev, *eol; + const char *encoding; + const char *p, *abbrev, *eol; + char *q; int abbrev_len, oneline_len; - if (!p) - die ("Could not read commit message of %s", - sha1_to_hex(commit->object.sha1)); + if (!raw_message) + return -1; + encoding = get_encoding(raw_message); + if (!encoding) + encoding = "UTF-8"; + if (!git_commit_encoding) + git_commit_encoding = "UTF-8"; + if ((out->reencoded_message = reencode_string(raw_message, + git_commit_encoding, encoding))) + out->message = out->reencoded_message; + + abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV); + abbrev_len = strlen(abbrev); + + /* Find beginning and end of commit subject. */ + p = out->message; while (*p && (*p != '\n' || p[1] != '\n')) p++; - if (*p) { p += 2; for (eol = p + 1; *eol && *eol != '\n'; eol++) ; /* do nothing */ } else eol = p; - abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV); - abbrev_len = strlen(abbrev); oneline_len = eol - p; - result = xmalloc(abbrev_len + 5 + oneline_len); - memcpy(result, abbrev, abbrev_len); - memcpy(result + abbrev_len, "... ", 4); - memcpy(result + abbrev_len + 4, p, oneline_len); - result[abbrev_len + 4 + oneline_len] = '\0'; - return result; + + out->parent_label = xmalloc(strlen("parent of ") + abbrev_len + + strlen("... ") + oneline_len + 1); + q = out->parent_label; + q = mempcpy(q, "parent of ", strlen("parent of ")); + out->label = q; + q = mempcpy(q, abbrev, abbrev_len); + q = mempcpy(q, "... ", strlen("... ")); + out->subject = q; + q = mempcpy(q, p, oneline_len); + *q = '\0'; + return 0; + } + + static void free_message(struct commit_message *msg) + { + free(msg->parent_label); + free(msg->reencoded_message); } static char *get_encoding(const char *message) @@@ -256,25 -277,15 +289,25 @@@ static NORETURN void die_dirty_index(co } } +static int fast_forward_to(const unsigned char *to, const unsigned char *from) +{ + struct ref_lock *ref_lock; + + read_cache(); + if (checkout_fast_forward(from, to)) + exit(1); /* the callee should have complained already */ + ref_lock = lock_any_ref_for_update("HEAD", from, 0); + return write_ref_sha1(ref_lock, to, "cherry-pick"); +} + static int revert_or_cherry_pick(int argc, const char **argv) { unsigned char head[20]; struct commit *base, *next, *parent; + const char *base_label, *next_label; int i, index_fd, clean; - char *oneline, *reencoded_message = NULL; - const char *message, *encoding; + struct commit_message msg = { NULL, NULL, NULL, NULL, NULL }; - - char *defmsg = git_pathdup("MERGE_MSG"); + char *defmsg = NULL; struct merge_options o; struct tree *result, *next_tree, *base_tree, *head_tree; static struct lock_file index_lock; @@@ -288,17 -299,6 +321,17 @@@ if (action == REVERT && !no_replay) die("revert is incompatible with replay"); + if (allow_ff) { + if (signoff) + die("cherry-pick --ff cannot be used with --signoff"); + if (no_commit) + die("cherry-pick --ff cannot be used with --no-commit"); + if (no_replay) + die("cherry-pick --ff cannot be used with -x"); + if (edit) + die("cherry-pick --ff cannot be used with --edit"); + } + if (read_cache() < 0) die("git %s: failed to read the index", me); if (no_commit) { @@@ -318,6 -318,8 +351,6 @@@ } discard_cache(); - index_fd = hold_locked_index(&index_lock, 1); - if (!commit->parents) { if (action == REVERT) die ("Cannot revert a root commit"); @@@ -346,17 -348,14 +379,17 @@@ else parent = commit->parents->item; + if (allow_ff && !hashcmp(parent->object.sha1, head)) + return fast_forward_to(commit->object.sha1, head); + - if (!(message = commit->buffer)) - die ("Cannot get commit message for %s", - sha1_to_hex(commit->object.sha1)); - if (parent && parse_commit(parent) < 0) die("%s: cannot parse parent commit %s", me, sha1_to_hex(parent->object.sha1)); + if (get_message(commit->buffer, &msg) != 0) + die("Cannot get commit message for %s", + sha1_to_hex(commit->object.sha1)); + /* * "commit" is an existing commit. We would want to apply * the difference it introduces since its first parent "prev" @@@ -364,30 -363,16 +397,19 @@@ * reverse of it if we are revert. */ + defmsg = git_pathdup("MERGE_MSG"); msg_fd = hold_lock_file_for_update(&msg_file, defmsg, LOCK_DIE_ON_ERROR); - encoding = get_encoding(message); - if (!encoding) - encoding = "UTF-8"; - if (!git_commit_encoding) - git_commit_encoding = "UTF-8"; - if ((reencoded_message = reencode_string(message, - git_commit_encoding, encoding))) - message = reencoded_message; - - oneline = get_oneline(message); - + index_fd = hold_locked_index(&index_lock, 1); + if (action == REVERT) { - char *oneline_body = strchr(oneline, ' '); - base = commit; + base_label = msg.label; next = parent; + next_label = msg.parent_label; add_to_msg("Revert \""); - add_to_msg(oneline_body + 1); + add_to_msg(msg.subject); add_to_msg("\"\n\nThis reverts commit "); add_to_msg(sha1_to_hex(commit->object.sha1)); @@@ -398,9 -383,11 +420,11 @@@ add_to_msg(".\n"); } else { base = parent; + base_label = msg.parent_label; next = commit; - set_author_ident_env(message); - add_message_to_msg(message); + next_label = msg.label; + set_author_ident_env(msg.message); + add_message_to_msg(msg.message); if (no_replay) { add_to_msg("(cherry picked from commit "); add_to_msg(sha1_to_hex(commit->object.sha1)); @@@ -410,8 -397,9 +434,9 @@@ read_cache(); init_merge_options(&o); + o.ancestor = base ? base_label : "(empty tree)"; o.branch1 = "HEAD"; - o.branch2 = oneline; + o.branch2 = next ? next_label : "(empty tree)"; head_tree = parse_tree_indirect(head); next_tree = next ? next->tree : empty_tree(); @@@ -475,7 -463,7 +500,7 @@@ args[i] = NULL; return execv_git_cmd(args); } - free(reencoded_message); + free_message(&msg); free(defmsg); return 0; diff --combined git-compat-util.h index e292926fec,9bed5a0b47..7e62b55270 --- a/git-compat-util.h +++ b/git-compat-util.h @@@ -55,8 -55,7 +55,8 @@@ # else # define _XOPEN_SOURCE 500 # endif -#elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && !defined(_M_UNIX) && !defined(sgi) +#elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && \ + !defined(_M_UNIX) && !defined(sgi) && !defined(__DragonFly__) #define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */ #define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */ #endif @@@ -332,6 -331,7 +332,7 @@@ extern int git_vsnprintf(char *str, siz #ifdef __GLIBC_PREREQ #if __GLIBC_PREREQ(2, 1) #define HAVE_STRCHRNUL + #define HAVE_MEMPCPY #endif #endif @@@ -345,6 -345,14 +346,14 @@@ static inline char *gitstrchrnul(const } #endif + #ifndef HAVE_MEMPCPY + #define mempcpy gitmempcpy + static inline void *gitmempcpy(void *dest, const void *src, size_t n) + { + return (char *)memcpy(dest, src, n) + n; + } + #endif + extern void release_pack_memory(size_t, int); extern char *xstrdup(const char *str);