diff --git a/revision.c b/revision.c index 486393cb0835ce70f685d665b916e1b67974f184..e9de8650d37398b5d46256eced053f3b7dd4e25a 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; diff --git a/revision.h b/revision.h index 5f3f628a9b1ec278dddc1d894066ab1278f6e473..8a026184287479272ececf5cf3d5000c52007553 100644 --- a/revision.h +++ b/revision.h @@ -47,6 +47,7 @@ struct rev_info { left_right:1, parents:1, reverse:1, + cherry_pick:1, first_parent_only:1; /* Diff flags */