/* * 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_submodule_h__ #define INCLUDE_git_submodule_h__ #include "common.h" #include "types.h" #include "oid.h" /** * @file git2/submodule.h * @brief Git submodule management utilities * @defgroup git_submodule Git submodule management routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Opaque structure representing a submodule. * * Submodule support in libgit2 builds a list of known submodules and keeps * it in the repository. The list is built from the .gitmodules file, the * .git/config file, the index, and the HEAD tree. Items in the working * directory that look like submodules (i.e. a git repo) but are not * mentioned in those places won't be tracked. */ typedef struct git_submodule git_submodule; /** * Values that could be specified for the update rule of a submodule. * * Use the DEFAULT value if you have altered the update value via * `git_submodule_set_update()` and wish to reset to the original default. */ typedef enum { GIT_SUBMODULE_UPDATE_DEFAULT = -1, GIT_SUBMODULE_UPDATE_CHECKOUT = 0, GIT_SUBMODULE_UPDATE_REBASE = 1, GIT_SUBMODULE_UPDATE_MERGE = 2, GIT_SUBMODULE_UPDATE_NONE = 3 } git_submodule_update_t; /** * Values that could be specified for how closely to examine the * working directory when getting submodule status. * * Use the DEFUALT value if you have altered the ignore value via * `git_submodule_set_ignore()` and wish to reset to the original value. */ typedef enum { GIT_SUBMODULE_IGNORE_DEFAULT = -1, /* reset to default */ GIT_SUBMODULE_IGNORE_NONE = 0, /* any change or untracked == dirty */ GIT_SUBMODULE_IGNORE_UNTRACKED = 1, /* dirty if tracked files change */ GIT_SUBMODULE_IGNORE_DIRTY = 2, /* only dirty if HEAD moved */ GIT_SUBMODULE_IGNORE_ALL = 3 /* never dirty */ } git_submodule_ignore_t; /** * Return codes for submodule status. * * A combination of these flags will be returned to describe the status of a * submodule. Depending on the "ignore" property of the submodule, some of * the flags may never be returned because they indicate changes that are * supposed to be ignored. * * Submodule info is contained in 4 places: the HEAD tree, the index, config * files (both .git/config and .gitmodules), and the working directory. Any * or all of those places might be missing information about the submodule * depending on what state the repo is in. We consider all four places to * build the combination of status flags. * * There are four values that are not really status, but give basic info * about what sources of submodule data are available. These will be * returned even if ignore is set to "ALL". * * * IN_HEAD - superproject head contains submodule * * IN_INDEX - superproject index contains submodule * * IN_CONFIG - superproject gitmodules has submodule * * IN_WD - superproject workdir has submodule * * The following values will be returned so long as ignore is not "ALL". * * * INDEX_ADDED - in index, not in head * * INDEX_DELETED - in head, not in index * * INDEX_MODIFIED - index and head don't match * * WD_UNINITIALIZED - workdir contains empty directory * * WD_ADDED - in workdir, not index * * WD_DELETED - in index, not workdir * * WD_MODIFIED - index and workdir head don't match * * The following can only be returned if ignore is "NONE" or "UNTRACKED". * * * WD_INDEX_MODIFIED - submodule workdir index is dirty * * WD_WD_MODIFIED - submodule workdir has modified files * * Lastly, the following will only be returned for ignore "NONE". * * * WD_UNTRACKED - wd contains untracked files */ typedef enum { GIT_SUBMODULE_STATUS_IN_HEAD = (1u << 0), GIT_SUBMODULE_STATUS_IN_INDEX = (1u << 1), GIT_SUBMODULE_STATUS_IN_CONFIG = (1u << 2), GIT_SUBMODULE_STATUS_IN_WD = (1u << 3), GIT_SUBMODULE_STATUS_INDEX_ADDED = (1u << 4), GIT_SUBMODULE_STATUS_INDEX_DELETED = (1u << 5), GIT_SUBMODULE_STATUS_INDEX_MODIFIED = (1u << 6), GIT_SUBMODULE_STATUS_WD_UNINITIALIZED = (1u << 7), GIT_SUBMODULE_STATUS_WD_ADDED = (1u << 8), GIT_SUBMODULE_STATUS_WD_DELETED = (1u << 9), GIT_SUBMODULE_STATUS_WD_MODIFIED = (1u << 10), GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED = (1u << 11), GIT_SUBMODULE_STATUS_WD_WD_MODIFIED = (1u << 12), GIT_SUBMODULE_STATUS_WD_UNTRACKED = (1u << 13), } git_submodule_status_t; #define GIT_SUBMODULE_STATUS__IN_FLAGS \ (GIT_SUBMODULE_STATUS_IN_HEAD | \ GIT_SUBMODULE_STATUS_IN_INDEX | \ GIT_SUBMODULE_STATUS_IN_CONFIG | \ GIT_SUBMODULE_STATUS_IN_WD) #define GIT_SUBMODULE_STATUS__INDEX_FLAGS \ (GIT_SUBMODULE_STATUS_INDEX_ADDED | \ GIT_SUBMODULE_STATUS_INDEX_DELETED | \ GIT_SUBMODULE_STATUS_INDEX_MODIFIED) #define GIT_SUBMODULE_STATUS__WD_FLAGS \ ~(GIT_SUBMODULE_STATUS__IN_FLAGS | GIT_SUBMODULE_STATUS__INDEX_FLAGS) #define GIT_SUBMODULE_STATUS_IS_UNMODIFIED(S) \ (((S) & ~GIT_SUBMODULE_STATUS__IN_FLAGS) == 0) #define GIT_SUBMODULE_STATUS_IS_INDEX_UNMODIFIED(S) \ (((S) & GIT_SUBMODULE_STATUS__INDEX_FLAGS) == 0) #define GIT_SUBMODULE_STATUS_IS_WD_UNMODIFIED(S) \ (((S) & GIT_SUBMODULE_STATUS__WD_FLAGS) == 0) #define GIT_SUBMODULE_STATUS_IS_WD_DIRTY(S) \ (((S) & (GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED | \ GIT_SUBMODULE_STATUS_WD_WD_MODIFIED | \ GIT_SUBMODULE_STATUS_WD_UNTRACKED)) != 0) /** * Lookup submodule information by name or path. * * Given either the submodule name or path (they are usually the same), this * returns a structure describing the submodule. * * There are two expected error scenarios: * * - The submodule is not mentioned in the HEAD, the index, and the config, * but does "exist" in the working directory (i.e. there is a subdirectory * that is a valid self-contained git repo). In this case, this function * returns GIT_EEXISTS to indicate the the submodule exists but not in a * state where a git_submodule can be instantiated. * - The submodule is not mentioned in the HEAD, index, or config and the * working directory doesn't contain a value git repo at that path. * There may or may not be anything else at that path, but nothing that * looks like a submodule. In this case, this returns GIT_ENOTFOUND. * * The submodule object is owned by the containing repo and will be freed * when the repo is freed. The caller need not free the submodule. * * @param submodule Pointer to submodule description object pointer.. * @param repo The repository. * @param name The name of the submodule. Trailing slashes will be ignored. * @return 0 on success, GIT_ENOTFOUND if submodule does not exist, * GIT_EEXISTS if submodule exists in working directory only, -1 on * other errors. */ GIT_EXTERN(int) git_submodule_lookup( git_submodule **submodule, git_repository *repo, const char *name); /** * Iterate over all tracked submodules of a repository. * * See the note on `git_submodule` above. This iterates over the tracked * submodules as decribed therein. * * If you are concerned about items in the working directory that look like * submodules but are not tracked, the diff API will generate a diff record * for workdir items that look like submodules but are not tracked, showing * them as added in the workdir. Also, the status API will treat the entire * subdirectory of a contained git repo as a single GIT_STATUS_WT_NEW item. * * @param repo The repository * @param callback Function to be called with the name of each submodule. * Return a non-zero value to terminate the iteration. * @param payload Extra data to pass to callback * @return 0 on success, -1 on error, or non-zero return value of callback */ GIT_EXTERN(int) git_submodule_foreach( git_repository *repo, int (*callback)(git_submodule *sm, const char *name, void *payload), void *payload); /** * Set up a new git submodule for checkout. * * This does "git submodule add" up to the fetch and checkout of the * submodule contents. It preps a new submodule, creates an entry in * .gitmodules and creates an empty initialized repository either at the * given path in the working directory or in .git/modules with a gitlink * from the working directory to the new repo. * * To fully emulate "git submodule add" call this function, then open the * submodule repo and perform the clone step as needed. Lastly, call * `git_submodule_add_finalize()` to wrap up adding the new submodule and * .gitmodules to the index to be ready to commit. * * @param submodule The newly created submodule ready to open for clone * @param repo Superproject repository to contain the new submodule * @param url URL for the submodules remote * @param path Path at which the submodule should be created * @param use_gitlink Should workdir contain a gitlink to the repo in * .git/modules vs. repo directly in workdir. * @return 0 on success, GIT_EEXISTS if submodule already exists, * -1 on other errors. */ GIT_EXTERN(int) git_submodule_add_setup( git_submodule **submodule, git_repository *repo, const char *url, const char *path, int use_gitlink); /** * Resolve the setup of a new git submodule. * * This should be called on a submodule once you have called add setup * and done the clone of the submodule. This adds the .gitmodules file * and the newly cloned submodule to the index to be ready to be committed * (but doesn't actually do the commit). * * @param submodule The submodule to finish adding. */ GIT_EXTERN(int) git_submodule_add_finalize(git_submodule *submodule); /** * Add current submodule HEAD commit to index of superproject. * * @param submodule The submodule to add to the index * @param write_index Boolean if this should immediately write the index * file. If you pass this as false, you will have to get the * git_index and explicitly call `git_index_write()` on it to * save the change. * @return 0 on success, <0 on failure */ GIT_EXTERN(int) git_submodule_add_to_index( git_submodule *submodule, int write_index); /** * Write submodule settings to .gitmodules file. * * This commits any in-memory changes to the submodule to the gitmodules * file on disk. You may also be interested in `git_submodule_init()` which * writes submodule info to ".git/config" (which is better for local changes * to submodule settings) and/or `git_submodule_sync()` which writes * settings about remotes to the actual submodule repository. * * @param submodule The submodule to write. * @return 0 on success, <0 on failure. */ GIT_EXTERN(int) git_submodule_save(git_submodule *submodule); /** * Get the containing repository for a submodule. * * This returns a pointer to the repository that contains the submodule. * This is a just a reference to the repository that was passed to the * original `git_submodule_lookup()` call, so if that repository has been * freed, then this may be a dangling reference. * * @param submodule Pointer to submodule object * @return Pointer to `git_repository` */ GIT_EXTERN(git_repository *) git_submodule_owner(git_submodule *submodule); /** * Get the name of submodule. * * @param submodule Pointer to submodule object * @return Pointer to the submodule name */ GIT_EXTERN(const char *) git_submodule_name(git_submodule *submodule); /** * Get the path to the submodule. * * The path is almost always the same as the submodule name, but the * two are actually not required to match. * * @param submodule Pointer to submodule object * @return Pointer to the submodule path */ GIT_EXTERN(const char *) git_submodule_path(git_submodule *submodule); /** * Get the URL for the submodule. * * @param submodule Pointer to submodule object * @return Pointer to the submodule url */ GIT_EXTERN(const char *) git_submodule_url(git_submodule *submodule); /** * Set the URL for the submodule. * * This sets the URL in memory for the submodule. This will be used for * any following submodule actions while this submodule data is in memory. * * After calling this, you may wish to call `git_submodule_save()` to write * the changes back to the ".gitmodules" file and `git_submodule_sync()` to * write the changes to the checked out submodule repository. * * @param submodule Pointer to the submodule object * @param url URL that should be used for the submodule * @return 0 on success, <0 on failure */ GIT_EXTERN(int) git_submodule_set_url(git_submodule *submodule, const char *url); /** * Get the OID for the submodule in the index. * * @param submodule Pointer to submodule object * @return Pointer to git_oid or NULL if submodule is not in index. */ GIT_EXTERN(const git_oid *) git_submodule_index_id(git_submodule *submodule); /** * Get the OID for the submodule in the current HEAD tree. * * @param submodule Pointer to submodule object * @return Pointer to git_oid or NULL if submodule is not in the HEAD. */ GIT_EXTERN(const git_oid *) git_submodule_head_id(git_submodule *submodule); /** * Get the OID for the submodule in the current working directory. * * This returns the OID that corresponds to looking up 'HEAD' in the checked * out submodule. If there are pending changes in the index or anything * else, this won't notice that. You should call `git_submodule_status()` * for a more complete picture about the state of the working directory. * * @param submodule Pointer to submodule object * @return Pointer to git_oid or NULL if submodule is not checked out. */ GIT_EXTERN(const git_oid *) git_submodule_wd_id(git_submodule *submodule); /** * Get the ignore rule for the submodule. * * There are four ignore values: * * - **GIT_SUBMODULE_IGNORE_NONE** will consider any change to the contents * of the submodule from a clean checkout to be dirty, including the * addition of untracked files. This is the default if unspecified. * - **GIT_SUBMODULE_IGNORE_UNTRACKED** examines the contents of the * working tree (i.e. call `git_status_foreach()` on the submodule) but * UNTRACKED files will not count as making the submodule dirty. * - **GIT_SUBMODULE_IGNORE_DIRTY** means to only check if the HEAD of the * submodule has moved for status. This is fast since it does not need to * scan the working tree of the submodule at all. * - **GIT_SUBMODULE_IGNORE_ALL** means not to open the submodule repo. * The working directory will be consider clean so long as there is a * checked out version present. */ GIT_EXTERN(git_submodule_ignore_t) git_submodule_ignore( git_submodule *submodule); /** * Set the ignore rule for the submodule. * * This sets the ignore rule in memory for the submodule. This will be used * for any following actions (such as `git_submodule_status()`) while the * submodule is in memory. You should call `git_submodule_save()` if you * want to persist the new ignore role. * * Calling this again with GIT_SUBMODULE_IGNORE_DEFAULT or calling * `git_submodule_reload()` will revert the rule to the value that was in the * original config. * * @return old value for ignore */ GIT_EXTERN(git_submodule_ignore_t) git_submodule_set_ignore( git_submodule *submodule, git_submodule_ignore_t ignore); /** * Get the update rule for the submodule. */ GIT_EXTERN(git_submodule_update_t) git_submodule_update( git_submodule *submodule); /** * Set the update rule for the submodule. * * This sets the update rule in memory for the submodule. You should call * `git_submodule_save()` if you want to persist the new update rule. * * Calling this again with GIT_SUBMODULE_UPDATE_DEFAULT or calling * `git_submodule_reload()` will revert the rule to the value that was in the * original config. * * @return old value for update */ GIT_EXTERN(git_submodule_update_t) git_submodule_set_update( git_submodule *submodule, git_submodule_update_t update); /** * Read the fetchRecurseSubmodules rule for a submodule. * * This accesses the submodule..fetchRecurseSubmodules value for * the submodule that controls fetching behavior for the submodule. * * Note that at this time, libgit2 does not honor this setting and the * fetch functionality current ignores submodules. * * @return 0 if fetchRecurseSubmodules is false, 1 if true */ GIT_EXTERN(int) git_submodule_fetch_recurse_submodules( git_submodule *submodule); /** * Set the fetchRecurseSubmodules rule for a submodule. * * This sets the submodule..fetchRecurseSubmodules value for * the submodule. You should call `git_submodule_save()` if you want * to persist the new value. * * @param submodule The submodule to modify * @param fetch_recurse_submodules Boolean value * @return old value for fetchRecurseSubmodules */ GIT_EXTERN(int) git_submodule_set_fetch_recurse_submodules( git_submodule *submodule, int fetch_recurse_submodules); /** * Copy submodule info into ".git/config" file. * * Just like "git submodule init", this copies information about the * submodule into ".git/config". You can use the accessor functions * above to alter the in-memory git_submodule object and control what * is written to the config, overriding what is in .gitmodules. * * @param submodule The submodule to write into the superproject config * @param overwrite By default, existing entries will not be overwritten, * but setting this to true forces them to be updated. * @return 0 on success, <0 on failure. */ GIT_EXTERN(int) git_submodule_init(git_submodule *submodule, int overwrite); /** * Copy submodule remote info into submodule repo. * * This copies the information about the submodules URL into the checked out * submodule config, acting like "git submodule sync". This is useful if * you have altered the URL for the submodule (or it has been altered by a * fetch of upstream changes) and you need to update your local repo. */ GIT_EXTERN(int) git_submodule_sync(git_submodule *submodule); /** * Open the repository for a submodule. * * This is a newly opened repository object. The caller is responsible for * calling `git_repository_free()` on it when done. Multiple calls to this * function will return distinct `git_repository` objects. This will only * work if the submodule is checked out into the working directory. * * @param subrepo Pointer to the submodule repo which was opened * @param submodule Submodule to be opened * @return 0 on success, <0 if submodule repo could not be opened. */ GIT_EXTERN(int) git_submodule_open( git_repository **repo, git_submodule *submodule); /** * Reread submodule info from config, index, and HEAD. * * Call this to reread cached submodule information for this submodule if * you have reason to believe that it has changed. */ GIT_EXTERN(int) git_submodule_reload(git_submodule *submodule); /** * Reread all submodule info. * * Call this to reload all cached submodule information for the repo. */ GIT_EXTERN(int) git_submodule_reload_all(git_repository *repo); /** * Get the status for a submodule. * * This looks at a submodule and tries to determine the status. It * will return a combination of the `GIT_SUBMODULE_STATUS` values above. * How deeply it examines the working directory to do this will depend * on the `git_submodule_ignore_t` value for the submodule - which can be * set either temporarily or permanently with `git_submodule_set_ignore()`. * * @param status Combination of `GIT_SUBMODULE_STATUS` flags * @param submodule Submodule for which to get status * @return 0 on success, <0 on error */ GIT_EXTERN(int) git_submodule_status( unsigned int *status, git_submodule *submodule); /** * Get the locations of submodule information. * * This is a bit like a very lightweight version of `git_submodule_status`. * It just returns a made of the first four submodule status values (i.e. * the ones like GIT_SUBMODULE_STATUS_IN_HEAD, etc) that tell you where the * submodule data comes from (i.e. the HEAD commit, gitmodules file, etc.). * This can be useful if you want to know if the submodule is present in the * working directory at this point in time, etc. * * @param status Combination of first four `GIT_SUBMODULE_STATUS` flags * @param submodule Submodule for which to get status * @return 0 on success, <0 on error */ GIT_EXTERN(int) git_submodule_location( unsigned int *location_status, git_submodule *submodule); /** @} */ GIT_END_DECL #endif