Commit 5a296ad0 by Carlos Martín Nieto

Merge pull request #3610 from ethomson/rebase_bare

rebase: introduce bare rebasing
parents 2f2129b1 a202e0d4
......@@ -39,6 +39,15 @@ typedef struct {
int quiet;
/**
* Used by `git_rebase_init`, this will begin an in-memory rebase,
* which will allow callers to step through the rebase operations and
* commit the rebased changes, but will not rewind HEAD or update the
* repository to be in a rebasing state. This will not interfere with
* the working directory (if there is one).
*/
int inmemory;
/**
* Used by `git_rebase_finish`, this is the name of the notes reference
* used to rewrite notes for rebased commits when finishing the rebase;
* if NULL, the contents of the configuration option `notes.rewriteRef`
......@@ -49,6 +58,11 @@ typedef struct {
const char *rewrite_notes_ref;
/**
* Options to control how trees are merged during `git_rebase_next`.
*/
git_merge_options merge_options;
/**
* Options to control how files are written during `git_rebase_init`,
* `git_checkout_next` and `git_checkout_abort`. Note that a minimum
* strategy of `GIT_CHECKOUT_SAFE` is defaulted in `init` and `next`,
......@@ -101,7 +115,8 @@ typedef enum {
#define GIT_REBASE_OPTIONS_VERSION 1
#define GIT_REBASE_OPTIONS_INIT \
{GIT_REBASE_OPTIONS_VERSION, 0, NULL, GIT_CHECKOUT_OPTIONS_INIT}
{ GIT_REBASE_OPTIONS_VERSION, 0, 0, NULL, GIT_MERGE_OPTIONS_INIT, \
GIT_CHECKOUT_OPTIONS_INIT}
/** Indicates that a rebase operation is not (yet) in progress. */
#define GIT_REBASE_NO_OPERATION SIZE_MAX
......@@ -127,6 +142,12 @@ typedef struct {
* be populated for operations of type `GIT_REBASE_OPERATION_EXEC`.
*/
const char *exec;
/**
* The index that is the result of an operation.
* This is set only for in-memory rebases.
*/
git_index *index;
} git_rebase_operation;
/**
......
#include "clar_libgit2.h"
#include "git2/rebase.h"
#include "posix.h"
#include <fcntl.h>
static git_repository *repo;
// Fixture setup and teardown
void test_rebase_inmemory__initialize(void)
{
repo = cl_git_sandbox_init("rebase");
}
void test_rebase_inmemory__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_rebase_inmemory__not_in_rebase_state(void)
{
git_rebase *rebase;
git_reference *branch_ref, *upstream_ref;
git_annotated_commit *branch_head, *upstream_head;
git_rebase_options opts = GIT_REBASE_OPTIONS_INIT;
opts.inmemory = true;
cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef"));
cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master"));
cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref));
cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref));
cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, &opts));
cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo));
git_rebase_free(rebase);
git_annotated_commit_free(branch_head);
git_annotated_commit_free(upstream_head);
git_reference_free(branch_ref);
git_reference_free(upstream_ref);
}
void test_rebase_inmemory__can_resolve_conflicts(void)
{
git_rebase *rebase;
git_reference *branch_ref, *upstream_ref;
git_annotated_commit *branch_head, *upstream_head;
git_rebase_operation *rebase_operation;
git_status_list *status_list;
git_oid pick_id, commit_id, expected_commit_id;
git_signature *signature;
git_index *repo_index;
git_index_entry resolution = {{0}};
git_rebase_options opts = GIT_REBASE_OPTIONS_INIT;
cl_git_pass(git_signature_new(&signature,
"Rebaser", "rebaser@rebaser.rb", 1405694510, 0));
opts.inmemory = true;
cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/asparagus"));
cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master"));
cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref));
cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref));
cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, &opts));
cl_git_pass(git_rebase_next(&rebase_operation, rebase));
git_oid_fromstr(&pick_id, "33f915f9e4dbd9f4b24430e48731a59b45b15500");
cl_assert_equal_i(GIT_REBASE_OPERATION_PICK, rebase_operation->type);
cl_assert_equal_oid(&pick_id, &rebase_operation->id);
/* ensure that we did not do anything stupid to the workdir or repo index */
cl_git_pass(git_repository_index(&repo_index, repo));
cl_assert(!git_index_has_conflicts(repo_index));
cl_git_pass(git_status_list_new(&status_list, repo, NULL));
cl_assert_equal_i(0, git_status_list_entrycount(status_list));
/* but that the index returned from rebase does have conflicts */
cl_assert(git_index_has_conflicts(rebase_operation->index));
cl_git_fail_with(GIT_EUNMERGED, git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL));
/* ensure that we can work with the in-memory index to resolve the conflict */
resolution.path = "asparagus.txt";
resolution.mode = GIT_FILEMODE_BLOB;
git_oid_fromstr(&resolution.id, "414dfc71ead79c07acd4ea47fecf91f289afc4b9");
cl_git_pass(git_index_conflict_remove(rebase_operation->index, "asparagus.txt"));
cl_git_pass(git_index_add(rebase_operation->index, &resolution));
/* and finally create a commit for the resolved rebase operation */
cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL));
cl_git_pass(git_oid_fromstr(&expected_commit_id, "db7af47222181e548810da2ab5fec0e9357c5637"));
cl_assert_equal_oid(&commit_id, &expected_commit_id);
git_signature_free(signature);
git_status_list_free(status_list);
git_annotated_commit_free(branch_head);
git_annotated_commit_free(upstream_head);
git_reference_free(branch_ref);
git_reference_free(upstream_ref);
git_index_free(repo_index);
git_rebase_free(rebase);
}
......@@ -46,26 +46,32 @@ static void test_operations(git_rebase *rebase, size_t expected_current)
}
}
void test_rebase_iterator__iterates(void)
void test_iterator(bool inmemory)
{
git_rebase *rebase;
git_rebase_options opts = GIT_REBASE_OPTIONS_INIT;
git_reference *branch_ref, *upstream_ref;
git_annotated_commit *branch_head, *upstream_head;
git_rebase_operation *rebase_operation;
git_oid commit_id;
int error;
opts.inmemory = inmemory;
cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef"));
cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master"));
cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref));
cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref));
cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL));
cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, &opts));
test_operations(rebase, GIT_REBASE_NO_OPERATION);
git_rebase_free(rebase);
cl_git_pass(git_rebase_open(&rebase, repo, NULL));
if (!inmemory) {
git_rebase_free(rebase);
cl_git_pass(git_rebase_open(&rebase, repo, NULL));
}
cl_git_pass(git_rebase_next(&rebase_operation, rebase));
cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature,
NULL, NULL));
......@@ -81,8 +87,10 @@ void test_rebase_iterator__iterates(void)
NULL, NULL));
test_operations(rebase, 2);
git_rebase_free(rebase);
cl_git_pass(git_rebase_open(&rebase, repo, NULL));
if (!inmemory) {
git_rebase_free(rebase);
cl_git_pass(git_rebase_open(&rebase, repo, NULL));
}
cl_git_pass(git_rebase_next(&rebase_operation, rebase));
cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature,
......@@ -104,3 +112,13 @@ void test_rebase_iterator__iterates(void)
git_reference_free(upstream_ref);
git_rebase_free(rebase);
}
void test_rebase_iterator__iterates(void)
{
test_iterator(false);
}
void test_rebase_iterator__iterates_inmemory(void)
{
test_iterator(true);
}
......@@ -565,3 +565,33 @@ void test_rebase_merge__custom_checkout_options(void)
git_reference_free(upstream_ref);
git_rebase_free(rebase);
}
void test_rebase_merge__custom_merge_options(void)
{
git_rebase *rebase;
git_reference *branch_ref, *upstream_ref;
git_annotated_commit *branch_head, *upstream_head;
git_rebase_options rebase_options = GIT_REBASE_OPTIONS_INIT;
git_rebase_operation *rebase_operation;
rebase_options.merge_options.flags |=
GIT_MERGE_FAIL_ON_CONFLICT |
GIT_MERGE_SKIP_REUC;
cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/asparagus"));
cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master"));
cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref));
cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref));
cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, &rebase_options));
cl_git_fail_with(GIT_EMERGECONFLICT, git_rebase_next(&rebase_operation, rebase));
git_annotated_commit_free(branch_head);
git_annotated_commit_free(upstream_head);
git_reference_free(branch_ref);
git_reference_free(upstream_ref);
git_rebase_free(rebase);
}
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