/* * 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_merge_h__ #define INCLUDE_git_merge_h__ #include "common.h" #include "types.h" #include "oid.h" #include "checkout.h" #include "index.h" /** * @file git2/merge.h * @brief Git merge routines * @defgroup git_merge Git merge routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Flags for `git_merge_tree` options. A combination of these flags can be * passed in via the `flags` value in the `git_merge_tree_opts`. */ typedef enum { /** * Detect renames that occur between the common ancestor and the "ours" * side or the common ancestor and the "theirs" side. This will enable * the ability to merge between a modified and renamed file. */ GIT_MERGE_TREE_FIND_RENAMES = (1 << 0), } git_merge_tree_flag_t; /** * Merge file favor options for `git_merge_trees_opts` instruct the file-level * merging functionality how to deal with conflicting regions of the files. */ typedef enum { /** * When a region of a file is changed in both branches, a conflict * will be recorded in the index so that `git_checkout` can produce * a merge file with conflict markers in the working directory. * This is the default. */ GIT_MERGE_FILE_FAVOR_NORMAL = 0, /** * When a region of a file is changed in both branches, the file * created in the index will contain the "ours" side of any conflicting * region. The index will not record a conflict. */ GIT_MERGE_FILE_FAVOR_OURS = 1, /** * When a region of a file is changed in both branches, the file * created in the index will contain the "theirs" side of any conflicting * region. The index will not record a conflict. */ GIT_MERGE_FILE_FAVOR_THEIRS = 2, /** * When a region of a file is changed in both branches, the file * created in the index will contain each unique line from each side, * which has the result of combining both files. The index will not * record a conflict. */ GIT_MERGE_FILE_FAVOR_UNION = 3, } git_merge_file_favor_t; typedef struct { unsigned int version; git_merge_tree_flag_t flags; /** * Similarity to consider a file renamed (default 50). If * `GIT_MERGE_TREE_FIND_RENAMES` is enabled, added files will be compared * with deleted files to determine their similarity. Files that are * more similar than the rename threshold (percentage-wise) will be * treated as a rename. */ unsigned int rename_threshold; /** * Maximum similarity sources to examine for renames (default 200). * If the number of rename candidates (add / delete pairs) is greater * than this value, inexact rename detection is aborted. * * This setting overrides the `merge.renameLimit` configuration value. */ unsigned int target_limit; /** Pluggable similarity metric; pass NULL to use internal metric */ git_diff_similarity_metric *metric; /** Flags for handling conflicting content. */ git_merge_file_favor_t file_favor; } git_merge_tree_opts; #define GIT_MERGE_TREE_OPTS_VERSION 1 #define GIT_MERGE_TREE_OPTS_INIT {GIT_MERGE_TREE_OPTS_VERSION} /** * Initializes a `git_merge_tree_opts` with default values. Equivalent to * creating an instance with GIT_MERGE_TREE_OPTS_INIT. * * @param opts the `git_merge_tree_opts` instance to initialize. * @param version the version of the struct; you should pass * `GIT_MERGE_TREE_OPTS_VERSION` here. * @return Zero on success; -1 on failure. */ GIT_EXTERN(int) git_merge_tree_init_opts( git_merge_tree_opts* opts, int version); /** * Option flags for `git_merge`. */ typedef enum { /** * The default behavior is to allow fast-forwards, returning * immediately with the commit ID to fast-forward to. */ GIT_MERGE_DEFAULT = 0, /** * Do not fast-forward; perform a merge and prepare a merge result even * if the inputs are eligible for fast-forwarding. */ GIT_MERGE_NO_FASTFORWARD = 1, /** * Ensure that the inputs are eligible for fast-forwarding, error if * a merge needs to be performed. */ GIT_MERGE_FASTFORWARD_ONLY = 2, } git_merge_flags_t; typedef struct { unsigned int version; /** Options for handling the commit-level merge. */ git_merge_flags_t merge_flags; /** Options for handling the merges of individual files. */ git_merge_tree_opts merge_tree_opts; /** Options for writing the merge result to the working directory. */ git_checkout_options checkout_opts; } git_merge_opts; #define GIT_MERGE_OPTS_VERSION 1 #define GIT_MERGE_OPTS_INIT {GIT_MERGE_OPTS_VERSION, 0, GIT_MERGE_TREE_OPTS_INIT, GIT_CHECKOUT_OPTIONS_INIT} /** * Initializes a `git_merge_opts` with default values. Equivalent to creating * an instance with GIT_MERGE_OPTS_INIT. * * @param opts the `git_merge_opts` instance to initialize. * @param version the version of the struct; you should pass * `GIT_MERGE_OPTS_VERSION` here. * @return Zero on success; -1 on failure. */ GIT_EXTERN(int) git_merge_init_opts( git_merge_opts* opts, int version); /** * Find a merge base between two commits * * @param out the OID of a merge base between 'one' and 'two' * @param repo the repository where the commits exist * @param one one of the commits * @param two the other commit * @return 0 on success, GIT_ENOTFOUND if not found or error code */ GIT_EXTERN(int) git_merge_base( git_oid *out, git_repository *repo, const git_oid *one, const git_oid *two); /** * Find a merge base given a list of commits * * @param out the OID of a merge base considering all the commits * @param repo the repository where the commits exist * @param length The number of commits in the provided `input_array` * @param input_array oids of the commits * @return Zero on success; GIT_ENOTFOUND or -1 on failure. */ GIT_EXTERN(int) git_merge_base_many( git_oid *out, git_repository *repo, size_t length, const git_oid input_array[]); /** * Find a merge base in preparation for an octopus merge * * @param out the OID of a merge base considering all the commits * @param repo the repository where the commits exist * @param length The number of commits in the provided `input_array` * @param input_array oids of the commits * @return Zero on success; GIT_ENOTFOUND or -1 on failure. */ GIT_EXTERN(int) git_merge_base_octopus( git_oid *out, git_repository *repo, 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, 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); /** * Frees a `git_merge_head`. * * @param head merge head to free */ GIT_EXTERN(void) git_merge_head_free( git_merge_head *head); /** * Merge two trees, producing a `git_index` that reflects the result of * the merge. The index may be written as-is to the working directory * or checked out. If the index is to be converted to a tree, the caller * should resolve any conflicts that arose as part of the merge. * * The returned index must be freed explicitly with `git_index_free`. * * @param out pointer to store the index result in * @param repo repository that contains the given trees * @param ancestor_tree the common ancestor between the trees (or null if none) * @param our_tree the tree that reflects the destination tree * @param their_tree the tree to merge in to `our_tree` * @param opts the merge tree options (or null for defaults) * @return 0 on success or error code */ GIT_EXTERN(int) git_merge_trees( git_index **out, git_repository *repo, const git_tree *ancestor_tree, const git_tree *our_tree, const git_tree *their_tree, const git_merge_tree_opts *opts); /** * Merge two commits, producing a `git_index` that reflects the result of * the merge. The index may be written as-is to the working directory * or checked out. If the index is to be converted to a tree, the caller * should resolve any conflicts that arose as part of the merge. * * The returned index must be freed explicitly with `git_index_free`. * * @param out pointer to store the index result in * @param repo repository that contains the given trees * @param our_commit the commit that reflects the destination tree * @param their_commit the commit to merge in to `our_commit` * @param opts the merge tree options (or null for defaults) * @return 0 on success or error code */ GIT_EXTERN(int) git_merge_commits( git_index **out, git_repository *repo, const git_commit *our_commit, const git_commit *their_commit, const git_merge_tree_opts *opts); /** * Merges the given commit(s) into HEAD and either returns immediately * if there was no merge to perform (the specified commits have already * been merged or would produce a fast-forward) or performs the merge * and writes the results into the working directory. * * Callers should inspect the `git_merge_result`: * * If `git_merge_result_is_uptodate` is true, there is no work to perform. * * If `git_merge_result_is_fastforward` is true, the caller should update * any necessary references to the commit ID returned by * `git_merge_result_fastforward_id` and check that out in order to complete * the fast-forward. * * Otherwise, callers should inspect the resulting index, resolve any * conflicts and prepare a commit. * * The resultant `git_merge_result` should be free with * `git_merge_result_free`. * * @param out the results of the merge * @param repo the repository to merge * @param merge_heads the heads to merge into * @param merge_heads_len the number of heads to merge * @param opts merge options * @return 0 on success or error code */ GIT_EXTERN(int) git_merge( git_merge_result **out, git_repository *repo, const git_merge_head **their_heads, size_t their_heads_len, const git_merge_opts *opts); /** * Returns true if a merge is "up-to-date", meaning that the commit(s) * that were provided to `git_merge` are already included in `HEAD` * and there is no work to do. * * @return true if the merge is up-to-date, false otherwise */ GIT_EXTERN(int) git_merge_result_is_uptodate(git_merge_result *merge_result); /** * Returns true if a merge is eligible to be "fast-forwarded", meaning that * the commit that was provided to `git_merge` need not be merged, it can * simply be checked out, because the current `HEAD` is the merge base of * itself and the given commit. To perform the fast-forward, the caller * should check out the results of `git_merge_result_fastforward_id`. * * This will never be true if `GIT_MERGE_NO_FASTFORWARD` is supplied as * a merge option. * * @return true if the merge is fast-forwardable, false otherwise */ GIT_EXTERN(int) git_merge_result_is_fastforward(git_merge_result *merge_result); /** * Gets the fast-forward OID if the merge was a fastforward. * * @param out pointer to populate with the OID of the fast-forward * @param merge_result the results of the merge * @return 0 on success or error code */ GIT_EXTERN(int) git_merge_result_fastforward_id(git_oid *out, git_merge_result *merge_result); /** * Frees a `git_merge_result`. * * @param result merge result to free */ GIT_EXTERN(void) git_merge_result_free(git_merge_result *merge_result); /** @} */ GIT_END_DECL #endif