summaryrefslogtreecommitdiff
path: root/revision.c
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2007-04-09 03:40:38 -0700
committerJunio C Hamano <junkio@cox.net>2007-04-11 20:02:03 -0700
commitd7a17cad9798693dc31043aa4efcce0b207483b9 (patch)
tree6e05ed931a1a9a6aeffab4dad24f74195b2ce171 /revision.c
parent5d23e133d23bc9e26d6f23a4d136901e18e6ffba (diff)
downloadgit-d7a17cad9798693dc31043aa4efcce0b207483b9.tar.gz
git-log --cherry-pick A...B
This is meant to be a saner replacement for "git-cherry". When used with "A...B", this filters out commits whose patch text has the same patch-id as a commit on the other side. It would probably most useful to use with --left-right. Signed-off-by: Junio C Hamano <junkio@cox.net>
Diffstat (limited to 'revision.c')
-rw-r--r--revision.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/revision.c b/revision.c
index 486393cb08..e9de8650d3 100644
--- a/revision.c
+++ b/revision.c
@@ -8,6 +8,7 @@
#include "revision.h"
#include "grep.h"
#include "reflog-walk.h"
+#include "patch-ids.h"
static char *path_name(struct name_path *path, const char *name)
{
@@ -422,6 +423,86 @@ static void add_parents_to_list(struct rev_info *revs, struct commit *commit, st
}
}
+static void cherry_pick_list(struct commit_list *list)
+{
+ struct commit_list *p;
+ int left_count = 0, right_count = 0;
+ int left_first;
+ struct patch_ids ids;
+
+ /* First count the commits on the left and on the right */
+ for (p = list; p; p = p->next) {
+ struct commit *commit = p->item;
+ unsigned flags = commit->object.flags;
+ if (flags & BOUNDARY)
+ ;
+ else if (flags & SYMMETRIC_LEFT)
+ left_count++;
+ else
+ right_count++;
+ }
+
+ left_first = left_count < right_count;
+ init_patch_ids(&ids);
+
+ /* Compute patch-ids for one side */
+ for (p = list; p; p = p->next) {
+ struct commit *commit = p->item;
+ unsigned flags = commit->object.flags;
+
+ if (flags & BOUNDARY)
+ continue;
+ /*
+ * If we have fewer left, left_first is set and we omit
+ * commits on the right branch in this loop. If we have
+ * fewer right, we skip the left ones.
+ */
+ if (left_first != !!(flags & SYMMETRIC_LEFT))
+ continue;
+ commit->util = add_commit_patch_id(commit, &ids);
+ }
+
+ /* Check the other side */
+ for (p = list; p; p = p->next) {
+ struct commit *commit = p->item;
+ struct patch_id *id;
+ unsigned flags = commit->object.flags;
+
+ if (flags & BOUNDARY)
+ continue;
+ /*
+ * If we have fewer left, left_first is set and we omit
+ * commits on the left branch in this loop.
+ */
+ if (left_first == !!(flags & SYMMETRIC_LEFT))
+ continue;
+
+ /*
+ * Have we seen the same patch id?
+ */
+ id = has_commit_patch_id(commit, &ids);
+ if (!id)
+ continue;
+ id->seen = 1;
+ commit->object.flags |= SHOWN;
+ }
+
+ /* Now check the original side for seen ones */
+ for (p = list; p; p = p->next) {
+ struct commit *commit = p->item;
+ struct patch_id *ent;
+
+ ent = commit->util;
+ if (!ent)
+ continue;
+ if (ent->seen)
+ commit->object.flags |= SHOWN;
+ commit->util = NULL;
+ }
+
+ free_patch_ids(&ids);
+}
+
static void limit_list(struct rev_info *revs)
{
struct commit_list *list = revs->commits;
@@ -449,6 +530,9 @@ static void limit_list(struct rev_info *revs)
continue;
p = &commit_list_insert(commit, p)->next;
}
+ if (revs->cherry_pick)
+ cherry_pick_list(newlist);
+
revs->commits = newlist;
}
@@ -913,6 +997,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
revs->left_right = 1;
continue;
}
+ if (!strcmp(arg, "--cherry-pick")) {
+ revs->cherry_pick = 1;
+ continue;
+ }
if (!strcmp(arg, "--objects")) {
revs->tag_objects = 1;
revs->tree_objects = 1;