Commit 95e517be by Edward Thomson

remote: optionally report unchanged tips

parent 4939fa74
...@@ -77,6 +77,17 @@ typedef enum { ...@@ -77,6 +77,17 @@ typedef enum {
} git_remote_create_flags; } git_remote_create_flags;
/** /**
* How to handle reference updates.
*/
typedef enum {
/* Write the fetch results to FETCH_HEAD. */
GIT_REMOTE_UPDATE_FETCHHEAD = (1 << 0),
/* Report unchanged tips in the update_tips callback. */
GIT_REMOTE_UPDATE_REPORT_UNCHANGED = (1 << 1)
} git_remote_update_flags;
/**
* Remote creation options structure * Remote creation options structure
* *
* Initialize with `GIT_REMOTE_CREATE_OPTIONS_INIT`. Alternatively, you can * Initialize with `GIT_REMOTE_CREATE_OPTIONS_INIT`. Alternatively, you can
...@@ -733,10 +744,10 @@ typedef struct { ...@@ -733,10 +744,10 @@ typedef struct {
git_fetch_prune_t prune; git_fetch_prune_t prune;
/** /**
* Whether to write the results to FETCH_HEAD. Defaults to * How to handle reference updates; a combination of
* on. Leave this default in order to behave like git. * `git_remote_update_flags`.
*/ */
int update_fetchhead; unsigned int update_flags;
/** /**
* Determines how to behave regarding tags on the remote, such * Determines how to behave regarding tags on the remote, such
...@@ -775,8 +786,13 @@ typedef struct { ...@@ -775,8 +786,13 @@ typedef struct {
} git_fetch_options; } git_fetch_options;
#define GIT_FETCH_OPTIONS_VERSION 1 #define GIT_FETCH_OPTIONS_VERSION 1
#define GIT_FETCH_OPTIONS_INIT { GIT_FETCH_OPTIONS_VERSION, GIT_REMOTE_CALLBACKS_INIT, GIT_FETCH_PRUNE_UNSPECIFIED, 1, \ #define GIT_FETCH_OPTIONS_INIT { \
GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, GIT_PROXY_OPTIONS_INIT } GIT_FETCH_OPTIONS_VERSION, \
GIT_REMOTE_CALLBACKS_INIT, \
GIT_FETCH_PRUNE_UNSPECIFIED, \
GIT_REMOTE_UPDATE_FETCHHEAD, \
GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, \
GIT_PROXY_OPTIONS_INIT }
/** /**
* Initialize git_fetch_options structure * Initialize git_fetch_options structure
...@@ -1001,7 +1017,7 @@ GIT_EXTERN(int) git_remote_upload( ...@@ -1001,7 +1017,7 @@ GIT_EXTERN(int) git_remote_upload(
* the name of the remote (or its url, for in-memory remotes). This * the name of the remote (or its url, for in-memory remotes). This
* parameter is ignored when pushing. * parameter is ignored when pushing.
* @param callbacks pointer to the callback structure to use or NULL * @param callbacks pointer to the callback structure to use or NULL
* @param update_fetchhead whether to write to FETCH_HEAD. Pass 1 to behave like git. * @param update_flags the git_remote_update_flags for these tips.
* @param download_tags what the behaviour for downloading tags is for this fetch. This is * @param download_tags what the behaviour for downloading tags is for this fetch. This is
* ignored for push. This must be the same value passed to `git_remote_download()`. * ignored for push. This must be the same value passed to `git_remote_download()`.
* @return 0 or an error code * @return 0 or an error code
...@@ -1009,7 +1025,7 @@ GIT_EXTERN(int) git_remote_upload( ...@@ -1009,7 +1025,7 @@ GIT_EXTERN(int) git_remote_upload(
GIT_EXTERN(int) git_remote_update_tips( GIT_EXTERN(int) git_remote_update_tips(
git_remote *remote, git_remote *remote,
const git_remote_callbacks *callbacks, const git_remote_callbacks *callbacks,
int update_fetchhead, unsigned int update_flags,
git_remote_autotag_option_t download_tags, git_remote_autotag_option_t download_tags,
const char *reflog_message); const char *reflog_message);
......
...@@ -419,7 +419,7 @@ static int clone_into( ...@@ -419,7 +419,7 @@ static int clone_into(
return error; return error;
memcpy(&fetch_opts, opts, sizeof(git_fetch_options)); memcpy(&fetch_opts, opts, sizeof(git_fetch_options));
fetch_opts.update_fetchhead = 0; fetch_opts.update_flags = ~GIT_REMOTE_UPDATE_FETCHHEAD;
if (!opts->depth) if (!opts->depth)
fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
......
...@@ -1348,13 +1348,14 @@ int git_remote_fetch( ...@@ -1348,13 +1348,14 @@ int git_remote_fetch(
const git_fetch_options *opts, const git_fetch_options *opts,
const char *reflog_message) const char *reflog_message)
{ {
int error, update_fetchhead = 1;
git_remote_autotag_option_t tagopt = remote->download_tags; git_remote_autotag_option_t tagopt = remote->download_tags;
bool prune = false; bool prune = false;
git_str reflog_msg_buf = GIT_STR_INIT; git_str reflog_msg_buf = GIT_STR_INIT;
git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT; git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
unsigned int capabilities; unsigned int capabilities;
git_oid_t oid_type; git_oid_t oid_type;
unsigned int update_flags = GIT_REMOTE_UPDATE_FETCHHEAD;
int error;
GIT_ASSERT_ARG(remote); GIT_ASSERT_ARG(remote);
...@@ -1371,7 +1372,7 @@ int git_remote_fetch( ...@@ -1371,7 +1372,7 @@ int git_remote_fetch(
return error; return error;
if (opts) { if (opts) {
update_fetchhead = opts->update_fetchhead; update_flags = opts->update_flags;
tagopt = opts->download_tags; tagopt = opts->download_tags;
} }
...@@ -1398,8 +1399,14 @@ int git_remote_fetch( ...@@ -1398,8 +1399,14 @@ int git_remote_fetch(
} }
/* Create "remote/foo" branches for all remote branches */ /* Create "remote/foo" branches for all remote branches */
error = git_remote_update_tips(remote, &connect_opts.callbacks, update_fetchhead, tagopt, git_str_cstr(&reflog_msg_buf)); error = git_remote_update_tips(remote,
&connect_opts.callbacks,
update_flags,
tagopt,
git_str_cstr(&reflog_msg_buf));
git_str_dispose(&reflog_msg_buf); git_str_dispose(&reflog_msg_buf);
if (error < 0) if (error < 0)
goto done; goto done;
...@@ -1774,6 +1781,7 @@ static int update_one_tip( ...@@ -1774,6 +1781,7 @@ static int update_one_tip(
git_refspec *spec, git_refspec *spec,
git_remote_head *head, git_remote_head *head,
git_refspec *tagspec, git_refspec *tagspec,
unsigned int update_flags,
git_remote_autotag_option_t tagopt, git_remote_autotag_option_t tagopt,
const char *log_message, const char *log_message,
const git_remote_callbacks *callbacks) const git_remote_callbacks *callbacks)
...@@ -1781,7 +1789,7 @@ static int update_one_tip( ...@@ -1781,7 +1789,7 @@ static int update_one_tip(
git_odb *odb; git_odb *odb;
git_str refname = GIT_STR_INIT; git_str refname = GIT_STR_INIT;
git_reference *ref = NULL; git_reference *ref = NULL;
bool autotag = false; bool autotag = false, updated = false;
git_oid old; git_oid old;
int valid; int valid;
int error; int error;
...@@ -1855,21 +1863,21 @@ static int update_one_tip( ...@@ -1855,21 +1863,21 @@ static int update_one_tip(
goto done; goto done;
} }
if (!git_oid__cmp(&old, &head->oid)) if ((updated = !git_oid_equal(&old, &head->oid))) {
goto done; /* In autotag mode, don't overwrite any locally-existing tags */
error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag,
log_message);
/* In autotag mode, don't overwrite any locally-existing tags */ if (error < 0) {
error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag, if (error == GIT_EEXISTS)
log_message); error = 0;
if (error < 0) {
if (error == GIT_EEXISTS)
error = 0;
goto done; goto done;
}
} }
if (callbacks && callbacks->update_tips != NULL && if (callbacks && callbacks->update_tips != NULL &&
(updated || (update_flags & GIT_REMOTE_UPDATE_REPORT_UNCHANGED)) &&
(error = callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload)) < 0) (error = callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload)) < 0)
git_error_set_after_callback_function(error, "git_remote_fetch"); git_error_set_after_callback_function(error, "git_remote_fetch");
...@@ -1882,7 +1890,7 @@ done: ...@@ -1882,7 +1890,7 @@ done:
static int update_tips_for_spec( static int update_tips_for_spec(
git_remote *remote, git_remote *remote,
const git_remote_callbacks *callbacks, const git_remote_callbacks *callbacks,
int update_fetchhead, unsigned int update_flags,
git_remote_autotag_option_t tagopt, git_remote_autotag_option_t tagopt,
git_refspec *spec, git_refspec *spec,
git_vector *refs, git_vector *refs,
...@@ -1905,7 +1913,10 @@ static int update_tips_for_spec( ...@@ -1905,7 +1913,10 @@ static int update_tips_for_spec(
/* Update tips based on the remote heads */ /* Update tips based on the remote heads */
git_vector_foreach(refs, i, head) { git_vector_foreach(refs, i, head) {
if (update_one_tip(&update_heads, remote, spec, head, &tagspec, tagopt, log_message, callbacks) < 0) if (update_one_tip(&update_heads,
remote, spec, head, &tagspec,
update_flags, tagopt, log_message,
callbacks) < 0)
goto on_error; goto on_error;
} }
...@@ -1927,7 +1938,7 @@ static int update_tips_for_spec( ...@@ -1927,7 +1938,7 @@ static int update_tips_for_spec(
goto on_error; goto on_error;
} }
if (update_fetchhead && if ((update_flags & GIT_REMOTE_UPDATE_FETCHHEAD) &&
(error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0) (error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0)
goto on_error; goto on_error;
...@@ -2058,11 +2069,11 @@ static int truncate_fetch_head(const char *gitdir) ...@@ -2058,11 +2069,11 @@ static int truncate_fetch_head(const char *gitdir)
} }
int git_remote_update_tips( int git_remote_update_tips(
git_remote *remote, git_remote *remote,
const git_remote_callbacks *callbacks, const git_remote_callbacks *callbacks,
int update_fetchhead, unsigned int update_flags,
git_remote_autotag_option_t download_tags, git_remote_autotag_option_t download_tags,
const char *reflog_message) const char *reflog_message)
{ {
git_refspec *spec, tagspec; git_refspec *spec, tagspec;
git_vector refs = GIT_VECTOR_INIT; git_vector refs = GIT_VECTOR_INIT;
...@@ -2091,7 +2102,7 @@ int git_remote_update_tips( ...@@ -2091,7 +2102,7 @@ int git_remote_update_tips(
goto out; goto out;
if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_ALL) { if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, &tagspec, &refs, reflog_message)) < 0) if ((error = update_tips_for_spec(remote, callbacks, update_flags, tagopt, &tagspec, &refs, reflog_message)) < 0)
goto out; goto out;
} }
...@@ -2099,7 +2110,7 @@ int git_remote_update_tips( ...@@ -2099,7 +2110,7 @@ int git_remote_update_tips(
if (spec->push) if (spec->push)
continue; continue;
if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, spec, &refs, reflog_message)) < 0) if ((error = update_tips_for_spec(remote, callbacks, update_flags, tagopt, spec, &refs, reflog_message)) < 0)
goto out; goto out;
} }
......
...@@ -128,6 +128,8 @@ void test_online_fetch__doesnt_retrieve_a_pack_when_the_repository_is_up_to_date ...@@ -128,6 +128,8 @@ void test_online_fetch__doesnt_retrieve_a_pack_when_the_repository_is_up_to_date
git_clone_options opts = GIT_CLONE_OPTIONS_INIT; git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
opts.bare = true; opts.bare = true;
counter = 0;
cl_git_pass(git_clone(&_repository, "https://github.com/libgit2/TestGitRepository.git", cl_git_pass(git_clone(&_repository, "https://github.com/libgit2/TestGitRepository.git",
"./fetch/lg2", &opts)); "./fetch/lg2", &opts));
git_repository_free(_repository); git_repository_free(_repository);
...@@ -141,11 +143,52 @@ void test_online_fetch__doesnt_retrieve_a_pack_when_the_repository_is_up_to_date ...@@ -141,11 +143,52 @@ void test_online_fetch__doesnt_retrieve_a_pack_when_the_repository_is_up_to_date
options.callbacks.transfer_progress = &transferProgressCallback; options.callbacks.transfer_progress = &transferProgressCallback;
options.callbacks.payload = &invoked; options.callbacks.payload = &invoked;
options.callbacks.update_tips = update_tips;
cl_git_pass(git_remote_download(remote, NULL, &options)); cl_git_pass(git_remote_download(remote, NULL, &options));
cl_assert_equal_i(false, invoked); cl_assert_equal_i(false, invoked);
cl_git_pass(git_remote_update_tips(remote, &options.callbacks, 1, options.download_tags, NULL)); cl_git_pass(git_remote_update_tips(remote, &options.callbacks, GIT_REMOTE_UPDATE_FETCHHEAD, options.download_tags, NULL));
cl_assert_equal_i(0, counter);
git_remote_disconnect(remote);
git_remote_free(remote);
git_repository_free(_repository);
}
void test_online_fetch__report_unchanged_tips(void)
{
git_repository *_repository;
bool invoked = false;
git_remote *remote;
git_fetch_options options = GIT_FETCH_OPTIONS_INIT;
git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
opts.bare = true;
counter = 0;
cl_git_pass(git_clone(&_repository, "https://github.com/libgit2/TestGitRepository.git",
"./fetch/lg2", &opts));
git_repository_free(_repository);
cl_git_pass(git_repository_open(&_repository, "./fetch/lg2"));
cl_git_pass(git_remote_lookup(&remote, _repository, "origin"));
cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL));
cl_assert_equal_i(false, invoked);
options.callbacks.transfer_progress = &transferProgressCallback;
options.callbacks.payload = &invoked;
options.callbacks.update_tips = update_tips;
cl_git_pass(git_remote_download(remote, NULL, &options));
cl_assert_equal_i(false, invoked);
cl_git_pass(git_remote_update_tips(remote, &options.callbacks, GIT_REMOTE_UPDATE_REPORT_UNCHANGED, options.download_tags, NULL));
cl_assert(counter > 0);
git_remote_disconnect(remote); git_remote_disconnect(remote);
git_remote_free(remote); git_remote_free(remote);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment