mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-02 21:34:15 +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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
git_remote_head *head;
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include "vector.h"
|
||||
#include "../submodule/submodule_helpers.h"
|
||||
#include "push_util.h"
|
||||
#include "refspec.h"
|
||||
#include "remote.h"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
git_push_free(push);
|
||||
|
||||
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user