mirror of
https://git.proxmox.com/git/libgit2
synced 2026-01-04 16:24:52 +00:00
Merge pull request #949 from nulltoken/topic/deploy_repository_set_head
Deploy git_repository_set_head()
This commit is contained in:
commit
9adfa7d147
@ -148,6 +148,17 @@ GIT_EXTERN(int) git_branch_tracking(
|
||||
git_reference **tracking_out,
|
||||
git_reference *branch);
|
||||
|
||||
/**
|
||||
* Determine if the current local branch is pointed at by HEAD.
|
||||
*
|
||||
* @param branch Current underlying reference of the branch.
|
||||
*
|
||||
* @return 1 if HEAD points at the branch, 0 if it isn't,
|
||||
* error code otherwise.
|
||||
*/
|
||||
GIT_EXTERN(int) git_branch_is_head(
|
||||
git_reference *branch);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
#endif
|
||||
|
||||
52
src/branch.c
52
src/branch.c
@ -92,7 +92,7 @@ cleanup:
|
||||
|
||||
int git_branch_delete(git_reference *branch)
|
||||
{
|
||||
git_reference *head = NULL;
|
||||
int is_head;
|
||||
|
||||
assert(branch);
|
||||
|
||||
@ -102,27 +102,16 @@ int git_branch_delete(git_reference *branch)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (git_reference_lookup(&head, git_reference_owner(branch), GIT_HEAD_FILE) < 0) {
|
||||
giterr_set(GITERR_REFERENCE, "Cannot locate HEAD.");
|
||||
goto on_error;
|
||||
if ((is_head = git_branch_is_head(branch)) < 0)
|
||||
return is_head;
|
||||
|
||||
if (is_head) {
|
||||
giterr_set(GITERR_REFERENCE,
|
||||
"Cannot delete branch '%s' as it is the current HEAD of the repository.", git_reference_name(branch));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((git_reference_type(head) == GIT_REF_SYMBOLIC)
|
||||
&& (strcmp(git_reference_target(head), git_reference_name(branch)) == 0)) {
|
||||
giterr_set(GITERR_REFERENCE,
|
||||
"Cannot delete branch '%s' as it is the current HEAD of the repository.", git_reference_name(branch));
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
if (git_reference_delete(branch) < 0)
|
||||
goto on_error;
|
||||
|
||||
git_reference_free(head);
|
||||
return 0;
|
||||
|
||||
on_error:
|
||||
git_reference_free(head);
|
||||
return -1;
|
||||
return git_reference_delete(branch);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
@ -271,3 +260,26 @@ cleanup:
|
||||
git_buf_free(&buf);
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_branch_is_head(
|
||||
git_reference *branch)
|
||||
{
|
||||
git_reference *head;
|
||||
bool is_same = false;
|
||||
|
||||
assert(branch);
|
||||
|
||||
if (!git_reference_is_branch(branch))
|
||||
return false;
|
||||
|
||||
if (git_repository_head(&head, git_reference_owner(branch)) < 0)
|
||||
return -1;
|
||||
|
||||
is_same = strcmp(
|
||||
git_reference_name(branch),
|
||||
git_reference_name(head)) == 0;
|
||||
|
||||
git_reference_free(head);
|
||||
|
||||
return is_same;
|
||||
}
|
||||
|
||||
285
src/clone.c
285
src/clone.c
@ -22,112 +22,219 @@
|
||||
#include "refs.h"
|
||||
#include "path.h"
|
||||
|
||||
struct HeadInfo {
|
||||
git_repository *repo;
|
||||
git_oid remote_head_oid;
|
||||
git_buf branchname;
|
||||
};
|
||||
|
||||
static int create_tracking_branch(git_repository *repo, const git_oid *target, const char *name)
|
||||
static int create_branch(
|
||||
git_reference **branch,
|
||||
git_repository *repo,
|
||||
const git_oid *target,
|
||||
const char *name)
|
||||
{
|
||||
git_object *head_obj = NULL;
|
||||
git_reference *branch_ref;
|
||||
int retcode = GIT_ERROR;
|
||||
int error;
|
||||
|
||||
/* Find the target commit */
|
||||
if (git_object_lookup(&head_obj, repo, target, GIT_OBJ_ANY) < 0)
|
||||
return GIT_ERROR;
|
||||
if ((error = git_object_lookup(&head_obj, repo, target, GIT_OBJ_ANY)) < 0)
|
||||
return error;
|
||||
|
||||
/* Create the new branch */
|
||||
if (!git_branch_create(&branch_ref, repo, name, head_obj, 0)) {
|
||||
git_config *cfg;
|
||||
|
||||
git_reference_free(branch_ref);
|
||||
/* Set up tracking */
|
||||
if (!git_repository_config(&cfg, repo)) {
|
||||
git_buf remote = GIT_BUF_INIT;
|
||||
git_buf merge = GIT_BUF_INIT;
|
||||
git_buf merge_target = GIT_BUF_INIT;
|
||||
if (!git_buf_printf(&remote, "branch.%s.remote", name) &&
|
||||
!git_buf_printf(&merge, "branch.%s.merge", name) &&
|
||||
!git_buf_printf(&merge_target, "refs/heads/%s", name) &&
|
||||
!git_config_set_string(cfg, git_buf_cstr(&remote), "origin") &&
|
||||
!git_config_set_string(cfg, git_buf_cstr(&merge), git_buf_cstr(&merge_target))) {
|
||||
retcode = 0;
|
||||
}
|
||||
git_buf_free(&remote);
|
||||
git_buf_free(&merge);
|
||||
git_buf_free(&merge_target);
|
||||
git_config_free(cfg);
|
||||
}
|
||||
}
|
||||
error = git_branch_create(&branch_ref, repo, name, head_obj, 0);
|
||||
|
||||
git_object_free(head_obj);
|
||||
return retcode;
|
||||
|
||||
if (!error)
|
||||
*branch = branch_ref;
|
||||
else
|
||||
git_reference_free(branch_ref);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int reference_matches_remote_head(const char *head_name, void *payload)
|
||||
static int setup_tracking_config(
|
||||
git_repository *repo,
|
||||
const char *branch_name,
|
||||
const char *remote_name,
|
||||
const char *merge_target)
|
||||
{
|
||||
struct HeadInfo *head_info = (struct HeadInfo *)payload;
|
||||
git_config *cfg;
|
||||
git_buf remote_key = GIT_BUF_INIT, merge_key = GIT_BUF_INIT;
|
||||
int error = -1;
|
||||
|
||||
if (git_repository_config__weakptr(&cfg, repo) < 0)
|
||||
return -1;
|
||||
|
||||
if (git_buf_printf(&remote_key, "branch.%s.remote", branch_name) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_buf_printf(&merge_key, "branch.%s.merge", branch_name) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_config_set_string(cfg, git_buf_cstr(&remote_key), remote_name) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_config_set_string(cfg, git_buf_cstr(&merge_key), merge_target) < 0)
|
||||
goto cleanup;
|
||||
|
||||
error = 0;
|
||||
|
||||
cleanup:
|
||||
git_buf_free(&remote_key);
|
||||
git_buf_free(&merge_key);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int create_tracking_branch(
|
||||
git_reference **branch,
|
||||
git_repository *repo,
|
||||
const git_oid *target,
|
||||
const char *branch_name)
|
||||
{
|
||||
int error;
|
||||
|
||||
if ((error = create_branch(branch, repo, target, branch_name)) < 0)
|
||||
return error;
|
||||
|
||||
return setup_tracking_config(
|
||||
repo,
|
||||
branch_name,
|
||||
GIT_REMOTE_ORIGIN,
|
||||
git_reference_name(*branch));
|
||||
}
|
||||
|
||||
struct head_info {
|
||||
git_repository *repo;
|
||||
git_oid remote_head_oid;
|
||||
git_buf branchname;
|
||||
const git_refspec *refspec;
|
||||
};
|
||||
|
||||
static int reference_matches_remote_head(
|
||||
const char *reference_name,
|
||||
void *payload)
|
||||
{
|
||||
struct head_info *head_info = (struct head_info *)payload;
|
||||
git_oid oid;
|
||||
|
||||
/* Stop looking if we've already found a match */
|
||||
if (git_buf_len(&head_info->branchname) > 0) return 0;
|
||||
/* TODO: Should we guard against references
|
||||
* which name doesn't start with refs/heads/ ?
|
||||
*/
|
||||
|
||||
if (!git_reference_name_to_oid(&oid, head_info->repo, head_name) &&
|
||||
!git_oid_cmp(&head_info->remote_head_oid, &oid)) {
|
||||
git_buf_puts(&head_info->branchname,
|
||||
head_name+strlen("refs/remotes/origin/"));
|
||||
/* Stop looking if we've already found a match */
|
||||
if (git_buf_len(&head_info->branchname) > 0)
|
||||
return 0;
|
||||
|
||||
if (git_reference_name_to_oid(
|
||||
&oid,
|
||||
head_info->repo,
|
||||
reference_name) < 0) {
|
||||
/* TODO: How to handle not found references?
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (git_oid_cmp(&head_info->remote_head_oid, &oid) == 0) {
|
||||
/* Determine the local reference name from the remote tracking one */
|
||||
if (git_refspec_transform_l(
|
||||
&head_info->branchname,
|
||||
head_info->refspec,
|
||||
reference_name) < 0)
|
||||
return -1;
|
||||
|
||||
if (git_buf_sets(
|
||||
&head_info->branchname,
|
||||
git_buf_cstr(&head_info->branchname) + strlen(GIT_REFS_HEADS_DIR)) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int update_head_to_new_branch(git_repository *repo, const git_oid *target, const char *name)
|
||||
static int update_head_to_new_branch(
|
||||
git_repository *repo,
|
||||
const git_oid *target,
|
||||
const char *name)
|
||||
{
|
||||
int retcode = GIT_ERROR;
|
||||
git_reference *tracking_branch;
|
||||
int error;
|
||||
|
||||
if (!create_tracking_branch(repo, target, name)) {
|
||||
git_reference *head;
|
||||
if (!git_reference_lookup(&head, repo, GIT_HEAD_FILE)) {
|
||||
git_buf targetbuf = GIT_BUF_INIT;
|
||||
if (!git_buf_printf(&targetbuf, "refs/heads/%s", name)) {
|
||||
retcode = git_reference_set_target(head, git_buf_cstr(&targetbuf));
|
||||
}
|
||||
git_buf_free(&targetbuf);
|
||||
git_reference_free(head);
|
||||
}
|
||||
}
|
||||
if ((error = create_tracking_branch(
|
||||
&tracking_branch,
|
||||
repo,
|
||||
target,
|
||||
name)) < 0)
|
||||
return error;
|
||||
|
||||
return retcode;
|
||||
error = git_repository_set_head(repo, git_reference_name(tracking_branch));
|
||||
|
||||
git_reference_free(tracking_branch);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int update_head_to_remote(git_repository *repo, git_remote *remote)
|
||||
{
|
||||
int retcode = GIT_ERROR;
|
||||
int retcode = -1;
|
||||
git_remote_head *remote_head;
|
||||
git_oid oid;
|
||||
struct HeadInfo head_info;
|
||||
struct head_info head_info;
|
||||
git_buf remote_master_name = GIT_BUF_INIT;
|
||||
|
||||
/* Did we just clone an empty repository? */
|
||||
if (remote->refs.length == 0) {
|
||||
return setup_tracking_config(
|
||||
repo,
|
||||
"master",
|
||||
GIT_REMOTE_ORIGIN,
|
||||
GIT_REFS_HEADS_MASTER_FILE);
|
||||
}
|
||||
|
||||
/* Get the remote's HEAD. This is always the first ref in remote->refs. */
|
||||
remote_head = remote->refs.contents[0];
|
||||
git_oid_cpy(&head_info.remote_head_oid, &remote_head->oid);
|
||||
git_buf_init(&head_info.branchname, 16);
|
||||
head_info.repo = repo;
|
||||
head_info.refspec = git_remote_fetchspec(remote);
|
||||
|
||||
/* Determine the remote tracking reference name from the local master */
|
||||
if (git_refspec_transform_r(
|
||||
&remote_master_name,
|
||||
head_info.refspec,
|
||||
GIT_REFS_HEADS_MASTER_FILE) < 0)
|
||||
return -1;
|
||||
|
||||
/* Check to see if "master" matches the remote head */
|
||||
if (!git_reference_name_to_oid(&oid, repo, "refs/remotes/origin/master") &&
|
||||
!git_oid_cmp(&remote_head->oid, &oid)) {
|
||||
retcode = update_head_to_new_branch(repo, &oid, "master");
|
||||
/* Check to see if the remote HEAD points to the remote master */
|
||||
if (reference_matches_remote_head(git_buf_cstr(&remote_master_name), &head_info) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_buf_len(&head_info.branchname) > 0) {
|
||||
retcode = update_head_to_new_branch(
|
||||
repo,
|
||||
&head_info.remote_head_oid,
|
||||
git_buf_cstr(&head_info.branchname));
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Not master. Check all the other refs. */
|
||||
else if (!git_reference_foreach(repo, GIT_REF_LISTALL,
|
||||
reference_matches_remote_head,
|
||||
&head_info) &&
|
||||
git_buf_len(&head_info.branchname) > 0) {
|
||||
retcode = update_head_to_new_branch(repo, &head_info.remote_head_oid,
|
||||
git_buf_cstr(&head_info.branchname));
|
||||
if (git_reference_foreach(
|
||||
repo,
|
||||
GIT_REF_LISTALL,
|
||||
reference_matches_remote_head,
|
||||
&head_info) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_buf_len(&head_info.branchname) > 0) {
|
||||
retcode = update_head_to_new_branch(
|
||||
repo,
|
||||
&head_info.remote_head_oid,
|
||||
git_buf_cstr(&head_info.branchname));
|
||||
|
||||
goto cleanup;
|
||||
} else {
|
||||
/* TODO: What should we do if nothing has been found?
|
||||
*/
|
||||
}
|
||||
|
||||
cleanup:
|
||||
git_buf_free(&remote_master_name);
|
||||
git_buf_free(&head_info.branchname);
|
||||
return retcode;
|
||||
}
|
||||
@ -150,7 +257,7 @@ static int setup_remotes_and_fetch(git_repository *repo,
|
||||
if (!fetch_stats) fetch_stats = &dummy_stats;
|
||||
|
||||
/* Create the "origin" remote */
|
||||
if (!git_remote_add(&origin, repo, "origin", origin_url)) {
|
||||
if (!git_remote_add(&origin, repo, GIT_REMOTE_ORIGIN, origin_url)) {
|
||||
/* Connect and download everything */
|
||||
if (!git_remote_connect(origin, GIT_DIR_FETCH)) {
|
||||
if (!git_remote_download(origin, &bytes, fetch_stats)) {
|
||||
@ -184,11 +291,14 @@ static bool path_is_okay(const char *path)
|
||||
}
|
||||
|
||||
|
||||
static int clone_internal(git_repository **out,
|
||||
const char *origin_url,
|
||||
const char *path,
|
||||
git_indexer_stats *fetch_stats,
|
||||
int is_bare)
|
||||
static int clone_internal(
|
||||
git_repository **out,
|
||||
const char *origin_url,
|
||||
const char *path,
|
||||
git_indexer_stats *fetch_stats,
|
||||
git_indexer_stats *checkout_stats,
|
||||
git_checkout_opts *checkout_opts,
|
||||
int is_bare)
|
||||
{
|
||||
int retcode = GIT_ERROR;
|
||||
git_repository *repo = NULL;
|
||||
@ -211,6 +321,9 @@ static int clone_internal(git_repository **out,
|
||||
}
|
||||
}
|
||||
|
||||
if (!retcode && !is_bare && !git_repository_head_orphan(repo))
|
||||
retcode = git_checkout_head(*out, checkout_opts, checkout_stats);
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
@ -220,7 +333,15 @@ int git_clone_bare(git_repository **out,
|
||||
git_indexer_stats *fetch_stats)
|
||||
{
|
||||
assert(out && origin_url && dest_path);
|
||||
return clone_internal(out, origin_url, dest_path, fetch_stats, 1);
|
||||
|
||||
return clone_internal(
|
||||
out,
|
||||
origin_url,
|
||||
dest_path,
|
||||
fetch_stats,
|
||||
NULL,
|
||||
NULL,
|
||||
1);
|
||||
}
|
||||
|
||||
|
||||
@ -231,12 +352,14 @@ int git_clone(git_repository **out,
|
||||
git_indexer_stats *checkout_stats,
|
||||
git_checkout_opts *checkout_opts)
|
||||
{
|
||||
int retcode = GIT_ERROR;
|
||||
|
||||
assert(out && origin_url && workdir_path);
|
||||
|
||||
if (!(retcode = clone_internal(out, origin_url, workdir_path, fetch_stats, 0)))
|
||||
retcode = git_checkout_head(*out, checkout_opts, checkout_stats);
|
||||
|
||||
return retcode;
|
||||
return clone_internal(
|
||||
out,
|
||||
origin_url,
|
||||
workdir_path,
|
||||
fetch_stats,
|
||||
checkout_stats,
|
||||
checkout_opts,
|
||||
0);
|
||||
}
|
||||
|
||||
31
src/refs.c
31
src/refs.c
@ -15,6 +15,7 @@
|
||||
#include <git2/tag.h>
|
||||
#include <git2/object.h>
|
||||
#include <git2/oid.h>
|
||||
#include <git2/branch.h>
|
||||
|
||||
GIT__USE_STRMAP;
|
||||
|
||||
@ -1343,9 +1344,7 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
|
||||
unsigned int normalization_flags;
|
||||
git_buf aux_path = GIT_BUF_INIT;
|
||||
char normalized[GIT_REFNAME_MAX];
|
||||
|
||||
const char *head_target = NULL;
|
||||
git_reference *head = NULL;
|
||||
bool should_head_be_updated = false;
|
||||
|
||||
normalization_flags = ref->flags & GIT_REF_SYMBOLIC ?
|
||||
GIT_REF_FORMAT_ALLOW_ONELEVEL
|
||||
@ -1366,6 +1365,12 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
|
||||
if (git_buf_joinpath(&aux_path, ref->owner->path_repository, new_name) < 0)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Check if we have to update HEAD.
|
||||
*/
|
||||
if ((should_head_be_updated = git_branch_is_head(ref)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
/*
|
||||
* Now delete the old ref and remove an possibly existing directory
|
||||
* named `new_name`. Note that using the internal `reference_delete`
|
||||
@ -1390,25 +1395,13 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
|
||||
goto rollback;
|
||||
|
||||
/*
|
||||
* Check if we have to update HEAD.
|
||||
* Update HEAD it was poiting to the reference being renamed.
|
||||
*/
|
||||
if (git_reference_lookup(&head, ref->owner, GIT_HEAD_FILE) < 0) {
|
||||
giterr_set(GITERR_REFERENCE,
|
||||
"Failed to update HEAD after renaming reference");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
head_target = git_reference_target(head);
|
||||
|
||||
if (head_target && !strcmp(head_target, ref->name)) {
|
||||
git_reference_free(head);
|
||||
head = NULL;
|
||||
|
||||
if (git_reference_create_symbolic(&head, ref->owner, "HEAD", new_name, 1) < 0) {
|
||||
if (should_head_be_updated &&
|
||||
git_repository_set_head(ref->owner, new_name) < 0) {
|
||||
giterr_set(GITERR_REFERENCE,
|
||||
"Failed to update HEAD after renaming reference");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1426,12 +1419,10 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
|
||||
/* The reference is no longer packed */
|
||||
ref->flags &= ~GIT_REF_PACKED;
|
||||
|
||||
git_reference_free(head);
|
||||
git_buf_free(&aux_path);
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
git_reference_free(head);
|
||||
git_buf_free(&aux_path);
|
||||
return -1;
|
||||
|
||||
|
||||
@ -194,20 +194,20 @@ int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, con
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_refspec_transform_r(git_buf *out, const git_refspec *spec, const char *name)
|
||||
static int refspec_transform(git_buf *out, const char *from, const char *to, const char *name)
|
||||
{
|
||||
if (git_buf_sets(out, spec->dst) < 0)
|
||||
if (git_buf_sets(out, to) < 0)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* No '*' at the end means that it's mapped to one specific local
|
||||
* No '*' at the end means that it's mapped to one specific
|
||||
* branch, so no actual transformation is needed.
|
||||
*/
|
||||
if (git_buf_len(out) > 0 && out->ptr[git_buf_len(out) - 1] != '*')
|
||||
return 0;
|
||||
|
||||
git_buf_truncate(out, git_buf_len(out) - 1); /* remove trailing '*' */
|
||||
git_buf_puts(out, name + strlen(spec->src) - 1);
|
||||
git_buf_puts(out, name + strlen(from) - 1);
|
||||
|
||||
if (git_buf_oom(out))
|
||||
return -1;
|
||||
@ -215,3 +215,13 @@ int git_refspec_transform_r(git_buf *out, const git_refspec *spec, const char *n
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_refspec_transform_r(git_buf *out, const git_refspec *spec, const char *name)
|
||||
{
|
||||
return refspec_transform(out, spec->src, spec->dst, name);
|
||||
}
|
||||
|
||||
int git_refspec_transform_l(git_buf *out, const git_refspec *spec, const char *name)
|
||||
{
|
||||
return refspec_transform(out, spec->dst, spec->src, name);
|
||||
}
|
||||
|
||||
|
||||
@ -40,4 +40,15 @@ void git_refspec__free(git_refspec *refspec);
|
||||
*/
|
||||
int git_refspec_transform_r(git_buf *out, const git_refspec *spec, const char *name);
|
||||
|
||||
/**
|
||||
* Transform a reference from its target following the refspec's rules,
|
||||
* and writes the results into a git_buf.
|
||||
*
|
||||
* @param out where to store the source name
|
||||
* @param spec the refspec
|
||||
* @param name the name of the reference to transform
|
||||
* @return 0 or error if buffer allocation fails
|
||||
*/
|
||||
int git_refspec_transform_l(git_buf *out, const git_refspec *spec, const char *name);
|
||||
|
||||
#endif
|
||||
|
||||
@ -13,6 +13,8 @@
|
||||
#include "transport.h"
|
||||
#include "repository.h"
|
||||
|
||||
#define GIT_REMOTE_ORIGIN "origin"
|
||||
|
||||
struct git_remote {
|
||||
char *name;
|
||||
char *url;
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
#include "refs.h"
|
||||
#include "filter.h"
|
||||
#include "odb.h"
|
||||
#include "remote.h"
|
||||
|
||||
#define GIT_FILE_CONTENT_PREFIX "gitdir:"
|
||||
|
||||
@ -654,10 +655,10 @@ static int repo_init_create_head(const char *git_dir, const char *ref_name)
|
||||
if (!ref_name)
|
||||
ref_name = GIT_BRANCH_MASTER;
|
||||
|
||||
if (git__prefixcmp(ref_name, "refs/") == 0)
|
||||
if (git__prefixcmp(ref_name, GIT_REFS_DIR) == 0)
|
||||
fmt = "ref: %s\n";
|
||||
else
|
||||
fmt = "ref: refs/heads/%s\n";
|
||||
fmt = "ref: " GIT_REFS_HEADS_DIR "%s\n";
|
||||
|
||||
if (git_filebuf_printf(&ref, fmt, ref_name) < 0 ||
|
||||
git_filebuf_commit(&ref, GIT_REFS_FILE_MODE) < 0)
|
||||
@ -1095,7 +1096,7 @@ static int repo_init_create_origin(git_repository *repo, const char *url)
|
||||
int error;
|
||||
git_remote *remote;
|
||||
|
||||
if (!(error = git_remote_add(&remote, repo, "origin", url))) {
|
||||
if (!(error = git_remote_add(&remote, repo, GIT_REMOTE_ORIGIN, url))) {
|
||||
error = git_remote_save(remote);
|
||||
git_remote_free(remote);
|
||||
}
|
||||
@ -1219,7 +1220,7 @@ int git_repository_is_empty(git_repository *repo)
|
||||
git_reference *head = NULL, *branch = NULL;
|
||||
int error;
|
||||
|
||||
if (git_reference_lookup(&head, repo, "HEAD") < 0)
|
||||
if (git_reference_lookup(&head, repo, GIT_HEAD_FILE) < 0)
|
||||
return -1;
|
||||
|
||||
if (git_reference_type(head) != GIT_REF_SYMBOLIC) {
|
||||
@ -1227,7 +1228,7 @@ int git_repository_is_empty(git_repository *repo)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(git_reference_target(head), "refs/heads/master") != 0) {
|
||||
if (strcmp(git_reference_target(head), GIT_REFS_HEADS_DIR "master") != 0) {
|
||||
git_reference_free(head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ int git_reset(
|
||||
git_tree *tree = NULL;
|
||||
int error = -1;
|
||||
git_checkout_opts opts;
|
||||
git_reference *head = NULL;
|
||||
|
||||
assert(repo && target);
|
||||
assert(reset_type == GIT_RESET_SOFT
|
||||
@ -49,7 +50,10 @@ int git_reset(
|
||||
|
||||
//TODO: Check for unmerged entries
|
||||
|
||||
if (git_reference__update(repo, git_object_id(commit), GIT_HEAD_FILE) < 0)
|
||||
if (git_repository_head(&head, repo) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_reference_set_oid(head, git_object_id(commit)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (reset_type == GIT_RESET_SOFT) {
|
||||
@ -96,6 +100,7 @@ int git_reset(
|
||||
error = 0;
|
||||
|
||||
cleanup:
|
||||
git_reference_free(head);
|
||||
git_object_free(commit);
|
||||
git_index_free(index);
|
||||
git_tree_free(tree);
|
||||
|
||||
@ -28,11 +28,11 @@ static int disambiguate_refname(git_reference **out, git_repository *repo, const
|
||||
|
||||
static const char* formatters[] = {
|
||||
"%s",
|
||||
"refs/%s",
|
||||
"refs/tags/%s",
|
||||
"refs/heads/%s",
|
||||
"refs/remotes/%s",
|
||||
"refs/remotes/%s/HEAD",
|
||||
GIT_REFS_DIR "%s",
|
||||
GIT_REFS_TAGS_DIR "%s",
|
||||
GIT_REFS_HEADS_DIR "%s",
|
||||
GIT_REFS_REMOTES_DIR "%s",
|
||||
GIT_REFS_REMOTES_DIR "%s/" GIT_HEAD_FILE,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -520,7 +520,7 @@ static int handle_grep_syntax(git_object **out, git_repository *repo, const git_
|
||||
|
||||
if (spec_oid == NULL) {
|
||||
// TODO: @carlosmn: The glob should be refs/* but this makes git_revwalk_next() fails
|
||||
if (git_revwalk_push_glob(walk, "refs/heads/*") < 0)
|
||||
if (git_revwalk_push_glob(walk, GIT_REFS_HEADS_DIR "*") < 0)
|
||||
goto cleanup;
|
||||
} else if (git_revwalk_push(walk, spec_oid) < 0)
|
||||
goto cleanup;
|
||||
|
||||
@ -1315,7 +1315,7 @@ static int lookup_head_remote(git_buf *url, git_repository *repo)
|
||||
/* remote should refer to something like refs/remotes/ORIGIN/BRANCH */
|
||||
|
||||
if (git_reference_type(remote) != GIT_REF_SYMBOLIC ||
|
||||
git__prefixcmp(git_reference_target(remote), "refs/remotes/") != 0)
|
||||
git__prefixcmp(git_reference_target(remote), GIT_REFS_REMOTES_DIR) != 0)
|
||||
{
|
||||
giterr_set(GITERR_SUBMODULE,
|
||||
"Cannot resolve relative URL when HEAD is not symbolic");
|
||||
@ -1323,7 +1323,7 @@ static int lookup_head_remote(git_buf *url, git_repository *repo)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
scan = tgt = git_reference_target(remote) + strlen("refs/remotes/");
|
||||
scan = tgt = git_reference_target(remote) + strlen(GIT_REFS_REMOTES_DIR);
|
||||
while (*scan && (*scan != '/' || (scan > tgt && scan[-1] != '\\')))
|
||||
scan++; /* find non-escaped slash to end ORIGIN name */
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#define DO_LOCAL_TEST 0
|
||||
#define DO_LIVE_NETWORK_TESTS 0
|
||||
#define LIVE_REPO_URL "git://github.com/nulltoken/TestGitRepository"
|
||||
#define LIVE_EMPTYREPO_URL "git://github.com/nulltoken/TestEmptyRepository"
|
||||
|
||||
|
||||
static git_repository *g_repo;
|
||||
@ -15,12 +16,11 @@ void test_clone_clone__initialize(void)
|
||||
g_repo = NULL;
|
||||
}
|
||||
|
||||
void test_clone_clone__cleanup(void)
|
||||
static void cleanup_repository(void *path)
|
||||
{
|
||||
if (g_repo) {
|
||||
if (g_repo)
|
||||
git_repository_free(g_repo);
|
||||
g_repo = NULL;
|
||||
}
|
||||
cl_fixture_cleanup((const char *)path);
|
||||
}
|
||||
|
||||
// TODO: This is copy/pasted from network/remotelocal.c.
|
||||
@ -63,7 +63,6 @@ static void build_local_file_url(git_buf *out, const char *fixture)
|
||||
git_buf_free(&path_buf);
|
||||
}
|
||||
|
||||
|
||||
void test_clone_clone__bad_url(void)
|
||||
{
|
||||
/* Clone should clean up the mess if the URL isn't a git repository */
|
||||
@ -73,33 +72,44 @@ void test_clone_clone__bad_url(void)
|
||||
cl_assert(!git_path_exists("./foo.git"));
|
||||
}
|
||||
|
||||
|
||||
void test_clone_clone__local(void)
|
||||
{
|
||||
git_buf src = GIT_BUF_INIT;
|
||||
build_local_file_url(&src, cl_fixture("testrepo.git"));
|
||||
|
||||
#if DO_LOCAL_TEST
|
||||
cl_set_cleanup(&cleanup_repository, "./local");
|
||||
|
||||
cl_git_pass(git_clone(&g_repo, git_buf_cstr(&src), "./local", NULL, NULL, NULL));
|
||||
git_repository_free(g_repo);
|
||||
git_futils_rmdir_r("./local", GIT_DIRREMOVAL_FILES_AND_DIRS);
|
||||
cl_git_pass(git_clone_bare(&g_repo, git_buf_cstr(&src), "./local.git", NULL));
|
||||
git_futils_rmdir_r("./local.git", GIT_DIRREMOVAL_FILES_AND_DIRS);
|
||||
#endif
|
||||
|
||||
git_buf_free(&src);
|
||||
}
|
||||
|
||||
void test_clone_clone__local_bare(void)
|
||||
{
|
||||
git_buf src = GIT_BUF_INIT;
|
||||
build_local_file_url(&src, cl_fixture("testrepo.git"));
|
||||
|
||||
#if DO_LOCAL_TEST
|
||||
cl_set_cleanup(&cleanup_repository, "./local.git");
|
||||
|
||||
cl_git_pass(git_clone_bare(&g_repo, git_buf_cstr(&src), "./local.git", NULL));
|
||||
#endif
|
||||
|
||||
git_buf_free(&src);
|
||||
}
|
||||
|
||||
void test_clone_clone__network_full(void)
|
||||
{
|
||||
#if DO_LIVE_NETWORK_TESTS
|
||||
git_remote *origin;
|
||||
|
||||
cl_set_cleanup(&cleanup_repository, "./test2");
|
||||
|
||||
cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./test2", NULL, NULL, NULL));
|
||||
cl_assert(!git_repository_is_bare(g_repo));
|
||||
cl_git_pass(git_remote_load(&origin, g_repo, "origin"));
|
||||
git_futils_rmdir_r("./test2", GIT_DIRREMOVAL_FILES_AND_DIRS);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -108,32 +118,58 @@ void test_clone_clone__network_bare(void)
|
||||
#if DO_LIVE_NETWORK_TESTS
|
||||
git_remote *origin;
|
||||
|
||||
cl_git_pass(git_clone_bare(&g_repo, LIVE_REPO_URL, "test", NULL));
|
||||
cl_set_cleanup(&cleanup_repository, "./test");
|
||||
|
||||
cl_git_pass(git_clone_bare(&g_repo, LIVE_REPO_URL, "./test", NULL));
|
||||
cl_assert(git_repository_is_bare(g_repo));
|
||||
cl_git_pass(git_remote_load(&origin, g_repo, "origin"));
|
||||
git_futils_rmdir_r("./test", GIT_DIRREMOVAL_FILES_AND_DIRS);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void test_clone_clone__already_exists(void)
|
||||
void test_clone_clone__cope_with_already_existing_directory(void)
|
||||
{
|
||||
#if DO_LIVE_NETWORK_TESTS
|
||||
/* Should pass with existing-but-empty dir */
|
||||
cl_set_cleanup(&cleanup_repository, "./foo");
|
||||
|
||||
p_mkdir("./foo", GIT_DIR_MODE);
|
||||
cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo", NULL, NULL, NULL));
|
||||
git_repository_free(g_repo); g_repo = NULL;
|
||||
git_futils_rmdir_r("./foo", GIT_DIRREMOVAL_FILES_AND_DIRS);
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_clone_clone__fail_when_the_target_is_a_file(void)
|
||||
{
|
||||
cl_set_cleanup(&cleanup_repository, "./foo");
|
||||
|
||||
/* Should fail with a file */
|
||||
cl_git_mkfile("./foo", "Bar!");
|
||||
cl_git_fail(git_clone(&g_repo, LIVE_REPO_URL, "./foo", NULL, NULL, NULL));
|
||||
git_futils_rmdir_r("./foo", GIT_DIRREMOVAL_FILES_AND_DIRS);
|
||||
}
|
||||
|
||||
void test_clone_clone__fail_with_already_existing_but_non_empty_directory(void)
|
||||
{
|
||||
cl_set_cleanup(&cleanup_repository, "./foo");
|
||||
|
||||
/* Should fail with existing-and-nonempty dir */
|
||||
p_mkdir("./foo", GIT_DIR_MODE);
|
||||
cl_git_mkfile("./foo/bar", "Baz!");
|
||||
cl_git_fail(git_clone(&g_repo, LIVE_REPO_URL, "./foo", NULL, NULL, NULL));
|
||||
git_futils_rmdir_r("./foo", GIT_DIRREMOVAL_FILES_AND_DIRS);
|
||||
}
|
||||
|
||||
void test_clone_clone__empty_repository(void)
|
||||
{
|
||||
#if DO_LIVE_NETWORK_TESTS
|
||||
git_reference *head;
|
||||
|
||||
cl_set_cleanup(&cleanup_repository, "./empty");
|
||||
|
||||
cl_git_pass(git_clone(&g_repo, LIVE_EMPTYREPO_URL, "./empty", NULL, NULL, NULL));
|
||||
|
||||
cl_assert_equal_i(true, git_repository_is_empty(g_repo));
|
||||
cl_assert_equal_i(true, git_repository_head_orphan(g_repo));
|
||||
|
||||
cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_FILE));
|
||||
cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head));
|
||||
cl_assert_equal_s("refs/heads/master", git_reference_target(head));
|
||||
|
||||
git_reference_free(head);
|
||||
#endif
|
||||
}
|
||||
|
||||
80
tests-clar/refs/branches/ishead.c
Normal file
80
tests-clar/refs/branches/ishead.c
Normal file
@ -0,0 +1,80 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "refs.h"
|
||||
|
||||
static git_repository *repo;
|
||||
static git_reference *branch;
|
||||
|
||||
void test_refs_branches_ishead__initialize(void)
|
||||
{
|
||||
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
|
||||
}
|
||||
|
||||
void test_refs_branches_ishead__cleanup(void)
|
||||
{
|
||||
git_reference_free(branch);
|
||||
git_repository_free(repo);
|
||||
}
|
||||
|
||||
void test_refs_branches_ishead__can_tell_if_a_branch_is_pointed_at_by_HEAD(void)
|
||||
{
|
||||
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master"));
|
||||
|
||||
cl_assert_equal_i(true, git_branch_is_head(branch));
|
||||
}
|
||||
|
||||
void test_refs_branches_ishead__can_tell_if_a_branch_is_not_pointed_at_by_HEAD(void)
|
||||
{
|
||||
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/br2"));
|
||||
|
||||
cl_assert_equal_i(false, git_branch_is_head(branch));
|
||||
}
|
||||
|
||||
void test_refs_branches_ishead__wont_be_fooled_by_a_non_branch(void)
|
||||
{
|
||||
cl_git_pass(git_reference_lookup(&branch, repo, "refs/tags/e90810b"));
|
||||
|
||||
cl_assert_equal_i(false, git_branch_is_head(branch));
|
||||
}
|
||||
|
||||
/*
|
||||
* $ git init .
|
||||
* Initialized empty Git repository in d:/temp/tempee/.git/
|
||||
*
|
||||
* $ touch a && git add a
|
||||
* $ git commit -m" boom"
|
||||
* [master (root-commit) b47b758] boom
|
||||
* 0 files changed
|
||||
* create mode 100644 a
|
||||
*
|
||||
* $ echo "ref: refs/heads/master" > .git/refs/heads/linked
|
||||
* $ echo "ref: refs/heads/linked" > .git/refs/heads/super
|
||||
* $ echo "ref: refs/heads/super" > .git/HEAD
|
||||
*
|
||||
* $ git branch
|
||||
* linked -> master
|
||||
* * master
|
||||
* super -> master
|
||||
*/
|
||||
void test_refs_branches_ishead__only_direct_references_are_considered(void)
|
||||
{
|
||||
git_reference *linked, *super, *head;
|
||||
|
||||
git_repository_free(repo);
|
||||
repo = cl_git_sandbox_init("testrepo.git");
|
||||
|
||||
cl_git_pass(git_reference_create_symbolic(&linked, repo, "refs/heads/linked", "refs/heads/master", 0));
|
||||
cl_git_pass(git_reference_create_symbolic(&super, repo, "refs/heads/super", "refs/heads/linked", 0));
|
||||
cl_git_pass(git_reference_create_symbolic(&head, repo, GIT_HEAD_FILE, "refs/heads/super", 1));
|
||||
|
||||
cl_assert_equal_i(false, git_branch_is_head(linked));
|
||||
cl_assert_equal_i(false, git_branch_is_head(super));
|
||||
|
||||
cl_git_pass(git_repository_head(&branch, repo));
|
||||
cl_assert_equal_s("refs/heads/master", git_reference_name(branch));
|
||||
|
||||
git_reference_free(linked);
|
||||
git_reference_free(super);
|
||||
git_reference_free(head);
|
||||
cl_git_sandbox_cleanup();
|
||||
repo = NULL;
|
||||
}
|
||||
@ -62,3 +62,16 @@ void test_refs_branches_move__can_force_move_over_an_existing_branch(void)
|
||||
{
|
||||
cl_git_pass(git_branch_move(ref, "master", 1));
|
||||
}
|
||||
|
||||
void test_refs_branches_move__moving_the_branch_pointed_at_by_HEAD_updates_HEAD(void)
|
||||
{
|
||||
git_reference *branch;
|
||||
|
||||
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master"));
|
||||
cl_git_pass(git_branch_move(branch, "master2", 0));
|
||||
git_reference_free(branch);
|
||||
|
||||
cl_git_pass(git_repository_head(&branch, repo));
|
||||
cl_assert_equal_s("refs/heads/master2", git_reference_name(branch));
|
||||
git_reference_free(branch);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user