diff options
Diffstat (limited to 'include/git2/checkout.h')
-rw-r--r-- | include/git2/checkout.h | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/include/git2/checkout.h b/include/git2/checkout.h new file mode 100644 index 0000000..9f83411 --- /dev/null +++ b/include/git2/checkout.h @@ -0,0 +1,417 @@ +/* + * 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_checkout_h__ +#define INCLUDE_git_checkout_h__ + +#include "common.h" +#include "types.h" +#include "diff.h" + +/** + * @file git2/checkout.h + * @brief Git checkout routines + * @defgroup git_checkout Git checkout routines + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * Checkout behavior flags + * + * In libgit2, checkout is used to update the working directory and index + * to match a target tree. Unlike git checkout, it does not move the HEAD + * commit for you - use `git_repository_set_head` or the like to do that. + * + * Checkout looks at (up to) four things: the "target" tree you want to + * check out, the "baseline" tree of what was checked out previously, the + * working directory for actual files, and the index for staged changes. + * + * You give checkout one of three strategies for update: + * + * - `GIT_CHECKOUT_NONE` is a dry-run strategy that checks for conflicts, + * etc., but doesn't make any actual changes. + * + * - `GIT_CHECKOUT_FORCE` is at the opposite extreme, taking any action to + * make the working directory match the target (including potentially + * discarding modified files). + * + * - `GIT_CHECKOUT_SAFE` is between these two options, it will only make + * modifications that will not lose changes. + * + * | target == baseline | target != baseline | + * ---------------------|-----------------------|----------------------| + * workdir == baseline | no action | create, update, or | + * | | delete file | + * ---------------------|-----------------------|----------------------| + * workdir exists and | no action | conflict (notify | + * is != baseline | notify dirty MODIFIED | and cancel checkout) | + * ---------------------|-----------------------|----------------------| + * workdir missing, | notify dirty DELETED | create file | + * baseline present | | | + * ---------------------|-----------------------|----------------------| + * + * To emulate `git checkout`, use `GIT_CHECKOUT_SAFE` with a checkout + * notification callback (see below) that displays information about dirty + * files. The default behavior will cancel checkout on conflicts. + * + * To emulate `git checkout-index`, use `GIT_CHECKOUT_SAFE` with a + * notification callback that cancels the operation if a dirty-but-existing + * file is found in the working directory. This core git command isn't + * quite "force" but is sensitive about some types of changes. + * + * To emulate `git checkout -f`, use `GIT_CHECKOUT_FORCE`. + * + * + * There are some additional flags to modify the behavior of checkout: + * + * - GIT_CHECKOUT_ALLOW_CONFLICTS makes SAFE mode apply safe file updates + * even if there are conflicts (instead of cancelling the checkout). + * + * - GIT_CHECKOUT_REMOVE_UNTRACKED means remove untracked files (i.e. not + * in target, baseline, or index, and not ignored) from the working dir. + * + * - GIT_CHECKOUT_REMOVE_IGNORED means remove ignored files (that are also + * untracked) from the working directory as well. + * + * - GIT_CHECKOUT_UPDATE_ONLY means to only update the content of files that + * already exist. Files will not be created nor deleted. This just skips + * applying adds, deletes, and typechanges. + * + * - GIT_CHECKOUT_DONT_UPDATE_INDEX prevents checkout from writing the + * updated files' information to the index. + * + * - Normally, checkout will reload the index and git attributes from disk + * before any operations. GIT_CHECKOUT_NO_REFRESH prevents this reload. + * + * - Unmerged index entries are conflicts. GIT_CHECKOUT_SKIP_UNMERGED skips + * files with unmerged index entries instead. GIT_CHECKOUT_USE_OURS and + * GIT_CHECKOUT_USE_THEIRS to proceed with the checkout using either the + * stage 2 ("ours") or stage 3 ("theirs") version of files in the index. + * + * - GIT_CHECKOUT_DONT_OVERWRITE_IGNORED prevents ignored files from being + * overwritten. Normally, files that are ignored in the working directory + * are not considered "precious" and may be overwritten if the checkout + * target contains that file. + * + * - GIT_CHECKOUT_DONT_REMOVE_EXISTING prevents checkout from removing + * files or folders that fold to the same name on case insensitive + * filesystems. This can cause files to retain their existing names + * and write through existing symbolic links. + */ +typedef enum { + GIT_CHECKOUT_NONE = 0, /**< default is a dry run, no actual updates */ + + /** + * Allow safe updates that cannot overwrite uncommitted data. + * If the uncommitted changes don't conflict with the checked out files, + * the checkout will still proceed, leaving the changes intact. + * + * Mutually exclusive with GIT_CHECKOUT_FORCE. + * GIT_CHECKOUT_FORCE takes precedence over GIT_CHECKOUT_SAFE. + */ + GIT_CHECKOUT_SAFE = (1u << 0), + + /** + * Allow all updates to force working directory to look like index. + * + * Mutually exclusive with GIT_CHECKOUT_SAFE. + * GIT_CHECKOUT_FORCE takes precedence over GIT_CHECKOUT_SAFE. + */ + GIT_CHECKOUT_FORCE = (1u << 1), + + + /** Allow checkout to recreate missing files */ + GIT_CHECKOUT_RECREATE_MISSING = (1u << 2), + + /** Allow checkout to make safe updates even if conflicts are found */ + GIT_CHECKOUT_ALLOW_CONFLICTS = (1u << 4), + + /** Remove untracked files not in index (that are not ignored) */ + GIT_CHECKOUT_REMOVE_UNTRACKED = (1u << 5), + + /** Remove ignored files not in index */ + GIT_CHECKOUT_REMOVE_IGNORED = (1u << 6), + + /** Only update existing files, don't create new ones */ + GIT_CHECKOUT_UPDATE_ONLY = (1u << 7), + + /** + * Normally checkout updates index entries as it goes; this stops that. + * Implies `GIT_CHECKOUT_DONT_WRITE_INDEX`. + */ + GIT_CHECKOUT_DONT_UPDATE_INDEX = (1u << 8), + + /** Don't refresh index/config/etc before doing checkout */ + GIT_CHECKOUT_NO_REFRESH = (1u << 9), + + /** Allow checkout to skip unmerged files */ + GIT_CHECKOUT_SKIP_UNMERGED = (1u << 10), + /** For unmerged files, checkout stage 2 from index */ + GIT_CHECKOUT_USE_OURS = (1u << 11), + /** For unmerged files, checkout stage 3 from index */ + GIT_CHECKOUT_USE_THEIRS = (1u << 12), + + /** Treat pathspec as simple list of exact match file paths */ + GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH = (1u << 13), + + /** Ignore directories in use, they will be left empty */ + GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES = (1u << 18), + + /** Don't overwrite ignored files that exist in the checkout target */ + GIT_CHECKOUT_DONT_OVERWRITE_IGNORED = (1u << 19), + + /** Write normal merge files for conflicts */ + GIT_CHECKOUT_CONFLICT_STYLE_MERGE = (1u << 20), + + /** Include common ancestor data in diff3 format files for conflicts */ + GIT_CHECKOUT_CONFLICT_STYLE_DIFF3 = (1u << 21), + + /** Don't overwrite existing files or folders */ + GIT_CHECKOUT_DONT_REMOVE_EXISTING = (1u << 22), + + /** Normally checkout writes the index upon completion; this prevents that. */ + GIT_CHECKOUT_DONT_WRITE_INDEX = (1u << 23), + + /** + * Show what would be done by a checkout. Stop after sending + * notifications; don't update the working directory or index. + */ + GIT_CHECKOUT_DRY_RUN = (1u << 24), + + /** Include common ancestor data in zdiff3 format for conflicts */ + GIT_CHECKOUT_CONFLICT_STYLE_ZDIFF3 = (1u << 25), + + /** + * THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED + */ + + /** Recursively checkout submodules with same options (NOT IMPLEMENTED) */ + GIT_CHECKOUT_UPDATE_SUBMODULES = (1u << 16), + /** Recursively checkout submodules if HEAD moved in super repo (NOT IMPLEMENTED) */ + GIT_CHECKOUT_UPDATE_SUBMODULES_IF_CHANGED = (1u << 17) + +} git_checkout_strategy_t; + +/** + * Checkout notification flags + * + * Checkout will invoke an options notification callback (`notify_cb`) for + * certain cases - you pick which ones via `notify_flags`: + * + * Returning a non-zero value from this callback will cancel the checkout. + * The non-zero return value will be propagated back and returned by the + * git_checkout_... call. + * + * Notification callbacks are made prior to modifying any files on disk, + * so canceling on any notification will still happen prior to any files + * being modified. + */ +typedef enum { + GIT_CHECKOUT_NOTIFY_NONE = 0, + + /** + * Invokes checkout on conflicting paths. + */ + GIT_CHECKOUT_NOTIFY_CONFLICT = (1u << 0), + + /** + * Notifies about "dirty" files, i.e. those that do not need an update + * but no longer match the baseline. Core git displays these files when + * checkout runs, but won't stop the checkout. + */ + GIT_CHECKOUT_NOTIFY_DIRTY = (1u << 1), + + /** + * Sends notification for any file changed. + */ + GIT_CHECKOUT_NOTIFY_UPDATED = (1u << 2), + + /** + * Notifies about untracked files. + */ + GIT_CHECKOUT_NOTIFY_UNTRACKED = (1u << 3), + + /** + * Notifies about ignored files. + */ + GIT_CHECKOUT_NOTIFY_IGNORED = (1u << 4), + + GIT_CHECKOUT_NOTIFY_ALL = 0x0FFFFu +} git_checkout_notify_t; + +/** Checkout performance-reporting structure */ +typedef struct { + size_t mkdir_calls; + size_t stat_calls; + size_t chmod_calls; +} git_checkout_perfdata; + +/** Checkout notification callback function */ +typedef int GIT_CALLBACK(git_checkout_notify_cb)( + git_checkout_notify_t why, + const char *path, + const git_diff_file *baseline, + const git_diff_file *target, + const git_diff_file *workdir, + void *payload); + +/** Checkout progress notification function */ +typedef void GIT_CALLBACK(git_checkout_progress_cb)( + const char *path, + size_t completed_steps, + size_t total_steps, + void *payload); + +/** Checkout perfdata notification function */ +typedef void GIT_CALLBACK(git_checkout_perfdata_cb)( + const git_checkout_perfdata *perfdata, + void *payload); + +/** + * Checkout options structure + * + * Initialize with `GIT_CHECKOUT_OPTIONS_INIT`. Alternatively, you can + * use `git_checkout_options_init`. + * + */ +typedef struct git_checkout_options { + unsigned int version; /**< The version */ + + unsigned int checkout_strategy; /**< default will be a safe checkout */ + + int disable_filters; /**< don't apply filters like CRLF conversion */ + unsigned int dir_mode; /**< default is 0755 */ + unsigned int file_mode; /**< default is 0644 or 0755 as dictated by blob */ + int file_open_flags; /**< default is O_CREAT | O_TRUNC | O_WRONLY */ + + unsigned int notify_flags; /**< see `git_checkout_notify_t` above */ + + /** + * Optional callback to get notifications on specific file states. + * @see git_checkout_notify_t + */ + git_checkout_notify_cb notify_cb; + + /** Payload passed to notify_cb */ + void *notify_payload; + + /** Optional callback to notify the consumer of checkout progress. */ + git_checkout_progress_cb progress_cb; + + /** Payload passed to progress_cb */ + void *progress_payload; + + /** + * A list of wildmatch patterns or paths. + * + * By default, all paths are processed. If you pass an array of wildmatch + * patterns, those will be used to filter which paths should be taken into + * account. + * + * Use GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH to treat as a simple list. + */ + git_strarray paths; + + /** + * The expected content of the working directory; defaults to HEAD. + * + * If the working directory does not match this baseline information, + * that will produce a checkout conflict. + */ + git_tree *baseline; + + /** + * Like `baseline` above, though expressed as an index. This + * option overrides `baseline`. + */ + git_index *baseline_index; + + const char *target_directory; /**< alternative checkout path to workdir */ + + const char *ancestor_label; /**< the name of the common ancestor side of conflicts */ + const char *our_label; /**< the name of the "our" side of conflicts */ + const char *their_label; /**< the name of the "their" side of conflicts */ + + /** Optional callback to notify the consumer of performance data. */ + git_checkout_perfdata_cb perfdata_cb; + + /** Payload passed to perfdata_cb */ + void *perfdata_payload; +} git_checkout_options; + +#define GIT_CHECKOUT_OPTIONS_VERSION 1 +#define GIT_CHECKOUT_OPTIONS_INIT {GIT_CHECKOUT_OPTIONS_VERSION, GIT_CHECKOUT_SAFE} + +/** + * Initialize git_checkout_options structure + * + * Initializes a `git_checkout_options` with default values. Equivalent to creating + * an instance with GIT_CHECKOUT_OPTIONS_INIT. + * + * @param opts The `git_checkout_options` struct to initialize. + * @param version The struct version; pass `GIT_CHECKOUT_OPTIONS_VERSION`. + * @return Zero on success; -1 on failure. + */ +GIT_EXTERN(int) git_checkout_options_init( + git_checkout_options *opts, + unsigned int version); + +/** + * Updates files in the index and the working tree to match the content of + * the commit pointed at by HEAD. + * + * Note that this is _not_ the correct mechanism used to switch branches; + * do not change your `HEAD` and then call this method, that would leave + * you with checkout conflicts since your working directory would then + * appear to be dirty. Instead, checkout the target of the branch and + * then update `HEAD` using `git_repository_set_head` to point to the + * branch you checked out. + * + * @param repo repository to check out (must be non-bare) + * @param opts specifies checkout options (may be NULL) + * @return 0 on success, GIT_EUNBORNBRANCH if HEAD points to a non + * existing branch, non-zero value returned by `notify_cb`, or + * other error code < 0 (use git_error_last for error details) + */ +GIT_EXTERN(int) git_checkout_head( + git_repository *repo, + const git_checkout_options *opts); + +/** + * Updates files in the working tree to match the content of the index. + * + * @param repo repository into which to check out (must be non-bare) + * @param index index to be checked out (or NULL to use repository index) + * @param opts specifies checkout options (may be NULL) + * @return 0 on success, non-zero return value from `notify_cb`, or error + * code < 0 (use git_error_last for error details) + */ +GIT_EXTERN(int) git_checkout_index( + git_repository *repo, + git_index *index, + const git_checkout_options *opts); + +/** + * Updates files in the index and working tree to match the content of the + * tree pointed at by the treeish. + * + * @param repo repository to check out (must be non-bare) + * @param treeish a commit, tag or tree which content will be used to update + * the working directory (or NULL to use HEAD) + * @param opts specifies checkout options (may be NULL) + * @return 0 on success, non-zero return value from `notify_cb`, or error + * code < 0 (use git_error_last for error details) + */ +GIT_EXTERN(int) git_checkout_tree( + git_repository *repo, + const git_object *treeish, + const git_checkout_options *opts); + +/** @} */ +GIT_END_DECL +#endif |