Commit 93a7004c by Edward Thomson Committed by Edward Thomson

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.
parent a35a9890
...@@ -43,6 +43,7 @@ typedef enum { ...@@ -43,6 +43,7 @@ typedef enum {
GIT_EMODIFIED = -15, /**< Reference value does not match expected */ GIT_EMODIFIED = -15, /**< Reference value does not match expected */
GIT_EAUTH = -16, /**< Authentication error */ GIT_EAUTH = -16, /**< Authentication error */
GIT_ECERTIFICATE = -17, /**< Server certificate is invalid */ GIT_ECERTIFICATE = -17, /**< Server certificate is invalid */
GIT_EAPPLIED = -18, /**< Patch/merge has already been applied */
GIT_PASSTHROUGH = -30, /**< Internal only */ GIT_PASSTHROUGH = -30, /**< Internal only */
GIT_ITEROVER = -31, /**< Signals end of iteration with iterator */ GIT_ITEROVER = -31, /**< Signals end of iteration with iterator */
......
...@@ -99,7 +99,9 @@ GIT_EXTERN(int) git_rebase_next( ...@@ -99,7 +99,9 @@ GIT_EXTERN(int) git_rebase_next(
* @param message The message for this commit, or NULL to keep the message * @param message The message for this commit, or NULL to keep the message
* from the original commit * from the original commit
* @return Zero on success, GIT_EUNMERGED if there are unmerged changes in * @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_EXTERN(int) git_rebase_commit(
git_oid *id, git_oid *id,
......
...@@ -674,7 +674,8 @@ static int rebase_commit_merge( ...@@ -674,7 +674,8 @@ static int rebase_commit_merge(
git_index *index = NULL; git_index *index = NULL;
git_reference *head = NULL; git_reference *head = NULL;
git_commit *head_commit = 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; git_oid tree_id;
char old_idstr[GIT_OID_HEXSZ], new_idstr[GIT_OID_HEXSZ]; char old_idstr[GIT_OID_HEXSZ], new_idstr[GIT_OID_HEXSZ];
int error; int error;
...@@ -694,11 +695,19 @@ static int rebase_commit_merge( ...@@ -694,11 +695,19 @@ static int rebase_commit_merge(
goto done; goto done;
} }
/* TODO: if there are no changes, error with a useful code */
if ((error = git_repository_head(&head, repo)) < 0 || if ((error = git_repository_head(&head, repo)) < 0 ||
(error = git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT)) < 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) (error = git_tree_lookup(&tree, repo, &tree_id)) < 0)
goto done; goto done;
...@@ -722,7 +731,9 @@ static int rebase_commit_merge( ...@@ -722,7 +731,9 @@ static int rebase_commit_merge(
"%.*s %.*s\n", GIT_OID_HEXSZ, old_idstr, GIT_OID_HEXSZ, new_idstr); "%.*s %.*s\n", GIT_OID_HEXSZ, old_idstr, GIT_OID_HEXSZ, new_idstr);
done: done:
git_diff_free(diff);
git_tree_free(tree); git_tree_free(tree);
git_tree_free(head_tree);
git_commit_free(head_commit); git_commit_free(head_commit);
git_reference_free(head); git_reference_free(head);
git_index_free(index); git_index_free(index);
......
...@@ -207,3 +207,41 @@ void test_rebase_merge__commit_updates_rewritten(void) ...@@ -207,3 +207,41 @@ void test_rebase_merge__commit_updates_rewritten(void)
git_reference_free(upstream_ref); 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);
}
d482e77aecb8e07da43e4cad6e0dcb59219e12af
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment