mirror of
				https://git.proxmox.com/git/libgit2
				synced 2025-11-04 03:05:04 +00:00 
			
		
		
		
	Introduce a convenience function for submodule update
This introduces the functionality of submodule update in 'git_submodule_do_update'. The existing 'git_submodule_update' function is renamed to 'git_submodule_update_strategy'. The 'git_submodule_update' function now refers to functionality similar to `git submodule update`, while `git_submodule_update_strategy` is used to get the configured value of submodule.<name>.update.
This commit is contained in:
		
							parent
							
								
									b2ab887e11
								
							
						
					
					
						commit
						9d1f97df10
					
				@ -145,3 +145,9 @@ v0.21 + 1
 | 
			
		||||
* git_treebuilder_create now takes a repository so that it can query
 | 
			
		||||
  repository configuration.  Subsequently, git_treebuilder_write no
 | 
			
		||||
  longer takes a repository.
 | 
			
		||||
 | 
			
		||||
* The git_submodule_update function was renamed to
 | 
			
		||||
  git_submodule_update_strategy. git_submodule_update is now used to
 | 
			
		||||
  provide functionalty similar to "git submodule update".
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,8 @@
 | 
			
		||||
#include "common.h"
 | 
			
		||||
#include "types.h"
 | 
			
		||||
#include "oid.h"
 | 
			
		||||
#include "remote.h"
 | 
			
		||||
#include "checkout.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file git2/submodule.h
 | 
			
		||||
@ -105,6 +107,68 @@ typedef enum {
 | 
			
		||||
	GIT_SUBMODULE_STATUS_WD_WD_MODIFIED | \
 | 
			
		||||
	GIT_SUBMODULE_STATUS_WD_UNTRACKED)) != 0)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Submodule update options structure
 | 
			
		||||
 *
 | 
			
		||||
 * Use the GIT_SUBMODULE_UPDATE_OPTIONS_INIT to get the default settings, like this:
 | 
			
		||||
 *
 | 
			
		||||
 *		git_submodule_update_options opts = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
 | 
			
		||||
 */
 | 
			
		||||
typedef struct git_submodule_update_options {
 | 
			
		||||
	unsigned int version;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * These options are passed to the checkout step. To disable
 | 
			
		||||
	 * checkout, set the `checkout_strategy` to
 | 
			
		||||
	 * `GIT_CHECKOUT_NONE`. Generally you will want the use
 | 
			
		||||
	 * GIT_CHECKOUT_SAFE to update files in the working
 | 
			
		||||
	 * directory. Use the `clone_checkout_strategy` field
 | 
			
		||||
	 * to set the checkout strategy that will be used in
 | 
			
		||||
	 * the case where update needs to clone the repository.
 | 
			
		||||
	 */
 | 
			
		||||
	git_checkout_options checkout_opts;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Callbacks to use for reporting fetch progress, and for acquiring
 | 
			
		||||
	 * credentials in the event they are needed.
 | 
			
		||||
	 */
 | 
			
		||||
	git_remote_callbacks remote_callbacks;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * The checkout strategy to use when the sub repository needs to
 | 
			
		||||
	 * be cloned. Use GIT_CHECKOUT_SAFE_CREATE to create all files
 | 
			
		||||
	 * in the working directory for the newly cloned repository.
 | 
			
		||||
	 */
 | 
			
		||||
	unsigned int clone_checkout_strategy;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * The identity used when updating the reflog. NULL means to
 | 
			
		||||
	 * use the default signature using the config.
 | 
			
		||||
	 */
 | 
			
		||||
	git_signature *signature;
 | 
			
		||||
} git_submodule_update_options;
 | 
			
		||||
 | 
			
		||||
#define GIT_SUBMODULE_UPDATE_OPTIONS_VERSION 1
 | 
			
		||||
#define GIT_SUBMODULE_UPDATE_OPTIONS_INIT {GIT_CHECKOUT_OPTIONS_VERSION, {GIT_CHECKOUT_OPTIONS_VERSION, GIT_CHECKOUT_SAFE}, GIT_REMOTE_CALLBACKS_INIT, GIT_CHECKOUT_SAFE_CREATE}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Update a submodule. This will clone a missing submodule and
 | 
			
		||||
 * checkout the subrepository to the commit specified in the index of
 | 
			
		||||
 * containing repository.
 | 
			
		||||
 *
 | 
			
		||||
 * @param submodule Submodule object
 | 
			
		||||
 * @param init If the submodule is not initialized, setting this flag to true
 | 
			
		||||
 *        will initialize the submodule before updating. Otherwise, this will
 | 
			
		||||
 *        return an error if attempting to update an uninitialzed repository.
 | 
			
		||||
 *        but setting this to true forces them to be updated.
 | 
			
		||||
 * @param options configuration options for the update.  If NULL, the
 | 
			
		||||
 *        function works as though GIT_SUBMODULE_UPDATE_OPTIONS_INIT was passed.
 | 
			
		||||
 * @return 0 on success, any non-zero return value from a callback
 | 
			
		||||
 *         function, or a negative value to indicate an error (use
 | 
			
		||||
 *         `giterr_last` for a detailed error message).
 | 
			
		||||
 */
 | 
			
		||||
GIT_EXTERN(int) git_submodule_update(git_submodule *submodule, int init, git_submodule_update_options *options);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Lookup submodule information by name or path.
 | 
			
		||||
 *
 | 
			
		||||
@ -403,7 +467,7 @@ GIT_EXTERN(git_submodule_ignore_t) git_submodule_set_ignore(
 | 
			
		||||
 * @return The current git_submodule_update_t value that will be used
 | 
			
		||||
 *         for this submodule.
 | 
			
		||||
 */
 | 
			
		||||
GIT_EXTERN(git_submodule_update_t) git_submodule_update(
 | 
			
		||||
GIT_EXTERN(git_submodule_update_t) git_submodule_update_strategy(
 | 
			
		||||
	git_submodule *submodule);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										209
									
								
								src/submodule.c
									
									
									
									
									
								
							
							
						
						
									
										209
									
								
								src/submodule.c
									
									
									
									
									
								
							@ -475,7 +475,7 @@ int git_submodule_repo_init(
 | 
			
		||||
 | 
			
		||||
	/* get the configured remote url of the submodule */
 | 
			
		||||
	if ((error = git_buf_printf(&buf, "submodule.%s.url", sm->name)) < 0 ||
 | 
			
		||||
		(error = git_repository_config(&cfg, sm->repo)) < 0 ||
 | 
			
		||||
		(error = git_repository_config_snapshot(&cfg, sm->repo)) < 0 ||
 | 
			
		||||
		(error = git_config_get_string(&configured_url, cfg, buf.ptr)) < 0 ||
 | 
			
		||||
		(error = submodule_repo_init(&sub_repo, sm->repo, sm->path, configured_url, use_gitlink)) < 0)
 | 
			
		||||
		goto done;
 | 
			
		||||
@ -790,7 +790,7 @@ git_submodule_ignore_t git_submodule_set_ignore(
 | 
			
		||||
	return old;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
git_submodule_update_t git_submodule_update(git_submodule *submodule)
 | 
			
		||||
git_submodule_update_t git_submodule_update_strategy(git_submodule *submodule)
 | 
			
		||||
{
 | 
			
		||||
	assert(submodule);
 | 
			
		||||
	return (submodule->update < GIT_SUBMODULE_UPDATE_CHECKOUT) ?
 | 
			
		||||
@ -835,6 +835,178 @@ git_submodule_recurse_t git_submodule_set_fetch_recurse_submodules(
 | 
			
		||||
	return old;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int submodule_repo_create(
 | 
			
		||||
	git_repository **out,
 | 
			
		||||
	git_repository *parent_repo,
 | 
			
		||||
	const char *path)
 | 
			
		||||
{
 | 
			
		||||
	int error = 0;
 | 
			
		||||
	git_buf workdir = GIT_BUF_INIT, repodir = GIT_BUF_INIT;
 | 
			
		||||
	git_repository_init_options initopt = GIT_REPOSITORY_INIT_OPTIONS_INIT;
 | 
			
		||||
	git_repository *subrepo = NULL;
 | 
			
		||||
 | 
			
		||||
	initopt.flags =
 | 
			
		||||
		GIT_REPOSITORY_INIT_MKPATH |
 | 
			
		||||
		GIT_REPOSITORY_INIT_NO_REINIT |
 | 
			
		||||
		GIT_REPOSITORY_INIT_NO_DOTGIT_DIR |
 | 
			
		||||
		GIT_REPOSITORY_INIT_RELATIVE_GITLINK;
 | 
			
		||||
 | 
			
		||||
	/* Workdir: path to sub-repo working directory */
 | 
			
		||||
	error = git_buf_joinpath(&workdir, git_repository_workdir(parent_repo), path);
 | 
			
		||||
	if (error < 0)
 | 
			
		||||
		goto cleanup;
 | 
			
		||||
 | 
			
		||||
	initopt.workdir_path = workdir.ptr;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Repodir: path to the sub-repo. sub-repo goes in:
 | 
			
		||||
	 * <repo-dir>/modules/<name>/ with a gitlink in the 
 | 
			
		||||
	 * sub-repo workdir directory to that repository.
 | 
			
		||||
	 */
 | 
			
		||||
	error = git_buf_join3(
 | 
			
		||||
		&repodir, '/', git_repository_path(parent_repo), "modules", path);
 | 
			
		||||
	if (error < 0)
 | 
			
		||||
		goto cleanup;
 | 
			
		||||
 | 
			
		||||
	error = git_repository_init_ext(&subrepo, repodir.ptr, &initopt);
 | 
			
		||||
 | 
			
		||||
cleanup:
 | 
			
		||||
	git_buf_free(&workdir);
 | 
			
		||||
	git_buf_free(&repodir);
 | 
			
		||||
 | 
			
		||||
	*out = subrepo;
 | 
			
		||||
 | 
			
		||||
	return error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Callback to override sub-repository creation when
 | 
			
		||||
 * cloning a sub-repository.
 | 
			
		||||
 */
 | 
			
		||||
static int git_submodule_update_repo_init_cb(
 | 
			
		||||
	git_repository **out,
 | 
			
		||||
	const char *path,
 | 
			
		||||
	int bare,
 | 
			
		||||
	void *payload)
 | 
			
		||||
{
 | 
			
		||||
	GIT_UNUSED(bare);
 | 
			
		||||
	git_submodule *sm = payload;
 | 
			
		||||
 | 
			
		||||
	return submodule_repo_create(out, sm->repo, path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int git_submodule_update(git_submodule *sm, int init, git_submodule_update_options *_update_options)
 | 
			
		||||
{
 | 
			
		||||
	int error;
 | 
			
		||||
	unsigned int submodule_status;
 | 
			
		||||
	git_config *config = NULL;
 | 
			
		||||
	const char *submodule_url;
 | 
			
		||||
	git_repository *sub_repo = NULL;
 | 
			
		||||
	git_remote *remote = NULL;
 | 
			
		||||
	git_object *target_commit = NULL;
 | 
			
		||||
	git_buf buf = GIT_BUF_INIT;
 | 
			
		||||
	git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
 | 
			
		||||
	git_clone_options clone_options = GIT_CLONE_OPTIONS_INIT;
 | 
			
		||||
 | 
			
		||||
	assert(sm);
 | 
			
		||||
 | 
			
		||||
	if (_update_options)
 | 
			
		||||
		memcpy(&update_options, _update_options, sizeof(git_submodule_update_options));
 | 
			
		||||
 | 
			
		||||
	GITERR_CHECK_VERSION(&update_options, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, "git_submodule_update_options");
 | 
			
		||||
 | 
			
		||||
	/* Copy over the remote callbacks */
 | 
			
		||||
	clone_options.remote_callbacks = update_options.remote_callbacks;
 | 
			
		||||
	clone_options.signature = update_options.signature;
 | 
			
		||||
 | 
			
		||||
	/* Get the status of the submodule to determine if it is already initialized  */
 | 
			
		||||
	if ((error = git_submodule_status(&submodule_status, sm)) < 0)
 | 
			
		||||
		goto done;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If submodule work dir is not already initialized, check to see
 | 
			
		||||
	 * what we need to do (initialize, clone, return error...)
 | 
			
		||||
	 */
 | 
			
		||||
	if (submodule_status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Work dir is not initialized, check to see if the submodule
 | 
			
		||||
		 * info has been copied into .git/config
 | 
			
		||||
		 */
 | 
			
		||||
		if ((error = git_repository_config_snapshot(&config, sm->repo)) < 0 ||
 | 
			
		||||
			(error = git_buf_printf(&buf, "submodule.%s.url", git_submodule_name(sm))) < 0)
 | 
			
		||||
			goto done;
 | 
			
		||||
 | 
			
		||||
		if ((error = git_config_get_string(&submodule_url, config, git_buf_cstr(&buf))) < 0) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * If the error is not "not found" or if it is "not found" and we are not
 | 
			
		||||
			 * initializing the submodule, then return error.
 | 
			
		||||
			 */
 | 
			
		||||
			if (error != GIT_ENOTFOUND)
 | 
			
		||||
				goto done;
 | 
			
		||||
 | 
			
		||||
			if (error == GIT_ENOTFOUND && !init) {
 | 
			
		||||
				giterr_set(GITERR_SUBMODULE, "Submodule is not initialized.");
 | 
			
		||||
				error = GIT_ERROR;
 | 
			
		||||
				goto done;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* The submodule has not been initialized yet - initialize it now.*/
 | 
			
		||||
			if ((error = git_submodule_init(sm, 0)) < 0)
 | 
			
		||||
				goto done;
 | 
			
		||||
 | 
			
		||||
			git_config_free(config);
 | 
			
		||||
			config = NULL;
 | 
			
		||||
 | 
			
		||||
			if ((error = git_repository_config_snapshot(&config, sm->repo)) < 0 ||
 | 
			
		||||
				(error = git_config_get_string(&submodule_url, config, git_buf_cstr(&buf))) < 0)
 | 
			
		||||
				goto done;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/** submodule is initialized - now clone it **/
 | 
			
		||||
		/* override repo creation */
 | 
			
		||||
		clone_options.repository_cb = git_submodule_update_repo_init_cb;
 | 
			
		||||
		clone_options.repository_cb_payload = sm;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Do not perform checkout as part of clone, instead we 
 | 
			
		||||
		 * will checkout the specific commit manually.
 | 
			
		||||
		 */
 | 
			
		||||
		clone_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE;
 | 
			
		||||
		update_options.checkout_opts.checkout_strategy = update_options.clone_checkout_strategy;
 | 
			
		||||
 | 
			
		||||
		if ((error = git_clone(&sub_repo, submodule_url, sm->path, &clone_options)) < 0 ||
 | 
			
		||||
			(error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm), update_options.signature, NULL)) < 0 ||
 | 
			
		||||
			(error = git_checkout_head(sub_repo, &update_options.checkout_opts)) != 0)
 | 
			
		||||
			goto done;
 | 
			
		||||
	} else {
 | 
			
		||||
		/**
 | 
			
		||||
		 * Work dir is initialized - look up the commit in the parent repository's index,
 | 
			
		||||
		 * update the workdir contents of the subrepository, and set the subrepository's
 | 
			
		||||
		 * head to the new commit.
 | 
			
		||||
		 */
 | 
			
		||||
		if ((error = git_submodule_open(&sub_repo, sm)) < 0 ||
 | 
			
		||||
			(error = git_object_lookup(&target_commit, sub_repo, git_submodule_index_id(sm), GIT_OBJ_COMMIT)) < 0 ||
 | 
			
		||||
			(error = git_checkout_tree(sub_repo, target_commit, &update_options.checkout_opts)) != 0 ||
 | 
			
		||||
			(error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm), update_options.signature, NULL)) < 0)
 | 
			
		||||
			goto done;
 | 
			
		||||
 | 
			
		||||
		/* Invalidate the wd flags as the workdir has been updated. */
 | 
			
		||||
		sm->flags = sm->flags &
 | 
			
		||||
			~(GIT_SUBMODULE_STATUS_IN_WD |
 | 
			
		||||
		  	GIT_SUBMODULE_STATUS__WD_OID_VALID |
 | 
			
		||||
		  	GIT_SUBMODULE_STATUS__WD_SCANNED);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	git_buf_free(&buf);
 | 
			
		||||
	git_config_free(config);
 | 
			
		||||
	git_object_free(target_commit);
 | 
			
		||||
	git_remote_free(remote);
 | 
			
		||||
	git_repository_free(sub_repo);
 | 
			
		||||
 | 
			
		||||
	return error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int git_submodule_init(git_submodule *sm, int overwrite)
 | 
			
		||||
{
 | 
			
		||||
	int error;
 | 
			
		||||
@ -853,7 +1025,7 @@ int git_submodule_init(git_submodule *sm, int overwrite)
 | 
			
		||||
 | 
			
		||||
	/* write "submodule.NAME.url" */
 | 
			
		||||
 | 
			
		||||
	if ((git_submodule_resolve_url(&effective_submodule_url, sm->repo, sm->url)) < 0 ||
 | 
			
		||||
	if ((error = git_submodule_resolve_url(&effective_submodule_url, sm->repo, sm->url)) < 0 ||
 | 
			
		||||
		(error = git_buf_printf(&key, "submodule.%s.url", sm->name)) < 0 ||
 | 
			
		||||
		(error = git_config__update_entry(
 | 
			
		||||
			cfg, key.ptr, effective_submodule_url.ptr, overwrite != 0, false)) < 0)
 | 
			
		||||
@ -1867,16 +2039,31 @@ static int lookup_head_remote_key(git_buf *remote_name, git_repository *repo)
 | 
			
		||||
	if ((error = git_repository_head(&head, repo)) < 0)
 | 
			
		||||
		return error;
 | 
			
		||||
 | 
			
		||||
	/* lookup remote tracking branch of HEAD */
 | 
			
		||||
	if (!(error = git_branch_upstream_name(
 | 
			
		||||
			&upstream_name, repo, git_reference_name(head))))
 | 
			
		||||
	{
 | 
			
		||||
		/* lookup remote of remote tracking branch */
 | 
			
		||||
		error = git_branch_remote_name(remote_name, repo, upstream_name.ptr);
 | 
			
		||||
 | 
			
		||||
		git_buf_free(&upstream_name);
 | 
			
		||||
	/**
 | 
			
		||||
	 * If head does not refer to a branch, then return
 | 
			
		||||
	 * GIT_ENOTFOUND to indicate that we could not find
 | 
			
		||||
	 * a remote key for the local tracking branch HEAD points to.
 | 
			
		||||
	 **/
 | 
			
		||||
	if (!git_reference_is_branch(head)) {
 | 
			
		||||
		giterr_set(GITERR_INVALID,
 | 
			
		||||
			"HEAD does not refer to a branch.");
 | 
			
		||||
		error = GIT_ENOTFOUND;
 | 
			
		||||
		goto done;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* lookup remote tracking branch of HEAD */
 | 
			
		||||
	if ((error = git_branch_upstream_name(
 | 
			
		||||
		&upstream_name,
 | 
			
		||||
		repo,
 | 
			
		||||
		git_reference_name(head))) < 0)
 | 
			
		||||
		goto done;
 | 
			
		||||
 | 
			
		||||
	/* lookup remote of remote tracking branch */
 | 
			
		||||
	if ((error = git_branch_remote_name(remote_name, repo, upstream_name.ptr)) < 0)
 | 
			
		||||
		goto done;
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	git_buf_free(&upstream_name);
 | 
			
		||||
	git_reference_free(head);
 | 
			
		||||
 | 
			
		||||
	return error;
 | 
			
		||||
 | 
			
		||||
@ -71,3 +71,41 @@ void test_submodule_init__relative_url(void)
 | 
			
		||||
	git_buf_free(&absolute_url);
 | 
			
		||||
	git_config_free(cfg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test_submodule_init__relative_url_detached_head(void)
 | 
			
		||||
{
 | 
			
		||||
	git_submodule *sm;
 | 
			
		||||
	git_config *cfg;
 | 
			
		||||
	git_buf absolute_url = GIT_BUF_INIT;
 | 
			
		||||
	const char *config_url;
 | 
			
		||||
	git_reference *head_ref = NULL;
 | 
			
		||||
	git_object *head_commit = NULL;
 | 
			
		||||
 | 
			
		||||
	g_repo = setup_fixture_submodule_simple();
 | 
			
		||||
 | 
			
		||||
	/* Put the parent repository into a detached head state. */
 | 
			
		||||
	cl_git_pass(git_repository_head(&head_ref, g_repo));
 | 
			
		||||
	cl_git_pass(git_reference_peel(&head_commit, head_ref, GIT_OBJ_COMMIT));
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_repository_set_head_detached(g_repo, git_commit_id((git_commit *)head_commit), NULL, NULL));
 | 
			
		||||
 | 
			
		||||
	cl_assert(git_path_dirname_r(&absolute_url, git_repository_workdir(g_repo)) > 0);
 | 
			
		||||
	cl_git_pass(git_buf_joinpath(&absolute_url, absolute_url.ptr, "testrepo.git"));
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo"));
 | 
			
		||||
 | 
			
		||||
	/* verify that the .gitmodules is set with an absolute path*/
 | 
			
		||||
	cl_assert_equal_s("../testrepo.git", git_submodule_url(sm));
 | 
			
		||||
 | 
			
		||||
	/* init and verify that absolute path is written to .git/config */
 | 
			
		||||
	cl_git_pass(git_submodule_init(sm, false));
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_repository_config(&cfg, g_repo));
 | 
			
		||||
 | 
			
		||||
	git_config_get_string(&config_url, cfg, "submodule.testrepo.url");
 | 
			
		||||
	cl_assert_equal_s(absolute_url.ptr, config_url);
 | 
			
		||||
 | 
			
		||||
	git_buf_free(&absolute_url);
 | 
			
		||||
	git_config_free(cfg);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -49,7 +49,7 @@ void test_submodule_lookup__accessors(void)
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_wd_id(sm), oid) == 0);
 | 
			
		||||
 | 
			
		||||
	cl_assert(git_submodule_ignore(sm) == GIT_SUBMODULE_IGNORE_NONE);
 | 
			
		||||
	cl_assert(git_submodule_update(sm) == GIT_SUBMODULE_UPDATE_CHECKOUT);
 | 
			
		||||
	cl_assert(git_submodule_update_strategy(sm) == GIT_SUBMODULE_UPDATE_CHECKOUT);
 | 
			
		||||
 | 
			
		||||
	git_submodule_free(sm);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -160,7 +160,7 @@ void test_submodule_modify__edit_and_save(void)
 | 
			
		||||
	cl_assert_equal_i(
 | 
			
		||||
		GIT_SUBMODULE_IGNORE_UNTRACKED, git_submodule_ignore(sm1));
 | 
			
		||||
	cl_assert_equal_i(
 | 
			
		||||
		GIT_SUBMODULE_UPDATE_REBASE, git_submodule_update(sm1));
 | 
			
		||||
		GIT_SUBMODULE_UPDATE_REBASE, git_submodule_update_strategy(sm1));
 | 
			
		||||
	cl_assert_equal_i(
 | 
			
		||||
		GIT_SUBMODULE_RECURSE_YES, git_submodule_fetch_recurse_submodules(sm1));
 | 
			
		||||
 | 
			
		||||
@ -179,7 +179,7 @@ void test_submodule_modify__edit_and_save(void)
 | 
			
		||||
	/* check that revert was successful */
 | 
			
		||||
	cl_assert_equal_s(old_url, git_submodule_url(sm1));
 | 
			
		||||
	cl_assert_equal_i((int)old_ignore, (int)git_submodule_ignore(sm1));
 | 
			
		||||
	cl_assert_equal_i((int)old_update, (int)git_submodule_update(sm1));
 | 
			
		||||
	cl_assert_equal_i((int)old_update, (int)git_submodule_update_strategy(sm1));
 | 
			
		||||
	cl_assert_equal_i(
 | 
			
		||||
		old_fetchrecurse, git_submodule_fetch_recurse_submodules(sm1));
 | 
			
		||||
 | 
			
		||||
@ -202,7 +202,7 @@ void test_submodule_modify__edit_and_save(void)
 | 
			
		||||
	cl_assert_equal_i(
 | 
			
		||||
		(int)GIT_SUBMODULE_IGNORE_UNTRACKED, (int)git_submodule_ignore(sm1));
 | 
			
		||||
	cl_assert_equal_i(
 | 
			
		||||
		(int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_update(sm1));
 | 
			
		||||
		(int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_update_strategy(sm1));
 | 
			
		||||
	cl_assert_equal_i(GIT_SUBMODULE_RECURSE_YES, git_submodule_fetch_recurse_submodules(sm1));
 | 
			
		||||
 | 
			
		||||
	/* call reload and check that the new values are loaded */
 | 
			
		||||
@ -212,7 +212,7 @@ void test_submodule_modify__edit_and_save(void)
 | 
			
		||||
	cl_assert_equal_i(
 | 
			
		||||
		(int)GIT_SUBMODULE_IGNORE_UNTRACKED, (int)git_submodule_ignore(sm1));
 | 
			
		||||
	cl_assert_equal_i(
 | 
			
		||||
		(int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_update(sm1));
 | 
			
		||||
		(int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_update_strategy(sm1));
 | 
			
		||||
	cl_assert_equal_i(GIT_SUBMODULE_RECURSE_YES, git_submodule_fetch_recurse_submodules(sm1));
 | 
			
		||||
 | 
			
		||||
	/* open a second copy of the repo and compare submodule */
 | 
			
		||||
@ -223,7 +223,7 @@ void test_submodule_modify__edit_and_save(void)
 | 
			
		||||
	cl_assert_equal_i(
 | 
			
		||||
		GIT_SUBMODULE_IGNORE_UNTRACKED, git_submodule_ignore(sm2));
 | 
			
		||||
	cl_assert_equal_i(
 | 
			
		||||
		GIT_SUBMODULE_UPDATE_REBASE, git_submodule_update(sm2));
 | 
			
		||||
		GIT_SUBMODULE_UPDATE_REBASE, git_submodule_update_strategy(sm2));
 | 
			
		||||
	cl_assert_equal_i(
 | 
			
		||||
		GIT_SUBMODULE_RECURSE_NO, git_submodule_fetch_recurse_submodules(sm2));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										380
									
								
								tests/submodule/update.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										380
									
								
								tests/submodule/update.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,380 @@
 | 
			
		||||
#include "clar_libgit2.h"
 | 
			
		||||
#include "posix.h"
 | 
			
		||||
#include "path.h"
 | 
			
		||||
#include "submodule_helpers.h"
 | 
			
		||||
#include "fileops.h"
 | 
			
		||||
 | 
			
		||||
static git_repository *g_repo = NULL;
 | 
			
		||||
 | 
			
		||||
void test_submodule_update__cleanup(void)
 | 
			
		||||
{
 | 
			
		||||
	cl_git_sandbox_cleanup();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test_submodule_update__unitialized_submodule_no_init(void)
 | 
			
		||||
{
 | 
			
		||||
	git_submodule *sm;
 | 
			
		||||
	git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
 | 
			
		||||
 | 
			
		||||
	g_repo = setup_fixture_submodule_simple();
 | 
			
		||||
 | 
			
		||||
	/* get the submodule */
 | 
			
		||||
	cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo"));
 | 
			
		||||
 | 
			
		||||
	/* updating an unitialized repository throws */
 | 
			
		||||
	cl_git_fail_with(
 | 
			
		||||
		GIT_ERROR,
 | 
			
		||||
		git_submodule_update(sm, 0, &update_options));
 | 
			
		||||
 | 
			
		||||
	git_submodule_free(sm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct update_submodule_cb_payload {
 | 
			
		||||
	int update_tips_called;
 | 
			
		||||
	int checkout_progress_called;
 | 
			
		||||
	int checkout_notify_called;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void checkout_progress_cb(
 | 
			
		||||
	const char *path,
 | 
			
		||||
	size_t completed_steps,
 | 
			
		||||
	size_t total_steps,
 | 
			
		||||
	void *payload)
 | 
			
		||||
{
 | 
			
		||||
	struct update_submodule_cb_payload *update_payload = payload;
 | 
			
		||||
 | 
			
		||||
	GIT_UNUSED(path);
 | 
			
		||||
	GIT_UNUSED(completed_steps);
 | 
			
		||||
	GIT_UNUSED(total_steps);
 | 
			
		||||
 | 
			
		||||
	update_payload->checkout_progress_called = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int 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)
 | 
			
		||||
{
 | 
			
		||||
	struct update_submodule_cb_payload *update_payload = payload;
 | 
			
		||||
 | 
			
		||||
	GIT_UNUSED(why);
 | 
			
		||||
	GIT_UNUSED(path);
 | 
			
		||||
	GIT_UNUSED(baseline);
 | 
			
		||||
	GIT_UNUSED(target);
 | 
			
		||||
	GIT_UNUSED(workdir);
 | 
			
		||||
 | 
			
		||||
	update_payload->checkout_notify_called = 1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int update_tips(const char *refname, const git_oid *a, const git_oid *b, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct update_submodule_cb_payload *update_payload = data;
 | 
			
		||||
 | 
			
		||||
	GIT_UNUSED(refname);
 | 
			
		||||
	GIT_UNUSED(a);
 | 
			
		||||
	GIT_UNUSED(b);
 | 
			
		||||
 | 
			
		||||
	update_payload->update_tips_called = 1;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test_submodule_update__update_submodule(void)
 | 
			
		||||
{
 | 
			
		||||
	git_submodule *sm;
 | 
			
		||||
	git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
 | 
			
		||||
	unsigned int submodule_status = 0;
 | 
			
		||||
	struct update_submodule_cb_payload update_payload = { 0 };
 | 
			
		||||
 | 
			
		||||
	g_repo = setup_fixture_submodule_simple();
 | 
			
		||||
 | 
			
		||||
	update_options.checkout_opts.progress_cb = checkout_progress_cb;
 | 
			
		||||
	update_options.checkout_opts.progress_payload = &update_payload;
 | 
			
		||||
 | 
			
		||||
	update_options.remote_callbacks.update_tips = update_tips;
 | 
			
		||||
	update_options.remote_callbacks.payload = &update_payload;
 | 
			
		||||
 | 
			
		||||
	/* get the submodule */
 | 
			
		||||
	cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo"));
 | 
			
		||||
 | 
			
		||||
	/* verify the initial state of the submodule */
 | 
			
		||||
	cl_git_pass(git_submodule_status(&submodule_status, sm));
 | 
			
		||||
	cl_assert_equal_i(submodule_status, GIT_SUBMODULE_STATUS_IN_HEAD |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_INDEX |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_CONFIG |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_WD_UNINITIALIZED);
 | 
			
		||||
 | 
			
		||||
	/* initialize and update the submodule */
 | 
			
		||||
	cl_git_pass(git_submodule_init(sm, 0));
 | 
			
		||||
	cl_git_pass(git_submodule_update(sm, 0, &update_options));
 | 
			
		||||
 | 
			
		||||
	/* verify state */
 | 
			
		||||
	cl_git_pass(git_submodule_status(&submodule_status, sm));
 | 
			
		||||
	cl_assert_equal_i(submodule_status, GIT_SUBMODULE_STATUS_IN_HEAD |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_INDEX |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_CONFIG |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_WD);
 | 
			
		||||
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_head_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_wd_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_index_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
 | 
			
		||||
	/* verify that the expected callbacks have been called. */
 | 
			
		||||
	cl_assert_equal_i(1, update_payload.checkout_progress_called);
 | 
			
		||||
	cl_assert_equal_i(1, update_payload.update_tips_called);
 | 
			
		||||
 | 
			
		||||
	git_submodule_free(sm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test_submodule_update__update_and_init_submodule(void)
 | 
			
		||||
{
 | 
			
		||||
	git_submodule *sm;
 | 
			
		||||
	git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
 | 
			
		||||
	unsigned int submodule_status = 0;
 | 
			
		||||
 | 
			
		||||
	g_repo = setup_fixture_submodule_simple();
 | 
			
		||||
 | 
			
		||||
	/* get the submodule */
 | 
			
		||||
	cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo"));
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_submodule_status(&submodule_status, sm));
 | 
			
		||||
	cl_assert_equal_i(submodule_status, GIT_SUBMODULE_STATUS_IN_HEAD |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_INDEX |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_CONFIG |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_WD_UNINITIALIZED);
 | 
			
		||||
 | 
			
		||||
	/* update (with option to initialize sub repo) */
 | 
			
		||||
	cl_git_pass(git_submodule_update(sm, 1, &update_options));
 | 
			
		||||
 | 
			
		||||
	/* verify expected state */
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_head_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_wd_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_index_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
 | 
			
		||||
	git_submodule_free(sm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test_submodule_update__update_already_checked_out_submodule(void)
 | 
			
		||||
{
 | 
			
		||||
	git_submodule *sm = NULL;
 | 
			
		||||
	git_checkout_options checkout_options = GIT_CHECKOUT_OPTIONS_INIT;
 | 
			
		||||
	git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
 | 
			
		||||
	unsigned int submodule_status = 0;
 | 
			
		||||
	git_reference *branch_reference = NULL;
 | 
			
		||||
	git_object *branch_commit = NULL;
 | 
			
		||||
	struct update_submodule_cb_payload update_payload = { 0 };
 | 
			
		||||
 | 
			
		||||
	g_repo = setup_fixture_submodule_simple();
 | 
			
		||||
 | 
			
		||||
	update_options.checkout_opts.progress_cb = checkout_progress_cb;
 | 
			
		||||
	update_options.checkout_opts.progress_payload = &update_payload;
 | 
			
		||||
 | 
			
		||||
	/* Initialize and update the sub repository */
 | 
			
		||||
	cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo"));
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_submodule_status(&submodule_status, sm));
 | 
			
		||||
	cl_assert_equal_i(submodule_status, GIT_SUBMODULE_STATUS_IN_HEAD |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_INDEX |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_CONFIG |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_WD_UNINITIALIZED);
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_submodule_update(sm, 1, &update_options));
 | 
			
		||||
 | 
			
		||||
	/* verify expected state */
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_head_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_wd_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_index_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
 | 
			
		||||
	/* checkout the alternate_1 branch */
 | 
			
		||||
	checkout_options.checkout_strategy = GIT_CHECKOUT_SAFE;
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_reference_lookup(&branch_reference, g_repo, "refs/heads/alternate_1"));
 | 
			
		||||
	cl_git_pass(git_reference_peel(&branch_commit, branch_reference, GIT_OBJ_COMMIT));
 | 
			
		||||
	cl_git_pass(git_checkout_tree(g_repo, branch_commit, &checkout_options));
 | 
			
		||||
	cl_git_pass(git_repository_set_head(g_repo, git_reference_name(branch_reference), NULL, NULL));
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Verify state after checkout of parent repository. The submodule ID in the
 | 
			
		||||
	 * HEAD commit and index should be updated, but not the workdir.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_submodule_status(&submodule_status, sm));
 | 
			
		||||
	cl_assert_equal_i(submodule_status, GIT_SUBMODULE_STATUS_IN_HEAD |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_INDEX |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_CONFIG |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_WD |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_WD_MODIFIED);
 | 
			
		||||
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_head_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_wd_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_index_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Update the submodule and verify the state.
 | 
			
		||||
	 * Now, the HEAD, index, and Workdir commits should all be updated to
 | 
			
		||||
	 * the new commit.
 | 
			
		||||
	 */
 | 
			
		||||
	cl_git_pass(git_submodule_update(sm, 0, &update_options));
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_head_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_wd_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_index_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
 | 
			
		||||
 | 
			
		||||
	/* verify that the expected callbacks have been called. */
 | 
			
		||||
	cl_assert_equal_i(1, update_payload.checkout_progress_called);
 | 
			
		||||
	
 | 
			
		||||
	git_submodule_free(sm);
 | 
			
		||||
	git_object_free(branch_commit);
 | 
			
		||||
	git_reference_free(branch_reference);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test_submodule_update__update_blocks_on_dirty_wd(void)
 | 
			
		||||
{
 | 
			
		||||
	git_submodule *sm = NULL;
 | 
			
		||||
	git_checkout_options checkout_options = GIT_CHECKOUT_OPTIONS_INIT;
 | 
			
		||||
	git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
 | 
			
		||||
	unsigned int submodule_status = 0;
 | 
			
		||||
	git_reference *branch_reference = NULL;
 | 
			
		||||
	git_object *branch_commit = NULL;
 | 
			
		||||
	struct update_submodule_cb_payload update_payload = { 0 };
 | 
			
		||||
 | 
			
		||||
	g_repo = setup_fixture_submodule_simple();
 | 
			
		||||
 | 
			
		||||
	update_options.checkout_opts.notify_flags = GIT_CHECKOUT_NOTIFY_CONFLICT;
 | 
			
		||||
	update_options.checkout_opts.notify_cb = checkout_notify_cb;
 | 
			
		||||
	update_options.checkout_opts.notify_payload = &update_payload;
 | 
			
		||||
 | 
			
		||||
	/* Initialize and update the sub repository */
 | 
			
		||||
	cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo"));
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_submodule_status(&submodule_status, sm));
 | 
			
		||||
	cl_assert_equal_i(submodule_status, GIT_SUBMODULE_STATUS_IN_HEAD |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_INDEX |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_CONFIG |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_WD_UNINITIALIZED);
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_submodule_update(sm, 1, &update_options));
 | 
			
		||||
 | 
			
		||||
	/* verify expected state */
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_head_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_wd_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_index_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
 | 
			
		||||
	/* checkout the alternate_1 branch */
 | 
			
		||||
	checkout_options.checkout_strategy = GIT_CHECKOUT_SAFE;
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_reference_lookup(&branch_reference, g_repo, "refs/heads/alternate_1"));
 | 
			
		||||
	cl_git_pass(git_reference_peel(&branch_commit, branch_reference, GIT_OBJ_COMMIT));
 | 
			
		||||
	cl_git_pass(git_checkout_tree(g_repo, branch_commit, &checkout_options));
 | 
			
		||||
	cl_git_pass(git_repository_set_head(g_repo, git_reference_name(branch_reference), NULL, NULL));
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Verify state after checkout of parent repository. The submodule ID in the
 | 
			
		||||
	 * HEAD commit and index should be updated, but not the workdir.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_submodule_status(&submodule_status, sm));
 | 
			
		||||
	cl_assert_equal_i(submodule_status, GIT_SUBMODULE_STATUS_IN_HEAD |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_INDEX |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_CONFIG |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_WD |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_WD_MODIFIED);
 | 
			
		||||
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_head_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_wd_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_index_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Create a conflicting edit in the subrepository to verify that
 | 
			
		||||
	 * the submodule update action is blocked.
 | 
			
		||||
	 */
 | 
			
		||||
	cl_git_write2file("submodule_simple/testrepo/branch_file.txt", "a conflicting edit", 0,
 | 
			
		||||
		O_WRONLY | O_CREAT | O_TRUNC, 0755);
 | 
			
		||||
 | 
			
		||||
	cl_git_fail(git_submodule_update(sm, 0, &update_options));
 | 
			
		||||
 | 
			
		||||
	/* verify that the expected callbacks have been called. */
 | 
			
		||||
	cl_assert_equal_i(1, update_payload.checkout_notify_called);
 | 
			
		||||
 | 
			
		||||
	/* verify that the submodule state has not changed. */
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_head_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_wd_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_index_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
 | 
			
		||||
 | 
			
		||||
	git_submodule_free(sm);
 | 
			
		||||
	git_object_free(branch_commit);
 | 
			
		||||
	git_reference_free(branch_reference);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test_submodule_update__can_force_update(void)
 | 
			
		||||
{
 | 
			
		||||
	git_submodule *sm = NULL;
 | 
			
		||||
	git_checkout_options checkout_options = GIT_CHECKOUT_OPTIONS_INIT;
 | 
			
		||||
	git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
 | 
			
		||||
	unsigned int submodule_status = 0;
 | 
			
		||||
	git_reference *branch_reference = NULL;
 | 
			
		||||
	git_object *branch_commit = NULL;
 | 
			
		||||
 | 
			
		||||
	g_repo = setup_fixture_submodule_simple();
 | 
			
		||||
 | 
			
		||||
	/* Initialize and update the sub repository */
 | 
			
		||||
	cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo"));
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_submodule_status(&submodule_status, sm));
 | 
			
		||||
	cl_assert_equal_i(submodule_status, GIT_SUBMODULE_STATUS_IN_HEAD |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_INDEX |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_CONFIG |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_WD_UNINITIALIZED);
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_submodule_update(sm, 1, &update_options));
 | 
			
		||||
 | 
			
		||||
	/* verify expected state */
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_head_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_wd_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_index_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
 | 
			
		||||
	/* checkout the alternate_1 branch */
 | 
			
		||||
	checkout_options.checkout_strategy = GIT_CHECKOUT_SAFE;
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_reference_lookup(&branch_reference, g_repo, "refs/heads/alternate_1"));
 | 
			
		||||
	cl_git_pass(git_reference_peel(&branch_commit, branch_reference, GIT_OBJ_COMMIT));
 | 
			
		||||
	cl_git_pass(git_checkout_tree(g_repo, branch_commit, &checkout_options));
 | 
			
		||||
	cl_git_pass(git_repository_set_head(g_repo, git_reference_name(branch_reference), NULL, NULL));
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Verify state after checkout of parent repository. The submodule ID in the
 | 
			
		||||
	 * HEAD commit and index should be updated, but not the workdir.
 | 
			
		||||
	 */
 | 
			
		||||
	cl_git_pass(git_submodule_status(&submodule_status, sm));
 | 
			
		||||
	cl_assert_equal_i(submodule_status, GIT_SUBMODULE_STATUS_IN_HEAD |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_INDEX |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_CONFIG |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_IN_WD |
 | 
			
		||||
		GIT_SUBMODULE_STATUS_WD_MODIFIED);
 | 
			
		||||
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_head_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_wd_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_index_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Create a conflicting edit in the subrepository to verify that
 | 
			
		||||
	 * the submodule update action is blocked.
 | 
			
		||||
	 */
 | 
			
		||||
	cl_git_write2file("submodule_simple/testrepo/branch_file.txt", "a conflicting edit", 0,
 | 
			
		||||
		O_WRONLY | O_CREAT | O_TRUNC, 0777);
 | 
			
		||||
 | 
			
		||||
	/* forcefully checkout and verify the submodule state was updated. */
 | 
			
		||||
	update_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
 | 
			
		||||
	cl_git_pass(git_submodule_update(sm, 0, &update_options));
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_head_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_wd_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
 | 
			
		||||
	cl_assert(git_oid_streq(git_submodule_index_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
 | 
			
		||||
 | 
			
		||||
	git_submodule_free(sm);
 | 
			
		||||
	git_object_free(branch_commit);
 | 
			
		||||
	git_reference_free(branch_reference);
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user