]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'jk/log-cherry-pick-duplicate-patches'
authorJunio C Hamano <gitster@pobox.com>
Mon, 25 Jan 2021 22:19:19 +0000 (14:19 -0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 25 Jan 2021 22:19:19 +0000 (14:19 -0800)
When more than one commit with the same patch ID appears on one
side, "git log --cherry-pick A...B" did not exclude them all when a
commit with the same patch ID appears on the other side.  Now it
does.

* jk/log-cherry-pick-duplicate-patches:
  patch-ids: handle duplicate hashmap entries

patch-ids.c
patch-ids.h
revision.c
t/t6007-rev-list-cherry-pick-file.sh

index cf5e8045b71073873a5a36f844d1c1ceb283384b..3f404e4b0b4cc24d02ae9cbf3c8498c37f673094 100644 (file)
@@ -89,7 +89,7 @@ static int init_patch_id_entry(struct patch_id *patch,
        return 0;
 }
 
-struct patch_id *has_commit_patch_id(struct commit *commit,
+struct patch_id *patch_id_iter_first(struct commit *commit,
                                     struct patch_ids *ids)
 {
        struct patch_id patch;
@@ -104,6 +104,18 @@ struct patch_id *has_commit_patch_id(struct commit *commit,
        return hashmap_get_entry(&ids->patches, &patch, ent, NULL);
 }
 
+struct patch_id *patch_id_iter_next(struct patch_id *cur,
+                                   struct patch_ids *ids)
+{
+       return hashmap_get_next_entry(&ids->patches, cur, ent);
+}
+
+int has_commit_patch_id(struct commit *commit,
+                       struct patch_ids *ids)
+{
+       return !!patch_id_iter_first(commit, ids);
+}
+
 struct patch_id *add_commit_patch_id(struct commit *commit,
                                     struct patch_ids *ids)
 {
index 03bb04e7071f5f65a3b09f138aa4473fa0a0a655..ab6c6a680474c9b2a37725fc9392683ac5a33083 100644 (file)
@@ -23,7 +23,25 @@ int commit_patch_id(struct commit *commit, struct diff_options *options,
                    struct object_id *oid, int, int);
 int init_patch_ids(struct repository *, struct patch_ids *);
 int free_patch_ids(struct patch_ids *);
+
+/* Add a patch_id for a single commit to the set. */
 struct patch_id *add_commit_patch_id(struct commit *, struct patch_ids *);
-struct patch_id *has_commit_patch_id(struct commit *, struct patch_ids *);
+
+/* Returns true if the patch-id of "commit" is present in the set. */
+int has_commit_patch_id(struct commit *commit, struct patch_ids *);
+
+/*
+ * Iterate over all commits in the set whose patch id matches that of
+ * "commit", like:
+ *
+ *   struct patch_id *cur;
+ *   for (cur = patch_id_iter_first(commit, ids);
+ *        cur;
+ *        cur = patch_id_iter_next(cur, ids) {
+ *           ... look at cur->commit
+ *   }
+ */
+struct patch_id *patch_id_iter_first(struct commit *commit, struct patch_ids *);
+struct patch_id *patch_id_iter_next(struct patch_id *cur, struct patch_ids *);
 
 #endif /* PATCH_IDS_H */
index 1bb590ece787573a1f46026453c5921150b8a1d1..0b5c723140148ab08816b7bde9d45715ae8371d6 100644 (file)
@@ -1241,12 +1241,14 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
                /*
                 * Have we seen the same patch id?
                 */
-               id = has_commit_patch_id(commit, &ids);
+               id = patch_id_iter_first(commit, &ids);
                if (!id)
                        continue;
 
                commit->object.flags |= cherry_flag;
-               id->commit->object.flags |= cherry_flag;
+               do {
+                       id->commit->object.flags |= cherry_flag;
+               } while ((id = patch_id_iter_next(id, &ids)));
        }
 
        free_patch_ids(&ids);
index b22bf00598bf013a7bbc8a6069394e10469379fb..aebe4b69e13ea56444dc760cb1b6058702f2d241 100755 (executable)
@@ -248,6 +248,18 @@ test_expect_success '--count --left-right' '
        test_cmp expect actual
 '
 
+test_expect_success '--cherry-pick with duplicates on each side' '
+       git checkout -b dup-orig &&
+       test_commit dup-base &&
+       git revert dup-base &&
+       git cherry-pick dup-base &&
+       git checkout -b dup-side HEAD~3 &&
+       test_tick &&
+       git cherry-pick -3 dup-orig &&
+       git rev-list --cherry-pick dup-orig...dup-side >actual &&
+       test_must_be_empty actual
+'
+
 # Corrupt the object store deliberately to make sure
 # the object is not even checked for its existence.
 remove_loose_object () {