rev-list --cherry-pick may be used in combination with the symmetric difference operator (A...B) to squelch showing commits which are identical in content. Sometimes this is too strict of a test, for example if the cherry-picked commits required conflict resolution, altering their patch-ids. However, it is still useful to be able to squelch such commits as they need not be cherry-picked again. Using --cherry-pick=loose tells git to ignore the patch content and instead examine its metadata. Specifically, commits with identical authorship (name and timestamp) and subject are not shown in the output. Signed-off-by: Jay Soffian <jaysoffian@xxxxxxxxx> --- This is a bit of a hack just to stimulate conversation. My use case for this is that I'm cherry-picking commits from a release branch onto a development branch. (I cannot use a different branching strategy that would allow me to merge instead.) Sometimes those cherry-picks require conflict resolution. The current --cherry-pick behavior requires that I maintain (externally to git) a list of commits which have already been cherry-picked. So I started experimenting with a wrapper around rev-list A...B that looks at commit metadata to determine what's been cherry-picked and what not, and it works quite well for me. The functionality in this patch would let me get rid of that wrapper. Thoughts? patch-ids.c | 23 +++++++++++++++++++++-- patch-ids.h | 2 +- revision.c | 9 +++++++++ revision.h | 1 + 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/patch-ids.c b/patch-ids.c index 5717257..6a1f3e3 100644 --- a/patch-ids.c +++ b/patch-ids.c @@ -16,6 +16,20 @@ static int commit_patch_id(struct commit *commit, struct diff_options *options, return diff_flush_patch_id(options, sha1); } +static int commit_patch_id_loose(struct commit *commit, unsigned char *sha1) +{ + git_SHA_CTX ctx; + struct strbuf buf = STRBUF_INIT; + struct pretty_print_context pctx = {0}; + + git_SHA1_Init(&ctx); + format_commit_message(commit, "%an %ae %at %s", &buf, &pctx); + git_SHA1_Update(&ctx, buf.buf, buf.len); + strbuf_release(&buf); + git_SHA1_Final(sha1, &ctx); + return 0; +} + static const unsigned char *patch_id_access(size_t index, void *table) { struct patch_id **id_table = table; @@ -65,8 +79,13 @@ static struct patch_id *add_commit(struct commit *commit, unsigned char sha1[20]; int pos; - if (commit_patch_id(commit, &ids->diffopts, sha1)) - return NULL; + if (ids->loose) { + if (commit_patch_id_loose(commit, sha1)) + return NULL; + } else { + if (commit_patch_id(commit, &ids->diffopts, sha1)) + return NULL; + } pos = patch_pos(ids->table, ids->nr, sha1); if (0 <= pos) return ids->table[pos]; diff --git a/patch-ids.h b/patch-ids.h index c8c7ca1..f54b0ee 100644 --- a/patch-ids.h +++ b/patch-ids.h @@ -8,7 +8,7 @@ struct patch_id { struct patch_ids { struct diff_options diffopts; - int nr, alloc; + int nr, alloc, loose; struct patch_id **table; struct patch_id_bucket *patches; }; diff --git a/revision.c b/revision.c index 7b9eaef..6dbbf5d 100644 --- a/revision.c +++ b/revision.c @@ -558,6 +558,8 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs) ids.diffopts.paths = revs->diffopt.paths; ids.diffopts.pathlens = revs->diffopt.pathlens; } + if (revs->cherry_pick_loose) + ids.loose = 1; /* Compute patch-ids for one side */ for (p = list; p; p = p->next) { @@ -1268,6 +1270,13 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } else if (!strcmp(arg, "--cherry-pick")) { revs->cherry_pick = 1; revs->limited = 1; + } else if (!prefixcmp(arg, "--cherry-pick=")) { + revs->cherry_pick = 1; + revs->limited = 1; + if (!strcmp(arg+14, "loose")) + revs->cherry_pick_loose = 1; + else if (strcmp(arg+14, "strict")) + return error("bad --cherry-pick argument"); } else if (!strcmp(arg, "--objects")) { revs->tag_objects = 1; revs->tree_objects = 1; diff --git a/revision.h b/revision.h index 05659c6..3f94b27 100644 --- a/revision.h +++ b/revision.h @@ -66,6 +66,7 @@ struct rev_info { reverse:1, reverse_output_stage:1, cherry_pick:1, + cherry_pick_loose:1, bisect:1, ancestry_path:1, first_parent_only:1; -- 1.7.4.1.51.g2cc0c.dirty -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html