From 93a7004cc234da31d912bb0f266c39b99ab8c8db Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 18 Jul 2014 14:50:06 -0400 Subject: [PATCH] git_rebase_commit: drop already-picked commits Already cherry-picked commits should not be re-included. If all changes included in a commit exist in the upstream, then we should error with GIT_EAPPLIED. --- include/git2/errors.h | 1 + include/git2/rebase.h | 4 +- src/rebase.c | 19 +++++++-- tests/rebase/merge.c | 38 ++++++++++++++++++ .../05/3808a709cf91385985369159b296cf61a177ac | Bin 0 -> 241 bytes .../50/8be4ff49d38465ad3de58f66d38f70e59f881f | Bin 0 -> 241 bytes .../61/139b9b40a3e489f4abbc6af14e10ae14006e47 | Bin 0 -> 224 bytes .../ad/c97cfb874cdfb9d5ab17b54f3771dea6e02ccf | Bin 0 -> 240 bytes .../cb/20a10406172afd6ca3138ce36ecaf8b1269e8e | Bin 0 -> 213 bytes .../d4/82e77aecb8e07da43e4cad6e0dcb59219e12af | Bin 0 -> 175 bytes .../dc/12ac1e10f2be70e8ecd52132a08da98a309c3a | Bin 0 -> 187 bytes .../e7/bb00c4eab291e08361fda376733a12b4150aa9 | Bin 0 -> 241 bytes .../ed/f7b3ffde1624c60d2d6b1a2bb792d86de172e0 | Bin 0 -> 171 bytes .../rebase/.gitted/refs/heads/green_pea | Bin 0 -> 41 bytes 14 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 tests/resources/rebase/.gitted/objects/05/3808a709cf91385985369159b296cf61a177ac create mode 100644 tests/resources/rebase/.gitted/objects/50/8be4ff49d38465ad3de58f66d38f70e59f881f create mode 100644 tests/resources/rebase/.gitted/objects/61/139b9b40a3e489f4abbc6af14e10ae14006e47 create mode 100644 tests/resources/rebase/.gitted/objects/ad/c97cfb874cdfb9d5ab17b54f3771dea6e02ccf create mode 100644 tests/resources/rebase/.gitted/objects/cb/20a10406172afd6ca3138ce36ecaf8b1269e8e create mode 100644 tests/resources/rebase/.gitted/objects/d4/82e77aecb8e07da43e4cad6e0dcb59219e12af create mode 100644 tests/resources/rebase/.gitted/objects/dc/12ac1e10f2be70e8ecd52132a08da98a309c3a create mode 100644 tests/resources/rebase/.gitted/objects/e7/bb00c4eab291e08361fda376733a12b4150aa9 create mode 100644 tests/resources/rebase/.gitted/objects/ed/f7b3ffde1624c60d2d6b1a2bb792d86de172e0 create mode 100644 tests/resources/rebase/.gitted/refs/heads/green_pea diff --git a/include/git2/errors.h b/include/git2/errors.h index 5dfa72ab8..b33118e02 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -43,6 +43,7 @@ typedef enum { GIT_EMODIFIED = -15, /**< Reference value does not match expected */ GIT_EAUTH = -16, /**< Authentication error */ GIT_ECERTIFICATE = -17, /**< Server certificate is invalid */ + GIT_EAPPLIED = -18, /**< Patch/merge has already been applied */ GIT_PASSTHROUGH = -30, /**< Internal only */ GIT_ITEROVER = -31, /**< Signals end of iteration with iterator */ diff --git a/include/git2/rebase.h b/include/git2/rebase.h index 0fe2b263d..32b4ff614 100644 --- a/include/git2/rebase.h +++ b/include/git2/rebase.h @@ -99,7 +99,9 @@ GIT_EXTERN(int) git_rebase_next( * @param message The message for this commit, or NULL to keep the message * from the original commit * @return Zero on success, GIT_EUNMERGED if there are unmerged changes in - * the index, -1 on failure. + * the index, GIT_EAPPLIED if the current commit has already + * been applied to the upstream and there is nothing to commit, + * -1 on failure. */ GIT_EXTERN(int) git_rebase_commit( git_oid *id, diff --git a/src/rebase.c b/src/rebase.c index 9245dcada..a28a928fc 100644 --- a/src/rebase.c +++ b/src/rebase.c @@ -674,7 +674,8 @@ static int rebase_commit_merge( git_index *index = NULL; git_reference *head = NULL; git_commit *head_commit = NULL; - git_tree *tree = NULL; + git_tree *head_tree = NULL, *tree = NULL; + git_diff *diff = NULL; git_oid tree_id; char old_idstr[GIT_OID_HEXSZ], new_idstr[GIT_OID_HEXSZ]; int error; @@ -694,11 +695,19 @@ static int rebase_commit_merge( goto done; } - /* TODO: if there are no changes, error with a useful code */ - if ((error = git_repository_head(&head, repo)) < 0 || (error = git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT)) < 0 || - (error = git_index_write_tree(&tree_id, index)) < 0 || + (error = git_commit_tree(&head_tree, head_commit)) < 0 || + (error = git_diff_tree_to_index(&diff, repo, head_tree, index, NULL)) < 0) + goto done; + + if (git_diff_num_deltas(diff) == 0) { + giterr_set(GITERR_REBASE, "This patch has already been applied"); + error = GIT_EAPPLIED; + goto done; + } + + if ((error = git_index_write_tree(&tree_id, index)) < 0 || (error = git_tree_lookup(&tree, repo, &tree_id)) < 0) goto done; @@ -722,7 +731,9 @@ static int rebase_commit_merge( "%.*s %.*s\n", GIT_OID_HEXSZ, old_idstr, GIT_OID_HEXSZ, new_idstr); done: + git_diff_free(diff); git_tree_free(tree); + git_tree_free(head_tree); git_commit_free(head_commit); git_reference_free(head); git_index_free(index); diff --git a/tests/rebase/merge.c b/tests/rebase/merge.c index e578bef9b..04d06d2e8 100644 --- a/tests/rebase/merge.c +++ b/tests/rebase/merge.c @@ -207,3 +207,41 @@ void test_rebase_merge__commit_updates_rewritten(void) git_reference_free(upstream_ref); } +void test_rebase_merge__commit_drops_already_applied(void) +{ + git_reference *branch_ref, *upstream_ref; + git_merge_head *branch_head, *upstream_head; + git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; + git_oid commit_id; + int error; + + checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; + + cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef")); + cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/green_pea")); + + cl_git_pass(git_merge_head_from_ref(&branch_head, repo, branch_ref)); + cl_git_pass(git_merge_head_from_ref(&upstream_head, repo, upstream_ref)); + + cl_git_pass(git_rebase(repo, branch_head, upstream_head, NULL, signature, NULL)); + + cl_git_pass(git_rebase_next(repo, &checkout_opts)); + cl_git_fail(error = git_rebase_commit(&commit_id, repo, NULL, signature, + NULL, NULL)); + + cl_assert_equal_i(GIT_EAPPLIED, error); + + cl_git_pass(git_rebase_next(repo, &checkout_opts)); + cl_git_pass(git_rebase_commit(&commit_id, repo, NULL, signature, + NULL, NULL)); + + cl_assert_equal_file( + "8d1f13f93c4995760ac07d129246ac1ff64c0be9 2ac4fb7b74c1287f6c792acad759e1ec01e18dae\n", + 82, "rebase/.git/rebase-merge/rewritten"); + + git_merge_head_free(branch_head); + git_merge_head_free(upstream_head); + git_reference_free(branch_ref); + git_reference_free(upstream_ref); +} + diff --git a/tests/resources/rebase/.gitted/objects/05/3808a709cf91385985369159b296cf61a177ac b/tests/resources/rebase/.gitted/objects/05/3808a709cf91385985369159b296cf61a177ac new file mode 100644 index 0000000000000000000000000000000000000000..c38c5b2559b84ceb7258e8da700eedc03890bbe9 GIT binary patch literal 241 zcmV5vtTeZFfcPQQAjK(d zZoQKFhYj;yN6FsfYiQ+yDoZa)EUN@7I`Zty;x}0jMEWin{wxZ=-(x7p7!OyJnwl41 zkeUcqm?%7Zw!`8lonKb($@=Iguug;_&mF2Tzp}U_wFs;#W4-)whx(gq?~608sM~ll rrew;|8BkSasfjsYHOn`o1=nRi7nrsG$^YrwO0PU9zoh^G>x*v?$P9A> literal 0 HcmV?d00001 diff --git a/tests/resources/rebase/.gitted/objects/50/8be4ff49d38465ad3de58f66d38f70e59f881f b/tests/resources/rebase/.gitted/objects/50/8be4ff49d38465ad3de58f66d38f70e59f881f new file mode 100644 index 0000000000000000000000000000000000000000..7ce4452b20d881ce6da47bae4d2d29bb7ab34217 GIT binary patch literal 241 zcmV5vtTeZFfcPQQAjKe(PQ)+_MOo)7?gvz}m=zMMibgQv(a}64W|_7wiExw9II8;hqyn+C zu8;3=$Dzaiet-9L()t}oUE|zdk2|H_>KBc}1^T0Yyu98}pK)uiXj)vJHJZ~wH~)Br z;CY4fh-`X77$KHaPfYWQL^M>0Szus|AI8iZF*z^jZHSQuq{%Q>DBA+XZBvLfWdErm znN(r1uD6(S5_E(vI4)O3SUgA}M~GvFkRND%D5>ke$ioR1Cl*G1XEO`UTWt}P;$a)R aEG7K)$`X)b2tNHiIC9AIPW=FMfM2`M3u^%Y literal 0 HcmV?d00001 diff --git a/tests/resources/rebase/.gitted/objects/ad/c97cfb874cdfb9d5ab17b54f3771dea6e02ccf b/tests/resources/rebase/.gitted/objects/ad/c97cfb874cdfb9d5ab17b54f3771dea6e02ccf new file mode 100644 index 0000000000000000000000000000000000000000..cc7ccd086741e69c8497d5d45ab28f9c6aff4754 GIT binary patch literal 240 zcmV5vtTeZFfcPQQAjK*bF-)ZbitUz~A8-NutK qB~y;hfT}7>P0RtSS-v4HxGwv-z^wgG{!ialdgVd+Ed>CSKW@m+7H>=d literal 0 HcmV?d00001 diff --git a/tests/resources/rebase/.gitted/objects/cb/20a10406172afd6ca3138ce36ecaf8b1269e8e b/tests/resources/rebase/.gitted/objects/cb/20a10406172afd6ca3138ce36ecaf8b1269e8e new file mode 100644 index 0000000000000000000000000000000000000000..acd6bdc56c66e9a9d28822b20e7d525bf8edd683 GIT binary patch literal 213 zcmV;`04o1@0WFR(Zo@DPMLX*h{{TjYOa(e+FgmpjQuF|_L{~y&QI#k-zI`dQ8$mw) z_m{*A&d=wk*V{b5<2qmP`SEo<8S`fEgeahgb&?L)hJ!miLju9qNFIeO8uv1Rvm!C0 zBOVfqDgJDDNWF;LSy#Q$aOB@Ly8cI5PwDGPXh2tm~aeWNp26Qv?q|r<) zIZqW#XEt>e0gqu6my#RU2G@CF%i=@oy5>`l;)fK1PHLf5<_a9Op{PY;GNUveB(gW! z8p6Od1hP0pONyTLURF5qi&loqz2rxkVJ|KHsH1$r&+TH#2ha|EkG-}Iw&)O5OWW8g df7YmT;VDg#>eMD^s0D8A`+Qx5)Ej|dR+c2HQEvbM literal 0 HcmV?d00001 diff --git a/tests/resources/rebase/.gitted/objects/dc/12ac1e10f2be70e8ecd52132a08da98a309c3a b/tests/resources/rebase/.gitted/objects/dc/12ac1e10f2be70e8ecd52132a08da98a309c3a new file mode 100644 index 0000000000000000000000000000000000000000..9907248f80272eb58e06e82f680ad4640f9f1cd2 GIT binary patch literal 187 zcmV;s07UJ&!nb7WI$ZH^8!^##STMvhD=1fy-~b@yZ7D) zk1w@ts{1m4XX_-`BQh`M%3b#XnhS|9C991tq=?z& zD3+ZFEiRwp1mqMAe~h(tc*&pKGrX;ByR{u2b*?|@tiRx|J*2ihfem;hj6@6EV?Z=> pow7s!d1Ibe?fna`HC^id4u{v4YpIDxok|u)15qsp^9{O>T6wLJR`>t_ literal 0 HcmV?d00001 diff --git a/tests/resources/rebase/.gitted/objects/e7/bb00c4eab291e08361fda376733a12b4150aa9 b/tests/resources/rebase/.gitted/objects/e7/bb00c4eab291e08361fda376733a12b4150aa9 new file mode 100644 index 0000000000000000000000000000000000000000..da96e9d9c06f9526ab0d57d2fe2b2accd1b5475f GIT binary patch literal 241 zcmV5vtTeZFfcPQQAjKr68u>*Q zZbXQ!aF%GUeveB(;6r}uA#l3%?W^zbqEr1tZ+bKC?1}sK3L*ML9Kr@t ZpE2%TWF70Q?*^aq^?tr;b-!AYRfImAR)qin literal 0 HcmV?d00001 diff --git a/tests/resources/rebase/.gitted/refs/heads/green_pea b/tests/resources/rebase/.gitted/refs/heads/green_pea new file mode 100644 index 0000000000000000000000000000000000000000..3bffe27d1e1b412f5a7e62fb191b68805fd34921 GIT binary patch literal 41 ucmV~$NdW*L2n4{tX#i0m4#(O*f-|EoFiUhf$R>3|JLiI?>x6KCCExl0mka3t literal 0 HcmV?d00001