/* * 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