mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-03 01:58:32 +00:00
worktree: implement functions reading HEAD
Implement `git_repository_head_for_worktree` and `git_repository_head_detached_for_worktree` for directly accessing a worktree's HEAD without opening it as a `git_repository` first.
This commit is contained in:
parent
f0cfc34105
commit
04fb12abb2
@ -345,6 +345,17 @@ GIT_EXTERN(int) git_repository_init_ext(
|
||||
*/
|
||||
GIT_EXTERN(int) git_repository_head(git_reference **out, git_repository *repo);
|
||||
|
||||
/**
|
||||
* Retrieve the referenced HEAD for the worktree
|
||||
*
|
||||
* @param out pointer to the reference which will be retrieved
|
||||
* @param repo a repository object
|
||||
* @param name name of the worktree to retrieve HEAD for
|
||||
* @return 0 when successful, error-code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_repository_head_for_worktree(git_reference **out, git_repository *repo,
|
||||
const char *name);
|
||||
|
||||
/**
|
||||
* Check if a repository's HEAD is detached
|
||||
*
|
||||
@ -357,6 +368,20 @@ GIT_EXTERN(int) git_repository_head(git_reference **out, git_repository *repo);
|
||||
*/
|
||||
GIT_EXTERN(int) git_repository_head_detached(git_repository *repo);
|
||||
|
||||
/*
|
||||
* Check if a worktree's HEAD is detached
|
||||
*
|
||||
* A worktree's HEAD is detached when it points directly to a
|
||||
* commit instead of a branch.
|
||||
*
|
||||
* @param repo a repository object
|
||||
* @param name name of the worktree to retrieve HEAD for
|
||||
* @return 1 if HEAD is detached, 0 if its not; error code if
|
||||
* there was an error
|
||||
*/
|
||||
GIT_EXTERN(int) git_repository_head_detached_for_worktree(git_repository *repo,
|
||||
const char *name);
|
||||
|
||||
/**
|
||||
* Check if the current branch is unborn
|
||||
*
|
||||
|
@ -77,7 +77,7 @@ GIT_EXTERN(int) git_worktree_validate(const git_worktree *wt);
|
||||
*/
|
||||
GIT_EXTERN(int) git_worktree_add(git_worktree **out, git_repository *repo, const char *name, const char *path);
|
||||
|
||||
/*
|
||||
/**
|
||||
* Lock worktree if not already locked
|
||||
*
|
||||
* Lock a worktree, optionally specifying a reason why the linked
|
||||
|
@ -2032,6 +2032,49 @@ int git_repository_head_detached(git_repository *repo)
|
||||
return exists;
|
||||
}
|
||||
|
||||
static int read_worktree_head(git_buf *out, git_repository *repo, const char *name)
|
||||
{
|
||||
git_buf path = GIT_BUF_INIT;
|
||||
int err;
|
||||
|
||||
assert(out && repo && name);
|
||||
|
||||
git_buf_clear(out);
|
||||
|
||||
if ((err = git_buf_printf(&path, "%s/worktrees/%s/HEAD", repo->commondir, name)) < 0)
|
||||
goto out;
|
||||
if (!git_path_exists(path.ptr))
|
||||
{
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((err = git_futils_readbuffer(out, path.ptr)) < 0)
|
||||
goto out;
|
||||
git_buf_rtrim(out);
|
||||
|
||||
out:
|
||||
git_buf_free(&path);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int git_repository_head_detached_for_worktree(git_repository *repo, const char *name)
|
||||
{
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
int ret;
|
||||
|
||||
assert(repo && name);
|
||||
|
||||
if (read_worktree_head(&buf, repo, name) < 0)
|
||||
return -1;
|
||||
|
||||
ret = git__strncmp(buf.ptr, GIT_SYMREF, strlen(GIT_SYMREF)) != 0;
|
||||
git_buf_free(&buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int git_repository_head(git_reference **head_out, git_repository *repo)
|
||||
{
|
||||
git_reference *head;
|
||||
@ -2051,6 +2094,48 @@ int git_repository_head(git_reference **head_out, git_repository *repo)
|
||||
return error == GIT_ENOTFOUND ? GIT_EUNBORNBRANCH : error;
|
||||
}
|
||||
|
||||
int git_repository_head_for_worktree(git_reference **out, git_repository *repo, const char *name)
|
||||
{
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
git_reference *head;
|
||||
int err;
|
||||
|
||||
assert(out && repo && name);
|
||||
|
||||
*out = NULL;
|
||||
|
||||
if (git_repository_head_detached_for_worktree(repo, name))
|
||||
return -1;
|
||||
if ((err = read_worktree_head(&buf, repo, name)) < 0)
|
||||
goto out;
|
||||
|
||||
/* We can only resolve symbolic references */
|
||||
if (git__strncmp(buf.ptr, GIT_SYMREF, strlen(GIT_SYMREF)))
|
||||
{
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
git_buf_consume(&buf, buf.ptr + strlen(GIT_SYMREF));
|
||||
|
||||
if ((err = git_reference_lookup(&head, repo, buf.ptr)) < 0)
|
||||
goto out;
|
||||
if (git_reference_type(head) == GIT_REF_OID)
|
||||
{
|
||||
*out = head;
|
||||
err = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = git_reference_lookup_resolved(
|
||||
out, repo, git_reference_symbolic_target(head), -1);
|
||||
git_reference_free(head);
|
||||
|
||||
out:
|
||||
git_buf_free(&buf);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int git_repository_head_unborn(git_repository *repo)
|
||||
{
|
||||
git_reference *ref = NULL;
|
||||
|
63
tests/worktree/repository.c
Normal file
63
tests/worktree/repository.c
Normal file
@ -0,0 +1,63 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "worktree_helpers.h"
|
||||
#include "submodule/submodule_helpers.h"
|
||||
|
||||
#include "repository.h"
|
||||
|
||||
#define COMMON_REPO "testrepo"
|
||||
#define WORKTREE_REPO "testrepo-worktree"
|
||||
|
||||
static worktree_fixture fixture =
|
||||
WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO);
|
||||
|
||||
void test_worktree_repository__initialize(void)
|
||||
{
|
||||
setup_fixture_worktree(&fixture);
|
||||
}
|
||||
|
||||
void test_worktree_repository__cleanup(void)
|
||||
{
|
||||
cleanup_fixture_worktree(&fixture);
|
||||
}
|
||||
|
||||
void test_worktree_repository__head(void)
|
||||
{
|
||||
git_reference *ref, *head;
|
||||
|
||||
cl_git_pass(git_reference_lookup(&ref, fixture.repo, "refs/heads/testrepo-worktree"));
|
||||
cl_git_pass(git_repository_head_for_worktree(&head, fixture.repo, "testrepo-worktree"));
|
||||
cl_assert(git_reference_cmp(ref, head) == 0);
|
||||
|
||||
git_reference_free(ref);
|
||||
git_reference_free(head);
|
||||
}
|
||||
|
||||
void test_worktree_repository__head_fails_for_invalid_worktree(void)
|
||||
{
|
||||
git_reference *head = NULL;
|
||||
|
||||
cl_git_fail(git_repository_head_for_worktree(&head, fixture.repo, "invalid"));
|
||||
cl_assert(head == NULL);
|
||||
}
|
||||
|
||||
void test_worktree_repository__head_detached(void)
|
||||
{
|
||||
git_reference *ref, *head;
|
||||
|
||||
cl_git_pass(git_reference_lookup(&ref, fixture.repo, "refs/heads/testrepo-worktree"));
|
||||
cl_git_pass(git_repository_set_head_detached(fixture.worktree, &ref->target.oid));
|
||||
|
||||
cl_assert(git_repository_head_detached(fixture.worktree));
|
||||
cl_assert(git_repository_head_detached_for_worktree(fixture.repo, "testrepo-worktree"));
|
||||
cl_git_fail(git_repository_head_for_worktree(&head, fixture.repo, "testrepo-worktree"));
|
||||
|
||||
git_reference_free(ref);
|
||||
}
|
||||
|
||||
void test_worktree_repository__head_detached_fails_for_invalid_worktree(void)
|
||||
{
|
||||
git_reference *head = NULL;
|
||||
|
||||
cl_git_fail(git_repository_head_detached_for_worktree(fixture.repo, "invalid"));
|
||||
cl_assert(head == NULL);
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "worktree_helpers.h"
|
||||
|
||||
#include "checkout.h"
|
||||
#include "repository.h"
|
||||
#include "worktree.h"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user