mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-03 20:02:04 +00:00
remote: add api to guess the remote's default branch
If the remote supports the symref protocol extension, then we return that, otherwise we guess with git's rules.
This commit is contained in:
parent
04865aa05e
commit
d22db24fb7
@ -623,6 +623,24 @@ GIT_EXTERN(int) git_remote_is_valid_name(const char *remote_name);
|
|||||||
*/
|
*/
|
||||||
GIT_EXTERN(int) git_remote_delete(git_remote *remote);
|
GIT_EXTERN(int) git_remote_delete(git_remote *remote);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the name of the remote's default branch
|
||||||
|
*
|
||||||
|
* The default branch of a repository is the branch which HEAD points
|
||||||
|
* to. If the remote does not support reporting this information
|
||||||
|
* directly, it performs the guess as git does; that is, if there are
|
||||||
|
* multiple branches which point to the same commit, the first one is
|
||||||
|
* chosen. If the master branch is a candidate, it wins.
|
||||||
|
*
|
||||||
|
* This function must only be called after connecting.
|
||||||
|
*
|
||||||
|
* @param out the buffern in which to store the reference name
|
||||||
|
* @param remote the remote
|
||||||
|
* @return 0, GIT_ENOTFOUND if the remote does not have any references
|
||||||
|
* or none of them point to HEAD's commit, or an error message.
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(int) git_remote_default_branch(git_buf *out, git_remote *remote);
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
GIT_END_DECL
|
GIT_END_DECL
|
||||||
#endif
|
#endif
|
||||||
|
47
src/remote.c
47
src/remote.c
@ -1885,3 +1885,50 @@ int git_remote_delete(git_remote *remote)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git_remote_default_branch(git_buf *out, git_remote *remote)
|
||||||
|
{
|
||||||
|
const git_remote_head **heads;
|
||||||
|
const git_remote_head *guess = NULL;
|
||||||
|
const git_oid *head_id;
|
||||||
|
size_t heads_len, i;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if ((error = git_remote_ls(&heads, &heads_len, remote)) < 0)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (heads_len == 0)
|
||||||
|
return GIT_ENOTFOUND;
|
||||||
|
|
||||||
|
git_buf_sanitize(out);
|
||||||
|
/* the first one must be HEAD so if that has the symref info, we're done */
|
||||||
|
if (heads[0]->symref_target)
|
||||||
|
return git_buf_puts(out, heads[0]->symref_target);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there's no symref information, we have to look over them
|
||||||
|
* and guess. We return the first match unless the master
|
||||||
|
* branch is a candidate. Then we return the master branch.
|
||||||
|
*/
|
||||||
|
head_id = &heads[0]->oid;
|
||||||
|
|
||||||
|
for (i = 1; i < heads_len; i++) {
|
||||||
|
if (git_oid_cmp(head_id, &heads[i]->oid))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!guess) {
|
||||||
|
guess = heads[i];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!git__strcmp(GIT_REFS_HEADS_MASTER_FILE, heads[i]->name)) {
|
||||||
|
guess = heads[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!guess)
|
||||||
|
return GIT_ENOTFOUND;
|
||||||
|
|
||||||
|
return git_buf_puts(out, guess->name);
|
||||||
|
}
|
||||||
|
50
tests/network/remote/defaultbranch.c
Normal file
50
tests/network/remote/defaultbranch.c
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include "clar_libgit2.h"
|
||||||
|
#include "buffer.h"
|
||||||
|
#include "refspec.h"
|
||||||
|
#include "remote.h"
|
||||||
|
|
||||||
|
static git_remote *g_remote;
|
||||||
|
static git_repository *g_repo_a, *g_repo_b;
|
||||||
|
|
||||||
|
void test_network_remote_defaultbranch__initialize(void)
|
||||||
|
{
|
||||||
|
g_repo_a = cl_git_sandbox_init("testrepo.git");
|
||||||
|
cl_git_pass(git_repository_init(&g_repo_b, "repo-b.git", true));
|
||||||
|
cl_git_pass(git_remote_create(&g_remote, g_repo_b, "origin", git_repository_path(g_repo_a)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_network_remote_defaultbranch__cleanup(void)
|
||||||
|
{
|
||||||
|
git_remote_free(g_remote);
|
||||||
|
git_repository_free(g_repo_b);
|
||||||
|
|
||||||
|
cl_git_sandbox_cleanup();
|
||||||
|
cl_fixture_cleanup("repo-b.git");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assert_default_branch(const char *should)
|
||||||
|
{
|
||||||
|
git_buf name = GIT_BUF_INIT;
|
||||||
|
|
||||||
|
cl_git_pass(git_remote_connect(g_remote, GIT_DIRECTION_FETCH));
|
||||||
|
cl_git_pass(git_remote_default_branch(&name, g_remote));
|
||||||
|
cl_assert_equal_s(should, name.ptr);
|
||||||
|
git_buf_free(&name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_network_remote_defaultbranch__master(void)
|
||||||
|
{
|
||||||
|
assert_default_branch("refs/heads/master");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_network_remote_defaultbranch__master_does_not_win(void)
|
||||||
|
{
|
||||||
|
cl_git_pass(git_repository_set_head(g_repo_a, "refs/heads/not-good", NULL, NULL));
|
||||||
|
assert_default_branch("refs/heads/not-good");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_network_remote_defaultbranch__master_on_detached(void)
|
||||||
|
{
|
||||||
|
cl_git_pass(git_repository_detach_head(g_repo_a, NULL, NULL));
|
||||||
|
assert_default_branch("refs/heads/master");
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user