mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-03 12:32:19 +00:00
Update remote tips on push
This commit is contained in:
parent
47fc264203
commit
1d645aabef
@ -38,6 +38,15 @@ GIT_EXTERN(int) git_push_new(git_push **out, git_remote *remote);
|
|||||||
*/
|
*/
|
||||||
GIT_EXTERN(int) git_push_add_refspec(git_push *push, const char *refspec);
|
GIT_EXTERN(int) git_push_add_refspec(git_push *push, const char *refspec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update remote tips after a push
|
||||||
|
*
|
||||||
|
* @param push The push object
|
||||||
|
*
|
||||||
|
* @return 0 or an error code
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(int) git_push_update_tips(git_push *push);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actually push all given refspecs
|
* Actually push all given refspecs
|
||||||
*
|
*
|
||||||
|
54
src/push.c
54
src/push.c
@ -161,6 +161,60 @@ int git_push_add_refspec(git_push *push, const char *refspec)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git_push_update_tips(git_push *push)
|
||||||
|
{
|
||||||
|
git_refspec *fetch_spec = &push->remote->fetch;
|
||||||
|
git_buf remote_ref_name = GIT_BUF_INIT;
|
||||||
|
size_t i, j;
|
||||||
|
push_spec *push_spec;
|
||||||
|
git_reference *remote_ref;
|
||||||
|
push_status *status;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
git_vector_foreach(&push->status, i, status) {
|
||||||
|
/* If this ref update was successful (ok, not ng), it will have an empty message */
|
||||||
|
if (status->msg)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Find the corresponding remote ref */
|
||||||
|
if (!git_refspec_src_matches(fetch_spec, status->ref))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((error = git_refspec_transform_r(&remote_ref_name, fetch_spec, status->ref)) < 0)
|
||||||
|
goto on_error;
|
||||||
|
|
||||||
|
/* Find matching push ref spec */
|
||||||
|
git_vector_foreach(&push->specs, j, push_spec) {
|
||||||
|
if (!strcmp(push_spec->rref, status->ref))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Could not find the corresponding push ref spec for this push update */
|
||||||
|
if (j == push->specs.length)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Update the remote ref */
|
||||||
|
if (git_oid_iszero(&push_spec->loid)) {
|
||||||
|
error = git_reference_lookup(&remote_ref, push->remote->repo, git_buf_cstr(&remote_ref_name));
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
if ((error = git_reference_delete(remote_ref)) < 0)
|
||||||
|
goto on_error;
|
||||||
|
} else if (error == GIT_ENOTFOUND)
|
||||||
|
giterr_clear();
|
||||||
|
else
|
||||||
|
goto on_error;
|
||||||
|
} else if ((error = git_reference_create(NULL, push->remote->repo, git_buf_cstr(&remote_ref_name), &push_spec->loid, 1)) < 0)
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = 0;
|
||||||
|
|
||||||
|
on_error:
|
||||||
|
git_buf_free(&remote_ref_name);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
static int revwalk(git_vector *commits, git_push *push)
|
static int revwalk(git_vector *commits, git_push *push)
|
||||||
{
|
{
|
||||||
git_remote_head *head;
|
git_remote_head *head;
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
#include "../submodule/submodule_helpers.h"
|
#include "../submodule/submodule_helpers.h"
|
||||||
#include "push_util.h"
|
#include "push_util.h"
|
||||||
|
#include "refspec.h"
|
||||||
|
#include "remote.h"
|
||||||
|
|
||||||
static git_repository *_repo;
|
static git_repository *_repo;
|
||||||
|
|
||||||
@ -127,6 +129,100 @@ static void verify_refs(git_remote *remote, expected_ref expected_refs[], size_t
|
|||||||
git_vector_free(&actual_refs);
|
git_vector_free(&actual_refs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tracking_branch_list_cb(const char *branch_name, git_branch_t branch_type, void *payload)
|
||||||
|
{
|
||||||
|
git_vector *tracking = (git_vector *)payload;
|
||||||
|
|
||||||
|
if (branch_type == GIT_BRANCH_REMOTE)
|
||||||
|
git_vector_insert(tracking, git__strdup(branch_name));
|
||||||
|
else
|
||||||
|
GIT_UNUSED(branch_name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies that after git_push_update_tips(), remote tracking branches have the expected
|
||||||
|
* names and oids.
|
||||||
|
*
|
||||||
|
* @param remote remote to verify
|
||||||
|
* @param expected_refs expected remote refs after push
|
||||||
|
* @param expected_refs_len length of expected_refs
|
||||||
|
*/
|
||||||
|
static void verify_tracking_branches(git_remote *remote, expected_ref expected_refs[], size_t expected_refs_len)
|
||||||
|
{
|
||||||
|
git_refspec *fetch_spec = &remote->fetch;
|
||||||
|
size_t i, j;
|
||||||
|
git_buf msg = GIT_BUF_INIT;
|
||||||
|
git_buf ref_name = GIT_BUF_INIT;
|
||||||
|
git_buf canonical_ref_name = GIT_BUF_INIT;
|
||||||
|
git_vector actual_refs = GIT_VECTOR_INIT;
|
||||||
|
char *actual_ref;
|
||||||
|
git_oid oid;
|
||||||
|
int failed = 0;
|
||||||
|
|
||||||
|
/* Get current remote branches */
|
||||||
|
cl_git_pass(git_branch_foreach(remote->repo, GIT_BRANCH_REMOTE, tracking_branch_list_cb, &actual_refs));
|
||||||
|
|
||||||
|
/* Loop through expected refs, make sure they exist */
|
||||||
|
for (i = 0; i < expected_refs_len; i++) {
|
||||||
|
|
||||||
|
/* Convert remote reference name into tracking branch name.
|
||||||
|
* If the spec is not under refs/heads/, then skip.
|
||||||
|
*/
|
||||||
|
if (!git_refspec_src_matches(fetch_spec, expected_refs[i].name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cl_git_pass(git_refspec_transform_r(&ref_name, fetch_spec, expected_refs[i].name));
|
||||||
|
|
||||||
|
/* Find matching remote branch */
|
||||||
|
git_vector_foreach(&actual_refs, j, actual_ref) {
|
||||||
|
|
||||||
|
/* Construct canonical ref name from the actual_ref name */
|
||||||
|
git_buf_clear(&canonical_ref_name);
|
||||||
|
cl_git_pass(git_buf_printf(&canonical_ref_name, "refs/remotes/%s", actual_ref));
|
||||||
|
if (!strcmp(git_buf_cstr(&ref_name), git_buf_cstr(&canonical_ref_name)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j == actual_refs.length) {
|
||||||
|
git_buf_printf(&msg, "Did not find expected tracking branch '%s'.", git_buf_cstr(&ref_name));
|
||||||
|
failed = 1;
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure tracking branch is at expected commit ID */
|
||||||
|
cl_git_pass(git_reference_name_to_id(&oid, remote->repo, git_buf_cstr(&canonical_ref_name)));
|
||||||
|
|
||||||
|
if (git_oid_cmp(expected_refs[i].oid, &oid) != 0) {
|
||||||
|
git_buf_puts(&msg, "Tracking branch commit does not match expected ID.");
|
||||||
|
failed = 1;
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
cl_git_pass(git_vector_remove(&actual_refs, j));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure there are no extra branches */
|
||||||
|
if (actual_refs.length > 0) {
|
||||||
|
git_buf_puts(&msg, "Unexpected remote tracking branches exist.");
|
||||||
|
failed = 1;
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
failed:
|
||||||
|
|
||||||
|
if(failed)
|
||||||
|
cl_fail(git_buf_cstr(&msg));
|
||||||
|
|
||||||
|
git_vector_foreach(&actual_refs, i, actual_ref)
|
||||||
|
git__free(actual_ref);
|
||||||
|
|
||||||
|
git_vector_free(&actual_refs);
|
||||||
|
git_buf_free(&msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void test_online_push__initialize(void)
|
void test_online_push__initialize(void)
|
||||||
{
|
{
|
||||||
git_vector delete_specs = GIT_VECTOR_INIT;
|
git_vector delete_specs = GIT_VECTOR_INIT;
|
||||||
@ -265,11 +361,12 @@ static void do_push(const char *refspecs[], size_t refspecs_len,
|
|||||||
|
|
||||||
cl_assert_equal_i(expected_ret, ret);
|
cl_assert_equal_i(expected_ret, ret);
|
||||||
|
|
||||||
git_push_free(push);
|
|
||||||
|
|
||||||
verify_refs(_remote, expected_refs, expected_refs_len);
|
verify_refs(_remote, expected_refs, expected_refs_len);
|
||||||
|
|
||||||
cl_git_pass(git_remote_update_tips(_remote));
|
cl_git_pass(git_push_update_tips(push));
|
||||||
|
verify_tracking_branches(_remote, expected_refs, expected_refs_len);
|
||||||
|
|
||||||
|
git_push_free(push);
|
||||||
|
|
||||||
git_remote_disconnect(_remote);
|
git_remote_disconnect(_remote);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user