diff --git a/CHANGELOG.md b/CHANGELOG.md index e076dd5ab..93b189c05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -90,3 +90,17 @@ v0.21 + 1 * Introduce git_merge_bases_many() to expose all merge bases between multiple commits. + +* git_merge_head is now git_annotated_commit, to better reflect its usage + for multiple functions (including rebase) + +* Introduce rebase functionality (using the merge algorithm only). + Introduce git_rebase_init() to begin a new rebase session, + git_rebase_open() to open an in-progress rebase session, + git_rebase_commit() to commit the current rebase operation, + git_rebase_next() to apply the next rebase operation, + git_rebase_abort() to abort an in-progress rebase and git_rebase_finish() + to complete a rebase operation. + +* Introduce git_note_author() and git_note_committer() to get the author + and committer information on a git_note, respectively. diff --git a/include/git2.h b/include/git2.h index baa7fcaf8..41adbbad2 100644 --- a/include/git2.h +++ b/include/git2.h @@ -8,6 +8,7 @@ #ifndef INCLUDE_git_git_h__ #define INCLUDE_git_git_h__ +#include "git2/annotated_commit.h" #include "git2/attr.h" #include "git2/blob.h" #include "git2/blame.h" @@ -39,6 +40,7 @@ #include "git2/patch.h" #include "git2/pathspec.h" #include "git2/push.h" +#include "git2/rebase.h" #include "git2/refdb.h" #include "git2/reflog.h" #include "git2/refs.h" diff --git a/include/git2/annotated_commit.h b/include/git2/annotated_commit.h new file mode 100644 index 000000000..87e3398a0 --- /dev/null +++ b/include/git2/annotated_commit.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_git_annotated_commit_h__ +#define INCLUDE_git_annotated_commit_h__ + +#include "common.h" +#include "repository.h" +#include "types.h" + +/** + * @file git2/annotated_commit.h + * @brief Git annotated commit routines + * @defgroup git_annotated_commit Git annotated commit routines + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * Creates a `git_annotated_commit` from the given reference. + * The resulting git_annotated_commit must be freed with + * `git_annotated_commit_free`. + * + * @param out pointer to store the git_annotated_commit result in + * @param repo repository that contains the given reference + * @param ref reference to use to lookup the git_annotated_commit + * @return 0 on success or error code + */ +GIT_EXTERN(int) git_annotated_commit_from_ref( + git_annotated_commit **out, + git_repository *repo, + const git_reference *ref); + +/** + * Creates a `git_annotated_commit` from the given fetch head data. + * The resulting git_annotated_commit must be freed with + * `git_annotated_commit_free`. + * + * @param out pointer to store the git_annotated_commit result in + * @param repo repository that contains the given commit + * @param branch_name name of the (remote) branch + * @param remote_url url of the remote + * @param oid the commit object id of the remote branch + * @return 0 on success or error code + */ +GIT_EXTERN(int) git_annotated_commit_from_fetchhead( + git_annotated_commit **out, + git_repository *repo, + const char *branch_name, + const char *remote_url, + const git_oid *id); + +/** + * Creates a `git_annotated_commit` from the given commit id. + * The resulting git_annotated_commit must be freed with + * `git_annotated_commit_free`. + * + * An annotated commit contains information about how it was + * looked up, which may be useful for functions like merge or + * rebase to provide context to the operation. For example, + * conflict files will include the name of the source or target + * branches being merged. It is therefore preferable to use the + * most specific function (eg `git_annotated_commit_from_ref`) + * instead of this one when that data is known. + * + * @param out pointer to store the git_annotated_commit result in + * @param repo repository that contains the given commit + * @param id the commit object id to lookup + * @return 0 on success or error code + */ +GIT_EXTERN(int) git_annotated_commit_lookup( + git_annotated_commit **out, + git_repository *repo, + const git_oid *id); + +/** + * Gets the commit ID that the given `git_annotated_commit` refers to. + * + * @param head the given annotated commit + * @return commit id + */ +GIT_EXTERN(const git_oid *) git_annotated_commit_id( + const git_annotated_commit *commit); + +/** + * Frees a `git_annotated_commit`. + * + * @param annotated_commit annotated commit to free + */ +GIT_EXTERN(void) git_annotated_commit_free( + git_annotated_commit *commit); + +/** @} */ +GIT_END_DECL +#endif diff --git a/include/git2/errors.h b/include/git2/errors.h index 1e3ed3acb..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 */ @@ -90,6 +91,7 @@ typedef enum { GITERR_CALLBACK, GITERR_CHERRYPICK, GITERR_DESCRIBE, + GITERR_REBASE, } git_error_t; /** diff --git a/include/git2/merge.h b/include/git2/merge.h index ed1b9a30f..9082fd6fb 100644 --- a/include/git2/merge.h +++ b/include/git2/merge.h @@ -13,6 +13,7 @@ #include "oidarray.h" #include "checkout.h" #include "index.h" +#include "annotated_commit.h" /** * @file git2/merge.h @@ -303,7 +304,7 @@ GIT_EXTERN(int) git_merge_analysis( git_merge_analysis_t *analysis_out, git_merge_preference_t *preference_out, git_repository *repo, - const git_merge_head **their_heads, + const git_annotated_commit **their_heads, size_t their_heads_len); /** @@ -381,69 +382,6 @@ GIT_EXTERN(int) git_merge_base_octopus( size_t length, const git_oid input_array[]); -/** - * Creates a `git_merge_head` from the given reference. The resulting - * git_merge_head must be freed with `git_merge_head_free`. - * - * @param out pointer to store the git_merge_head result in - * @param repo repository that contains the given reference - * @param ref reference to use as a merge input - * @return 0 on success or error code - */ -GIT_EXTERN(int) git_merge_head_from_ref( - git_merge_head **out, - git_repository *repo, - const git_reference *ref); - -/** - * Creates a `git_merge_head` from the given fetch head data. The resulting - * git_merge_head must be freed with `git_merge_head_free`. - * - * @param out pointer to store the git_merge_head result in - * @param repo repository that contains the given commit - * @param branch_name name of the (remote) branch - * @param remote_url url of the remote - * @param oid the commit object id to use as a merge input - * @return 0 on success or error code - */ -GIT_EXTERN(int) git_merge_head_from_fetchhead( - git_merge_head **out, - git_repository *repo, - const char *branch_name, - const char *remote_url, - const git_oid *oid); - -/** - * Creates a `git_merge_head` from the given commit id. The resulting - * git_merge_head must be freed with `git_merge_head_free`. - * - * @param out pointer to store the git_merge_head result in - * @param repo repository that contains the given commit - * @param id the commit object id to use as a merge input - * @return 0 on success or error code - */ -GIT_EXTERN(int) git_merge_head_from_id( - git_merge_head **out, - git_repository *repo, - const git_oid *id); - -/** - * Gets the commit ID that the given `git_merge_head` refers to. - * - * @param head the given merge head - * @return commit id - */ -GIT_EXTERN(const git_oid *) git_merge_head_id( - const git_merge_head *head); - -/** - * Frees a `git_merge_head`. - * - * @param head merge head to free - */ -GIT_EXTERN(void) git_merge_head_free( - git_merge_head *head); - /** * Merge two files as they exist in the in-memory data structures, using * the given common ancestor as the baseline, producing a @@ -557,7 +495,7 @@ GIT_EXTERN(int) git_merge_commits( */ GIT_EXTERN(int) git_merge( git_repository *repo, - const git_merge_head **their_heads, + const git_annotated_commit **their_heads, size_t their_heads_len, const git_merge_options *merge_opts, const git_checkout_options *checkout_opts); diff --git a/include/git2/notes.h b/include/git2/notes.h index 98eb2aef3..1a7794a5c 100644 --- a/include/git2/notes.h +++ b/include/git2/notes.h @@ -96,6 +96,23 @@ GIT_EXTERN(int) git_note_read( const char *notes_ref, const git_oid *oid); +/** + * Get the note author + * + * @param note the note + * @return the author + */ +GIT_EXTERN(const git_signature *) git_note_author(const git_note *note); + +/** + * Get the note committer + * + * @param note the note + * @return the committer + */ +GIT_EXTERN(const git_signature *) git_note_committer(const git_note *note); + + /** * Get the note message * diff --git a/include/git2/rebase.h b/include/git2/rebase.h new file mode 100644 index 000000000..095975edb --- /dev/null +++ b/include/git2/rebase.h @@ -0,0 +1,261 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_git_rebase_h__ +#define INCLUDE_git_rebase_h__ + +#include "common.h" +#include "types.h" +#include "oid.h" +#include "annotated_commit.h" + +/** + * @file git2/rebase.h + * @brief Git rebase routines + * @defgroup git_rebase Git merge routines + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +typedef struct { + unsigned int version; + + /** + * Provide a quiet rebase experience; unused by libgit2 but provided for + * interoperability with other clients. + */ + int quiet; + + /** + * Canonical name of the notes reference used to rewrite notes for + * rebased commits when finishing the rebase; if NULL, the contents of + * the coniguration option `notes.rewriteRef` is examined, unless the + * configuration option `notes.rewrite.rebase` is set to false. If + * `notes.rewriteRef` is NULL, notes will not be rewritten. + */ + const char *rewrite_notes_ref; +} git_rebase_options; + +/** Type of rebase operation in-progress after calling `git_rebase_next`. */ +typedef enum { + /** + * The given commit is to be cherry-picked. The client should commit + * the changes and continue if there are no conflicts. + */ + GIT_REBASE_OPERATION_PICK = 0, + + /** + * The given commit is to be cherry-picked, but the client should prompt + * the user to provide an updated commit message. + */ + GIT_REBASE_OPERATION_REWORD, + + /** + * The given commit is to be cherry-picked, but the client should stop + * to allow the user to edit the changes before committing them. + */ + GIT_REBASE_OPERATION_EDIT, + + /** + * The given commit is to be squashed into the previous commit. The + * commit message will be merged with the previous message. + */ + GIT_REBASE_OPERATION_SQUASH, + + /** + * The given commit is to be squashed into the previous commit. The + * commit message from this commit will be discarded. + */ + GIT_REBASE_OPERATION_FIXUP, + + /** + * No commit will be cherry-picked. The client should run the given + * command and (if successful) continue. + */ + GIT_REBASE_OPERATION_EXEC, +} git_rebase_operation_t; + +#define GIT_REBASE_OPTIONS_VERSION 1 +#define GIT_REBASE_OPTIONS_INIT {GIT_REBASE_OPTIONS_VERSION} + +typedef struct { + /** The type of rebase operation. */ + git_rebase_operation_t type; + + /** + * The commit ID being cherry-picked. This will be populated for + * all operations except those of type `GIT_REBASE_OPERATION_EXEC`. + */ + const git_oid id; + + /** + * The executable the user has requested be run. This will only + * be populated for operations of type `GIT_REBASE_OPERATION_EXEC`. + */ + const char *exec; +} git_rebase_operation; + +/** + * Initializes a `git_rebase_options` with default values. Equivalent to + * creating an instance with GIT_REBASE_OPTIONS_INIT. + * + * @param opts the `git_rebase_options` instance to initialize. + * @param version the version of the struct; you should pass + * `GIT_REBASE_OPTIONS_VERSION` here. + * @return Zero on success; -1 on failure. + */ +GIT_EXTERN(int) git_rebase_init_options( + git_rebase_options *opts, + unsigned int version); + +/** + * Initializes a rebase operation to rebase the changes in `branch` + * relative to `upstream` onto another branch. To begin the rebase + * process, call `git_rebase_next`. When you have finished with this + * object, call `git_rebase_free`. + * + * @param out Pointer to store the rebase object + * @param repo The repository to perform the rebase + * @param branch The terminal commit to rebase + * @param upstream The commit to begin rebasing from, or NULL to rebase all + * reachable commits + * @param onto The branch to rebase onto, or NULL to rebase onto the given + * upstream + * @param signature The signature of the rebaser (optional) + * @param opts Options to specify how rebase is performed + * @return Zero on success; -1 on failure. + */ +GIT_EXTERN(int) git_rebase_init( + git_rebase **out, + git_repository *repo, + const git_annotated_commit *branch, + const git_annotated_commit *upstream, + const git_annotated_commit *onto, + const git_signature *signature, + const git_rebase_options *opts); + +/** + * Opens an existing rebase that was previously started by either an + * invocation of `git_rebase_init` or by another client. + * + * @param out Pointer to store the rebase object + * @param reop The repository that has a rebase in-progress + * @return Zero on success; -1 on failure. + */ +GIT_EXTERN(int) git_rebase_open(git_rebase **out, git_repository *repo); + +/** + * Gets the count of rebase operations that are to be applied. + * + * @param rebase The in-progress rebase + * @return The number of rebase operations in total + */ +GIT_EXTERN(size_t) git_rebase_operation_entrycount(git_rebase *rebase); + +/** + * Gets the index of the rebase operation that is currently being applied. + * + * @param rebase The in-progress rebase + * @return The index of the rebase operation currently being applied. + */ +GIT_EXTERN(size_t) git_rebase_operation_current(git_rebase *rebase); + +/** + * Gets the rebase operation specified by the given index. + * + * @param rebase The in-progress rebase + * @param idx The index of the rebase operation to retrieve + * @return The rebase operation or NULL if `idx` was out of bounds + */ +GIT_EXTERN(git_rebase_operation *) git_rebase_operation_byindex( + git_rebase *rebase, + size_t idx); + +/** + * Performs the next rebase operation and returns the information about it. + * If the operation is one that applies a patch (which is any operation except + * GIT_REBASE_OPERATION_EXEC) then the patch will be applied and the index and + * working directory will be updated with the changes. If there are conflicts, + * you will need to address those before committing the changes. + * + * @param out Pointer to store the rebase operation that is to be performed next + * @param repo The rebase in progress + * @param checkout_opts Options to specify how the patch should be checked out + * @return Zero on success; -1 on failure. + */ +GIT_EXTERN(int) git_rebase_next( + git_rebase_operation **operation, + git_rebase *rebase, + git_checkout_options *checkout_opts); + +/** + * Commits the current patch. You must have resolved any conflicts that + * were introduced during the patch application from the `git_rebase_next` + * invocation. + * + * @param id Pointer in which to store the OID of the newly created commit + * @param repo The rebase that is in-progress + * @param author The author of the updated commit, or NULL to keep the + * author from the original commit + * @param committer The committer of the rebase + * @param message_encoding The encoding for the message in the commit, + * represented with a standard encoding name. If message is NULL, + * this should also be NULL, and the encoding from the original + * commit will be maintained. If message is specified, this may be + * NULL to indicate that "UTF-8" is to be used. + * @param message The message for this commit, or NULL to use the message + * from the original commit. + * @return Zero on success, GIT_EUNMERGED if there are unmerged changes in + * 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, + git_rebase *rebase, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message); + +/** + * Aborts a rebase that is currently in progress, resetting the repository + * and working directory to their state before rebase began. + * + * @param rebase The rebase that is in-progress + * @param signature The identity that is aborting the rebase + * @return Zero on success; GIT_ENOTFOUND if a rebase is not in progress, + * -1 on other errors. + */ +GIT_EXTERN(int) git_rebase_abort( + git_rebase *rebase, + const git_signature *signature); + +/** + * Finishes a rebase that is currently in progress once all patches have + * been applied. + * + * @param rebase The rebase that is in-progress + * @param signature The identity that is finishing the rebase (optional) + * @param opts Options to specify how rebase is finished + * @param Zero on success; -1 on error + */ +GIT_EXTERN(int) git_rebase_finish( + git_rebase *rebase, + const git_signature *signature, + const git_rebase_options *opts); + +/** + * Frees the `git_rebase` object. + * + * @param rebase The rebase object + */ +GIT_EXTERN(void) git_rebase_free(git_rebase *rebase); + +/** @} */ +GIT_END_DECL +#endif diff --git a/include/git2/reset.h b/include/git2/reset.h index 5f2ba572d..53f3e891e 100644 --- a/include/git2/reset.h +++ b/include/git2/reset.h @@ -70,7 +70,7 @@ GIT_EXTERN(int) git_reset( git_object *target, git_reset_t reset_type, git_checkout_options *checkout_opts, - git_signature *signature, + const git_signature *signature, const char *log_message); /** diff --git a/include/git2/types.h b/include/git2/types.h index 16933976e..aa7a56f56 100644 --- a/include/git2/types.h +++ b/include/git2/types.h @@ -174,8 +174,8 @@ typedef struct git_reference_iterator git_reference_iterator; /** Transactional interface to references */ typedef struct git_transaction git_transaction; -/** Merge heads, the input to merge */ -typedef struct git_merge_head git_merge_head; +/** Annotated commits, the input to merge and rebase. */ +typedef struct git_annotated_commit git_annotated_commit; /** Merge result */ typedef struct git_merge_result git_merge_result; @@ -183,6 +183,8 @@ typedef struct git_merge_result git_merge_result; /** Representation of a status collection */ typedef struct git_status_list git_status_list; +/** Representation of a rebase */ +typedef struct git_rebase git_rebase; /** Basic type of any Git reference. */ typedef enum { diff --git a/src/annotated_commit.c b/src/annotated_commit.c new file mode 100644 index 000000000..0a917802a --- /dev/null +++ b/src/annotated_commit.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" +#include "annotated_commit.h" + +#include "git2/commit.h" +#include "git2/refs.h" +#include "git2/repository.h" +#include "git2/annotated_commit.h" + +static int annotated_commit_init( + git_annotated_commit **out, + git_repository *repo, + const git_oid *id, + const char *ref_name, + const char *remote_url) +{ + git_annotated_commit *annotated_commit; + int error = 0; + + assert(out && id); + + *out = NULL; + + annotated_commit = git__calloc(1, sizeof(git_annotated_commit)); + GITERR_CHECK_ALLOC(annotated_commit); + + if (ref_name) { + annotated_commit->ref_name = git__strdup(ref_name); + GITERR_CHECK_ALLOC(annotated_commit->ref_name); + } + + if (remote_url) { + annotated_commit->remote_url = git__strdup(remote_url); + GITERR_CHECK_ALLOC(annotated_commit->remote_url); + } + + git_oid_fmt(annotated_commit->id_str, id); + annotated_commit->id_str[GIT_OID_HEXSZ] = '\0'; + + if ((error = git_commit_lookup(&annotated_commit->commit, repo, id)) < 0) { + git_annotated_commit_free(annotated_commit); + return error; + } + + *out = annotated_commit; + return error; +} + +int git_annotated_commit_from_ref( + git_annotated_commit **out, + git_repository *repo, + const git_reference *ref) +{ + git_reference *resolved; + int error = 0; + + assert(out && repo && ref); + + *out = NULL; + + if ((error = git_reference_resolve(&resolved, ref)) < 0) + return error; + + error = annotated_commit_init(out, repo, git_reference_target(resolved), + git_reference_name(ref), NULL); + + git_reference_free(resolved); + return error; +} + +int git_annotated_commit_lookup( + git_annotated_commit **out, + git_repository *repo, + const git_oid *id) +{ + assert(out && repo && id); + + return annotated_commit_init(out, repo, id, NULL, NULL); +} + +int git_annotated_commit_from_fetchhead( + git_annotated_commit **out, + git_repository *repo, + const char *branch_name, + const char *remote_url, + const git_oid *id) +{ + assert(repo && id && branch_name && remote_url); + + return annotated_commit_init(out, repo, id, branch_name, remote_url); +} + +const git_oid *git_annotated_commit_id( + const git_annotated_commit *annotated_commit) +{ + assert(annotated_commit); + return git_commit_id(annotated_commit->commit); +} + +void git_annotated_commit_free(git_annotated_commit *annotated_commit) +{ + if (annotated_commit == NULL) + return; + + if (annotated_commit->commit != NULL) + git_commit_free(annotated_commit->commit); + + if (annotated_commit->ref_name != NULL) + git__free(annotated_commit->ref_name); + + if (annotated_commit->remote_url != NULL) + git__free(annotated_commit->remote_url); + + git__free(annotated_commit); +} diff --git a/src/annotated_commit.h b/src/annotated_commit.h new file mode 100644 index 000000000..e873184ae --- /dev/null +++ b/src/annotated_commit.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_annotated_commit_h__ +#define INCLUDE_annotated_commit_h__ + +#include "git2/oid.h" + +/** Internal structure for merge inputs */ +struct git_annotated_commit { + git_commit *commit; + + char *ref_name; + char *remote_url; + + char id_str[GIT_OID_HEXSZ+1]; +}; + +#endif diff --git a/src/commit.c b/src/commit.c index 227d5c4a5..78c4b9de3 100644 --- a/src/commit.c +++ b/src/commit.c @@ -16,6 +16,7 @@ #include "commit.h" #include "signature.h" #include "message.h" +#include "refs.h" void git_commit__free(void *_commit) { @@ -34,35 +35,6 @@ void git_commit__free(void *_commit) git__free(commit); } -static int update_ref_for_commit(git_repository *repo, git_reference *ref, const char *update_ref, const git_oid *id, const git_signature *committer) -{ - git_reference *ref2 = NULL; - int error; - git_commit *c; - const char *shortmsg; - git_buf reflog_msg = GIT_BUF_INIT; - - if ((error = git_commit_lookup(&c, repo, id)) < 0) { - return error; - } - - shortmsg = git_commit_summary(c); - git_buf_printf(&reflog_msg, "commit%s: %s", - git_commit_parentcount(c) == 0 ? " (initial)" : "", - shortmsg); - git_commit_free(c); - - if (ref) { - error = git_reference_set_target(&ref2, ref, id, committer, git_buf_cstr(&reflog_msg)); - git_reference_free(ref2); - } else { - error = git_reference__update_terminal(repo, update_ref, id, committer, git_buf_cstr(&reflog_msg)); - } - - git_buf_free(&reflog_msg); - return error; -} - int git_commit_create_from_callback( git_oid *id, git_repository *repo, @@ -131,7 +103,8 @@ int git_commit_create_from_callback( git_buf_free(&commit); if (update_ref != NULL) { - error = update_ref_for_commit(repo, ref, update_ref, id, committer); + error = git_reference__update_for_commit( + repo, ref, update_ref, id, committer, "commit"); git_reference_free(ref); return error; } @@ -321,7 +294,8 @@ int git_commit_amend( &tree_id, commit_parent_for_amend, (void *)commit_to_amend); if (!error && update_ref) { - error = update_ref_for_commit(repo, ref, NULL, id, committer); + error = git_reference__update_for_commit( + repo, ref, NULL, id, committer, "commit"); git_reference_free(ref); } diff --git a/src/merge.c b/src/merge.c index 8252f6767..1c55e797b 100644 --- a/src/merge.c +++ b/src/merge.c @@ -27,6 +27,7 @@ #include "filebuf.h" #include "config.h" #include "oidarray.h" +#include "annotated_commit.h" #include "git2/types.h" #include "git2/repository.h" @@ -40,6 +41,7 @@ #include "git2/config.h" #include "git2/tree.h" #include "git2/oidarray.h" +#include "git2/annotated_commit.h" #include "git2/sys/index.h" #include "git2/sys/hashsig.h" @@ -1835,32 +1837,9 @@ done: /* Merge setup / cleanup */ -static int write_orig_head( - git_repository *repo, - const git_merge_head *our_head) -{ - git_filebuf file = GIT_FILEBUF_INIT; - git_buf file_path = GIT_BUF_INIT; - int error = 0; - - assert(repo && our_head); - - if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_ORIG_HEAD_FILE)) == 0 && - (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) == 0 && - (error = git_filebuf_printf(&file, "%s\n", our_head->oid_str)) == 0) - error = git_filebuf_commit(&file); - - if (error < 0) - git_filebuf_cleanup(&file); - - git_buf_free(&file_path); - - return error; -} - static int write_merge_head( git_repository *repo, - const git_merge_head *heads[], + const git_annotated_commit *heads[], size_t heads_len) { git_filebuf file = GIT_FILEBUF_INIT; @@ -1875,7 +1854,7 @@ static int write_merge_head( goto cleanup; for (i = 0; i < heads_len; i++) { - if ((error = git_filebuf_printf(&file, "%s\n", heads[i]->oid_str)) < 0) + if ((error = git_filebuf_printf(&file, "%s\n", heads[i]->id_str)) < 0) goto cleanup; } @@ -1917,7 +1896,7 @@ cleanup: } struct merge_msg_entry { - const git_merge_head *merge_head; + const git_annotated_commit *merge_head; bool written; }; @@ -2105,7 +2084,7 @@ static int merge_msg_write_remotes( static int write_merge_msg( git_repository *repo, - const git_merge_head *heads[], + const git_annotated_commit *heads[], size_t heads_len) { git_filebuf file = GIT_FILEBUF_INIT; @@ -2151,7 +2130,7 @@ static int write_merge_msg( if ((error = git_filebuf_printf(&file, "%scommit '%s'", (i > 0) ? "; " : "", - entries[i].merge_head->oid_str)) < 0) + entries[i].merge_head->id_str)) < 0) goto cleanup; entries[i].written = 1; @@ -2199,7 +2178,7 @@ static int write_merge_msg( continue; if ((error = git_filebuf_printf(&file, "; commit '%s'", - entries[i].merge_head->oid_str)) < 0) + entries[i].merge_head->id_str)) < 0) goto cleanup; } @@ -2221,15 +2200,15 @@ cleanup: int git_merge__setup( git_repository *repo, - const git_merge_head *our_head, - const git_merge_head *heads[], + const git_annotated_commit *our_head, + const git_annotated_commit *heads[], size_t heads_len) { int error = 0; assert (repo && our_head && heads); - if ((error = write_orig_head(repo, our_head)) == 0 && + if ((error = git_repository__set_orig_head(repo, git_annotated_commit_id(our_head))) == 0 && (error = write_merge_head(repo, heads, heads_len)) == 0 && (error = write_merge_mode(repo)) == 0) { error = write_merge_msg(repo, heads, heads_len); @@ -2241,10 +2220,10 @@ int git_merge__setup( /* Merge branches */ static int merge_ancestor_head( - git_merge_head **ancestor_head, + git_annotated_commit **ancestor_head, git_repository *repo, - const git_merge_head *our_head, - const git_merge_head **their_heads, + const git_annotated_commit *our_head, + const git_annotated_commit **their_heads, size_t their_heads_len) { git_oid *oids, ancestor_oid; @@ -2259,12 +2238,12 @@ static int merge_ancestor_head( git_oid_cpy(&oids[0], git_commit_id(our_head->commit)); for (i = 0; i < their_heads_len; i++) - git_oid_cpy(&oids[i + 1], &their_heads[i]->oid); + git_oid_cpy(&oids[i + 1], git_annotated_commit_id(their_heads[i])); if ((error = git_merge_base_many(&ancestor_oid, repo, their_heads_len + 1, oids)) < 0) goto on_error; - error = git_merge_head_from_id(ancestor_head, repo, &ancestor_oid); + error = git_annotated_commit_lookup(ancestor_head, repo, &ancestor_oid); on_error: git__free(oids); @@ -2288,10 +2267,10 @@ static int merge_normalize_checkout_opts( git_repository *repo, git_checkout_options *checkout_opts, const git_checkout_options *given_checkout_opts, - const git_merge_head *ancestor_head, - const git_merge_head *our_head, + const git_annotated_commit *ancestor_head, + const git_annotated_commit *our_head, size_t their_heads_len, - const git_merge_head **their_heads) + const git_annotated_commit **their_heads) { int error = 0; @@ -2325,7 +2304,7 @@ static int merge_normalize_checkout_opts( if (their_heads_len == 1 && their_heads[0]->ref_name) checkout_opts->their_label = merge_their_label(their_heads[0]->ref_name); else if (their_heads_len == 1) - checkout_opts->their_label = their_heads[0]->oid_str; + checkout_opts->their_label = their_heads[0]->id_str; else checkout_opts->their_label = "theirs"; } @@ -2539,13 +2518,13 @@ static int merge_state_cleanup(git_repository *repo) } static int merge_heads( - git_merge_head **ancestor_head_out, - git_merge_head **our_head_out, + git_annotated_commit **ancestor_head_out, + git_annotated_commit **our_head_out, git_repository *repo, - const git_merge_head **their_heads, + const git_annotated_commit **their_heads, size_t their_heads_len) { - git_merge_head *ancestor_head = NULL, *our_head = NULL; + git_annotated_commit *ancestor_head = NULL, *our_head = NULL; git_reference *our_ref = NULL; int error = 0; @@ -2556,7 +2535,7 @@ static int merge_heads( goto done; if ((error = git_reference_lookup(&our_ref, repo, GIT_HEAD_FILE)) < 0 || - (error = git_merge_head_from_ref(&our_head, repo, our_ref)) < 0) + (error = git_annotated_commit_from_ref(&our_head, repo, our_ref)) < 0) goto done; if ((error = merge_ancestor_head(&ancestor_head, repo, our_head, their_heads, their_heads_len)) < 0) { @@ -2572,8 +2551,8 @@ static int merge_heads( done: if (error < 0) { - git_merge_head_free(ancestor_head); - git_merge_head_free(our_head); + git_annotated_commit_free(ancestor_head); + git_annotated_commit_free(our_head); } git_reference_free(our_ref); @@ -2618,10 +2597,10 @@ int git_merge_analysis( git_merge_analysis_t *analysis_out, git_merge_preference_t *preference_out, git_repository *repo, - const git_merge_head **their_heads, + const git_annotated_commit **their_heads, size_t their_heads_len) { - git_merge_head *ancestor_head = NULL, *our_head = NULL; + git_annotated_commit *ancestor_head = NULL, *our_head = NULL; int error = 0; assert(analysis_out && preference_out && repo && their_heads); @@ -2646,11 +2625,13 @@ int git_merge_analysis( goto done; /* We're up-to-date if we're trying to merge our own common ancestor. */ - if (ancestor_head && git_oid_equal(&ancestor_head->oid, &their_heads[0]->oid)) + if (ancestor_head && git_oid_equal( + git_annotated_commit_id(ancestor_head), git_annotated_commit_id(their_heads[0]))) *analysis_out |= GIT_MERGE_ANALYSIS_UP_TO_DATE; /* We're fastforwardable if we're our own common ancestor. */ - else if (ancestor_head && git_oid_equal(&ancestor_head->oid, &our_head->oid)) + else if (ancestor_head && git_oid_equal( + git_annotated_commit_id(ancestor_head), git_annotated_commit_id(our_head))) *analysis_out |= GIT_MERGE_ANALYSIS_FASTFORWARD | GIT_MERGE_ANALYSIS_NORMAL; /* Otherwise, just a normal merge is possible. */ @@ -2658,21 +2639,21 @@ int git_merge_analysis( *analysis_out |= GIT_MERGE_ANALYSIS_NORMAL; done: - git_merge_head_free(ancestor_head); - git_merge_head_free(our_head); + git_annotated_commit_free(ancestor_head); + git_annotated_commit_free(our_head); return error; } int git_merge( git_repository *repo, - const git_merge_head **their_heads, + const git_annotated_commit **their_heads, size_t their_heads_len, const git_merge_options *merge_opts, const git_checkout_options *given_checkout_opts) { git_reference *our_ref = NULL; git_checkout_options checkout_opts; - git_merge_head *ancestor_head = NULL, *our_head = NULL; + git_annotated_commit *ancestor_head = NULL, *our_head = NULL; git_tree *ancestor_tree = NULL, *our_tree = NULL, **their_trees = NULL; git_index *index_new = NULL; size_t i; @@ -2735,126 +2716,14 @@ done: git__free(their_trees); - git_merge_head_free(our_head); - git_merge_head_free(ancestor_head); + git_annotated_commit_free(our_head); + git_annotated_commit_free(ancestor_head); git_reference_free(our_ref); return error; } -/* Merge heads are the input to merge */ - -static int merge_head_init( - git_merge_head **out, - git_repository *repo, - const char *ref_name, - const char *remote_url, - const git_oid *oid) -{ - git_merge_head *head; - int error = 0; - - assert(out && oid); - - *out = NULL; - - head = git__calloc(1, sizeof(git_merge_head)); - GITERR_CHECK_ALLOC(head); - - if (ref_name) { - head->ref_name = git__strdup(ref_name); - GITERR_CHECK_ALLOC(head->ref_name); - } - - if (remote_url) { - head->remote_url = git__strdup(remote_url); - GITERR_CHECK_ALLOC(head->remote_url); - } - - git_oid_cpy(&head->oid, oid); - - git_oid_fmt(head->oid_str, oid); - head->oid_str[GIT_OID_HEXSZ] = '\0'; - - if ((error = git_commit_lookup(&head->commit, repo, &head->oid)) < 0) { - git_merge_head_free(head); - return error; - } - - *out = head; - return error; -} - -int git_merge_head_from_ref( - git_merge_head **out, - git_repository *repo, - const git_reference *ref) -{ - git_reference *resolved; - int error = 0; - - assert(out && repo && ref); - - *out = NULL; - - if ((error = git_reference_resolve(&resolved, ref)) < 0) - return error; - - error = merge_head_init(out, repo, git_reference_name(ref), NULL, - git_reference_target(resolved)); - - git_reference_free(resolved); - return error; -} - -int git_merge_head_from_id( - git_merge_head **out, - git_repository *repo, - const git_oid *oid) -{ - assert(out && repo && oid); - - return merge_head_init(out, repo, NULL, NULL, oid); -} - -int git_merge_head_from_fetchhead( - git_merge_head **out, - git_repository *repo, - const char *branch_name, - const char *remote_url, - const git_oid *oid) -{ - assert(repo && branch_name && remote_url && oid); - - return merge_head_init(out, repo, branch_name, remote_url, oid); -} - -const git_oid *git_merge_head_id( - const git_merge_head *head) -{ - assert(head); - - return &head->oid; -} - -void git_merge_head_free(git_merge_head *head) -{ - if (head == NULL) - return; - - if (head->commit != NULL) - git_object_free((git_object *)head->commit); - - if (head->ref_name != NULL) - git__free(head->ref_name); - - if (head->remote_url != NULL) - git__free(head->remote_url); - - git__free(head); -} - int git_merge_init_options(git_merge_options *opts, unsigned int version) { GIT_INIT_STRUCTURE_FROM_TEMPLATE( diff --git a/src/merge.h b/src/merge.h index cc17389ab..2684c15f8 100644 --- a/src/merge.h +++ b/src/merge.h @@ -110,16 +110,6 @@ typedef struct { int binary:1; } git_merge_diff; -/** Internal structure for merge inputs */ -struct git_merge_head { - char *ref_name; - char *remote_url; - - git_oid oid; - char oid_str[GIT_OID_HEXSZ+1]; - git_commit *commit; -}; - int git_merge__bases_many( git_commit_list **out, git_revwalk *walk, @@ -145,8 +135,8 @@ void git_merge_diff_list__free(git_merge_diff_list *diff_list); int git_merge__setup( git_repository *repo, - const git_merge_head *our_head, - const git_merge_head *heads[], + const git_annotated_commit *our_head, + const git_annotated_commit *heads[], size_t heads_len); int git_merge__check_result(git_repository *repo, git_index *index_new); diff --git a/src/notes.c b/src/notes.c index ffe5d345a..046a91614 100644 --- a/src/notes.c +++ b/src/notes.c @@ -306,7 +306,11 @@ cleanup: return error; } -static int note_new(git_note **out, git_oid *note_oid, git_blob *blob) +static int note_new( + git_note **out, + git_oid *note_oid, + git_commit *commit, + git_blob *blob) { git_note *note = NULL; @@ -314,6 +318,11 @@ static int note_new(git_note **out, git_oid *note_oid, git_blob *blob) GITERR_CHECK_ALLOC(note); git_oid_cpy(¬e->id, note_oid); + + if (git_signature_dup(¬e->author, git_commit_author(commit)) < 0 || + git_signature_dup(¬e->committer, git_commit_committer(commit)) < 0) + return -1; + note->message = git__strdup((char *)git_blob_rawcontent(blob)); GITERR_CHECK_ALLOC(note->message); @@ -323,7 +332,11 @@ static int note_new(git_note **out, git_oid *note_oid, git_blob *blob) } static int note_lookup( - git_note **out, git_repository *repo, git_tree *tree, const char *target) + git_note **out, + git_repository *repo, + git_commit *commit, + git_tree *tree, + const char *target) { int error, fanout = 0; git_oid oid; @@ -340,7 +353,7 @@ static int note_lookup( if ((error = git_blob_lookup(&blob, repo, &oid)) < 0) goto cleanup; - if ((error = note_new(¬e, &oid, blob)) < 0) + if ((error = note_new(¬e, &oid, commit, blob)) < 0) goto cleanup; *out = note; @@ -432,7 +445,7 @@ int git_note_read(git_note **out, git_repository *repo, if (!(error = retrieve_note_tree_and_commit( &tree, &commit, repo, ¬es_ref))) - error = note_lookup(out, repo, tree, target); + error = note_lookup(out, repo, commit, tree, target); git__free(target); git_tree_free(tree); @@ -502,6 +515,18 @@ int git_note_default_ref(const char **out, git_repository *repo) return note_get_default_ref(out, repo); } +const git_signature *git_note_committer(const git_note *note) +{ + assert(note); + return note->committer; +} + +const git_signature *git_note_author(const git_note *note) +{ + assert(note); + return note->author; +} + const char * git_note_message(const git_note *note) { assert(note); @@ -519,6 +544,8 @@ void git_note_free(git_note *note) if (note == NULL) return; + git_signature_free(note->committer); + git_signature_free(note->author); git__free(note->message); git__free(note); } diff --git a/src/notes.h b/src/notes.h index e9cfa00fa..cfc0ca239 100644 --- a/src/notes.h +++ b/src/notes.h @@ -23,6 +23,9 @@ struct git_note { git_oid id; + git_signature *author; + git_signature *committer; + char *message; }; diff --git a/src/rebase.c b/src/rebase.c new file mode 100644 index 000000000..6453ecc67 --- /dev/null +++ b/src/rebase.c @@ -0,0 +1,1125 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" +#include "buffer.h" +#include "repository.h" +#include "posix.h" +#include "filebuf.h" +#include "merge.h" +#include "array.h" +#include "config.h" +#include "annotated_commit.h" + +#include +#include +#include +#include +#include +#include +#include + +#define REBASE_APPLY_DIR "rebase-apply" +#define REBASE_MERGE_DIR "rebase-merge" + +#define HEAD_NAME_FILE "head-name" +#define ORIG_HEAD_FILE "orig-head" +#define HEAD_FILE "head" +#define ONTO_FILE "onto" +#define ONTO_NAME_FILE "onto_name" +#define QUIET_FILE "quiet" + +#define MSGNUM_FILE "msgnum" +#define END_FILE "end" +#define CMT_FILE_FMT "cmt.%" PRIuZ +#define CURRENT_FILE "current" +#define REWRITTEN_FILE "rewritten" + +#define ORIG_DETACHED_HEAD "detached HEAD" + +#define NOTES_DEFAULT_REF NULL + +#define REBASE_DIR_MODE 0777 +#define REBASE_FILE_MODE 0666 + +typedef enum { + GIT_REBASE_TYPE_NONE = 0, + GIT_REBASE_TYPE_APPLY = 1, + GIT_REBASE_TYPE_MERGE = 2, + GIT_REBASE_TYPE_INTERACTIVE = 3, +} git_rebase_type_t; + +struct git_rebase { + git_repository *repo; + + git_rebase_type_t type; + char *state_path; + + int head_detached : 1, + quiet : 1, + started : 1; + + char *orig_head_name; + git_oid orig_head_id; + + git_oid onto_id; + char *onto_name; + + git_array_t(git_rebase_operation) operations; + size_t current; +}; + +#define GIT_REBASE_STATE_INIT {0} + +static int rebase_state_type( + git_rebase_type_t *type_out, + char **path_out, + git_repository *repo) +{ + git_buf path = GIT_BUF_INIT; + git_rebase_type_t type = GIT_REBASE_TYPE_NONE; + + if (git_buf_joinpath(&path, repo->path_repository, REBASE_APPLY_DIR) < 0) + return -1; + + if (git_path_isdir(git_buf_cstr(&path))) { + type = GIT_REBASE_TYPE_APPLY; + goto done; + } + + git_buf_clear(&path); + if (git_buf_joinpath(&path, repo->path_repository, REBASE_MERGE_DIR) < 0) + return -1; + + if (git_path_isdir(git_buf_cstr(&path))) { + type = GIT_REBASE_TYPE_MERGE; + goto done; + } + +done: + *type_out = type; + + if (type != GIT_REBASE_TYPE_NONE && path_out) + *path_out = git_buf_detach(&path); + + git_buf_free(&path); + + return 0; +} + +GIT_INLINE(int) rebase_readfile( + git_buf *out, + git_buf *state_path, + const char *filename) +{ + size_t state_path_len = state_path->size; + int error; + + git_buf_clear(out); + + if ((error = git_buf_joinpath(state_path, state_path->ptr, filename)) < 0 || + (error = git_futils_readbuffer(out, state_path->ptr)) < 0) + goto done; + + git_buf_rtrim(out); + +done: + git_buf_truncate(state_path, state_path_len); + return error; +} + +GIT_INLINE(int) rebase_readint( + size_t *out, git_buf *asc_out, git_buf *state_path, const char *filename) +{ + int32_t num; + const char *eol; + int error = 0; + + if ((error = rebase_readfile(asc_out, state_path, filename)) < 0) + return error; + + if (git__strtol32(&num, asc_out->ptr, &eol, 10) < 0 || num < 0 || *eol) { + giterr_set(GITERR_REBASE, "The file '%s' contains an invalid numeric value", filename); + return -1; + } + + *out = (size_t) num; + + return 0; +} + +GIT_INLINE(int) rebase_readoid( + git_oid *out, git_buf *str_out, git_buf *state_path, const char *filename) +{ + int error; + + if ((error = rebase_readfile(str_out, state_path, filename)) < 0) + return error; + + if (str_out->size != GIT_OID_HEXSZ || git_oid_fromstr(out, str_out->ptr) < 0) { + giterr_set(GITERR_REBASE, "The file '%s' contains an invalid object ID", filename); + return -1; + } + + return 0; +} + +static int rebase_open_merge(git_rebase *rebase) +{ + git_buf state_path = GIT_BUF_INIT, buf = GIT_BUF_INIT, cmt = GIT_BUF_INIT; + git_oid current_id = {{0}}; + git_rebase_operation *operation; + size_t i, msgnum = 0, end; + int error; + + if ((error = git_buf_puts(&state_path, rebase->state_path)) < 0) + goto done; + + /* Read 'msgnum' if it exists (otherwise, let msgnum = 0) */ + if ((error = rebase_readint(&msgnum, &buf, &state_path, MSGNUM_FILE)) < 0 && + error != GIT_ENOTFOUND) + goto done; + + if (msgnum) { + rebase->started = 1; + rebase->current = msgnum - 1; + } + + /* Read 'end' */ + if ((error = rebase_readint(&end, &buf, &state_path, END_FILE)) < 0) + goto done; + + /* Read 'current' if it exists */ + if ((error = rebase_readoid(¤t_id, &buf, &state_path, CURRENT_FILE)) < 0 && + error != GIT_ENOTFOUND) + goto done; + + /* Read cmt.* */ + git_array_init_to_size(rebase->operations, end); + GITERR_CHECK_ARRAY(rebase->operations); + + for (i = 0; i < end; i++) { + operation = git_array_alloc(rebase->operations); + GITERR_CHECK_ALLOC(operation); + + git_buf_clear(&cmt); + + if ((error = git_buf_printf(&cmt, "cmt.%" PRIuZ, (i+1))) < 0 || + (error = rebase_readoid((git_oid *)&operation->id, &buf, &state_path, cmt.ptr)) < 0) + goto done; + } + + /* Read 'onto_name' */ + if ((error = rebase_readfile(&buf, &state_path, ONTO_NAME_FILE)) < 0) + goto done; + + rebase->onto_name = git_buf_detach(&buf); + +done: + git_buf_free(&cmt); + git_buf_free(&state_path); + git_buf_free(&buf); + + return error; +} + +int git_rebase_open(git_rebase **out, git_repository *repo) +{ + git_rebase *rebase; + git_buf path = GIT_BUF_INIT, orig_head_name = GIT_BUF_INIT, + orig_head_id = GIT_BUF_INIT, onto_id = GIT_BUF_INIT; + int state_path_len, error; + + assert(repo); + + rebase = git__calloc(1, sizeof(git_rebase)); + GITERR_CHECK_ALLOC(rebase); + + rebase->repo = repo; + + if ((error = rebase_state_type(&rebase->type, &rebase->state_path, repo)) < 0) + goto done; + + if (rebase->type == GIT_REBASE_TYPE_NONE) { + giterr_set(GITERR_REBASE, "There is no rebase in progress"); + return GIT_ENOTFOUND; + } + + if ((error = git_buf_puts(&path, rebase->state_path)) < 0) + goto done; + + state_path_len = git_buf_len(&path); + + if ((error = git_buf_joinpath(&path, path.ptr, HEAD_NAME_FILE)) < 0 || + (error = git_futils_readbuffer(&orig_head_name, path.ptr)) < 0) + goto done; + + git_buf_rtrim(&orig_head_name); + + if (strcmp(ORIG_DETACHED_HEAD, orig_head_name.ptr) == 0) + rebase->head_detached = 1; + + git_buf_truncate(&path, state_path_len); + + if ((error = git_buf_joinpath(&path, path.ptr, ORIG_HEAD_FILE)) < 0) + goto done; + + if (!git_path_isfile(path.ptr)) { + /* Previous versions of git.git used 'head' here; support that. */ + git_buf_truncate(&path, state_path_len); + + if ((error = git_buf_joinpath(&path, path.ptr, HEAD_FILE)) < 0) + goto done; + } + + if ((error = git_futils_readbuffer(&orig_head_id, path.ptr)) < 0) + goto done; + + git_buf_rtrim(&orig_head_id); + + if ((error = git_oid_fromstr(&rebase->orig_head_id, orig_head_id.ptr)) < 0) + goto done; + + git_buf_truncate(&path, state_path_len); + + if ((error = git_buf_joinpath(&path, path.ptr, ONTO_FILE)) < 0 || + (error = git_futils_readbuffer(&onto_id, path.ptr)) < 0) + goto done; + + git_buf_rtrim(&onto_id); + + if ((error = git_oid_fromstr(&rebase->onto_id, onto_id.ptr)) < 0) + goto done; + + if (!rebase->head_detached) + rebase->orig_head_name = git_buf_detach(&orig_head_name); + + switch (rebase->type) { + case GIT_REBASE_TYPE_INTERACTIVE: + giterr_set(GITERR_REBASE, "Interactive rebase is not supported"); + error = -1; + break; + case GIT_REBASE_TYPE_MERGE: + error = rebase_open_merge(rebase); + break; + case GIT_REBASE_TYPE_APPLY: + giterr_set(GITERR_REBASE, "Patch application rebase is not supported"); + error = -1; + break; + default: + abort(); + } + +done: + if (error == 0) + *out = rebase; + else + git_rebase_free(rebase); + + git_buf_free(&path); + git_buf_free(&orig_head_name); + git_buf_free(&orig_head_id); + git_buf_free(&onto_id); + return error; +} + +static int rebase_cleanup(git_rebase *rebase) +{ + return git_path_isdir(rebase->state_path) ? + git_futils_rmdir_r(rebase->state_path, NULL, GIT_RMDIR_REMOVE_FILES) : + 0; +} + +static int rebase_setupfile(git_rebase *rebase, const char *filename, int flags, const char *fmt, ...) +{ + git_buf path = GIT_BUF_INIT, + contents = GIT_BUF_INIT; + va_list ap; + int error; + + va_start(ap, fmt); + git_buf_vprintf(&contents, fmt, ap); + va_end(ap); + + if ((error = git_buf_joinpath(&path, rebase->state_path, filename)) == 0) + error = git_futils_writebuffer(&contents, path.ptr, flags, REBASE_FILE_MODE); + + git_buf_free(&path); + git_buf_free(&contents); + + return error; +} + +static const char *rebase_onto_name(const git_annotated_commit *onto) +{ + if (onto->ref_name && git__strncmp(onto->ref_name, "refs/heads/", 11) == 0) + return onto->ref_name + 11; + else if (onto->ref_name) + return onto->ref_name; + else + return onto->id_str; +} + +static int rebase_setupfiles_merge(git_rebase *rebase) +{ + git_buf commit_filename = GIT_BUF_INIT; + char id_str[GIT_OID_HEXSZ]; + git_rebase_operation *operation; + size_t i; + int error = 0; + + if ((error = rebase_setupfile(rebase, END_FILE, -1, "%d\n", git_array_size(rebase->operations))) < 0 || + (error = rebase_setupfile(rebase, ONTO_NAME_FILE, -1, "%s\n", rebase->onto_name)) < 0) + goto done; + + for (i = 0; i < git_array_size(rebase->operations); i++) { + operation = git_array_get(rebase->operations, i); + + git_buf_clear(&commit_filename); + git_buf_printf(&commit_filename, CMT_FILE_FMT, i+1); + + git_oid_fmt(id_str, &operation->id); + + if ((error = rebase_setupfile(rebase, commit_filename.ptr, -1, + "%.*s\n", GIT_OID_HEXSZ, id_str)) < 0) + goto done; + } + +done: + git_buf_free(&commit_filename); + return error; +} + +static int rebase_setupfiles(git_rebase *rebase) +{ + char onto[GIT_OID_HEXSZ], orig_head[GIT_OID_HEXSZ]; + + git_oid_fmt(onto, &rebase->onto_id); + git_oid_fmt(orig_head, &rebase->orig_head_id); + + if (p_mkdir(rebase->state_path, REBASE_DIR_MODE) < 0) { + giterr_set(GITERR_OS, "Failed to create rebase directory '%s'", rebase->state_path); + return -1; + } + + if (git_repository__set_orig_head(rebase->repo, &rebase->orig_head_id) < 0 || + rebase_setupfile(rebase, HEAD_NAME_FILE, -1, "%s\n", rebase->orig_head_name) < 0 || + rebase_setupfile(rebase, ONTO_FILE, -1, "%.*s\n", GIT_OID_HEXSZ, onto) < 0 || + rebase_setupfile(rebase, ORIG_HEAD_FILE, -1, "%.*s\n", GIT_OID_HEXSZ, orig_head) < 0 || + rebase_setupfile(rebase, QUIET_FILE, -1, rebase->quiet ? "t\n" : "\n") < 0) + return -1; + + return rebase_setupfiles_merge(rebase); +} + +int git_rebase_init_options(git_rebase_options *opts, unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE( + opts, version, git_rebase_options, GIT_REBASE_OPTIONS_INIT); + return 0; +} + +static int rebase_normalize_opts( + git_repository *repo, + git_rebase_options *opts, + const git_rebase_options *given_opts) +{ + git_rebase_options default_opts = GIT_REBASE_OPTIONS_INIT; + git_config *config; + + if (given_opts) + memcpy(opts, given_opts, sizeof(git_rebase_options)); + else + memcpy(opts, &default_opts, sizeof(git_rebase_options)); + + if (git_repository_config(&config, repo) < 0) + return -1; + + if (given_opts && given_opts->rewrite_notes_ref) { + opts->rewrite_notes_ref = git__strdup(given_opts->rewrite_notes_ref); + GITERR_CHECK_ALLOC(opts->rewrite_notes_ref); + } else if (git_config__get_bool_force(config, "notes.rewrite.rebase", 1)) { + const char *rewrite_ref = git_config__get_string_force( + config, "notes.rewriteref", NOTES_DEFAULT_REF); + + if (rewrite_ref) { + opts->rewrite_notes_ref = git__strdup(rewrite_ref); + GITERR_CHECK_ALLOC(opts->rewrite_notes_ref); + } + } + + git_config_free(config); + + return 0; +} + +static void rebase_opts_free(git_rebase_options *opts) +{ + if (!opts) + return; + + git__free((char *)opts->rewrite_notes_ref); +} + +static int rebase_ensure_not_in_progress(git_repository *repo) +{ + int error; + git_rebase_type_t type; + + if ((error = rebase_state_type(&type, NULL, repo)) < 0) + return error; + + if (type != GIT_REBASE_TYPE_NONE) { + giterr_set(GITERR_REBASE, "There is an existing rebase in progress"); + return -1; + } + + return 0; +} + +static int rebase_ensure_not_dirty(git_repository *repo) +{ + git_tree *head = NULL; + git_index *index = NULL; + git_diff *diff = NULL; + int error; + + if ((error = git_repository_head_tree(&head, repo)) < 0 || + (error = git_repository_index(&index, repo)) < 0 || + (error = git_diff_tree_to_index(&diff, repo, head, index, NULL)) < 0) + goto done; + + if (git_diff_num_deltas(diff) > 0) { + giterr_set(GITERR_REBASE, "Uncommitted changes exist in index"); + error = -1; + goto done; + } + + git_diff_free(diff); + diff = NULL; + + if ((error = git_diff_index_to_workdir(&diff, repo, index, NULL)) < 0) + goto done; + + if (git_diff_num_deltas(diff) > 0) { + giterr_set(GITERR_REBASE, "Unstaged changes exist in workdir"); + error = -1; + } + +done: + git_diff_free(diff); + git_index_free(index); + git_tree_free(head); + + return error; +} + +static int rebase_init_operations( + git_rebase *rebase, + git_repository *repo, + const git_annotated_commit *branch, + const git_annotated_commit *upstream, + const git_annotated_commit *onto) +{ + git_revwalk *revwalk = NULL; + git_commit *commit; + git_oid id; + bool merge; + git_rebase_operation *operation; + int error; + + if (!upstream) + upstream = onto; + + if ((error = git_revwalk_new(&revwalk, rebase->repo)) < 0 || + (error = git_revwalk_push(revwalk, git_annotated_commit_id(branch))) < 0 || + (error = git_revwalk_hide(revwalk, git_annotated_commit_id(upstream))) < 0) + goto done; + + git_revwalk_sorting(revwalk, GIT_SORT_REVERSE | GIT_SORT_TIME); + + while ((error = git_revwalk_next(&id, revwalk)) == 0) { + if ((error = git_commit_lookup(&commit, repo, &id)) < 0) + goto done; + + merge = (git_commit_parentcount(commit) > 1); + git_commit_free(commit); + + if (merge) + continue; + + operation = git_array_alloc(rebase->operations); + operation->type = GIT_REBASE_OPERATION_PICK; + git_oid_cpy((git_oid *)&operation->id, &id); + } + + error = 0; + +done: + git_revwalk_free(revwalk); + return error; +} + +static int rebase_init_merge( + git_rebase *rebase, + git_repository *repo, + const git_annotated_commit *branch, + const git_annotated_commit *upstream, + const git_annotated_commit *onto) +{ + if (rebase_init_operations(rebase, repo, branch, upstream, onto) < 0) + return -1; + + rebase->onto_name = git__strdup(rebase_onto_name(onto)); + GITERR_CHECK_ALLOC(rebase->onto_name); + + return 0; +} + +static int rebase_init( + git_rebase *rebase, + git_repository *repo, + const git_annotated_commit *branch, + const git_annotated_commit *upstream, + const git_annotated_commit *onto, + const git_rebase_options *opts) +{ + git_buf state_path = GIT_BUF_INIT; + int error; + + git_buf_joinpath(&state_path, repo->path_repository, REBASE_MERGE_DIR); + + rebase->repo = repo; + rebase->type = GIT_REBASE_TYPE_MERGE; + rebase->state_path = git_buf_detach(&state_path); + rebase->orig_head_name = git__strdup(branch->ref_name ? branch->ref_name : ORIG_DETACHED_HEAD); + rebase->quiet = opts->quiet; + + git_oid_cpy(&rebase->orig_head_id, git_annotated_commit_id(branch)); + git_oid_cpy(&rebase->onto_id, git_annotated_commit_id(onto)); + + if (!rebase->orig_head_name || !rebase->state_path) + return -1; + + error = rebase_init_merge(rebase, repo, branch, upstream, onto); + + git_buf_free(&state_path); + + return error; +} + +int git_rebase_init( + git_rebase **out, + git_repository *repo, + const git_annotated_commit *branch, + const git_annotated_commit *upstream, + const git_annotated_commit *onto, + const git_signature *signature, + const git_rebase_options *given_opts) +{ + git_rebase *rebase = NULL; + git_rebase_options opts; + git_reference *head_ref = NULL; + git_buf reflog = GIT_BUF_INIT; + git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; + int error; + + assert(repo && branch && (upstream || onto)); + + *out = NULL; + + GITERR_CHECK_VERSION(given_opts, GIT_MERGE_OPTIONS_VERSION, "git_merge_options"); + + if (!onto) + onto = upstream; + + checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE; + + if ((error = rebase_normalize_opts(repo, &opts, given_opts)) < 0 || + (error = git_repository__ensure_not_bare(repo, "rebase")) < 0 || + (error = rebase_ensure_not_in_progress(repo)) < 0 || + (error = rebase_ensure_not_dirty(repo)) < 0) + return error; + + rebase = git__calloc(1, sizeof(git_rebase)); + GITERR_CHECK_ALLOC(rebase); + + if ((error = rebase_init(rebase, repo, branch, upstream, onto, &opts)) < 0 || + (error = rebase_setupfiles(rebase)) < 0 || + (error = git_buf_printf(&reflog, + "rebase: checkout %s", rebase_onto_name(onto))) < 0 || + (error = git_reference_create(&head_ref, repo, GIT_HEAD_FILE, + git_annotated_commit_id(onto), 1, signature, reflog.ptr)) < 0 || + (error = git_checkout_head(repo, &checkout_opts)) < 0) + goto done; + + *out = rebase; + +done: + if (error < 0) { + rebase_cleanup(rebase); + git_rebase_free(rebase); + } + + git_reference_free(head_ref); + git_buf_free(&reflog); + rebase_opts_free(&opts); + + return error; +} + +static void normalize_checkout_opts( + git_rebase *rebase, + git_commit *current_commit, + git_checkout_options *checkout_opts, + const git_checkout_options *given_checkout_opts) +{ + if (given_checkout_opts != NULL) + memcpy(checkout_opts, given_checkout_opts, sizeof(git_checkout_options)); + else { + git_checkout_options default_checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; + default_checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; + + memcpy(checkout_opts, &default_checkout_opts, sizeof(git_checkout_options)); + } + + if (!checkout_opts->ancestor_label) + checkout_opts->ancestor_label = "ancestor"; + + if (rebase->type == GIT_REBASE_TYPE_MERGE) { + if (!checkout_opts->our_label) + checkout_opts->our_label = rebase->onto_name; + + if (!checkout_opts->their_label) + checkout_opts->their_label = git_commit_summary(current_commit); + } else { + abort(); + } +} + +GIT_INLINE(int) rebase_movenext(git_rebase *rebase) +{ + size_t next = rebase->started ? rebase->current + 1 : 0; + + if (next == git_array_size(rebase->operations)) + return GIT_ITEROVER; + + rebase->started = 1; + rebase->current = next; + + return 0; +} + +static int rebase_next_merge( + git_rebase_operation **out, + git_rebase *rebase, + git_checkout_options *given_checkout_opts) +{ + git_buf path = GIT_BUF_INIT; + git_checkout_options checkout_opts = {0}; + git_commit *current_commit = NULL, *parent_commit = NULL; + git_tree *current_tree = NULL, *head_tree = NULL, *parent_tree = NULL; + git_index *index = NULL; + git_rebase_operation *operation; + char current_idstr[GIT_OID_HEXSZ]; + unsigned int parent_count; + int error; + + *out = NULL; + + if ((error = rebase_movenext(rebase)) < 0) + goto done; + + operation = git_array_get(rebase->operations, rebase->current); + + if ((error = git_commit_lookup(¤t_commit, rebase->repo, &operation->id)) < 0 || + (error = git_commit_tree(¤t_tree, current_commit)) < 0 || + (error = git_repository_head_tree(&head_tree, rebase->repo)) < 0) + goto done; + + if ((parent_count = git_commit_parentcount(current_commit)) > 1) { + giterr_set(GITERR_REBASE, "Cannot rebase a merge commit"); + error = -1; + goto done; + } else if (parent_count) { + if ((error = git_commit_parent(&parent_commit, current_commit, 0)) < 0 || + (error = git_commit_tree(&parent_tree, parent_commit)) < 0) + goto done; + } + + git_oid_fmt(current_idstr, &operation->id); + + if ((error = rebase_setupfile(rebase, MSGNUM_FILE, -1, "%d\n", rebase->current+1)) < 0 || + (error = rebase_setupfile(rebase, CURRENT_FILE, -1, "%.*s\n", GIT_OID_HEXSZ, current_idstr)) < 0) + goto done; + + normalize_checkout_opts(rebase, current_commit, &checkout_opts, given_checkout_opts); + + if ((error = git_merge_trees(&index, rebase->repo, parent_tree, head_tree, current_tree, NULL)) < 0 || + (error = git_merge__check_result(rebase->repo, index)) < 0 || + (error = git_checkout_index(rebase->repo, index, &checkout_opts)) < 0) + goto done; + + *out = operation; + +done: + git_index_free(index); + git_tree_free(current_tree); + git_tree_free(head_tree); + git_tree_free(parent_tree); + git_commit_free(parent_commit); + git_commit_free(current_commit); + git_buf_free(&path); + + return error; +} + +int git_rebase_next( + git_rebase_operation **out, + git_rebase *rebase, + git_checkout_options *checkout_opts) +{ + int error; + + assert(out && rebase); + + switch (rebase->type) { + case GIT_REBASE_TYPE_MERGE: + error = rebase_next_merge(out, rebase, checkout_opts); + break; + default: + abort(); + } + + return error; +} + +static int rebase_commit_merge( + git_oid *commit_id, + git_rebase *rebase, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message) +{ + git_index *index = NULL; + git_reference *head = NULL; + git_commit *current_commit = NULL, *head_commit = NULL, *commit = NULL; + git_rebase_operation *operation; + git_tree *head_tree = NULL, *tree = NULL; + git_diff *diff = NULL; + git_oid tree_id; + git_buf reflog_msg = GIT_BUF_INIT; + char old_idstr[GIT_OID_HEXSZ], new_idstr[GIT_OID_HEXSZ]; + int error; + + operation = git_array_get(rebase->operations, rebase->current); + assert(operation); + + if ((error = git_repository_index(&index, rebase->repo)) < 0) + goto done; + + if (git_index_has_conflicts(index)) { + giterr_set(GITERR_REBASE, "Conflicts have not been resolved"); + error = GIT_EMERGECONFLICT; + goto done; + } + + if ((error = git_commit_lookup(¤t_commit, rebase->repo, &operation->id)) < 0 || + (error = git_repository_head(&head, rebase->repo)) < 0 || + (error = git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT)) < 0 || + (error = git_commit_tree(&head_tree, head_commit)) < 0 || + (error = git_diff_tree_to_index(&diff, rebase->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, rebase->repo, &tree_id)) < 0) + goto done; + + if (!author) + author = git_commit_author(current_commit); + + if (!message) { + message_encoding = git_commit_message_encoding(current_commit); + message = git_commit_message(current_commit); + } + + if ((error = git_commit_create(commit_id, rebase->repo, NULL, author, + committer, message_encoding, message, tree, 1, + (const git_commit **)&head_commit)) < 0 || + (error = git_commit_lookup(&commit, rebase->repo, commit_id)) < 0 || + (error = git_reference__update_for_commit( + rebase->repo, NULL, "HEAD", commit_id, committer, "rebase")) < 0) + goto done; + + git_oid_fmt(old_idstr, git_commit_id(current_commit)); + git_oid_fmt(new_idstr, commit_id); + + error = rebase_setupfile(rebase, REWRITTEN_FILE, O_CREAT|O_WRONLY|O_APPEND, + "%.*s %.*s\n", GIT_OID_HEXSZ, old_idstr, GIT_OID_HEXSZ, new_idstr); + +done: + git_buf_free(&reflog_msg); + git_commit_free(commit); + git_diff_free(diff); + git_tree_free(tree); + git_tree_free(head_tree); + git_commit_free(head_commit); + git_commit_free(current_commit); + git_reference_free(head); + git_index_free(index); + + return error; +} + +int git_rebase_commit( + git_oid *id, + git_rebase *rebase, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message) +{ + int error; + + assert(rebase && committer); + + switch (rebase->type) { + case GIT_REBASE_TYPE_MERGE: + error = rebase_commit_merge( + id, rebase, author, committer, message_encoding, message); + break; + default: + abort(); + } + + return error; +} + +int git_rebase_abort(git_rebase *rebase, const git_signature *signature) +{ + git_reference *orig_head_ref = NULL; + git_commit *orig_head_commit = NULL; + int error; + + assert(rebase && signature); + + error = rebase->head_detached ? + git_reference_create(&orig_head_ref, rebase->repo, GIT_HEAD_FILE, + &rebase->orig_head_id, 1, signature, "rebase: aborting") : + git_reference_symbolic_create( + &orig_head_ref, rebase->repo, GIT_HEAD_FILE, rebase->orig_head_name, 1, + signature, "rebase: aborting"); + + if (error < 0) + goto done; + + if ((error = git_commit_lookup( + &orig_head_commit, rebase->repo, &rebase->orig_head_id)) < 0 || + (error = git_reset(rebase->repo, (git_object *)orig_head_commit, + GIT_RESET_HARD, NULL, signature, NULL)) < 0) + goto done; + + error = rebase_cleanup(rebase); + +done: + git_commit_free(orig_head_commit); + git_reference_free(orig_head_ref); + + return error; +} + +static int rebase_copy_note( + git_rebase *rebase, + git_oid *from, + git_oid *to, + const git_signature *committer, + const git_rebase_options *opts) +{ + git_note *note = NULL; + git_oid note_id; + git_signature *who = NULL; + int error; + + if ((error = git_note_read(¬e, rebase->repo, opts->rewrite_notes_ref, from)) < 0) { + if (error == GIT_ENOTFOUND) { + giterr_clear(); + error = 0; + } + + goto done; + } + + if (!committer) { + if((error = git_signature_default(&who, rebase->repo)) < 0) { + if (error != GIT_ENOTFOUND || + (error = git_signature_now(&who, "unknown", "unknown")) < 0) + goto done; + + giterr_clear(); + } + + committer = who; + } + + error = git_note_create(¬e_id, rebase->repo, git_note_author(note), + committer, opts->rewrite_notes_ref, to, git_note_message(note), 0); + +done: + git_note_free(note); + git_signature_free(who); + + return error; +} + +static int rebase_copy_notes( + git_rebase *rebase, + const git_signature *committer, + const git_rebase_options *opts) +{ + git_buf path = GIT_BUF_INIT, rewritten = GIT_BUF_INIT; + char *pair_list, *fromstr, *tostr, *end; + git_oid from, to; + unsigned int linenum = 1; + int error = 0; + + if (!opts->rewrite_notes_ref) + goto done; + + if ((error = git_buf_joinpath(&path, rebase->state_path, REWRITTEN_FILE)) < 0 || + (error = git_futils_readbuffer(&rewritten, path.ptr)) < 0) + goto done; + + pair_list = rewritten.ptr; + + while (*pair_list) { + fromstr = pair_list; + + if ((end = strchr(fromstr, '\n')) == NULL) + goto on_error; + + pair_list = end+1; + *end = '\0'; + + if ((end = strchr(fromstr, ' ')) == NULL) + goto on_error; + + tostr = end+1; + *end = '\0'; + + if (strlen(fromstr) != GIT_OID_HEXSZ || + strlen(tostr) != GIT_OID_HEXSZ || + git_oid_fromstr(&from, fromstr) < 0 || + git_oid_fromstr(&to, tostr) < 0) + goto on_error; + + if ((error = rebase_copy_note(rebase, &from, &to, committer, opts)) < 0) + goto done; + + linenum++; + } + + goto done; + +on_error: + giterr_set(GITERR_REBASE, "Invalid rewritten file at line %d", linenum); + error = -1; + +done: + git_buf_free(&rewritten); + git_buf_free(&path); + + return error; +} + +int git_rebase_finish( + git_rebase *rebase, + const git_signature *signature, + const git_rebase_options *given_opts) +{ + git_rebase_options opts; + git_reference *terminal_ref = NULL, *branch_ref = NULL, *head_ref = NULL; + git_commit *terminal_commit = NULL; + git_buf branch_msg = GIT_BUF_INIT, head_msg = GIT_BUF_INIT; + char onto[GIT_OID_HEXSZ]; + int error; + + assert(rebase); + + if ((error = rebase_normalize_opts(rebase->repo, &opts, given_opts)) < 0) + goto done; + + git_oid_fmt(onto, &rebase->onto_id); + + if ((error = git_buf_printf(&branch_msg, "rebase finished: %s onto %.*s", + rebase->orig_head_name, GIT_OID_HEXSZ, onto)) < 0 || + (error = git_buf_printf(&head_msg, "rebase finished: returning to %s", + rebase->orig_head_name)) < 0 || + (error = git_repository_head(&terminal_ref, rebase->repo)) < 0 || + (error = git_reference_peel((git_object **)&terminal_commit, + terminal_ref, GIT_OBJ_COMMIT)) < 0 || + (error = git_reference_create_matching(&branch_ref, + rebase->repo, rebase->orig_head_name, git_commit_id(terminal_commit), 1, + &rebase->orig_head_id, signature, branch_msg.ptr)) < 0 || + (error = git_reference_symbolic_create(&head_ref, + rebase->repo, GIT_HEAD_FILE, rebase->orig_head_name, 1, + signature, head_msg.ptr)) < 0 || + (error = rebase_copy_notes(rebase, signature, &opts)) < 0) + goto done; + + error = rebase_cleanup(rebase); + +done: + git_buf_free(&head_msg); + git_buf_free(&branch_msg); + git_commit_free(terminal_commit); + git_reference_free(head_ref); + git_reference_free(branch_ref); + git_reference_free(terminal_ref); + rebase_opts_free(&opts); + + return error; +} + +size_t git_rebase_operation_entrycount(git_rebase *rebase) +{ + assert(rebase); + + return git_array_size(rebase->operations); +} + +size_t git_rebase_operation_current(git_rebase *rebase) +{ + assert(rebase); + + return rebase->current; +} + +git_rebase_operation *git_rebase_operation_byindex(git_rebase *rebase, size_t idx) +{ + assert(rebase); + + return git_array_get(rebase->operations, idx); +} + +void git_rebase_free(git_rebase *rebase) +{ + if (rebase == NULL) + return; + + git__free(rebase->onto_name); + git__free(rebase->orig_head_name); + git__free(rebase->state_path); + git_array_clear(rebase->operations); + git__free(rebase); +} diff --git a/src/refs.c b/src/refs.c index 08e407e48..43c7333f2 100644 --- a/src/refs.c +++ b/src/refs.c @@ -22,6 +22,7 @@ #include #include #include +#include GIT__USE_STRMAP; @@ -1090,6 +1091,40 @@ int git_reference__update_terminal( return reference__update_terminal(repo, ref_name, oid, 0, signature, log_message); } +int git_reference__update_for_commit( + git_repository *repo, + git_reference *ref, + const char *ref_name, + const git_oid *id, + const git_signature *committer, + const char *operation) +{ + git_reference *ref_new = NULL; + git_commit *commit = NULL; + git_buf reflog_msg = GIT_BUF_INIT; + int error; + + if ((error = git_commit_lookup(&commit, repo, id)) < 0 || + (error = git_buf_printf(&reflog_msg, "%s%s: %s", + operation ? operation : "commit", + git_commit_parentcount(commit) == 0 ? " (initial)" : "", + git_commit_summary(commit))) < 0) + goto done; + + if (ref) + error = git_reference_set_target( + &ref_new, ref, id, committer, git_buf_cstr(&reflog_msg)); + else + error = git_reference__update_terminal( + repo, ref_name, id, committer, git_buf_cstr(&reflog_msg)); + +done: + git_reference_free(ref_new); + git_buf_free(&reflog_msg); + git_commit_free(commit); + return error; +} + int git_reference_has_log(git_repository *repo, const char *refname) { int error; diff --git a/src/refs.h b/src/refs.h index c6ec429a5..5f48efc41 100644 --- a/src/refs.h +++ b/src/refs.h @@ -100,4 +100,13 @@ int git_reference_lookup_resolved( int git_reference__log_signature(git_signature **out, git_repository *repo); +/** Update a reference after a commit. */ +int git_reference__update_for_commit( + git_repository *repo, + git_reference *ref, + const char *ref_name, + const git_oid *id, + const git_signature *committer, + const char *operation); + #endif diff --git a/src/repository.c b/src/repository.c index f032c899d..2bab52919 100644 --- a/src/repository.c +++ b/src/repository.c @@ -1728,6 +1728,28 @@ cleanup: return error; } +int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head) +{ + git_filebuf file = GIT_FILEBUF_INIT; + git_buf file_path = GIT_BUF_INIT; + char orig_head_str[GIT_OID_HEXSZ]; + int error = 0; + + git_oid_fmt(orig_head_str, orig_head); + + if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_ORIG_HEAD_FILE)) == 0 && + (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) == 0 && + (error = git_filebuf_printf(&file, "%.*s\n", GIT_OID_HEXSZ, orig_head_str)) == 0) + error = git_filebuf_commit(&file); + + if (error < 0) + git_filebuf_cleanup(&file); + + git_buf_free(&file_path); + + return error; +} + int git_repository_message(git_buf *out, git_repository *repo) { git_buf path = GIT_BUF_INIT; diff --git a/src/repository.h b/src/repository.h index aba16a016..45b95a0f0 100644 --- a/src/repository.h +++ b/src/repository.h @@ -170,6 +170,8 @@ GIT_INLINE(int) git_repository__ensure_not_bare( return GIT_EBAREREPO; } +int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head); + int git_repository__cleanup_files(git_repository *repo, const char *files[], size_t files_len); #endif diff --git a/src/reset.c b/src/reset.c index d063abe25..dc3aa4a66 100644 --- a/src/reset.c +++ b/src/reset.c @@ -101,7 +101,7 @@ int git_reset( git_object *target, git_reset_t reset_type, git_checkout_options *checkout_opts, - git_signature *signature, + const git_signature *signature, const char *log_message) { git_object *commit = NULL; diff --git a/src/signature.c b/src/signature.c index 514b153ac..818cd300e 100644 --- a/src/signature.c +++ b/src/signature.c @@ -270,3 +270,14 @@ void git_signature__writebuf(git_buf *buf, const char *header, const git_signatu (unsigned)sig->when.time, sign, hours, mins); } +bool git_signature__equal(const git_signature *one, const git_signature *two) +{ + assert(one && two); + + return + git__strcmp(one->name, two->name) == 0 && + git__strcmp(one->email, two->email) == 0 && + one->when.time == two->when.time && + one->when.offset == two->when.offset; +} + diff --git a/src/signature.h b/src/signature.h index eb71db7db..75265df52 100644 --- a/src/signature.h +++ b/src/signature.h @@ -14,6 +14,7 @@ int git_signature__parse(git_signature *sig, const char **buffer_out, const char *buffer_end, const char *header, char ender); void git_signature__writebuf(git_buf *buf, const char *header, const git_signature *sig); +bool git_signature__equal(const git_signature *one, const git_signature *two); int git_signature__pdup(git_signature **dest, const git_signature *source, git_pool *pool); diff --git a/tests/merge/merge_helpers.c b/tests/merge/merge_helpers.c index e3e703943..9a6ead984 100644 --- a/tests/merge/merge_helpers.c +++ b/tests/merge/merge_helpers.c @@ -6,6 +6,7 @@ #include "merge.h" #include "git2/merge.h" #include "git2/sys/index.h" +#include "git2/annotated_commit.h" int merge_trees_from_branches( git_index **index, git_repository *repo, @@ -84,7 +85,7 @@ int merge_branches(git_repository *repo, git_merge_options *merge_opts, git_checkout_options *checkout_opts) { git_reference *head_ref, *theirs_ref; - git_merge_head *theirs_head; + git_annotated_commit *theirs_head; git_checkout_options head_checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; head_checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE; @@ -93,13 +94,13 @@ int merge_branches(git_repository *repo, cl_git_pass(git_checkout_head(repo, &head_checkout_opts)); cl_git_pass(git_reference_lookup(&theirs_ref, repo, theirs_branch)); - cl_git_pass(git_merge_head_from_ref(&theirs_head, repo, theirs_ref)); + cl_git_pass(git_annotated_commit_from_ref(&theirs_head, repo, theirs_ref)); - cl_git_pass(git_merge(repo, (const git_merge_head **)&theirs_head, 1, merge_opts, checkout_opts)); + cl_git_pass(git_merge(repo, (const git_annotated_commit **)&theirs_head, 1, merge_opts, checkout_opts)); git_reference_free(head_ref); git_reference_free(theirs_ref); - git_merge_head_free(theirs_head); + git_annotated_commit_free(theirs_head); return 0; } diff --git a/tests/merge/workdir/analysis.c b/tests/merge/workdir/analysis.c index 85918abe4..351cfbdd5 100644 --- a/tests/merge/workdir/analysis.c +++ b/tests/merge/workdir/analysis.c @@ -1,6 +1,7 @@ #include "clar_libgit2.h" #include "git2/repository.h" #include "git2/merge.h" +#include "git2/annotated_commit.h" #include "git2/sys/index.h" #include "merge.h" #include "../merge_helpers.h" @@ -43,17 +44,17 @@ static void analysis_from_branch( { git_buf refname = GIT_BUF_INIT; git_reference *their_ref; - git_merge_head *their_head; + git_annotated_commit *their_head; git_buf_printf(&refname, "%s%s", GIT_REFS_HEADS_DIR, branchname); cl_git_pass(git_reference_lookup(&their_ref, repo, git_buf_cstr(&refname))); - cl_git_pass(git_merge_head_from_ref(&their_head, repo, their_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_head, repo, their_ref)); - cl_git_pass(git_merge_analysis(merge_analysis, merge_pref, repo, (const git_merge_head **)&their_head, 1)); + cl_git_pass(git_merge_analysis(merge_analysis, merge_pref, repo, (const git_annotated_commit **)&their_head, 1)); git_buf_free(&refname); - git_merge_head_free(their_head); + git_annotated_commit_free(their_head); git_reference_free(their_ref); } diff --git a/tests/merge/workdir/dirty.c b/tests/merge/workdir/dirty.c index 0549b06b3..4b68b213b 100644 --- a/tests/merge/workdir/dirty.c +++ b/tests/merge/workdir/dirty.c @@ -89,18 +89,18 @@ static void set_core_autocrlf_to(git_repository *repo, bool value) static int merge_branch(void) { git_oid their_oids[1]; - git_merge_head *their_heads[1]; + git_annotated_commit *their_head; git_merge_options merge_opts = GIT_MERGE_OPTIONS_INIT; git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; int error; cl_git_pass(git_oid_fromstr(&their_oids[0], MERGE_BRANCH_OID)); - cl_git_pass(git_merge_head_from_id(&their_heads[0], repo, &their_oids[0])); + cl_git_pass(git_annotated_commit_lookup(&their_head, repo, &their_oids[0])); checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; - error = git_merge(repo, (const git_merge_head **)their_heads, 1, &merge_opts, &checkout_opts); + error = git_merge(repo, (const git_annotated_commit **)&their_head, 1, &merge_opts, &checkout_opts); - git_merge_head_free(their_heads[0]); + git_annotated_commit_free(their_head); return error; } diff --git a/tests/merge/workdir/setup.c b/tests/merge/workdir/setup.c index a0028ec6d..099bc1211 100644 --- a/tests/merge/workdir/setup.c +++ b/tests/merge/workdir/setup.c @@ -76,15 +76,15 @@ void test_merge_workdir_setup__one_branch(void) { git_oid our_oid; git_reference *octo1_ref; - git_merge_head *our_head, *their_heads[1]; + git_annotated_commit *our_head, *their_heads[1]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[0], repo, octo1_ref)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 1)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 1)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); @@ -93,8 +93,8 @@ void test_merge_workdir_setup__one_branch(void) git_reference_free(octo1_ref); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); } /* git merge --no-ff 16f825815cfd20a07a75c71554e82d8eede0b061 */ @@ -102,23 +102,23 @@ void test_merge_workdir_setup__one_oid(void) { git_oid our_oid; git_oid octo1_oid; - git_merge_head *our_head, *their_heads[1]; + git_annotated_commit *our_head, *their_heads[1]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_oid, OCTO1_OID)); - cl_git_pass(git_merge_head_from_id(&their_heads[0], repo, &octo1_oid)); + cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &octo1_oid)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 1)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 1)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge commit '" OCTO1_OID "'\n")); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); } /* git merge octo1 octo2 */ @@ -127,18 +127,18 @@ void test_merge_workdir_setup__two_branches(void) git_oid our_oid; git_reference *octo1_ref; git_reference *octo2_ref; - git_merge_head *our_head, *their_heads[2]; + git_annotated_commit *our_head, *their_heads[2]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo2_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[1], repo, octo2_ref)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 2)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 2)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); @@ -148,9 +148,9 @@ void test_merge_workdir_setup__two_branches(void) git_reference_free(octo1_ref); git_reference_free(octo2_ref); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); - git_merge_head_free(their_heads[1]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); + git_annotated_commit_free(their_heads[1]); } /* git merge octo1 octo2 octo3 */ @@ -160,21 +160,21 @@ void test_merge_workdir_setup__three_branches(void) git_reference *octo1_ref; git_reference *octo2_ref; git_reference *octo3_ref; - git_merge_head *our_head, *their_heads[3]; + git_annotated_commit *our_head, *their_heads[3]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo2_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[1], repo, octo2_ref)); cl_git_pass(git_reference_lookup(&octo3_ref, repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[2], repo, octo3_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[2], repo, octo3_ref)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 3)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 3)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); @@ -185,10 +185,10 @@ void test_merge_workdir_setup__three_branches(void) git_reference_free(octo2_ref); git_reference_free(octo3_ref); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); - git_merge_head_free(their_heads[1]); - git_merge_head_free(their_heads[2]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); + git_annotated_commit_free(their_heads[1]); + git_annotated_commit_free(their_heads[2]); } /* git merge 16f825815cfd20a07a75c71554e82d8eede0b061 158dc7bedb202f5b26502bf3574faa7f4238d56c 50ce7d7d01217679e26c55939eef119e0c93e272 */ @@ -198,31 +198,31 @@ void test_merge_workdir_setup__three_oids(void) git_oid octo1_oid; git_oid octo2_oid; git_oid octo3_oid; - git_merge_head *our_head, *their_heads[3]; + git_annotated_commit *our_head, *their_heads[3]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_oid, OCTO1_OID)); - cl_git_pass(git_merge_head_from_id(&their_heads[0], repo, &octo1_oid)); + cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &octo1_oid)); cl_git_pass(git_oid_fromstr(&octo2_oid, OCTO2_OID)); - cl_git_pass(git_merge_head_from_id(&their_heads[1], repo, &octo2_oid)); + cl_git_pass(git_annotated_commit_lookup(&their_heads[1], repo, &octo2_oid)); cl_git_pass(git_oid_fromstr(&octo3_oid, OCTO3_OID)); - cl_git_pass(git_merge_head_from_id(&their_heads[2], repo, &octo3_oid)); + cl_git_pass(git_annotated_commit_lookup(&their_heads[2], repo, &octo3_oid)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 3)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 3)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge commit '" OCTO1_OID "'; commit '" OCTO2_OID "'; commit '" OCTO3_OID "'\n")); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); - git_merge_head_free(their_heads[1]); - git_merge_head_free(their_heads[2]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); + git_annotated_commit_free(their_heads[1]); + git_annotated_commit_free(their_heads[2]); } /* git merge octo1 158dc7bedb202f5b26502bf3574faa7f4238d56c */ @@ -231,18 +231,18 @@ void test_merge_workdir_setup__branches_and_oids_1(void) git_oid our_oid; git_reference *octo1_ref; git_oid octo2_oid; - git_merge_head *our_head, *their_heads[2]; + git_annotated_commit *our_head, *their_heads[2]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_oid_fromstr(&octo2_oid, OCTO2_OID)); - cl_git_pass(git_merge_head_from_id(&their_heads[1], repo, &octo2_oid)); + cl_git_pass(git_annotated_commit_lookup(&their_heads[1], repo, &octo2_oid)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 2)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 2)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); @@ -251,9 +251,9 @@ void test_merge_workdir_setup__branches_and_oids_1(void) git_reference_free(octo1_ref); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); - git_merge_head_free(their_heads[1]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); + git_annotated_commit_free(their_heads[1]); } /* git merge octo1 158dc7bedb202f5b26502bf3574faa7f4238d56c octo3 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae */ @@ -264,24 +264,24 @@ void test_merge_workdir_setup__branches_and_oids_2(void) git_oid octo2_oid; git_reference *octo3_ref; git_oid octo4_oid; - git_merge_head *our_head, *their_heads[4]; + git_annotated_commit *our_head, *their_heads[4]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_oid_fromstr(&octo2_oid, OCTO2_OID)); - cl_git_pass(git_merge_head_from_id(&their_heads[1], repo, &octo2_oid)); + cl_git_pass(git_annotated_commit_lookup(&their_heads[1], repo, &octo2_oid)); cl_git_pass(git_reference_lookup(&octo3_ref, repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[2], repo, octo3_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[2], repo, octo3_ref)); cl_git_pass(git_oid_fromstr(&octo4_oid, OCTO4_OID)); - cl_git_pass(git_merge_head_from_id(&their_heads[3], repo, &octo4_oid)); + cl_git_pass(git_annotated_commit_lookup(&their_heads[3], repo, &octo4_oid)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 4)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 4)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n" OCTO4_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); @@ -291,11 +291,11 @@ void test_merge_workdir_setup__branches_and_oids_2(void) git_reference_free(octo1_ref); git_reference_free(octo3_ref); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); - git_merge_head_free(their_heads[1]); - git_merge_head_free(their_heads[2]); - git_merge_head_free(their_heads[3]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); + git_annotated_commit_free(their_heads[1]); + git_annotated_commit_free(their_heads[2]); + git_annotated_commit_free(their_heads[3]); } /* git merge 16f825815cfd20a07a75c71554e82d8eede0b061 octo2 50ce7d7d01217679e26c55939eef119e0c93e272 octo4 */ @@ -306,24 +306,24 @@ void test_merge_workdir_setup__branches_and_oids_3(void) git_reference *octo2_ref; git_oid octo3_oid; git_reference *octo4_ref; - git_merge_head *our_head, *their_heads[4]; + git_annotated_commit *our_head, *their_heads[4]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_oid, OCTO1_OID)); - cl_git_pass(git_merge_head_from_id(&their_heads[0], repo, &octo1_oid)); + cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &octo1_oid)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo2_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[1], repo, octo2_ref)); cl_git_pass(git_oid_fromstr(&octo3_oid, OCTO3_OID)); - cl_git_pass(git_merge_head_from_id(&their_heads[2], repo, &octo3_oid)); + cl_git_pass(git_annotated_commit_lookup(&their_heads[2], repo, &octo3_oid)); cl_git_pass(git_reference_lookup(&octo4_ref, repo, GIT_REFS_HEADS_DIR OCTO4_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[3], repo, octo4_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[3], repo, octo4_ref)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 4)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 4)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n" OCTO4_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); @@ -333,11 +333,11 @@ void test_merge_workdir_setup__branches_and_oids_3(void) git_reference_free(octo2_ref); git_reference_free(octo4_ref); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); - git_merge_head_free(their_heads[1]); - git_merge_head_free(their_heads[2]); - git_merge_head_free(their_heads[3]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); + git_annotated_commit_free(their_heads[1]); + git_annotated_commit_free(their_heads[2]); + git_annotated_commit_free(their_heads[3]); } /* git merge 16f825815cfd20a07a75c71554e82d8eede0b061 octo2 50ce7d7d01217679e26c55939eef119e0c93e272 octo4 octo5 */ @@ -349,27 +349,27 @@ void test_merge_workdir_setup__branches_and_oids_4(void) git_oid octo3_oid; git_reference *octo4_ref; git_reference *octo5_ref; - git_merge_head *our_head, *their_heads[5]; + git_annotated_commit *our_head, *their_heads[5]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_oid, OCTO1_OID)); - cl_git_pass(git_merge_head_from_id(&their_heads[0], repo, &octo1_oid)); + cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &octo1_oid)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo2_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[1], repo, octo2_ref)); cl_git_pass(git_oid_fromstr(&octo3_oid, OCTO3_OID)); - cl_git_pass(git_merge_head_from_id(&their_heads[2], repo, &octo3_oid)); + cl_git_pass(git_annotated_commit_lookup(&their_heads[2], repo, &octo3_oid)); cl_git_pass(git_reference_lookup(&octo4_ref, repo, GIT_REFS_HEADS_DIR OCTO4_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[3], repo, octo4_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[3], repo, octo4_ref)); cl_git_pass(git_reference_lookup(&octo5_ref, repo, GIT_REFS_HEADS_DIR OCTO5_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[4], repo, octo5_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[4], repo, octo5_ref)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 5)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 5)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n" OCTO4_OID "\n" OCTO5_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); @@ -380,12 +380,12 @@ void test_merge_workdir_setup__branches_and_oids_4(void) git_reference_free(octo4_ref); git_reference_free(octo5_ref); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); - git_merge_head_free(their_heads[1]); - git_merge_head_free(their_heads[2]); - git_merge_head_free(their_heads[3]); - git_merge_head_free(their_heads[4]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); + git_annotated_commit_free(their_heads[1]); + git_annotated_commit_free(their_heads[2]); + git_annotated_commit_free(their_heads[3]); + git_annotated_commit_free(their_heads[4]); } /* git merge octo1 octo1 octo1 */ @@ -395,21 +395,21 @@ void test_merge_workdir_setup__three_same_branches(void) git_reference *octo1_1_ref; git_reference *octo1_2_ref; git_reference *octo1_3_ref; - git_merge_head *our_head, *their_heads[3]; + git_annotated_commit *our_head, *their_heads[3]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_1_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[0], repo, octo1_1_ref)); cl_git_pass(git_reference_lookup(&octo1_2_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo1_2_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[1], repo, octo1_2_ref)); cl_git_pass(git_reference_lookup(&octo1_3_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[2], repo, octo1_3_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[2], repo, octo1_3_ref)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 3)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 3)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO1_OID "\n" OCTO1_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); @@ -420,10 +420,10 @@ void test_merge_workdir_setup__three_same_branches(void) git_reference_free(octo1_2_ref); git_reference_free(octo1_3_ref); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); - git_merge_head_free(their_heads[1]); - git_merge_head_free(their_heads[2]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); + git_annotated_commit_free(their_heads[1]); + git_annotated_commit_free(their_heads[2]); } /* git merge 16f825815cfd20a07a75c71554e82d8eede0b061 16f825815cfd20a07a75c71554e82d8eede0b061 16f825815cfd20a07a75c71554e82d8eede0b061 */ @@ -433,31 +433,31 @@ void test_merge_workdir_setup__three_same_oids(void) git_oid octo1_1_oid; git_oid octo1_2_oid; git_oid octo1_3_oid; - git_merge_head *our_head, *their_heads[3]; + git_annotated_commit *our_head, *their_heads[3]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_1_oid, OCTO1_OID)); - cl_git_pass(git_merge_head_from_id(&their_heads[0], repo, &octo1_1_oid)); + cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &octo1_1_oid)); cl_git_pass(git_oid_fromstr(&octo1_2_oid, OCTO1_OID)); - cl_git_pass(git_merge_head_from_id(&their_heads[1], repo, &octo1_2_oid)); + cl_git_pass(git_annotated_commit_lookup(&their_heads[1], repo, &octo1_2_oid)); cl_git_pass(git_oid_fromstr(&octo1_3_oid, OCTO1_OID)); - cl_git_pass(git_merge_head_from_id(&their_heads[2], repo, &octo1_3_oid)); + cl_git_pass(git_annotated_commit_lookup(&their_heads[2], repo, &octo1_3_oid)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 3)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 3)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO1_OID "\n" OCTO1_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge commit '" OCTO1_OID "'; commit '" OCTO1_OID "'; commit '" OCTO1_OID "'\n")); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); - git_merge_head_free(their_heads[1]); - git_merge_head_free(their_heads[2]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); + git_annotated_commit_free(their_heads[1]); + git_annotated_commit_free(their_heads[2]); } static int create_remote_tracking_branch(const char *branch_name, const char *oid_str) @@ -508,17 +508,17 @@ void test_merge_workdir_setup__remote_tracking_one_branch(void) { git_oid our_oid; git_reference *octo1_ref; - git_merge_head *our_head, *their_heads[1]; + git_annotated_commit *our_head, *their_heads[1]; cl_git_pass(create_remote_tracking_branch(OCTO1_BRANCH, OCTO1_OID)); cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO1_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[0], repo, octo1_ref)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 1)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 1)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); @@ -527,8 +527,8 @@ void test_merge_workdir_setup__remote_tracking_one_branch(void) git_reference_free(octo1_ref); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); } /* git merge refs/remotes/origin/octo1 refs/remotes/origin/octo2 */ @@ -537,21 +537,21 @@ void test_merge_workdir_setup__remote_tracking_two_branches(void) git_oid our_oid; git_reference *octo1_ref; git_reference *octo2_ref; - git_merge_head *our_head, *their_heads[2]; + git_annotated_commit *our_head, *their_heads[2]; cl_git_pass(create_remote_tracking_branch(OCTO1_BRANCH, OCTO1_OID)); cl_git_pass(create_remote_tracking_branch(OCTO2_BRANCH, OCTO2_OID)); cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO1_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO2_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo2_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[1], repo, octo2_ref)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 2)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 2)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); @@ -561,9 +561,9 @@ void test_merge_workdir_setup__remote_tracking_two_branches(void) git_reference_free(octo1_ref); git_reference_free(octo2_ref); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); - git_merge_head_free(their_heads[1]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); + git_annotated_commit_free(their_heads[1]); } /* git merge refs/remotes/origin/octo1 refs/remotes/origin/octo2 refs/remotes/origin/octo3 */ @@ -573,25 +573,25 @@ void test_merge_workdir_setup__remote_tracking_three_branches(void) git_reference *octo1_ref; git_reference *octo2_ref; git_reference *octo3_ref; - git_merge_head *our_head, *their_heads[3]; + git_annotated_commit *our_head, *their_heads[3]; cl_git_pass(create_remote_tracking_branch(OCTO1_BRANCH, OCTO1_OID)); cl_git_pass(create_remote_tracking_branch(OCTO2_BRANCH, OCTO2_OID)); cl_git_pass(create_remote_tracking_branch(OCTO3_BRANCH, OCTO3_OID)); cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO1_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO2_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo2_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[1], repo, octo2_ref)); cl_git_pass(git_reference_lookup(&octo3_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO3_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[2], repo, octo3_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[2], repo, octo3_ref)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 3)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 3)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); @@ -602,10 +602,10 @@ void test_merge_workdir_setup__remote_tracking_three_branches(void) git_reference_free(octo2_ref); git_reference_free(octo3_ref); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); - git_merge_head_free(their_heads[1]); - git_merge_head_free(their_heads[2]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); + git_annotated_commit_free(their_heads[1]); + git_annotated_commit_free(their_heads[2]); } /* git merge octo1 refs/remotes/origin/octo2 */ @@ -614,20 +614,20 @@ void test_merge_workdir_setup__normal_branch_and_remote_tracking_branch(void) git_oid our_oid; git_reference *octo1_ref; git_reference *octo2_ref; - git_merge_head *our_head, *their_heads[2]; + git_annotated_commit *our_head, *their_heads[2]; cl_git_pass(create_remote_tracking_branch(OCTO2_BRANCH, OCTO2_OID)); cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO2_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo2_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[1], repo, octo2_ref)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 2)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 2)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); @@ -637,9 +637,9 @@ void test_merge_workdir_setup__normal_branch_and_remote_tracking_branch(void) git_reference_free(octo1_ref); git_reference_free(octo2_ref); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); - git_merge_head_free(their_heads[1]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); + git_annotated_commit_free(their_heads[1]); } /* git merge refs/remotes/origin/octo1 octo2 */ @@ -648,20 +648,20 @@ void test_merge_workdir_setup__remote_tracking_branch_and_normal_branch(void) git_oid our_oid; git_reference *octo1_ref; git_reference *octo2_ref; - git_merge_head *our_head, *their_heads[2]; + git_annotated_commit *our_head, *their_heads[2]; cl_git_pass(create_remote_tracking_branch(OCTO1_BRANCH, OCTO1_OID)); cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO1_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo2_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[1], repo, octo2_ref)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 2)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 2)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); @@ -671,9 +671,9 @@ void test_merge_workdir_setup__remote_tracking_branch_and_normal_branch(void) git_reference_free(octo1_ref); git_reference_free(octo2_ref); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); - git_merge_head_free(their_heads[1]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); + git_annotated_commit_free(their_heads[1]); } /* git merge octo1 refs/remotes/origin/octo2 octo3 refs/remotes/origin/octo4 */ @@ -684,27 +684,27 @@ void test_merge_workdir_setup__two_remote_tracking_branch_and_two_normal_branche git_reference *octo2_ref; git_reference *octo3_ref; git_reference *octo4_ref; - git_merge_head *our_head, *their_heads[4]; + git_annotated_commit *our_head, *their_heads[4]; cl_git_pass(create_remote_tracking_branch(OCTO2_BRANCH, OCTO2_OID)); cl_git_pass(create_remote_tracking_branch(OCTO4_BRANCH, OCTO4_OID)); cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO2_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo2_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[1], repo, octo2_ref)); cl_git_pass(git_reference_lookup(&octo3_ref, repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[2], repo, octo3_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[2], repo, octo3_ref)); cl_git_pass(git_reference_lookup(&octo4_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO4_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[3], repo, octo4_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[3], repo, octo4_ref)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 4)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 4)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n" OCTO4_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); @@ -716,11 +716,11 @@ void test_merge_workdir_setup__two_remote_tracking_branch_and_two_normal_branche git_reference_free(octo3_ref); git_reference_free(octo4_ref); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); - git_merge_head_free(their_heads[1]); - git_merge_head_free(their_heads[2]); - git_merge_head_free(their_heads[3]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); + git_annotated_commit_free(their_heads[1]); + git_annotated_commit_free(their_heads[2]); + git_annotated_commit_free(their_heads[3]); } /* git pull origin branch octo1 */ @@ -728,23 +728,23 @@ void test_merge_workdir_setup__pull_one(void) { git_oid our_oid; git_oid octo1_1_oid; - git_merge_head *our_head, *their_heads[1]; + git_annotated_commit *our_head, *their_heads[1]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_1_oid, OCTO1_OID)); - cl_git_pass(git_merge_head_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.url/repo.git", &octo1_1_oid)); + cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.url/repo.git", &octo1_1_oid)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 1)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 1)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branch 'octo1' of http://remote.url/repo.git\n")); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); } /* git pull origin octo1 octo2 */ @@ -753,27 +753,27 @@ void test_merge_workdir_setup__pull_two(void) git_oid our_oid; git_oid octo1_oid; git_oid octo2_oid; - git_merge_head *our_head, *their_heads[2]; + git_annotated_commit *our_head, *their_heads[2]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_oid, OCTO1_OID)); - cl_git_pass(git_merge_head_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.url/repo.git", &octo1_oid)); + cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.url/repo.git", &octo1_oid)); cl_git_pass(git_oid_fromstr(&octo2_oid, OCTO2_OID)); - cl_git_pass(git_merge_head_from_fetchhead(&their_heads[1], repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH, "http://remote.url/repo.git", &octo2_oid)); + cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[1], repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH, "http://remote.url/repo.git", &octo2_oid)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 2)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 2)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "' and '" OCTO2_BRANCH "' of http://remote.url/repo.git\n")); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); - git_merge_head_free(their_heads[1]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); + git_annotated_commit_free(their_heads[1]); } /* git pull origin octo1 octo2 octo3 */ @@ -783,31 +783,31 @@ void test_merge_workdir_setup__pull_three(void) git_oid octo1_oid; git_oid octo2_oid; git_oid octo3_oid; - git_merge_head *our_head, *their_heads[3]; + git_annotated_commit *our_head, *their_heads[3]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_oid, OCTO1_OID)); - cl_git_pass(git_merge_head_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.url/repo.git", &octo1_oid)); + cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.url/repo.git", &octo1_oid)); cl_git_pass(git_oid_fromstr(&octo2_oid, OCTO2_OID)); - cl_git_pass(git_merge_head_from_fetchhead(&their_heads[1], repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH, "http://remote.url/repo.git", &octo2_oid)); + cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[1], repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH, "http://remote.url/repo.git", &octo2_oid)); cl_git_pass(git_oid_fromstr(&octo3_oid, OCTO3_OID)); - cl_git_pass(git_merge_head_from_fetchhead(&their_heads[2], repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH, "http://remote.url/repo.git", &octo3_oid)); + cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[2], repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH, "http://remote.url/repo.git", &octo3_oid)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 3)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 3)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "', '" OCTO2_BRANCH "' and '" OCTO3_BRANCH "' of http://remote.url/repo.git\n")); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); - git_merge_head_free(their_heads[1]); - git_merge_head_free(their_heads[2]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); + git_annotated_commit_free(their_heads[1]); + git_annotated_commit_free(their_heads[2]); } void test_merge_workdir_setup__three_remotes(void) @@ -816,31 +816,31 @@ void test_merge_workdir_setup__three_remotes(void) git_oid octo1_oid; git_oid octo2_oid; git_oid octo3_oid; - git_merge_head *our_head, *their_heads[3]; + git_annotated_commit *our_head, *their_heads[3]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_oid, OCTO1_OID)); - cl_git_pass(git_merge_head_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.first/repo.git", &octo1_oid)); + cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.first/repo.git", &octo1_oid)); cl_git_pass(git_oid_fromstr(&octo2_oid, OCTO2_OID)); - cl_git_pass(git_merge_head_from_fetchhead(&their_heads[1], repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH, "http://remote.second/repo.git", &octo2_oid)); + cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[1], repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH, "http://remote.second/repo.git", &octo2_oid)); cl_git_pass(git_oid_fromstr(&octo3_oid, OCTO3_OID)); - cl_git_pass(git_merge_head_from_fetchhead(&their_heads[2], repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH, "http://remote.third/repo.git", &octo3_oid)); + cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[2], repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH, "http://remote.third/repo.git", &octo3_oid)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 3)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 3)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branch '" OCTO1_BRANCH "' of http://remote.first/repo.git, branch '" OCTO2_BRANCH "' of http://remote.second/repo.git, branch '" OCTO3_BRANCH "' of http://remote.third/repo.git\n")); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); - git_merge_head_free(their_heads[1]); - git_merge_head_free(their_heads[2]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); + git_annotated_commit_free(their_heads[1]); + git_annotated_commit_free(their_heads[2]); } void test_merge_workdir_setup__two_remotes(void) @@ -850,35 +850,35 @@ void test_merge_workdir_setup__two_remotes(void) git_oid octo2_oid; git_oid octo3_oid; git_oid octo4_oid; - git_merge_head *our_head, *their_heads[4]; + git_annotated_commit *our_head, *their_heads[4]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_oid, OCTO1_OID)); - cl_git_pass(git_merge_head_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.first/repo.git", &octo1_oid)); + cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.first/repo.git", &octo1_oid)); cl_git_pass(git_oid_fromstr(&octo2_oid, OCTO2_OID)); - cl_git_pass(git_merge_head_from_fetchhead(&their_heads[1], repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH, "http://remote.second/repo.git", &octo2_oid)); + cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[1], repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH, "http://remote.second/repo.git", &octo2_oid)); cl_git_pass(git_oid_fromstr(&octo3_oid, OCTO3_OID)); - cl_git_pass(git_merge_head_from_fetchhead(&their_heads[2], repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH, "http://remote.first/repo.git", &octo3_oid)); + cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[2], repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH, "http://remote.first/repo.git", &octo3_oid)); cl_git_pass(git_oid_fromstr(&octo4_oid, OCTO4_OID)); - cl_git_pass(git_merge_head_from_fetchhead(&their_heads[3], repo, GIT_REFS_HEADS_DIR OCTO4_BRANCH, "http://remote.second/repo.git", &octo4_oid)); + cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[3], repo, GIT_REFS_HEADS_DIR OCTO4_BRANCH, "http://remote.second/repo.git", &octo4_oid)); - cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 4)); + cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 4)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n" OCTO4_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "' and '" OCTO3_BRANCH "' of http://remote.first/repo.git, branches '" OCTO2_BRANCH "' and '" OCTO4_BRANCH "' of http://remote.second/repo.git\n")); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); - git_merge_head_free(their_heads[1]); - git_merge_head_free(their_heads[2]); - git_merge_head_free(their_heads[3]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); + git_annotated_commit_free(their_heads[1]); + git_annotated_commit_free(their_heads[2]); + git_annotated_commit_free(their_heads[3]); } void test_merge_workdir_setup__id_from_head(void) @@ -886,39 +886,39 @@ void test_merge_workdir_setup__id_from_head(void) git_oid expected_id; const git_oid *id; git_reference *ref; - git_merge_head *heads[3]; + git_annotated_commit *heads[3]; cl_git_pass(git_oid_fromstr(&expected_id, OCTO1_OID)); - cl_git_pass(git_merge_head_from_fetchhead(&heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.url/repo.git", &expected_id)); - id = git_merge_head_id(heads[0]); + cl_git_pass(git_annotated_commit_from_fetchhead(&heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.url/repo.git", &expected_id)); + id = git_annotated_commit_id(heads[0]); cl_assert_equal_i(1, git_oid_equal(id, &expected_id)); - cl_git_pass(git_merge_head_from_id(&heads[1], repo, &expected_id)); - id = git_merge_head_id(heads[1]); + cl_git_pass(git_annotated_commit_lookup(&heads[1], repo, &expected_id)); + id = git_annotated_commit_id(heads[1]); cl_assert_equal_i(1, git_oid_equal(id, &expected_id)); cl_git_pass(git_reference_lookup(&ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&heads[2], repo, ref)); - id = git_merge_head_id(heads[2]); + cl_git_pass(git_annotated_commit_from_ref(&heads[2], repo, ref)); + id = git_annotated_commit_id(heads[2]); cl_assert_equal_i(1, git_oid_equal(id, &expected_id)); git_reference_free(ref); - git_merge_head_free(heads[0]); - git_merge_head_free(heads[1]); - git_merge_head_free(heads[2]); + git_annotated_commit_free(heads[0]); + git_annotated_commit_free(heads[1]); + git_annotated_commit_free(heads[2]); } -struct merge_head_cb_data { +struct annotated_commit_cb_data { const char **oid_str; unsigned int len; unsigned int i; }; -static int merge_head_foreach_cb(const git_oid *oid, void *payload) +static int annotated_commit_foreach_cb(const git_oid *oid, void *payload) { git_oid expected_oid; - struct merge_head_cb_data *cb_data = payload; + struct annotated_commit_cb_data *cb_data = payload; git_oid_fromstr(&expected_oid, cb_data->oid_str[cb_data->i]); cl_assert(git_oid_cmp(&expected_oid, oid) == 0); @@ -931,7 +931,7 @@ void test_merge_workdir_setup__head_notfound(void) int error; cl_git_fail((error = git_repository_mergehead_foreach(repo, - merge_head_foreach_cb, NULL))); + annotated_commit_foreach_cb, NULL))); cl_assert(error == GIT_ENOTFOUND); } @@ -942,7 +942,7 @@ void test_merge_workdir_setup__head_invalid_oid(void) write_file_contents(GIT_MERGE_HEAD_FILE, "invalid-oid\n"); cl_git_fail((error = git_repository_mergehead_foreach(repo, - merge_head_foreach_cb, NULL))); + annotated_commit_foreach_cb, NULL))); cl_assert(error == -1); } @@ -953,7 +953,7 @@ void test_merge_workdir_setup__head_foreach_nonewline(void) write_file_contents(GIT_MERGE_HEAD_FILE, THEIRS_SIMPLE_OID); cl_git_fail((error = git_repository_mergehead_foreach(repo, - merge_head_foreach_cb, NULL))); + annotated_commit_foreach_cb, NULL))); cl_assert(error == -1); } @@ -961,12 +961,12 @@ void test_merge_workdir_setup__head_foreach_one(void) { const char *expected = THEIRS_SIMPLE_OID; - struct merge_head_cb_data cb_data = { &expected, 1 }; + struct annotated_commit_cb_data cb_data = { &expected, 1 }; write_file_contents(GIT_MERGE_HEAD_FILE, THEIRS_SIMPLE_OID "\n"); cl_git_pass(git_repository_mergehead_foreach(repo, - merge_head_foreach_cb, &cb_data)); + annotated_commit_foreach_cb, &cb_data)); cl_assert(cb_data.i == cb_data.len); } @@ -976,7 +976,7 @@ void test_merge_workdir_setup__head_foreach_octopus(void) const char *expected[] = { THEIRS_SIMPLE_OID, OCTO1_OID, OCTO2_OID, OCTO3_OID, OCTO4_OID, OCTO5_OID }; - struct merge_head_cb_data cb_data = { expected, 6 }; + struct annotated_commit_cb_data cb_data = { expected, 6 }; write_file_contents(GIT_MERGE_HEAD_FILE, THEIRS_SIMPLE_OID "\n" @@ -987,7 +987,7 @@ void test_merge_workdir_setup__head_foreach_octopus(void) OCTO5_OID "\n"); cl_git_pass(git_repository_mergehead_foreach(repo, - merge_head_foreach_cb, &cb_data)); + annotated_commit_foreach_cb, &cb_data)); cl_assert(cb_data.i == cb_data.len); } @@ -996,16 +996,16 @@ void test_merge_workdir_setup__retained_after_success(void) { git_oid our_oid; git_reference *octo1_ref; - git_merge_head *our_head, *their_heads[1]; + git_annotated_commit *our_head, *their_heads[1]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[0], repo, octo1_ref)); - cl_git_pass(git_merge(repo, (const git_merge_head **)&their_heads[0], 1, NULL, NULL)); + cl_git_pass(git_merge(repo, (const git_annotated_commit **)&their_heads[0], 1, NULL, NULL)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); @@ -1014,27 +1014,27 @@ void test_merge_workdir_setup__retained_after_success(void) git_reference_free(octo1_ref); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); } void test_merge_workdir_setup__removed_after_failure(void) { git_oid our_oid; git_reference *octo1_ref; - git_merge_head *our_head, *their_heads[1]; + git_annotated_commit *our_head, *their_heads[1]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); - cl_git_pass(git_merge_head_from_id(&our_head, repo, &our_oid)); + cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_rewritefile("merge-resolve/new-in-octo1.txt", "Conflicting file!\n\nMerge will fail!\n"); cl_git_fail(git_merge( - repo, (const git_merge_head **)&their_heads[0], 1, NULL, NULL)); + repo, (const git_annotated_commit **)&their_heads[0], 1, NULL, NULL)); cl_assert(!git_path_exists("merge-resolve/" GIT_MERGE_HEAD_FILE)); cl_assert(!git_path_exists("merge-resolve/" GIT_ORIG_HEAD_FILE)); @@ -1043,6 +1043,6 @@ void test_merge_workdir_setup__removed_after_failure(void) git_reference_free(octo1_ref); - git_merge_head_free(our_head); - git_merge_head_free(their_heads[0]); + git_annotated_commit_free(our_head); + git_annotated_commit_free(their_heads[0]); } diff --git a/tests/merge/workdir/simple.c b/tests/merge/workdir/simple.c index fcd84dcd1..df531f48f 100644 --- a/tests/merge/workdir/simple.c +++ b/tests/merge/workdir/simple.c @@ -95,20 +95,20 @@ void test_merge_workdir_simple__cleanup(void) static void merge_simple_branch(int merge_file_favor, int addl_checkout_strategy) { git_oid their_oids[1]; - git_merge_head *their_heads[1]; + git_annotated_commit *their_heads[1]; git_merge_options merge_opts = GIT_MERGE_OPTIONS_INIT; git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_SIMPLE_OID)); - cl_git_pass(git_merge_head_from_id(&their_heads[0], repo, &their_oids[0])); + cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &their_oids[0])); merge_opts.file_favor = merge_file_favor; checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_ALLOW_CONFLICTS | addl_checkout_strategy; - cl_git_pass(git_merge(repo, (const git_merge_head **)their_heads, 1, &merge_opts, &checkout_opts)); + cl_git_pass(git_merge(repo, (const git_annotated_commit **)their_heads, 1, &merge_opts, &checkout_opts)); - git_merge_head_free(their_heads[0]); + git_annotated_commit_free(their_heads[0]); } static void set_core_autocrlf_to(git_repository *repo, bool value) @@ -486,7 +486,7 @@ void test_merge_workdir_simple__directory_file(void) { git_reference *head; git_oid their_oids[1], head_commit_id; - git_merge_head *their_heads[1]; + git_annotated_commit *their_heads[1]; git_merge_options merge_opts = GIT_MERGE_OPTIONS_INIT; git_commit *head_commit; @@ -519,22 +519,22 @@ void test_merge_workdir_simple__directory_file(void) cl_git_pass(git_reset(repo, (git_object *)head_commit, GIT_RESET_HARD, NULL, NULL, NULL)); cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_DIRECTORY_FILE)); - cl_git_pass(git_merge_head_from_id(&their_heads[0], repo, &their_oids[0])); + cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &their_oids[0])); merge_opts.file_favor = 0; - cl_git_pass(git_merge(repo, (const git_merge_head **)their_heads, 1, &merge_opts, NULL)); + cl_git_pass(git_merge(repo, (const git_annotated_commit **)their_heads, 1, &merge_opts, NULL)); cl_assert(merge_test_index(repo_index, merge_index_entries, 20)); git_reference_free(head); git_commit_free(head_commit); - git_merge_head_free(their_heads[0]); + git_annotated_commit_free(their_heads[0]); } void test_merge_workdir_simple__unrelated(void) { git_oid their_oids[1]; - git_merge_head *their_heads[1]; + git_annotated_commit *their_heads[1]; git_merge_options merge_opts = GIT_MERGE_OPTIONS_INIT; struct merge_index_entry merge_index_entries[] = { @@ -550,20 +550,20 @@ void test_merge_workdir_simple__unrelated(void) }; cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_UNRELATED_PARENT)); - cl_git_pass(git_merge_head_from_id(&their_heads[0], repo, &their_oids[0])); + cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &their_oids[0])); merge_opts.file_favor = 0; - cl_git_pass(git_merge(repo, (const git_merge_head **)their_heads, 1, &merge_opts, NULL)); + cl_git_pass(git_merge(repo, (const git_annotated_commit **)their_heads, 1, &merge_opts, NULL)); cl_assert(merge_test_index(repo_index, merge_index_entries, 9)); - git_merge_head_free(their_heads[0]); + git_annotated_commit_free(their_heads[0]); } void test_merge_workdir_simple__unrelated_with_conflicts(void) { git_oid their_oids[1]; - git_merge_head *their_heads[1]; + git_annotated_commit *their_heads[1]; git_merge_options merge_opts = GIT_MERGE_OPTIONS_INIT; struct merge_index_entry merge_index_entries[] = { @@ -581,21 +581,21 @@ void test_merge_workdir_simple__unrelated_with_conflicts(void) }; cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_UNRELATED_OID)); - cl_git_pass(git_merge_head_from_id(&their_heads[0], repo, &their_oids[0])); + cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &their_oids[0])); merge_opts.file_favor = 0; - cl_git_pass(git_merge(repo, (const git_merge_head **)their_heads, 1, &merge_opts, NULL)); + cl_git_pass(git_merge(repo, (const git_annotated_commit **)their_heads, 1, &merge_opts, NULL)); cl_assert(merge_test_index(repo_index, merge_index_entries, 11)); - git_merge_head_free(their_heads[0]); + git_annotated_commit_free(their_heads[0]); } void test_merge_workdir_simple__binary(void) { git_oid our_oid, their_oid, our_file_oid; git_commit *our_commit; - git_merge_head *their_head; + git_annotated_commit *their_head; const git_index_entry *binary_entry; struct merge_index_entry merge_index_entries[] = { @@ -610,9 +610,9 @@ void test_merge_workdir_simple__binary(void) cl_git_pass(git_commit_lookup(&our_commit, repo, &our_oid)); cl_git_pass(git_reset(repo, (git_object *)our_commit, GIT_RESET_HARD, NULL, NULL, NULL)); - cl_git_pass(git_merge_head_from_id(&their_head, repo, &their_oid)); + cl_git_pass(git_annotated_commit_lookup(&their_head, repo, &their_oid)); - cl_git_pass(git_merge(repo, (const git_merge_head **)&their_head, 1, NULL, NULL)); + cl_git_pass(git_merge(repo, (const git_annotated_commit **)&their_head, 1, NULL, NULL)); cl_assert(merge_test_index(repo_index, merge_index_entries, 3)); @@ -622,6 +622,6 @@ void test_merge_workdir_simple__binary(void) cl_git_pass(git_oid_fromstr(&our_file_oid, "23ed141a6ae1e798b2f721afedbe947c119111ba")); cl_assert(git_oid_cmp(&binary_entry->id, &our_file_oid) == 0); - git_merge_head_free(their_head); + git_annotated_commit_free(their_head); git_commit_free(our_commit); } diff --git a/tests/merge/workdir/submodules.c b/tests/merge/workdir/submodules.c index eec9f14a9..31ded4662 100644 --- a/tests/merge/workdir/submodules.c +++ b/tests/merge/workdir/submodules.c @@ -30,7 +30,7 @@ void test_merge_workdir_submodules__automerge(void) { git_reference *our_ref, *their_ref; git_commit *our_commit; - git_merge_head *their_head; + git_annotated_commit *their_head; git_index *index; struct merge_index_entry merge_index_entries[] = { @@ -47,15 +47,15 @@ void test_merge_workdir_submodules__automerge(void) cl_git_pass(git_reset(repo, (git_object *)our_commit, GIT_RESET_HARD, NULL, NULL, NULL)); cl_git_pass(git_reference_lookup(&their_ref, repo, "refs/heads/" SUBMODULE_OTHER_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_head, repo, their_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_head, repo, their_ref)); - cl_git_pass(git_merge(repo, (const git_merge_head **)&their_head, 1, NULL, NULL)); + cl_git_pass(git_merge(repo, (const git_annotated_commit **)&their_head, 1, NULL, NULL)); cl_git_pass(git_repository_index(&index, repo)); cl_assert(merge_test_index(index, merge_index_entries, 6)); git_index_free(index); - git_merge_head_free(their_head); + git_annotated_commit_free(their_head); git_commit_free(our_commit); git_reference_free(their_ref); git_reference_free(our_ref); @@ -65,7 +65,7 @@ void test_merge_workdir_submodules__take_changed(void) { git_reference *our_ref, *their_ref; git_commit *our_commit; - git_merge_head *their_head; + git_annotated_commit *their_head; git_index *index; struct merge_index_entry merge_index_entries[] = { @@ -80,15 +80,15 @@ void test_merge_workdir_submodules__take_changed(void) cl_git_pass(git_reset(repo, (git_object *)our_commit, GIT_RESET_HARD, NULL, NULL, NULL)); cl_git_pass(git_reference_lookup(&their_ref, repo, "refs/heads/" SUBMODULE_OTHER2_BRANCH)); - cl_git_pass(git_merge_head_from_ref(&their_head, repo, their_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_head, repo, their_ref)); - cl_git_pass(git_merge(repo, (const git_merge_head **)&their_head, 1, NULL, NULL)); + cl_git_pass(git_merge(repo, (const git_annotated_commit **)&their_head, 1, NULL, NULL)); cl_git_pass(git_repository_index(&index, repo)); cl_assert(merge_test_index(index, merge_index_entries, 4)); git_index_free(index); - git_merge_head_free(their_head); + git_annotated_commit_free(their_head); git_commit_free(our_commit); git_reference_free(their_ref); git_reference_free(our_ref); diff --git a/tests/merge/workdir/trivial.c b/tests/merge/workdir/trivial.c index cc82d990c..fa261c3a1 100644 --- a/tests/merge/workdir/trivial.c +++ b/tests/merge/workdir/trivial.c @@ -33,7 +33,7 @@ static int merge_trivial(const char *ours, const char *theirs) git_buf branch_buf = GIT_BUF_INIT; git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; git_reference *our_ref, *their_ref; - git_merge_head *their_heads[1]; + git_annotated_commit *their_heads[1]; checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE; @@ -45,14 +45,14 @@ static int merge_trivial(const char *ours, const char *theirs) git_buf_clear(&branch_buf); git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, theirs); cl_git_pass(git_reference_lookup(&their_ref, repo, branch_buf.ptr)); - cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, their_ref)); + cl_git_pass(git_annotated_commit_from_ref(&their_heads[0], repo, their_ref)); - cl_git_pass(git_merge(repo, (const git_merge_head **)their_heads, 1, NULL, NULL)); + cl_git_pass(git_merge(repo, (const git_annotated_commit **)their_heads, 1, NULL, NULL)); git_buf_free(&branch_buf); git_reference_free(our_ref); git_reference_free(their_ref); - git_merge_head_free(their_heads[0]); + git_annotated_commit_free(their_heads[0]); return 0; } diff --git a/tests/rebase/abort.c b/tests/rebase/abort.c new file mode 100644 index 000000000..71326433f --- /dev/null +++ b/tests/rebase/abort.c @@ -0,0 +1,158 @@ +#include "clar_libgit2.h" +#include "git2/rebase.h" +#include "merge.h" +#include "posix.h" +#include "annotated_commit.h" + +#include + +static git_repository *repo; + +// Fixture setup and teardown +void test_rebase_abort__initialize(void) +{ + repo = cl_git_sandbox_init("rebase"); +} + +void test_rebase_abort__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +static void test_abort(git_annotated_commit *branch, git_annotated_commit *onto) +{ + git_rebase *rebase; + git_reference *head_ref, *branch_ref = NULL; + git_signature *signature; + git_status_list *statuslist; + git_reflog *reflog; + const git_reflog_entry *reflog_entry; + + cl_git_pass(git_rebase_open(&rebase, repo)); + cl_git_pass(git_signature_new(&signature, "Rebaser", "rebaser@example.com", 1404157834, -400)); + cl_git_pass(git_rebase_abort(rebase, signature)); + + cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo)); + + /* Make sure the refs are updated appropriately */ + cl_git_pass(git_reference_lookup(&head_ref, repo, "HEAD")); + + if (branch->ref_name == NULL) + cl_assert_equal_oid(git_annotated_commit_id(branch), git_reference_target(head_ref)); + else { + cl_assert_equal_s("refs/heads/beef", git_reference_symbolic_target(head_ref)); + cl_git_pass(git_reference_lookup(&branch_ref, repo, git_reference_symbolic_target(head_ref))); + cl_assert_equal_oid(git_annotated_commit_id(branch), git_reference_target(branch_ref)); + } + + git_status_list_new(&statuslist, repo, NULL); + cl_assert_equal_i(0, git_status_list_entrycount(statuslist)); + git_status_list_free(statuslist); + + /* Make sure the reflogs are updated appropriately */ + cl_git_pass(git_reflog_read(&reflog, repo, "HEAD")); + + cl_assert(reflog_entry = git_reflog_entry_byindex(reflog, 0)); + cl_assert_equal_oid(git_annotated_commit_id(onto), git_reflog_entry_id_old(reflog_entry)); + cl_assert_equal_oid(git_annotated_commit_id(branch), git_reflog_entry_id_new(reflog_entry)); + cl_assert_equal_s("rebase: aborting", git_reflog_entry_message(reflog_entry)); + + git_reflog_free(reflog); + git_reference_free(head_ref); + git_reference_free(branch_ref); + git_signature_free(signature); + git_rebase_free(rebase); +} + +void test_rebase_abort__merge(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *onto_ref; + git_signature *signature; + git_annotated_commit *branch_head, *onto_head; + + cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef")); + cl_git_pass(git_reference_lookup(&onto_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(&onto_head, repo, onto_ref)); + + cl_git_pass(git_signature_new(&signature, "Rebaser", "rebaser@example.com", 1404157834, -400)); + + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, signature, NULL)); + cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); + + test_abort(branch_head, onto_head); + + git_signature_free(signature); + + git_annotated_commit_free(branch_head); + git_annotated_commit_free(onto_head); + + git_reference_free(branch_ref); + git_reference_free(onto_ref); + git_rebase_free(rebase); +} + +void test_rebase_abort__detached_head(void) +{ + git_rebase *rebase; + git_oid branch_id; + git_reference *onto_ref; + git_signature *signature; + git_annotated_commit *branch_head, *onto_head; + + git_oid_fromstr(&branch_id, "b146bd7608eac53d9bf9e1a6963543588b555c64"); + cl_git_pass(git_reference_lookup(&onto_ref, repo, "refs/heads/master")); + + cl_git_pass(git_annotated_commit_lookup(&branch_head, repo, &branch_id)); + cl_git_pass(git_annotated_commit_from_ref(&onto_head, repo, onto_ref)); + + cl_git_pass(git_signature_new(&signature, "Rebaser", "rebaser@example.com", 1404157834, -400)); + + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, signature, NULL)); + cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); + + test_abort(branch_head, onto_head); + + git_signature_free(signature); + + git_annotated_commit_free(branch_head); + git_annotated_commit_free(onto_head); + + git_reference_free(onto_ref); + git_rebase_free(rebase); +} + +void test_rebase_abort__old_style_head_file(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *onto_ref; + git_signature *signature; + git_annotated_commit *branch_head, *onto_head; + + cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef")); + cl_git_pass(git_reference_lookup(&onto_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(&onto_head, repo, onto_ref)); + + cl_git_pass(git_signature_new(&signature, "Rebaser", "rebaser@example.com", 1404157834, -400)); + + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, signature, NULL)); + cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); + + p_rename("rebase-merge/.git/rebase-merge/orig-head", + "rebase-merge/.git/rebase-merge/head"); + + test_abort(branch_head, onto_head); + + git_signature_free(signature); + + git_annotated_commit_free(branch_head); + git_annotated_commit_free(onto_head); + + git_reference_free(branch_ref); + git_reference_free(onto_ref); + git_rebase_free(rebase); +} diff --git a/tests/rebase/iterator.c b/tests/rebase/iterator.c new file mode 100644 index 000000000..ddf4413d3 --- /dev/null +++ b/tests/rebase/iterator.c @@ -0,0 +1,108 @@ +#include "clar_libgit2.h" +#include "git2/rebase.h" +#include "posix.h" + +#include + +static git_repository *repo; +static git_index *_index; +static git_signature *signature; + +// Fixture setup and teardown +void test_rebase_iterator__initialize(void) +{ + repo = cl_git_sandbox_init("rebase"); + cl_git_pass(git_repository_index(&_index, repo)); + cl_git_pass(git_signature_now(&signature, "Rebaser", "rebaser@rebaser.rb")); +} + +void test_rebase_iterator__cleanup(void) +{ + git_signature_free(signature); + git_index_free(_index); + cl_git_sandbox_cleanup(); +} + +static void test_operations(git_rebase *rebase, size_t expected_current) +{ + size_t i, expected_count = 5; + git_oid expected_oid[5]; + git_rebase_operation *operation; + + git_oid_fromstr(&expected_oid[0], "da9c51a23d02d931a486f45ad18cda05cf5d2b94"); + git_oid_fromstr(&expected_oid[1], "8d1f13f93c4995760ac07d129246ac1ff64c0be9"); + git_oid_fromstr(&expected_oid[2], "3069cc907e6294623e5917ef6de663928c1febfb"); + git_oid_fromstr(&expected_oid[3], "588e5d2f04d49707fe4aab865e1deacaf7ef6787"); + git_oid_fromstr(&expected_oid[4], "b146bd7608eac53d9bf9e1a6963543588b555c64"); + + cl_assert_equal_i(expected_count, git_rebase_operation_entrycount(rebase)); + cl_assert_equal_i(expected_current, git_rebase_operation_current(rebase)); + + for (i = 0; i < expected_count; i++) { + operation = git_rebase_operation_byindex(rebase, i); + cl_assert_equal_i(GIT_REBASE_OPERATION_PICK, operation->type); + cl_assert_equal_oid(&expected_oid[i], &operation->id); + } +} + +void test_rebase_iterator__iterates(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *upstream_ref; + git_annotated_commit *branch_head, *upstream_head; + git_rebase_operation *rebase_operation; + 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/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, signature, NULL)); + test_operations(rebase, 0); + git_rebase_free(rebase); + + cl_git_pass(git_rebase_open(&rebase, repo)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + test_operations(rebase, 0); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + test_operations(rebase, 1); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + test_operations(rebase, 2); + + git_rebase_free(rebase); + cl_git_pass(git_rebase_open(&rebase, repo)); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + test_operations(rebase, 3); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + test_operations(rebase, 4); + + cl_git_fail(error = git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_assert_equal_i(GIT_ITEROVER, error); + test_operations(rebase, 4); + + 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); +} diff --git a/tests/rebase/merge.c b/tests/rebase/merge.c new file mode 100644 index 000000000..e7eb16713 --- /dev/null +++ b/tests/rebase/merge.c @@ -0,0 +1,487 @@ +#include "clar_libgit2.h" +#include "git2/rebase.h" +#include "posix.h" +#include "signature.h" + +#include + +static git_repository *repo; +static git_signature *signature; + +// Fixture setup and teardown +void test_rebase_merge__initialize(void) +{ + repo = cl_git_sandbox_init("rebase"); + cl_git_pass(git_signature_new(&signature, + "Rebaser", "rebaser@rebaser.rb", 1405694510, 0)); +} + +void test_rebase_merge__cleanup(void) +{ + git_signature_free(signature); + cl_git_sandbox_cleanup(); +} + +void test_rebase_merge__next(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *upstream_ref; + git_annotated_commit *branch_head, *upstream_head; + git_rebase_operation *rebase_operation; + git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; + git_status_list *status_list; + const git_status_entry *status_entry; + git_oid pick_id, file1_id; + + 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/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, signature, NULL)); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + + git_oid_fromstr(&pick_id, "da9c51a23d02d931a486f45ad18cda05cf5d2b94"); + + cl_assert_equal_i(GIT_REBASE_OPERATION_PICK, rebase_operation->type); + cl_assert_equal_oid(&pick_id, &rebase_operation->id); + cl_assert_equal_file("da9c51a23d02d931a486f45ad18cda05cf5d2b94\n", 41, "rebase/.git/rebase-merge/current"); + cl_assert_equal_file("1\n", 2, "rebase/.git/rebase-merge/msgnum"); + + cl_git_pass(git_status_list_new(&status_list, repo, NULL)); + cl_assert_equal_i(1, git_status_list_entrycount(status_list)); + cl_assert(status_entry = git_status_byindex(status_list, 0)); + + cl_assert_equal_s("beef.txt", status_entry->head_to_index->new_file.path); + + git_oid_fromstr(&file1_id, "8d95ea62e621f1d38d230d9e7d206e41096d76af"); + cl_assert_equal_oid(&file1_id, &status_entry->head_to_index->new_file.id); + + 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_rebase_free(rebase); +} + +void test_rebase_merge__next_with_conflicts(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *upstream_ref; + git_annotated_commit *branch_head, *upstream_head; + git_rebase_operation *rebase_operation; + git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; + git_status_list *status_list; + const git_status_entry *status_entry; + git_oid pick_id; + + const char *expected_merge = +"ASPARAGUS SOUP.\n" +"\n" +"<<<<<<< master\n" +"TAKE FOUR LARGE BUNCHES of asparagus, scrape it nicely, cut off one inch\n" +"OF THE TOPS, and lay them in water, chop the stalks and put them on the\n" +"FIRE WITH A PIECE OF BACON, a large onion cut up, and pepper and salt;\n" +"ADD TWO QUARTS OF WATER, boil them till the stalks are quite soft, then\n" +"PULP THEM THROUGH A SIEVE, and strain the water to it, which must be put\n" +"=======\n" +"Take four large bunches of asparagus, scrape it nicely, CUT OFF ONE INCH\n" +"of the tops, and lay them in water, chop the stalks and PUT THEM ON THE\n" +"fire with a piece of bacon, a large onion cut up, and pepper and salt;\n" +"add two quarts of water, boil them till the stalks are quite soft, then\n" +"pulp them through a sieve, and strain the water to it, which must be put\n" +">>>>>>> Conflicting modification 1 to asparagus\n" +"back in the pot; put into it a chicken cut up, with the tops of\n" +"asparagus which had been laid by, boil it until these last articles are\n" +"sufficiently done, thicken with flour, butter and milk, and serve it up.\n"; + + checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; + + 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, signature, NULL)); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + + 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); + cl_assert_equal_file("33f915f9e4dbd9f4b24430e48731a59b45b15500\n", 41, "rebase/.git/rebase-merge/current"); + cl_assert_equal_file("1\n", 2, "rebase/.git/rebase-merge/msgnum"); + + cl_git_pass(git_status_list_new(&status_list, repo, NULL)); + cl_assert_equal_i(1, git_status_list_entrycount(status_list)); + cl_assert(status_entry = git_status_byindex(status_list, 0)); + + cl_assert_equal_s("asparagus.txt", status_entry->head_to_index->new_file.path); + + cl_assert_equal_file(expected_merge, strlen(expected_merge), "rebase/asparagus.txt"); + + 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_rebase_free(rebase); +} + +void test_rebase_merge__next_stops_with_iterover(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *upstream_ref; + git_annotated_commit *branch_head, *upstream_head; + git_rebase_operation *rebase_operation; + 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/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, signature, NULL)); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + + cl_git_fail(error = git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_assert_equal_i(GIT_ITEROVER, error); + + cl_assert_equal_file("5\n", 2, "rebase/.git/rebase-merge/end"); + cl_assert_equal_file("5\n", 2, "rebase/.git/rebase-merge/msgnum"); + + 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); +} + +void test_rebase_merge__commit(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *upstream_ref; + git_annotated_commit *branch_head, *upstream_head; + git_rebase_operation *rebase_operation; + git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; + git_oid commit_id, tree_id, parent_id; + git_signature *author; + git_commit *commit; + git_reflog *reflog; + const git_reflog_entry *reflog_entry; + + 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/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, signature, NULL)); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + + cl_git_pass(git_commit_lookup(&commit, repo, &commit_id)); + + git_oid_fromstr(&parent_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00"); + cl_assert_equal_i(1, git_commit_parentcount(commit)); + cl_assert_equal_oid(&parent_id, git_commit_parent_id(commit, 0)); + + git_oid_fromstr(&tree_id, "4461379789c777d2a6c1f2ee0e9d6c86731b9992"); + cl_assert_equal_oid(&tree_id, git_commit_tree_id(commit)); + + cl_assert_equal_s(NULL, git_commit_message_encoding(commit)); + cl_assert_equal_s("Modification 1 to beef\n", git_commit_message(commit)); + + cl_git_pass(git_signature_new(&author, + "Edward Thomson", "ethomson@edwardthomson.com", 1405621769, 0-(4*60))); + cl_assert(git_signature__equal(author, git_commit_author(commit))); + + cl_assert(git_signature__equal(signature, git_commit_committer(commit))); + + /* Make sure the reflogs are updated appropriately */ + cl_git_pass(git_reflog_read(&reflog, repo, "HEAD")); + cl_assert(reflog_entry = git_reflog_entry_byindex(reflog, 0)); + cl_assert_equal_oid(&parent_id, git_reflog_entry_id_old(reflog_entry)); + cl_assert_equal_oid(&commit_id, git_reflog_entry_id_new(reflog_entry)); + cl_assert_equal_s("rebase: Modification 1 to beef", git_reflog_entry_message(reflog_entry)); + + git_reflog_free(reflog); + git_signature_free(author); + git_commit_free(commit); + 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); +} + +void test_rebase_merge__commit_updates_rewritten(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *upstream_ref; + git_annotated_commit *branch_head, *upstream_head; + git_rebase_operation *rebase_operation; + git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; + git_oid commit_id; + + 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/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, signature, NULL)); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + + cl_assert_equal_file( + "da9c51a23d02d931a486f45ad18cda05cf5d2b94 776e4c48922799f903f03f5f6e51da8b01e4cce0\n" + "8d1f13f93c4995760ac07d129246ac1ff64c0be9 ba1f9b4fd5cf8151f7818be2111cc0869f1eb95a\n", + 164, "rebase/.git/rebase-merge/rewritten"); + + 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); +} + +void test_rebase_merge__commit_drops_already_applied(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *upstream_ref; + git_annotated_commit *branch_head, *upstream_head; + git_rebase_operation *rebase_operation; + 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_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, signature, NULL)); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_fail(error = git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + + cl_assert_equal_i(GIT_EAPPLIED, error); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + + cl_assert_equal_file( + "8d1f13f93c4995760ac07d129246ac1ff64c0be9 2ac4fb7b74c1287f6c792acad759e1ec01e18dae\n", + 82, "rebase/.git/rebase-merge/rewritten"); + + 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); +} + +void test_rebase_merge__finish(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *upstream_ref, *head_ref; + git_annotated_commit *branch_head, *upstream_head; + git_rebase_operation *rebase_operation; + git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; + git_oid commit_id; + git_reflog *reflog; + const git_reflog_entry *reflog_entry; + int error; + + checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; + + cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/gravy")); + cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/veal")); + + 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, signature, NULL)); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + + cl_git_fail(error = git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_assert_equal_i(GIT_ITEROVER, error); + + cl_git_pass(git_rebase_finish(rebase, signature, NULL)); + + cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo)); + + cl_git_pass(git_reference_lookup(&head_ref, repo, "HEAD")); + cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head_ref)); + cl_assert_equal_s("refs/heads/gravy", git_reference_symbolic_target(head_ref)); + + /* Make sure the reflogs are updated appropriately */ + cl_git_pass(git_reflog_read(&reflog, repo, "HEAD")); + cl_assert(reflog_entry = git_reflog_entry_byindex(reflog, 0)); + cl_assert_equal_oid(&commit_id, git_reflog_entry_id_old(reflog_entry)); + cl_assert_equal_oid(&commit_id, git_reflog_entry_id_new(reflog_entry)); + cl_assert_equal_s("rebase finished: returning to refs/heads/gravy", git_reflog_entry_message(reflog_entry)); + git_reflog_free(reflog); + + cl_git_pass(git_reflog_read(&reflog, repo, "refs/heads/gravy")); + cl_assert(reflog_entry = git_reflog_entry_byindex(reflog, 0)); + cl_assert_equal_oid(git_annotated_commit_id(branch_head), git_reflog_entry_id_old(reflog_entry)); + cl_assert_equal_oid(&commit_id, git_reflog_entry_id_new(reflog_entry)); + cl_assert_equal_s("rebase finished: refs/heads/gravy onto f87d14a4a236582a0278a916340a793714256864", git_reflog_entry_message(reflog_entry)); + + git_reflog_free(reflog); + git_annotated_commit_free(branch_head); + git_annotated_commit_free(upstream_head); + git_reference_free(head_ref); + git_reference_free(branch_ref); + git_reference_free(upstream_ref); + git_rebase_free(rebase); +} + +static void test_copy_note( + const git_rebase_options *opts, + bool should_exist) +{ + git_rebase *rebase; + git_reference *branch_ref, *upstream_ref; + git_annotated_commit *branch_head, *upstream_head; + git_commit *branch_commit; + git_rebase_operation *rebase_operation; + git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; + git_oid note_id, commit_id; + git_note *note = NULL; + int error; + + checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; + + cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/gravy")); + cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/veal")); + + 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_reference_peel((git_object **)&branch_commit, + branch_ref, GIT_OBJ_COMMIT)); + + /* Add a note to a commit */ + cl_git_pass(git_note_create(¬e_id, repo, + git_commit_author(branch_commit), git_commit_committer(branch_commit), + "refs/notes/test", git_commit_id(branch_commit), + "This is a commit note.", 0)); + + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, signature, opts)); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + + cl_git_pass(git_rebase_finish(rebase, signature, opts)); + + cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo)); + + if (should_exist) { + cl_git_pass(git_note_read(¬e, repo, "refs/notes/test", &commit_id)); + cl_assert_equal_s("This is a commit note.", git_note_message(note)); + } else { + cl_git_fail(error = + git_note_read(¬e, repo, "refs/notes/test", &commit_id)); + cl_assert_equal_i(GIT_ENOTFOUND, error); + } + + git_note_free(note); + git_commit_free(branch_commit); + 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); +} + +void test_rebase_merge__copy_notes_off_by_default(void) +{ + test_copy_note(NULL, 0); +} + +void test_rebase_merge__copy_notes_specified_in_options(void) +{ + git_rebase_options opts = GIT_REBASE_OPTIONS_INIT; + opts.rewrite_notes_ref = "refs/notes/test"; + + test_copy_note(&opts, 1); +} + +void test_rebase_merge__copy_notes_specified_in_config(void) +{ + git_config *config; + + cl_git_pass(git_repository_config(&config, repo)); + cl_git_pass(git_config_set_string(config, + "notes.rewriteRef", "refs/notes/test")); + + test_copy_note(NULL, 1); +} + +void test_rebase_merge__copy_notes_disabled_in_config(void) +{ + git_config *config; + + cl_git_pass(git_repository_config(&config, repo)); + cl_git_pass(git_config_set_bool(config, "notes.rewrite.rebase", 0)); + cl_git_pass(git_config_set_string(config, + "notes.rewriteRef", "refs/notes/test")); + + test_copy_note(NULL, 0); +} + diff --git a/tests/rebase/setup.c b/tests/rebase/setup.c new file mode 100644 index 000000000..c81ca1245 --- /dev/null +++ b/tests/rebase/setup.c @@ -0,0 +1,342 @@ +#include "clar_libgit2.h" +#include "git2/rebase.h" +#include "posix.h" + +#include + +static git_repository *repo; +static git_index *_index; +static git_signature *signature; + +// Fixture setup and teardown +void test_rebase_setup__initialize(void) +{ + repo = cl_git_sandbox_init("rebase"); + cl_git_pass(git_repository_index(&_index, repo)); + cl_git_pass(git_signature_now(&signature, "Rebaser", "rebaser@rebaser.rb")); +} + +void test_rebase_setup__cleanup(void) +{ + git_signature_free(signature); + git_index_free(_index); + cl_git_sandbox_cleanup(); +} + +/* git checkout beef ; git rebase --merge master + * git checkout beef ; git rebase --merge master */ +void test_rebase_setup__blocked_when_in_progress(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *upstream_ref; + git_annotated_commit *branch_head, *upstream_head; + + cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo)); + + 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, signature, NULL)); + git_rebase_free(rebase); + + cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); + + cl_git_fail(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, signature, NULL)); + + git_annotated_commit_free(branch_head); + git_annotated_commit_free(upstream_head); + git_reference_free(branch_ref); + git_reference_free(upstream_ref); +} + +/* git checkout beef ; git rebase --merge master */ +void test_rebase_setup__merge(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *upstream_ref; + git_annotated_commit *branch_head, *upstream_head; + git_reference *head; + git_commit *head_commit; + git_oid head_id; + + cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo)); + + 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, signature, NULL)); + + cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); + + git_oid_fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00"); + cl_git_pass(git_repository_head(&head, repo)); + cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT)); + cl_assert_equal_oid(&head_id, git_commit_id(head_commit)); + + cl_assert_equal_file("b146bd7608eac53d9bf9e1a6963543588b555c64\n", 41, "rebase/.git/ORIG_HEAD"); + + cl_assert_equal_file("da9c51a23d02d931a486f45ad18cda05cf5d2b94\n", 41, "rebase/.git/rebase-merge/cmt.1"); + cl_assert_equal_file("8d1f13f93c4995760ac07d129246ac1ff64c0be9\n", 41, "rebase/.git/rebase-merge/cmt.2"); + cl_assert_equal_file("3069cc907e6294623e5917ef6de663928c1febfb\n", 41, "rebase/.git/rebase-merge/cmt.3"); + cl_assert_equal_file("588e5d2f04d49707fe4aab865e1deacaf7ef6787\n", 41, "rebase/.git/rebase-merge/cmt.4"); + cl_assert_equal_file("b146bd7608eac53d9bf9e1a6963543588b555c64\n", 41, "rebase/.git/rebase-merge/cmt.5"); + cl_assert_equal_file("5\n", 2, "rebase/.git/rebase-merge/end"); + cl_assert_equal_file("efad0b11c47cb2f0220cbd6f5b0f93bb99064b00\n", 41, "rebase/.git/rebase-merge/onto"); + cl_assert_equal_file("master\n", 7, "rebase/.git/rebase-merge/onto_name"); + cl_assert_equal_file("b146bd7608eac53d9bf9e1a6963543588b555c64\n", 41, "rebase/.git/rebase-merge/orig-head"); + + git_commit_free(head_commit); + git_reference_free(head); + 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); +} + +/* git checkout beef && git rebase --merge --root --onto master */ +void test_rebase_setup__merge_root(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *onto_ref; + git_annotated_commit *branch_head, *onto_head; + git_reference *head; + git_commit *head_commit; + git_oid head_id; + + cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo)); + + cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef")); + cl_git_pass(git_reference_lookup(&onto_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(&onto_head, repo, onto_ref)); + + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, signature, NULL)); + + git_oid_fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00"); + cl_git_pass(git_repository_head(&head, repo)); + cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT)); + cl_assert_equal_oid(&head_id, git_commit_id(head_commit)); + + cl_assert_equal_file("b146bd7608eac53d9bf9e1a6963543588b555c64\n", 41, "rebase/.git/ORIG_HEAD"); + + cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); + + cl_assert_equal_file("da9c51a23d02d931a486f45ad18cda05cf5d2b94\n", 41, "rebase/.git/rebase-merge/cmt.1"); + cl_assert_equal_file("8d1f13f93c4995760ac07d129246ac1ff64c0be9\n", 41, "rebase/.git/rebase-merge/cmt.2"); + cl_assert_equal_file("3069cc907e6294623e5917ef6de663928c1febfb\n", 41, "rebase/.git/rebase-merge/cmt.3"); + cl_assert_equal_file("588e5d2f04d49707fe4aab865e1deacaf7ef6787\n", 41, "rebase/.git/rebase-merge/cmt.4"); + cl_assert_equal_file("b146bd7608eac53d9bf9e1a6963543588b555c64\n", 41, "rebase/.git/rebase-merge/cmt.5"); + cl_assert_equal_file("5\n", 2, "rebase/.git/rebase-merge/end"); + cl_assert_equal_file("efad0b11c47cb2f0220cbd6f5b0f93bb99064b00\n", 41, "rebase/.git/rebase-merge/onto"); + cl_assert_equal_file("master\n", 7, "rebase/.git/rebase-merge/onto_name"); + cl_assert_equal_file("b146bd7608eac53d9bf9e1a6963543588b555c64\n", 41, "rebase/.git/rebase-merge/orig-head"); + + git_commit_free(head_commit); + git_reference_free(head); + git_annotated_commit_free(branch_head); + git_annotated_commit_free(onto_head); + git_reference_free(branch_ref); + git_reference_free(onto_ref); + git_rebase_free(rebase); +} + +/* git checkout gravy && git rebase --merge --onto master veal */ +void test_rebase_setup__merge_onto_and_upstream(void) +{ + git_rebase *rebase; + git_reference *branch1_ref, *branch2_ref, *onto_ref; + git_annotated_commit *branch1_head, *branch2_head, *onto_head; + git_reference *head; + git_commit *head_commit; + git_oid head_id; + + cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo)); + + cl_git_pass(git_reference_lookup(&branch1_ref, repo, "refs/heads/gravy")); + cl_git_pass(git_reference_lookup(&branch2_ref, repo, "refs/heads/veal")); + cl_git_pass(git_reference_lookup(&onto_ref, repo, "refs/heads/master")); + + cl_git_pass(git_annotated_commit_from_ref(&branch1_head, repo, branch1_ref)); + cl_git_pass(git_annotated_commit_from_ref(&branch2_head, repo, branch2_ref)); + cl_git_pass(git_annotated_commit_from_ref(&onto_head, repo, onto_ref)); + + cl_git_pass(git_rebase_init(&rebase, repo, branch1_head, branch2_head, onto_head, signature, NULL)); + + git_oid_fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00"); + cl_git_pass(git_repository_head(&head, repo)); + cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT)); + cl_assert_equal_oid(&head_id, git_commit_id(head_commit)); + + cl_assert_equal_file("d616d97082eb7bb2dc6f180a7cca940993b7a56f\n", 41, "rebase/.git/ORIG_HEAD"); + + cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); + + cl_assert_equal_file("d616d97082eb7bb2dc6f180a7cca940993b7a56f\n", 41, "rebase/.git/rebase-merge/cmt.1"); + cl_assert_equal_file("1\n", 2, "rebase/.git/rebase-merge/end"); + cl_assert_equal_file("efad0b11c47cb2f0220cbd6f5b0f93bb99064b00\n", 41, "rebase/.git/rebase-merge/onto"); + cl_assert_equal_file("master\n", 7, "rebase/.git/rebase-merge/onto_name"); + cl_assert_equal_file("d616d97082eb7bb2dc6f180a7cca940993b7a56f\n", 41, "rebase/.git/rebase-merge/orig-head"); + + git_commit_free(head_commit); + git_reference_free(head); + git_annotated_commit_free(branch1_head); + git_annotated_commit_free(branch2_head); + git_annotated_commit_free(onto_head); + git_reference_free(branch1_ref); + git_reference_free(branch2_ref); + git_reference_free(onto_ref); + git_rebase_free(rebase); +} + +/* Ensure merge commits are dropped in a rebase */ +/* git checkout veal && git rebase --merge master */ +void test_rebase_setup__branch_with_merges(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *upstream_ref; + git_annotated_commit *branch_head, *upstream_head; + git_reference *head; + git_commit *head_commit; + git_oid head_id; + + cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo)); + + cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/veal")); + 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, signature, NULL)); + + cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); + + git_oid_fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00"); + cl_git_pass(git_repository_head(&head, repo)); + cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT)); + cl_assert_equal_oid(&head_id, git_commit_id(head_commit)); + + cl_assert_equal_file("f87d14a4a236582a0278a916340a793714256864\n", 41, "rebase/.git/ORIG_HEAD"); + + cl_assert_equal_file("4bed71df7017283cac61bbf726197ad6a5a18b84\n", 41, "rebase/.git/rebase-merge/cmt.1"); + cl_assert_equal_file("2aa3ce842094e08ebac152b3d6d5b0fff39f9c6e\n", 41, "rebase/.git/rebase-merge/cmt.2"); + cl_assert_equal_file("3e8989b5a16d5258c935d998ef0e6bb139cc4757\n", 41, "rebase/.git/rebase-merge/cmt.3"); + cl_assert_equal_file("4cacc6f6e740a5bc64faa33e04b8ef0733d8a127\n", 41, "rebase/.git/rebase-merge/cmt.4"); + cl_assert_equal_file("f87d14a4a236582a0278a916340a793714256864\n", 41, "rebase/.git/rebase-merge/cmt.5"); + cl_assert_equal_file("5\n", 2, "rebase/.git/rebase-merge/end"); + cl_assert_equal_file("efad0b11c47cb2f0220cbd6f5b0f93bb99064b00\n", 41, "rebase/.git/rebase-merge/onto"); + cl_assert_equal_file("master\n", 7, "rebase/.git/rebase-merge/onto_name"); + cl_assert_equal_file("f87d14a4a236582a0278a916340a793714256864\n", 41, "rebase/.git/rebase-merge/orig-head"); + + git_commit_free(head_commit); + git_reference_free(head); + 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); +} + +/* git checkout barley && git rebase --merge master */ +void test_rebase_setup__orphan_branch(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *upstream_ref; + git_annotated_commit *branch_head, *upstream_head; + git_reference *head; + git_commit *head_commit; + git_oid head_id; + + cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo)); + + cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/barley")); + 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, signature, NULL)); + + cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); + + git_oid_fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00"); + cl_git_pass(git_repository_head(&head, repo)); + cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT)); + cl_assert_equal_oid(&head_id, git_commit_id(head_commit)); + + cl_assert_equal_file("12c084412b952396962eb420716df01022b847cc\n", 41, "rebase/.git/ORIG_HEAD"); + + cl_assert_equal_file("aa4c42aecdfc7cd989bbc3209934ea7cda3f4d88\n", 41, "rebase/.git/rebase-merge/cmt.1"); + cl_assert_equal_file("e4f809f826c1a9fc929874bc0e4644dd2f2a1af4\n", 41, "rebase/.git/rebase-merge/cmt.2"); + cl_assert_equal_file("9539b2cc291d6a6b1b266df8474d31fdd344dd79\n", 41, "rebase/.git/rebase-merge/cmt.3"); + cl_assert_equal_file("013cc32d341bab0e6f039f50f153c18986f16c58\n", 41, "rebase/.git/rebase-merge/cmt.4"); + cl_assert_equal_file("12c084412b952396962eb420716df01022b847cc\n", 41, "rebase/.git/rebase-merge/cmt.5"); + cl_assert_equal_file("5\n", 2, "rebase/.git/rebase-merge/end"); + cl_assert_equal_file("efad0b11c47cb2f0220cbd6f5b0f93bb99064b00\n", 41, "rebase/.git/rebase-merge/onto"); + cl_assert_equal_file("master\n", 7, "rebase/.git/rebase-merge/onto_name"); + cl_assert_equal_file("12c084412b952396962eb420716df01022b847cc\n", 41, "rebase/.git/rebase-merge/orig-head"); + + git_commit_free(head_commit); + git_reference_free(head); + 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); +} + +static int rebase_is_blocked(void) +{ + git_rebase *rebase = NULL; + int error; + + git_reference *branch_ref, *upstream_ref; + git_annotated_commit *branch_head, *upstream_head; + + cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo)); + + 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)); + + error = git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, signature, NULL); + + 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); + + return error; +} + +void test_rebase_setup__blocked_for_staged_change(void) +{ + cl_git_rewritefile("rebase/newfile.txt", "Stage an add"); + git_index_add_bypath(_index, "newfile.txt"); + cl_git_fail(rebase_is_blocked()); +} + +void test_rebase_setup__blocked_for_unstaged_change(void) +{ + cl_git_rewritefile("rebase/asparagus.txt", "Unstaged change"); + cl_git_fail(rebase_is_blocked()); +} + +void test_rebase_setup__not_blocked_for_untracked_add(void) +{ + cl_git_rewritefile("rebase/newfile.txt", "Untracked file"); + cl_git_pass(rebase_is_blocked()); +} + diff --git a/tests/resources/rebase/.gitted/HEAD b/tests/resources/rebase/.gitted/HEAD new file mode 100644 index 000000000..cb089cd89 Binary files /dev/null and b/tests/resources/rebase/.gitted/HEAD differ diff --git a/tests/resources/rebase/.gitted/config b/tests/resources/rebase/.gitted/config new file mode 100644 index 000000000..17e58b1c2 Binary files /dev/null and b/tests/resources/rebase/.gitted/config differ diff --git a/tests/resources/rebase/.gitted/index b/tests/resources/rebase/.gitted/index new file mode 100644 index 000000000..0f53a2167 Binary files /dev/null and b/tests/resources/rebase/.gitted/index differ diff --git a/tests/resources/rebase/.gitted/info/exclude b/tests/resources/rebase/.gitted/info/exclude new file mode 100644 index 000000000..a5196d1be Binary files /dev/null and b/tests/resources/rebase/.gitted/info/exclude differ diff --git a/tests/resources/rebase/.gitted/logs/HEAD b/tests/resources/rebase/.gitted/logs/HEAD new file mode 100644 index 000000000..62d3b164e Binary files /dev/null and b/tests/resources/rebase/.gitted/logs/HEAD differ diff --git a/tests/resources/rebase/.gitted/objects/00/66204dd469ee930e551fbcf123f98e211c99ce b/tests/resources/rebase/.gitted/objects/00/66204dd469ee930e551fbcf123f98e211c99ce new file mode 100644 index 000000000..e6f72ce24 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/00/66204dd469ee930e551fbcf123f98e211c99ce differ diff --git a/tests/resources/rebase/.gitted/objects/00/f1b9a0948a7d5d14405eba6030efcdfbb8ff4a b/tests/resources/rebase/.gitted/objects/00/f1b9a0948a7d5d14405eba6030efcdfbb8ff4a new file mode 100644 index 000000000..a23f526b5 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/00/f1b9a0948a7d5d14405eba6030efcdfbb8ff4a differ diff --git a/tests/resources/rebase/.gitted/objects/01/3cc32d341bab0e6f039f50f153c18986f16c58 b/tests/resources/rebase/.gitted/objects/01/3cc32d341bab0e6f039f50f153c18986f16c58 new file mode 100644 index 000000000..2e32bd339 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/01/3cc32d341bab0e6f039f50f153c18986f16c58 differ diff --git a/tests/resources/rebase/.gitted/objects/01/a17f7d154ab5bf9f8bfede3d82dd00ddf7e7dc b/tests/resources/rebase/.gitted/objects/01/a17f7d154ab5bf9f8bfede3d82dd00ddf7e7dc new file mode 100644 index 000000000..c21329f33 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/01/a17f7d154ab5bf9f8bfede3d82dd00ddf7e7dc differ diff --git a/tests/resources/rebase/.gitted/objects/02/2d3b6bbd0bfbdf147319476fb8bf405691cb0d b/tests/resources/rebase/.gitted/objects/02/2d3b6bbd0bfbdf147319476fb8bf405691cb0d new file mode 100644 index 000000000..b1f7468ac Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/02/2d3b6bbd0bfbdf147319476fb8bf405691cb0d differ diff --git a/tests/resources/rebase/.gitted/objects/05/3808a709cf91385985369159b296cf61a177ac b/tests/resources/rebase/.gitted/objects/05/3808a709cf91385985369159b296cf61a177ac new file mode 100644 index 000000000..c38c5b255 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/05/3808a709cf91385985369159b296cf61a177ac differ diff --git a/tests/resources/rebase/.gitted/objects/0e/f2e2b2a2b8d6e1f8dff5e621e0eca21b693d0c b/tests/resources/rebase/.gitted/objects/0e/f2e2b2a2b8d6e1f8dff5e621e0eca21b693d0c new file mode 100644 index 000000000..d8ef47c62 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/0e/f2e2b2a2b8d6e1f8dff5e621e0eca21b693d0c differ diff --git a/tests/resources/rebase/.gitted/objects/0f/5f6d3353be1a9966fa5767b7d604b051798224 b/tests/resources/rebase/.gitted/objects/0f/5f6d3353be1a9966fa5767b7d604b051798224 new file mode 100644 index 000000000..739aca383 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/0f/5f6d3353be1a9966fa5767b7d604b051798224 differ diff --git a/tests/resources/rebase/.gitted/objects/11/fac10ca1b9318ce361a0be0c3d889d777e299c b/tests/resources/rebase/.gitted/objects/11/fac10ca1b9318ce361a0be0c3d889d777e299c new file mode 100644 index 000000000..5af5474b5 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/11/fac10ca1b9318ce361a0be0c3d889d777e299c differ diff --git a/tests/resources/rebase/.gitted/objects/12/c084412b952396962eb420716df01022b847cc b/tests/resources/rebase/.gitted/objects/12/c084412b952396962eb420716df01022b847cc new file mode 100644 index 000000000..5244e469d Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/12/c084412b952396962eb420716df01022b847cc differ diff --git a/tests/resources/rebase/.gitted/objects/12/f28ed978639d331269d9dc2b74e87db58e1057 b/tests/resources/rebase/.gitted/objects/12/f28ed978639d331269d9dc2b74e87db58e1057 new file mode 100644 index 000000000..b0dbc3e07 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/12/f28ed978639d331269d9dc2b74e87db58e1057 differ diff --git a/tests/resources/rebase/.gitted/objects/19/14d57ddf6c5c997664521cc94f190df46dc1c2 b/tests/resources/rebase/.gitted/objects/19/14d57ddf6c5c997664521cc94f190df46dc1c2 new file mode 100644 index 000000000..921f2cd88 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/19/14d57ddf6c5c997664521cc94f190df46dc1c2 differ diff --git a/tests/resources/rebase/.gitted/objects/1b/1d19799fcc89fa3cb821581fcf7f2e8fd2cc4d b/tests/resources/rebase/.gitted/objects/1b/1d19799fcc89fa3cb821581fcf7f2e8fd2cc4d new file mode 100644 index 000000000..3d206b0cc Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/1b/1d19799fcc89fa3cb821581fcf7f2e8fd2cc4d differ diff --git a/tests/resources/rebase/.gitted/objects/1f/2214c1b13b134d5508f41f6a3b77cc6a8f5182 b/tests/resources/rebase/.gitted/objects/1f/2214c1b13b134d5508f41f6a3b77cc6a8f5182 new file mode 100644 index 000000000..84b875c50 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/1f/2214c1b13b134d5508f41f6a3b77cc6a8f5182 differ diff --git a/tests/resources/rebase/.gitted/objects/20/db906c85e78c6dde82eb2ec6d3231c4b96fce8 b/tests/resources/rebase/.gitted/objects/20/db906c85e78c6dde82eb2ec6d3231c4b96fce8 new file mode 100644 index 000000000..2a908da61 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/20/db906c85e78c6dde82eb2ec6d3231c4b96fce8 differ diff --git a/tests/resources/rebase/.gitted/objects/22/adb22bef75a0371e85ff6d82e5e60e4b425501 b/tests/resources/rebase/.gitted/objects/22/adb22bef75a0371e85ff6d82e5e60e4b425501 new file mode 100644 index 000000000..7f17ef059 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/22/adb22bef75a0371e85ff6d82e5e60e4b425501 differ diff --git a/tests/resources/rebase/.gitted/objects/2a/a3ce842094e08ebac152b3d6d5b0fff39f9c6e b/tests/resources/rebase/.gitted/objects/2a/a3ce842094e08ebac152b3d6d5b0fff39f9c6e new file mode 100644 index 000000000..38eca43dc Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/2a/a3ce842094e08ebac152b3d6d5b0fff39f9c6e differ diff --git a/tests/resources/rebase/.gitted/objects/2b/4ebffd3111546d278bb5df62e5630930b605fb b/tests/resources/rebase/.gitted/objects/2b/4ebffd3111546d278bb5df62e5630930b605fb new file mode 100644 index 000000000..5bdfc1e29 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/2b/4ebffd3111546d278bb5df62e5630930b605fb differ diff --git a/tests/resources/rebase/.gitted/objects/30/69cc907e6294623e5917ef6de663928c1febfb b/tests/resources/rebase/.gitted/objects/30/69cc907e6294623e5917ef6de663928c1febfb new file mode 100644 index 000000000..edd86f721 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/30/69cc907e6294623e5917ef6de663928c1febfb differ diff --git a/tests/resources/rebase/.gitted/objects/32/52a0692ace4c4c709f22011227d9dc4845f289 b/tests/resources/rebase/.gitted/objects/32/52a0692ace4c4c709f22011227d9dc4845f289 new file mode 100644 index 000000000..2b2434f87 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/32/52a0692ace4c4c709f22011227d9dc4845f289 differ diff --git a/tests/resources/rebase/.gitted/objects/33/f915f9e4dbd9f4b24430e48731a59b45b15500 b/tests/resources/rebase/.gitted/objects/33/f915f9e4dbd9f4b24430e48731a59b45b15500 new file mode 100644 index 000000000..c33f179bf Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/33/f915f9e4dbd9f4b24430e48731a59b45b15500 differ diff --git a/tests/resources/rebase/.gitted/objects/34/86a9d4cdf0b7b4a702c199eed541dc3af13a03 b/tests/resources/rebase/.gitted/objects/34/86a9d4cdf0b7b4a702c199eed541dc3af13a03 new file mode 100644 index 000000000..fdbe16d10 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/34/86a9d4cdf0b7b4a702c199eed541dc3af13a03 differ diff --git a/tests/resources/rebase/.gitted/objects/3c/33b080bf75724c8899d8e703614cb59bfbd047 b/tests/resources/rebase/.gitted/objects/3c/33b080bf75724c8899d8e703614cb59bfbd047 new file mode 100644 index 000000000..8716898f8 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/3c/33b080bf75724c8899d8e703614cb59bfbd047 differ diff --git a/tests/resources/rebase/.gitted/objects/3d/a85aca38a95b44d77ef55a8deb445e49ba19b4 b/tests/resources/rebase/.gitted/objects/3d/a85aca38a95b44d77ef55a8deb445e49ba19b4 new file mode 100644 index 000000000..fa6d9468d Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/3d/a85aca38a95b44d77ef55a8deb445e49ba19b4 differ diff --git a/tests/resources/rebase/.gitted/objects/3e/8989b5a16d5258c935d998ef0e6bb139cc4757 b/tests/resources/rebase/.gitted/objects/3e/8989b5a16d5258c935d998ef0e6bb139cc4757 new file mode 100644 index 000000000..1bbf138ef Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/3e/8989b5a16d5258c935d998ef0e6bb139cc4757 differ diff --git a/tests/resources/rebase/.gitted/objects/3f/05a038dd89f51ba2b3d7b14ba1f8c00f0e31ac b/tests/resources/rebase/.gitted/objects/3f/05a038dd89f51ba2b3d7b14ba1f8c00f0e31ac new file mode 100644 index 000000000..26bd353f7 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/3f/05a038dd89f51ba2b3d7b14ba1f8c00f0e31ac differ diff --git a/tests/resources/rebase/.gitted/objects/3f/d8d53cf02de539b9a25a5941030451f76a152f b/tests/resources/rebase/.gitted/objects/3f/d8d53cf02de539b9a25a5941030451f76a152f new file mode 100644 index 000000000..91c4d957e Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/3f/d8d53cf02de539b9a25a5941030451f76a152f differ diff --git a/tests/resources/rebase/.gitted/objects/40/0d89e8ee6cd91b67b1f45de1ca190e1c580c6f b/tests/resources/rebase/.gitted/objects/40/0d89e8ee6cd91b67b1f45de1ca190e1c580c6f new file mode 100644 index 000000000..f67475370 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/40/0d89e8ee6cd91b67b1f45de1ca190e1c580c6f differ diff --git a/tests/resources/rebase/.gitted/objects/41/4dfc71ead79c07acd4ea47fecf91f289afc4b9 b/tests/resources/rebase/.gitted/objects/41/4dfc71ead79c07acd4ea47fecf91f289afc4b9 new file mode 100644 index 000000000..546815ea8 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/41/4dfc71ead79c07acd4ea47fecf91f289afc4b9 differ diff --git a/tests/resources/rebase/.gitted/objects/41/c5a0a761bb4a7670924c1af0800b30fe9a21be b/tests/resources/rebase/.gitted/objects/41/c5a0a761bb4a7670924c1af0800b30fe9a21be new file mode 100644 index 000000000..ecb399264 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/41/c5a0a761bb4a7670924c1af0800b30fe9a21be differ diff --git a/tests/resources/rebase/.gitted/objects/42/cdad903aef3e7b614675e6584a8be417941911 b/tests/resources/rebase/.gitted/objects/42/cdad903aef3e7b614675e6584a8be417941911 new file mode 100644 index 000000000..99b5e6d2c Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/42/cdad903aef3e7b614675e6584a8be417941911 differ diff --git a/tests/resources/rebase/.gitted/objects/44/c801fe026abbc141b52a4dec5df15fa98249c6 b/tests/resources/rebase/.gitted/objects/44/c801fe026abbc141b52a4dec5df15fa98249c6 new file mode 100644 index 000000000..eaf24ae46 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/44/c801fe026abbc141b52a4dec5df15fa98249c6 differ diff --git a/tests/resources/rebase/.gitted/objects/4b/21eb6eeeec7f8fc89a1d334faff9bd5f5f8c34 b/tests/resources/rebase/.gitted/objects/4b/21eb6eeeec7f8fc89a1d334faff9bd5f5f8c34 new file mode 100644 index 000000000..0c9f4b944 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/4b/21eb6eeeec7f8fc89a1d334faff9bd5f5f8c34 differ diff --git a/tests/resources/rebase/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a b/tests/resources/rebase/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a new file mode 100644 index 000000000..016398531 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a differ diff --git a/tests/resources/rebase/.gitted/objects/4b/ed71df7017283cac61bbf726197ad6a5a18b84 b/tests/resources/rebase/.gitted/objects/4b/ed71df7017283cac61bbf726197ad6a5a18b84 new file mode 100644 index 000000000..f206618f1 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/4b/ed71df7017283cac61bbf726197ad6a5a18b84 differ diff --git a/tests/resources/rebase/.gitted/objects/4c/acc6f6e740a5bc64faa33e04b8ef0733d8a127 b/tests/resources/rebase/.gitted/objects/4c/acc6f6e740a5bc64faa33e04b8ef0733d8a127 new file mode 100644 index 000000000..36a6b31fa Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/4c/acc6f6e740a5bc64faa33e04b8ef0733d8a127 differ diff --git a/tests/resources/rebase/.gitted/objects/4f/b698bde45d7d2833e3f2aacfbfe8a7e7f60a65 b/tests/resources/rebase/.gitted/objects/4f/b698bde45d7d2833e3f2aacfbfe8a7e7f60a65 new file mode 100644 index 000000000..8bb69d099 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/4f/b698bde45d7d2833e3f2aacfbfe8a7e7f60a65 differ diff --git a/tests/resources/rebase/.gitted/objects/50/8be4ff49d38465ad3de58f66d38f70e59f881f b/tests/resources/rebase/.gitted/objects/50/8be4ff49d38465ad3de58f66d38f70e59f881f new file mode 100644 index 000000000..7ce4452b2 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/50/8be4ff49d38465ad3de58f66d38f70e59f881f differ diff --git a/tests/resources/rebase/.gitted/objects/53/f75e45a463033854e52fa8d39dc858e45537d0 b/tests/resources/rebase/.gitted/objects/53/f75e45a463033854e52fa8d39dc858e45537d0 new file mode 100644 index 000000000..f25ef1f73 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/53/f75e45a463033854e52fa8d39dc858e45537d0 differ diff --git a/tests/resources/rebase/.gitted/objects/58/8e5d2f04d49707fe4aab865e1deacaf7ef6787 b/tests/resources/rebase/.gitted/objects/58/8e5d2f04d49707fe4aab865e1deacaf7ef6787 new file mode 100644 index 000000000..766adc10c Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/58/8e5d2f04d49707fe4aab865e1deacaf7ef6787 differ diff --git a/tests/resources/rebase/.gitted/objects/5b/1e8bccf7787e942aecf61912f94a2c274f85a5 b/tests/resources/rebase/.gitted/objects/5b/1e8bccf7787e942aecf61912f94a2c274f85a5 new file mode 100644 index 000000000..d4776d883 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/5b/1e8bccf7787e942aecf61912f94a2c274f85a5 differ diff --git a/tests/resources/rebase/.gitted/objects/60/29cb003b59f710f9a8ebd9da9ece2d73070b69 b/tests/resources/rebase/.gitted/objects/60/29cb003b59f710f9a8ebd9da9ece2d73070b69 new file mode 100644 index 000000000..a48e023be Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/60/29cb003b59f710f9a8ebd9da9ece2d73070b69 differ diff --git a/tests/resources/rebase/.gitted/objects/61/139b9b40a3e489f4abbc6af14e10ae14006e47 b/tests/resources/rebase/.gitted/objects/61/139b9b40a3e489f4abbc6af14e10ae14006e47 new file mode 100644 index 000000000..b096a964c Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/61/139b9b40a3e489f4abbc6af14e10ae14006e47 differ diff --git a/tests/resources/rebase/.gitted/objects/61/30e5fcbdce2aa8b3cfd84706c58a892e7d8dd0 b/tests/resources/rebase/.gitted/objects/61/30e5fcbdce2aa8b3cfd84706c58a892e7d8dd0 new file mode 100644 index 000000000..116da7ca9 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/61/30e5fcbdce2aa8b3cfd84706c58a892e7d8dd0 differ diff --git a/tests/resources/rebase/.gitted/objects/63/c18bf188b8a1ab0bad85161dc3fb43c48ed0db b/tests/resources/rebase/.gitted/objects/63/c18bf188b8a1ab0bad85161dc3fb43c48ed0db new file mode 100644 index 000000000..297c43225 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/63/c18bf188b8a1ab0bad85161dc3fb43c48ed0db differ diff --git a/tests/resources/rebase/.gitted/objects/67/ed7afb256807556f9b74fa4f7c9284aaec1120 b/tests/resources/rebase/.gitted/objects/67/ed7afb256807556f9b74fa4f7c9284aaec1120 new file mode 100644 index 000000000..82da20626 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/67/ed7afb256807556f9b74fa4f7c9284aaec1120 differ diff --git a/tests/resources/rebase/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598 b/tests/resources/rebase/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598 new file mode 100644 index 000000000..6aaf79fcb Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598 differ diff --git a/tests/resources/rebase/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096 b/tests/resources/rebase/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096 new file mode 100644 index 000000000..ed1de3ada Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096 differ diff --git a/tests/resources/rebase/.gitted/objects/6c/8e16469b6ca09a07e00f0e07a5143c31dcfb64 b/tests/resources/rebase/.gitted/objects/6c/8e16469b6ca09a07e00f0e07a5143c31dcfb64 new file mode 100644 index 000000000..2b8d569ea Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/6c/8e16469b6ca09a07e00f0e07a5143c31dcfb64 differ diff --git a/tests/resources/rebase/.gitted/objects/6d/77ce8fa2cd93c6489236e33e45e35203ca748c b/tests/resources/rebase/.gitted/objects/6d/77ce8fa2cd93c6489236e33e45e35203ca748c new file mode 100644 index 000000000..5c3f68625 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/6d/77ce8fa2cd93c6489236e33e45e35203ca748c differ diff --git a/tests/resources/rebase/.gitted/objects/6d/fb87d20f3dbca02da4a39890114fd9ba6a51e7 b/tests/resources/rebase/.gitted/objects/6d/fb87d20f3dbca02da4a39890114fd9ba6a51e7 new file mode 100644 index 000000000..039c669aa Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/6d/fb87d20f3dbca02da4a39890114fd9ba6a51e7 differ diff --git a/tests/resources/rebase/.gitted/objects/73/f346c88d965227a03c0af8d555870b8c5021d4 b/tests/resources/rebase/.gitted/objects/73/f346c88d965227a03c0af8d555870b8c5021d4 new file mode 100644 index 000000000..215df59d8 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/73/f346c88d965227a03c0af8d555870b8c5021d4 differ diff --git a/tests/resources/rebase/.gitted/objects/74/0a804e8963759c98e5b8cb912e15ae74a7a4a6 b/tests/resources/rebase/.gitted/objects/74/0a804e8963759c98e5b8cb912e15ae74a7a4a6 new file mode 100644 index 000000000..b81718279 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/74/0a804e8963759c98e5b8cb912e15ae74a7a4a6 differ diff --git a/tests/resources/rebase/.gitted/objects/78/c320b06544e23d786a9ec84ee93861f2933094 b/tests/resources/rebase/.gitted/objects/78/c320b06544e23d786a9ec84ee93861f2933094 new file mode 100644 index 000000000..afa39fb97 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/78/c320b06544e23d786a9ec84ee93861f2933094 differ diff --git a/tests/resources/rebase/.gitted/objects/79/e28694aae0d3064b06f96a5207b943a2357f07 b/tests/resources/rebase/.gitted/objects/79/e28694aae0d3064b06f96a5207b943a2357f07 new file mode 100644 index 000000000..17ff306f1 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/79/e28694aae0d3064b06f96a5207b943a2357f07 differ diff --git a/tests/resources/rebase/.gitted/objects/7a/05900f340af0252aaa4e34941f040c5d2fe7f7 b/tests/resources/rebase/.gitted/objects/7a/05900f340af0252aaa4e34941f040c5d2fe7f7 new file mode 100644 index 000000000..43201f89b Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/7a/05900f340af0252aaa4e34941f040c5d2fe7f7 differ diff --git a/tests/resources/rebase/.gitted/objects/7a/677f6201c8f9d46bdfe1f4b08cb504e360a34e b/tests/resources/rebase/.gitted/objects/7a/677f6201c8f9d46bdfe1f4b08cb504e360a34e new file mode 100644 index 000000000..dc2fd5a36 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/7a/677f6201c8f9d46bdfe1f4b08cb504e360a34e differ diff --git a/tests/resources/rebase/.gitted/objects/7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f b/tests/resources/rebase/.gitted/objects/7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f new file mode 100644 index 000000000..fe8b15777 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f differ diff --git a/tests/resources/rebase/.gitted/objects/7f/37fe2d7320360f8a9118b1ed8fba6f38481679 b/tests/resources/rebase/.gitted/objects/7f/37fe2d7320360f8a9118b1ed8fba6f38481679 new file mode 100644 index 000000000..400df288f Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/7f/37fe2d7320360f8a9118b1ed8fba6f38481679 differ diff --git a/tests/resources/rebase/.gitted/objects/80/32d630f37266bace093e353f7b97d7f8b20950 b/tests/resources/rebase/.gitted/objects/80/32d630f37266bace093e353f7b97d7f8b20950 new file mode 100644 index 000000000..07050dfd4 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/80/32d630f37266bace093e353f7b97d7f8b20950 differ diff --git a/tests/resources/rebase/.gitted/objects/80/dce0e74f0534811db734a68c23b49f98584d7a b/tests/resources/rebase/.gitted/objects/80/dce0e74f0534811db734a68c23b49f98584d7a new file mode 100644 index 000000000..1b98b0a6f Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/80/dce0e74f0534811db734a68c23b49f98584d7a differ diff --git a/tests/resources/rebase/.gitted/objects/83/53b9f9deff7c707f280e0f656c80772cca7cd9 b/tests/resources/rebase/.gitted/objects/83/53b9f9deff7c707f280e0f656c80772cca7cd9 new file mode 100644 index 000000000..a4a7e3aa3 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/83/53b9f9deff7c707f280e0f656c80772cca7cd9 differ diff --git a/tests/resources/rebase/.gitted/objects/85/258e426a341cc1aa035ac7f6d18f84fed2ab38 b/tests/resources/rebase/.gitted/objects/85/258e426a341cc1aa035ac7f6d18f84fed2ab38 new file mode 100644 index 000000000..af1106d6a Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/85/258e426a341cc1aa035ac7f6d18f84fed2ab38 differ diff --git a/tests/resources/rebase/.gitted/objects/85/f34ce9ca9e0f33d4146afec9cbe5a26757500a b/tests/resources/rebase/.gitted/objects/85/f34ce9ca9e0f33d4146afec9cbe5a26757500a new file mode 100644 index 000000000..03e75165a Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/85/f34ce9ca9e0f33d4146afec9cbe5a26757500a differ diff --git a/tests/resources/rebase/.gitted/objects/86/a5415741ed3754ccb0cac1fc19fd82587840a4 b/tests/resources/rebase/.gitted/objects/86/a5415741ed3754ccb0cac1fc19fd82587840a4 new file mode 100644 index 000000000..fe00a22e3 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/86/a5415741ed3754ccb0cac1fc19fd82587840a4 differ diff --git a/tests/resources/rebase/.gitted/objects/8d/1f13f93c4995760ac07d129246ac1ff64c0be9 b/tests/resources/rebase/.gitted/objects/8d/1f13f93c4995760ac07d129246ac1ff64c0be9 new file mode 100644 index 000000000..a66cfccb2 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/8d/1f13f93c4995760ac07d129246ac1ff64c0be9 differ diff --git a/tests/resources/rebase/.gitted/objects/8d/95ea62e621f1d38d230d9e7d206e41096d76af b/tests/resources/rebase/.gitted/objects/8d/95ea62e621f1d38d230d9e7d206e41096d76af new file mode 100644 index 000000000..464de7c1c Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/8d/95ea62e621f1d38d230d9e7d206e41096d76af differ diff --git a/tests/resources/rebase/.gitted/objects/8f/4de6c781b9ff9cedfd7f9f9f224e744f97b259 b/tests/resources/rebase/.gitted/objects/8f/4de6c781b9ff9cedfd7f9f9f224e744f97b259 new file mode 100644 index 000000000..faa938958 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/8f/4de6c781b9ff9cedfd7f9f9f224e744f97b259 differ diff --git a/tests/resources/rebase/.gitted/objects/92/54a37fde7e97f9a28dee2967fdb2c5d1ed94e9 b/tests/resources/rebase/.gitted/objects/92/54a37fde7e97f9a28dee2967fdb2c5d1ed94e9 new file mode 100644 index 000000000..10d6c134f Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/92/54a37fde7e97f9a28dee2967fdb2c5d1ed94e9 differ diff --git a/tests/resources/rebase/.gitted/objects/95/39b2cc291d6a6b1b266df8474d31fdd344dd79 b/tests/resources/rebase/.gitted/objects/95/39b2cc291d6a6b1b266df8474d31fdd344dd79 new file mode 100644 index 000000000..964943473 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/95/39b2cc291d6a6b1b266df8474d31fdd344dd79 differ diff --git a/tests/resources/rebase/.gitted/objects/9a/8535dfcaf7554c728d874f047c5461fb2c71d1 b/tests/resources/rebase/.gitted/objects/9a/8535dfcaf7554c728d874f047c5461fb2c71d1 new file mode 100644 index 000000000..d997426b2 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/9a/8535dfcaf7554c728d874f047c5461fb2c71d1 differ diff --git a/tests/resources/rebase/.gitted/objects/9c/d483e7da23819d7f71d24e9843812337886753 b/tests/resources/rebase/.gitted/objects/9c/d483e7da23819d7f71d24e9843812337886753 new file mode 100644 index 000000000..d16845506 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/9c/d483e7da23819d7f71d24e9843812337886753 differ diff --git a/tests/resources/rebase/.gitted/objects/a0/1a6ee390f65d834375e072952deaee0c5e92f7 b/tests/resources/rebase/.gitted/objects/a0/1a6ee390f65d834375e072952deaee0c5e92f7 new file mode 100644 index 000000000..eb98c9da5 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/a0/1a6ee390f65d834375e072952deaee0c5e92f7 differ diff --git a/tests/resources/rebase/.gitted/objects/a0/fa65f96c1e3bdc7287e334229279dcc1248fa4 b/tests/resources/rebase/.gitted/objects/a0/fa65f96c1e3bdc7287e334229279dcc1248fa4 new file mode 100644 index 000000000..fd43545ce Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/a0/fa65f96c1e3bdc7287e334229279dcc1248fa4 differ diff --git a/tests/resources/rebase/.gitted/objects/a1/25b9b655932711abceaf8962948e6b601d67b6 b/tests/resources/rebase/.gitted/objects/a1/25b9b655932711abceaf8962948e6b601d67b6 new file mode 100644 index 000000000..50bcee109 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/a1/25b9b655932711abceaf8962948e6b601d67b6 differ diff --git a/tests/resources/rebase/.gitted/objects/a7/00acc970eccccc73be53cd269462176544e6d1 b/tests/resources/rebase/.gitted/objects/a7/00acc970eccccc73be53cd269462176544e6d1 new file mode 100644 index 000000000..e5c62dba7 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/a7/00acc970eccccc73be53cd269462176544e6d1 differ diff --git a/tests/resources/rebase/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20 b/tests/resources/rebase/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20 new file mode 100644 index 000000000..54f9b6617 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20 differ diff --git a/tests/resources/rebase/.gitted/objects/aa/4c42aecdfc7cd989bbc3209934ea7cda3f4d88 b/tests/resources/rebase/.gitted/objects/aa/4c42aecdfc7cd989bbc3209934ea7cda3f4d88 new file mode 100644 index 000000000..628c2d3a1 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/aa/4c42aecdfc7cd989bbc3209934ea7cda3f4d88 differ diff --git a/tests/resources/rebase/.gitted/objects/ab/25a53ef5622d443ecb0492b7516725f0deac8f b/tests/resources/rebase/.gitted/objects/ab/25a53ef5622d443ecb0492b7516725f0deac8f new file mode 100644 index 000000000..83ef51e26 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/ab/25a53ef5622d443ecb0492b7516725f0deac8f differ diff --git a/tests/resources/rebase/.gitted/objects/ad/c97cfb874cdfb9d5ab17b54f3771dea6e02ccf b/tests/resources/rebase/.gitted/objects/ad/c97cfb874cdfb9d5ab17b54f3771dea6e02ccf new file mode 100644 index 000000000..cc7ccd086 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/ad/c97cfb874cdfb9d5ab17b54f3771dea6e02ccf differ diff --git a/tests/resources/rebase/.gitted/objects/ae/87cae12879a3c37d7cc994afc6395bcb0eaf99 b/tests/resources/rebase/.gitted/objects/ae/87cae12879a3c37d7cc994afc6395bcb0eaf99 new file mode 100644 index 000000000..5c8469eb9 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/ae/87cae12879a3c37d7cc994afc6395bcb0eaf99 differ diff --git a/tests/resources/rebase/.gitted/objects/b1/46bd7608eac53d9bf9e1a6963543588b555c64 b/tests/resources/rebase/.gitted/objects/b1/46bd7608eac53d9bf9e1a6963543588b555c64 new file mode 100644 index 000000000..3e4b975a9 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/b1/46bd7608eac53d9bf9e1a6963543588b555c64 differ diff --git a/tests/resources/rebase/.gitted/objects/b1/b94ec02f8ed87d0efa4c65fb38d5d6da7e8b32 b/tests/resources/rebase/.gitted/objects/b1/b94ec02f8ed87d0efa4c65fb38d5d6da7e8b32 new file mode 100644 index 000000000..d15c02246 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/b1/b94ec02f8ed87d0efa4c65fb38d5d6da7e8b32 differ diff --git a/tests/resources/rebase/.gitted/objects/b6/72b141d48c369fee6c4deeb32a904387594365 b/tests/resources/rebase/.gitted/objects/b6/72b141d48c369fee6c4deeb32a904387594365 new file mode 100644 index 000000000..d8cdb71ae Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/b6/72b141d48c369fee6c4deeb32a904387594365 differ diff --git a/tests/resources/rebase/.gitted/objects/b7/c536a5883c8adaeb34d5e198c5a3dbbdc608b5 b/tests/resources/rebase/.gitted/objects/b7/c536a5883c8adaeb34d5e198c5a3dbbdc608b5 new file mode 100644 index 000000000..b59498472 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/b7/c536a5883c8adaeb34d5e198c5a3dbbdc608b5 differ diff --git a/tests/resources/rebase/.gitted/objects/b9/f72b9158fa8c49fb4e4c10b26817ed867be803 b/tests/resources/rebase/.gitted/objects/b9/f72b9158fa8c49fb4e4c10b26817ed867be803 new file mode 100644 index 000000000..970166755 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/b9/f72b9158fa8c49fb4e4c10b26817ed867be803 differ diff --git a/tests/resources/rebase/.gitted/objects/bc/cc8eabb5cfe2ec09959c7f4155aa73429fd604 b/tests/resources/rebase/.gitted/objects/bc/cc8eabb5cfe2ec09959c7f4155aa73429fd604 new file mode 100644 index 000000000..de778eb11 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/bc/cc8eabb5cfe2ec09959c7f4155aa73429fd604 differ diff --git a/tests/resources/rebase/.gitted/objects/c4/e6cca3ec6ae0148ed231f97257df8c311e015f b/tests/resources/rebase/.gitted/objects/c4/e6cca3ec6ae0148ed231f97257df8c311e015f new file mode 100644 index 000000000..2bbf28f57 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/c4/e6cca3ec6ae0148ed231f97257df8c311e015f differ diff --git a/tests/resources/rebase/.gitted/objects/c5/17380440ed78865ffe3fa130b9738615c76618 b/tests/resources/rebase/.gitted/objects/c5/17380440ed78865ffe3fa130b9738615c76618 new file mode 100644 index 000000000..b9a52a310 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/c5/17380440ed78865ffe3fa130b9738615c76618 differ diff --git a/tests/resources/rebase/.gitted/objects/cb/20a10406172afd6ca3138ce36ecaf8b1269e8e b/tests/resources/rebase/.gitted/objects/cb/20a10406172afd6ca3138ce36ecaf8b1269e8e new file mode 100644 index 000000000..acd6bdc56 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/cb/20a10406172afd6ca3138ce36ecaf8b1269e8e differ diff --git a/tests/resources/rebase/.gitted/objects/d4/82e77aecb8e07da43e4cad6e0dcb59219e12af b/tests/resources/rebase/.gitted/objects/d4/82e77aecb8e07da43e4cad6e0dcb59219e12af new file mode 100644 index 000000000..af3bd174a Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/d4/82e77aecb8e07da43e4cad6e0dcb59219e12af differ diff --git a/tests/resources/rebase/.gitted/objects/d6/16d97082eb7bb2dc6f180a7cca940993b7a56f b/tests/resources/rebase/.gitted/objects/d6/16d97082eb7bb2dc6f180a7cca940993b7a56f new file mode 100644 index 000000000..fa2e8d9ef Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/d6/16d97082eb7bb2dc6f180a7cca940993b7a56f differ diff --git a/tests/resources/rebase/.gitted/objects/d6/b9ec0dfb972a6815ace42545cde5f2631cd776 b/tests/resources/rebase/.gitted/objects/d6/b9ec0dfb972a6815ace42545cde5f2631cd776 new file mode 100644 index 000000000..123970457 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/d6/b9ec0dfb972a6815ace42545cde5f2631cd776 differ diff --git a/tests/resources/rebase/.gitted/objects/da/82b3a60c50cf5ac524ec3000d743447329465d b/tests/resources/rebase/.gitted/objects/da/82b3a60c50cf5ac524ec3000d743447329465d new file mode 100644 index 000000000..352a13ad3 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/da/82b3a60c50cf5ac524ec3000d743447329465d differ diff --git a/tests/resources/rebase/.gitted/objects/da/9c51a23d02d931a486f45ad18cda05cf5d2b94 b/tests/resources/rebase/.gitted/objects/da/9c51a23d02d931a486f45ad18cda05cf5d2b94 new file mode 100644 index 000000000..85b78eed5 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/da/9c51a23d02d931a486f45ad18cda05cf5d2b94 differ diff --git a/tests/resources/rebase/.gitted/objects/dc/12ac1e10f2be70e8ecd52132a08da98a309c3a b/tests/resources/rebase/.gitted/objects/dc/12ac1e10f2be70e8ecd52132a08da98a309c3a new file mode 100644 index 000000000..9907248f8 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/dc/12ac1e10f2be70e8ecd52132a08da98a309c3a differ diff --git a/tests/resources/rebase/.gitted/objects/df/d3d25264693fcd7348ad286f3c34f3f6b30918 b/tests/resources/rebase/.gitted/objects/df/d3d25264693fcd7348ad286f3c34f3f6b30918 new file mode 100644 index 000000000..3de3fda62 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/df/d3d25264693fcd7348ad286f3c34f3f6b30918 differ diff --git a/tests/resources/rebase/.gitted/objects/e4/f809f826c1a9fc929874bc0e4644dd2f2a1af4 b/tests/resources/rebase/.gitted/objects/e4/f809f826c1a9fc929874bc0e4644dd2f2a1af4 new file mode 100644 index 000000000..e47501905 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/e4/f809f826c1a9fc929874bc0e4644dd2f2a1af4 differ diff --git a/tests/resources/rebase/.gitted/objects/e5/2ff405da5b7e1e9b0929939fa8405d81fe8a45 b/tests/resources/rebase/.gitted/objects/e5/2ff405da5b7e1e9b0929939fa8405d81fe8a45 new file mode 100644 index 000000000..30c1987ed Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/e5/2ff405da5b7e1e9b0929939fa8405d81fe8a45 differ diff --git a/tests/resources/rebase/.gitted/objects/e7/bb00c4eab291e08361fda376733a12b4150aa9 b/tests/resources/rebase/.gitted/objects/e7/bb00c4eab291e08361fda376733a12b4150aa9 new file mode 100644 index 000000000..da96e9d9c Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/e7/bb00c4eab291e08361fda376733a12b4150aa9 differ diff --git a/tests/resources/rebase/.gitted/objects/e8/8cc0a6919a74599ce8e1dcb81eb2bbae33a645 b/tests/resources/rebase/.gitted/objects/e8/8cc0a6919a74599ce8e1dcb81eb2bbae33a645 new file mode 100644 index 000000000..e8ce1728b Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/e8/8cc0a6919a74599ce8e1dcb81eb2bbae33a645 differ diff --git a/tests/resources/rebase/.gitted/objects/e9/5f47e016dcc70b0b888df8e40e97b8aabafd4c b/tests/resources/rebase/.gitted/objects/e9/5f47e016dcc70b0b888df8e40e97b8aabafd4c new file mode 100644 index 000000000..cc3312a47 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/e9/5f47e016dcc70b0b888df8e40e97b8aabafd4c differ diff --git a/tests/resources/rebase/.gitted/objects/e9/f22c10ffb378446c0bbcab7ee3d9d5a0040672 b/tests/resources/rebase/.gitted/objects/e9/f22c10ffb378446c0bbcab7ee3d9d5a0040672 new file mode 100644 index 000000000..3446b2f8a Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/e9/f22c10ffb378446c0bbcab7ee3d9d5a0040672 differ diff --git a/tests/resources/rebase/.gitted/objects/ec/725f5639730640f91cd0be5f2d6d7ac5d69c79 b/tests/resources/rebase/.gitted/objects/ec/725f5639730640f91cd0be5f2d6d7ac5d69c79 new file mode 100644 index 000000000..0fb3334db Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/ec/725f5639730640f91cd0be5f2d6d7ac5d69c79 differ diff --git a/tests/resources/rebase/.gitted/objects/ed/f7b3ffde1624c60d2d6b1a2bb792d86de172e0 b/tests/resources/rebase/.gitted/objects/ed/f7b3ffde1624c60d2d6b1a2bb792d86de172e0 new file mode 100644 index 000000000..e2e98d6d8 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/ed/f7b3ffde1624c60d2d6b1a2bb792d86de172e0 differ diff --git a/tests/resources/rebase/.gitted/objects/ee/23c5eeedadf8595c0ff60a366d970a165e373d b/tests/resources/rebase/.gitted/objects/ee/23c5eeedadf8595c0ff60a366d970a165e373d new file mode 100644 index 000000000..b32600f78 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/ee/23c5eeedadf8595c0ff60a366d970a165e373d differ diff --git a/tests/resources/rebase/.gitted/objects/ee/f0edde5daa94da5f297d4ddb5dfbc1980f0902 b/tests/resources/rebase/.gitted/objects/ee/f0edde5daa94da5f297d4ddb5dfbc1980f0902 new file mode 100644 index 000000000..e9b3f58c6 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/ee/f0edde5daa94da5f297d4ddb5dfbc1980f0902 differ diff --git a/tests/resources/rebase/.gitted/objects/ef/ad0b11c47cb2f0220cbd6f5b0f93bb99064b00 b/tests/resources/rebase/.gitted/objects/ef/ad0b11c47cb2f0220cbd6f5b0f93bb99064b00 new file mode 100644 index 000000000..285e14056 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/ef/ad0b11c47cb2f0220cbd6f5b0f93bb99064b00 differ diff --git a/tests/resources/rebase/.gitted/objects/f5/56d5fef35003561dc0b64b37057d7541239105 b/tests/resources/rebase/.gitted/objects/f5/56d5fef35003561dc0b64b37057d7541239105 new file mode 100644 index 000000000..f4143e1f5 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/f5/56d5fef35003561dc0b64b37057d7541239105 differ diff --git a/tests/resources/rebase/.gitted/objects/f6/3fa37e285bd11b0a7b48fa584a4091814a3ada b/tests/resources/rebase/.gitted/objects/f6/3fa37e285bd11b0a7b48fa584a4091814a3ada new file mode 100644 index 000000000..e650383a2 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/f6/3fa37e285bd11b0a7b48fa584a4091814a3ada differ diff --git a/tests/resources/rebase/.gitted/objects/f7/5c193a1df47186727179f24867bc4d27a8991f b/tests/resources/rebase/.gitted/objects/f7/5c193a1df47186727179f24867bc4d27a8991f new file mode 100644 index 000000000..618cb6814 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/f7/5c193a1df47186727179f24867bc4d27a8991f differ diff --git a/tests/resources/rebase/.gitted/objects/f8/7d14a4a236582a0278a916340a793714256864 b/tests/resources/rebase/.gitted/objects/f8/7d14a4a236582a0278a916340a793714256864 new file mode 100644 index 000000000..1d29712c5 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/f8/7d14a4a236582a0278a916340a793714256864 differ diff --git a/tests/resources/rebase/.gitted/objects/fc/e0584b379f535e50e036db587db71884ea6b36 b/tests/resources/rebase/.gitted/objects/fc/e0584b379f535e50e036db587db71884ea6b36 new file mode 100644 index 000000000..ce8b2fb54 Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/fc/e0584b379f535e50e036db587db71884ea6b36 differ diff --git a/tests/resources/rebase/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d b/tests/resources/rebase/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d new file mode 100644 index 000000000..f655d12ea Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d differ diff --git a/tests/resources/rebase/.gitted/objects/ff/dfa89389040a87008c4ab1834120d3046daaea b/tests/resources/rebase/.gitted/objects/ff/dfa89389040a87008c4ab1834120d3046daaea new file mode 100644 index 000000000..54c938e2e Binary files /dev/null and b/tests/resources/rebase/.gitted/objects/ff/dfa89389040a87008c4ab1834120d3046daaea differ diff --git a/tests/resources/rebase/.gitted/refs/heads/asparagus b/tests/resources/rebase/.gitted/refs/heads/asparagus new file mode 100644 index 000000000..a3c9d67c4 Binary files /dev/null and b/tests/resources/rebase/.gitted/refs/heads/asparagus differ diff --git a/tests/resources/rebase/.gitted/refs/heads/barley b/tests/resources/rebase/.gitted/refs/heads/barley new file mode 100644 index 000000000..feab9443f Binary files /dev/null and b/tests/resources/rebase/.gitted/refs/heads/barley differ diff --git a/tests/resources/rebase/.gitted/refs/heads/beef b/tests/resources/rebase/.gitted/refs/heads/beef new file mode 100644 index 000000000..1c69e6ac5 Binary files /dev/null and b/tests/resources/rebase/.gitted/refs/heads/beef differ diff --git a/tests/resources/rebase/.gitted/refs/heads/dried_pea b/tests/resources/rebase/.gitted/refs/heads/dried_pea new file mode 100644 index 000000000..9ede6023c Binary files /dev/null and b/tests/resources/rebase/.gitted/refs/heads/dried_pea differ diff --git a/tests/resources/rebase/.gitted/refs/heads/gravy b/tests/resources/rebase/.gitted/refs/heads/gravy new file mode 100644 index 000000000..3753b7330 Binary files /dev/null and b/tests/resources/rebase/.gitted/refs/heads/gravy differ 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 000000000..3bffe27d1 Binary files /dev/null and b/tests/resources/rebase/.gitted/refs/heads/green_pea differ diff --git a/tests/resources/rebase/.gitted/refs/heads/master b/tests/resources/rebase/.gitted/refs/heads/master new file mode 100644 index 000000000..abbe9cc15 Binary files /dev/null and b/tests/resources/rebase/.gitted/refs/heads/master differ diff --git a/tests/resources/rebase/.gitted/refs/heads/veal b/tests/resources/rebase/.gitted/refs/heads/veal new file mode 100644 index 000000000..484f48976 Binary files /dev/null and b/tests/resources/rebase/.gitted/refs/heads/veal differ diff --git a/tests/resources/rebase/asparagus.txt b/tests/resources/rebase/asparagus.txt new file mode 100644 index 000000000..67ed7afb2 Binary files /dev/null and b/tests/resources/rebase/asparagus.txt differ diff --git a/tests/resources/rebase/beef.txt b/tests/resources/rebase/beef.txt new file mode 100644 index 000000000..68f6182f4 Binary files /dev/null and b/tests/resources/rebase/beef.txt differ diff --git a/tests/resources/rebase/bouilli.txt b/tests/resources/rebase/bouilli.txt new file mode 100644 index 000000000..4b7c56500 Binary files /dev/null and b/tests/resources/rebase/bouilli.txt differ diff --git a/tests/resources/rebase/gravy.txt b/tests/resources/rebase/gravy.txt new file mode 100644 index 000000000..c4e6cca3e Binary files /dev/null and b/tests/resources/rebase/gravy.txt differ diff --git a/tests/resources/rebase/oyster.txt b/tests/resources/rebase/oyster.txt new file mode 100644 index 000000000..68af1fc74 Binary files /dev/null and b/tests/resources/rebase/oyster.txt differ diff --git a/tests/resources/rebase/veal.txt b/tests/resources/rebase/veal.txt new file mode 100644 index 000000000..a7b066537 Binary files /dev/null and b/tests/resources/rebase/veal.txt differ