[RFC/PATCH] rev-list: new --cherry-pick=loose option

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]