mirror of
https://git.proxmox.com/git/libgit2
synced 2026-01-25 20:27:16 +00:00
Merge remote-tracking branch 'upstream/master' into cmn/host-cert-info
This commit is contained in:
commit
0fef38999a
14
.editorconfig
Normal file
14
.editorconfig
Normal file
@ -0,0 +1,14 @@
|
||||
; Check http://editorconfig.org/ for more informations
|
||||
; Top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
; tab indentation
|
||||
[*]
|
||||
indent_style = tab
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
; 4-column space indentation
|
||||
[*.md]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
@ -51,3 +51,6 @@ v0.21 + 1
|
||||
|
||||
* Add support for refspecs with the asterisk in the middle of a
|
||||
pattern.
|
||||
|
||||
* Introduce git_merge_bases() and the git_oidarray type to expose all
|
||||
merge bases between two commits.
|
||||
|
||||
@ -195,6 +195,8 @@ Here are the bindings to libgit2 that are currently available:
|
||||
* git2r <https://github.com/ropensci/git2r>
|
||||
* Ruby
|
||||
* Rugged <https://github.com/libgit2/rugged>
|
||||
* Rust
|
||||
* git2-rs <https://github.com/alexcrichton/git2-rs>
|
||||
* Vala
|
||||
* libgit2.vapi <https://github.com/apmasell/vapis/blob/master/libgit2.vapi>
|
||||
|
||||
|
||||
@ -236,7 +236,7 @@ static void action_create_tag(tag_state *state)
|
||||
git_signature_free(tagger);
|
||||
}
|
||||
|
||||
static void print_usage()
|
||||
static void print_usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: see `git help tag`\n");
|
||||
exit(1);
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#include "common.h"
|
||||
#include "types.h"
|
||||
#include "oid.h"
|
||||
#include "oidarray.h"
|
||||
#include "checkout.h"
|
||||
#include "index.h"
|
||||
|
||||
@ -320,6 +321,21 @@ GIT_EXTERN(int) git_merge_base(
|
||||
const git_oid *one,
|
||||
const git_oid *two);
|
||||
|
||||
/**
|
||||
* Find merge bases between two commits
|
||||
*
|
||||
* @param out array in which to store the resulting ids
|
||||
* @param repo the repository where the commits exist
|
||||
* @param one one of the commits
|
||||
* @param two the other commit
|
||||
* @return 0 on success, GIT_ENOTFOUND if not found or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_bases(
|
||||
git_oidarray *out,
|
||||
git_repository *repo,
|
||||
const git_oid *one,
|
||||
const git_oid *two);
|
||||
|
||||
/**
|
||||
* Find a merge base given a list of commits
|
||||
*
|
||||
|
||||
40
include/git2/oidarray.h
Normal file
40
include/git2/oidarray.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) the libgit2 contributors. All rights reserved.
|
||||
*
|
||||
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
||||
* a Linking Exception. For full terms see the included COPYING file.
|
||||
*/
|
||||
#ifndef INCLUDE_git_oidarray_h__
|
||||
#define INCLUDE_git_oidarray_h__
|
||||
|
||||
#include "common.h"
|
||||
#include "oid.h"
|
||||
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
/** Array of object ids */
|
||||
typedef struct git_oidarray {
|
||||
git_oid *ids;
|
||||
size_t count;
|
||||
} git_oidarray;
|
||||
|
||||
/**
|
||||
* Free the OID array
|
||||
*
|
||||
* This method must (and must only) be called on `git_oidarray`
|
||||
* objects where the array is allocated by the library. Not doing so,
|
||||
* will result in a memory leak.
|
||||
*
|
||||
* This does not free the `git_oidarray` itself, since the library will
|
||||
* never allocate that object directly itself (it is more commonly embedded
|
||||
* inside another struct or created on the stack).
|
||||
*
|
||||
* @param array git_oidarray from which to free oid data
|
||||
*/
|
||||
GIT_EXTERN(void) git_oidarray_free(git_oidarray *array);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
|
||||
#endif
|
||||
|
||||
@ -384,15 +384,12 @@ GIT_EXTERN(int) git_remote_fetch(
|
||||
const char *reflog_message);
|
||||
|
||||
/**
|
||||
* Return whether a string is a valid remote URL
|
||||
*
|
||||
* @param url the url to check
|
||||
* @return 1 if the url is valid, 0 otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_valid_url(const char *url);
|
||||
|
||||
/**
|
||||
* Return whether the passed URL is supported by this version of the library.
|
||||
* Return whether the library supports a particular URL scheme
|
||||
*
|
||||
* Both the built-in and externally-registered transport lists are
|
||||
* searched for a transport which supports the scheme of the given
|
||||
* URL.
|
||||
*
|
||||
* @param url the url to check
|
||||
* @return 1 if the url is supported, 0 otherwise
|
||||
|
||||
@ -196,6 +196,8 @@ GIT_EXTERN(int) git_repository_init(
|
||||
* looking the "template_path" from the options if set, or the
|
||||
* `init.templatedir` global config if not, or falling back on
|
||||
* "/usr/share/git-core/templates" if it exists.
|
||||
* * GIT_REPOSITORY_INIT_RELATIVE_GITLINK - If an alternate workdir is
|
||||
* specified, use relative paths for the gitdir and core.worktree.
|
||||
*/
|
||||
typedef enum {
|
||||
GIT_REPOSITORY_INIT_BARE = (1u << 0),
|
||||
@ -204,6 +206,7 @@ typedef enum {
|
||||
GIT_REPOSITORY_INIT_MKDIR = (1u << 3),
|
||||
GIT_REPOSITORY_INIT_MKPATH = (1u << 4),
|
||||
GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE = (1u << 5),
|
||||
GIT_REPOSITORY_INIT_RELATIVE_GITLINK = (1u << 6),
|
||||
} git_repository_init_flag_t;
|
||||
|
||||
/**
|
||||
|
||||
@ -470,6 +470,24 @@ GIT_EXTERN(git_submodule_recurse_t) git_submodule_set_fetch_recurse_submodules(
|
||||
*/
|
||||
GIT_EXTERN(int) git_submodule_init(git_submodule *submodule, int overwrite);
|
||||
|
||||
/**
|
||||
* Set up the subrepository for a submodule in preparation for clone.
|
||||
*
|
||||
* This function can be called to init and set up a submodule
|
||||
* repository from a submodule in preparation to clone it from
|
||||
* its remote.
|
||||
*
|
||||
* @param out Output pointer to the created git repository.
|
||||
* @param sm The submodule to create a new subrepository from.
|
||||
* @param use_gitlink Should the workdir contain a gitlink to
|
||||
* the repo in .git/modules vs. repo directly in workdir.
|
||||
* @return 0 on success, <0 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_submodule_repo_init(
|
||||
git_repository **out,
|
||||
const git_submodule *sm,
|
||||
int use_gitlink);
|
||||
|
||||
/**
|
||||
* Copy submodule remote info into submodule repo.
|
||||
*
|
||||
|
||||
@ -44,7 +44,5 @@ export GITTEST_REMOTE_SSH_PASSPHRASE=""
|
||||
|
||||
if [ -e ./libgit2_clar ]; then
|
||||
./libgit2_clar -sonline::push -sonline::clone::cred_callback -sonline::clone::ssh_cert &&
|
||||
rm -rf $HOME/_temp/test.git &&
|
||||
git init --bare $HOME/_temp/test.git && # create an empty one
|
||||
./libgit2_clar -sonline::clone::ssh_with_paths
|
||||
fi
|
||||
|
||||
@ -316,7 +316,6 @@ static int blame_internal(git_blame *blame)
|
||||
ent->suspect = o;
|
||||
|
||||
blame->ent = ent;
|
||||
blame->path = blame->path;
|
||||
|
||||
git_blame__like_git(blame, blame->options.flags);
|
||||
|
||||
|
||||
49
src/clone.c
49
src/clone.c
@ -144,9 +144,9 @@ static int update_head_to_remote(
|
||||
const git_signature *signature,
|
||||
const char *reflog_message)
|
||||
{
|
||||
int error = 0, found_branch = 0;
|
||||
int error = 0;
|
||||
size_t refs_len;
|
||||
git_refspec dummy_spec, *refspec;
|
||||
git_refspec *refspec;
|
||||
const git_remote_head *remote_head, **refs;
|
||||
const git_oid *remote_head_id;
|
||||
git_buf remote_master_name = GIT_BUF_INIT;
|
||||
@ -155,28 +155,30 @@ static int update_head_to_remote(
|
||||
if ((error = git_remote_ls(&refs, &refs_len, remote)) < 0)
|
||||
return error;
|
||||
|
||||
/* Did we just clone an empty repository? */
|
||||
if (refs_len == 0)
|
||||
/* We cloned an empty repository or one with an unborn HEAD */
|
||||
if (refs_len == 0 || strcmp(refs[0]->name, GIT_HEAD_FILE))
|
||||
return setup_tracking_config(
|
||||
repo, "master", GIT_REMOTE_ORIGIN, GIT_REFS_HEADS_MASTER_FILE);
|
||||
|
||||
error = git_remote_default_branch(&branch, remote);
|
||||
if (error == GIT_ENOTFOUND) {
|
||||
git_buf_puts(&branch, GIT_REFS_HEADS_MASTER_FILE);
|
||||
} else {
|
||||
found_branch = 1;
|
||||
}
|
||||
|
||||
/* Get the remote's HEAD. This is always the first ref in the list. */
|
||||
/* We know we have HEAD, let's see where it points */
|
||||
remote_head = refs[0];
|
||||
assert(remote_head);
|
||||
|
||||
remote_head_id = &remote_head->oid;
|
||||
|
||||
error = git_remote_default_branch(&branch, remote);
|
||||
if (error == GIT_ENOTFOUND) {
|
||||
error = git_repository_set_head_detached(
|
||||
repo, remote_head_id, signature, reflog_message);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
refspec = git_remote__matching_refspec(remote, git_buf_cstr(&branch));
|
||||
|
||||
if (refspec == NULL) {
|
||||
memset(&dummy_spec, 0, sizeof(git_refspec));
|
||||
refspec = &dummy_spec;
|
||||
giterr_set(GITERR_NET, "the remote's default branch does not fit the refspec configuration");
|
||||
error = GIT_EINVALIDSPEC;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Determine the remote tracking reference name from the local master */
|
||||
@ -184,21 +186,18 @@ static int update_head_to_remote(
|
||||
&remote_master_name,
|
||||
refspec,
|
||||
git_buf_cstr(&branch))) < 0)
|
||||
return error;
|
||||
goto cleanup;
|
||||
|
||||
if (found_branch) {
|
||||
error = update_head_to_new_branch(
|
||||
repo,
|
||||
remote_head_id,
|
||||
git_buf_cstr(&branch),
|
||||
signature, reflog_message);
|
||||
} else {
|
||||
error = git_repository_set_head_detached(
|
||||
repo, remote_head_id, signature, reflog_message);
|
||||
}
|
||||
error = update_head_to_new_branch(
|
||||
repo,
|
||||
remote_head_id,
|
||||
git_buf_cstr(&branch),
|
||||
signature, reflog_message);
|
||||
|
||||
cleanup:
|
||||
git_buf_free(&remote_master_name);
|
||||
git_buf_free(&branch);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
54
src/merge.c
54
src/merge.c
@ -27,6 +27,7 @@
|
||||
#include "index.h"
|
||||
#include "filebuf.h"
|
||||
#include "config.h"
|
||||
#include "oidarray.h"
|
||||
|
||||
#include "git2/types.h"
|
||||
#include "git2/repository.h"
|
||||
@ -39,6 +40,7 @@
|
||||
#include "git2/signature.h"
|
||||
#include "git2/config.h"
|
||||
#include "git2/tree.h"
|
||||
#include "git2/oidarray.h"
|
||||
#include "git2/sys/index.h"
|
||||
|
||||
#define GIT_MERGE_INDEX_ENTRY_EXISTS(X) ((X).mode != 0)
|
||||
@ -139,7 +141,7 @@ int git_merge_base_octopus(git_oid *out, git_repository *repo, size_t length, co
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_merge_base(git_oid *out, git_repository *repo, const git_oid *one, const git_oid *two)
|
||||
static int merge_bases(git_commit_list **out, git_revwalk **walk_out, git_repository *repo, const git_oid *one, const git_oid *two)
|
||||
{
|
||||
git_revwalk *walk;
|
||||
git_vector list;
|
||||
@ -173,13 +175,63 @@ int git_merge_base(git_oid *out, git_repository *repo, const git_oid *one, const
|
||||
return GIT_ENOTFOUND;
|
||||
}
|
||||
|
||||
*out = result;
|
||||
*walk_out = walk;
|
||||
|
||||
return 0;
|
||||
|
||||
on_error:
|
||||
git_revwalk_free(walk);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int git_merge_base(git_oid *out, git_repository *repo, const git_oid *one, const git_oid *two)
|
||||
{
|
||||
int error;
|
||||
git_revwalk *walk;
|
||||
git_commit_list *result;
|
||||
|
||||
if ((error = merge_bases(&result, &walk, repo, one, two)) < 0)
|
||||
return error;
|
||||
|
||||
git_oid_cpy(out, &result->item->oid);
|
||||
git_commit_list_free(&result);
|
||||
git_revwalk_free(walk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_merge_bases(git_oidarray *out, git_repository *repo, const git_oid *one, const git_oid *two)
|
||||
{
|
||||
int error;
|
||||
git_revwalk *walk;
|
||||
git_commit_list *result, *list;
|
||||
git_array_oid_t array;
|
||||
|
||||
git_array_init(array);
|
||||
|
||||
if ((error = merge_bases(&result, &walk, repo, one, two)) < 0)
|
||||
return error;
|
||||
|
||||
list = result;
|
||||
while (list) {
|
||||
git_oid *id = git_array_alloc(array);
|
||||
if (id == NULL)
|
||||
goto on_error;
|
||||
|
||||
git_oid_cpy(id, &list->item->oid);
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
git_oidarray__from_array(out, &array);
|
||||
git_commit_list_free(&result);
|
||||
git_revwalk_free(walk);
|
||||
|
||||
return 0;
|
||||
|
||||
on_error:
|
||||
git_commit_list_free(&result);
|
||||
git_revwalk_free(walk);
|
||||
return -1;
|
||||
}
|
||||
|
||||
21
src/oidarray.c
Normal file
21
src/oidarray.c
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) the libgit2 contributors. All rights reserved.
|
||||
*
|
||||
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
||||
* a Linking Exception. For full terms see the included COPYING file.
|
||||
*/
|
||||
|
||||
#include "git2/oidarray.h"
|
||||
#include "oidarray.h"
|
||||
#include "array.h"
|
||||
|
||||
void git_oidarray_free(git_oidarray *arr)
|
||||
{
|
||||
git__free(arr->ids);
|
||||
}
|
||||
|
||||
void git_oidarray__from_array(git_oidarray *arr, git_array_oid_t *array)
|
||||
{
|
||||
arr->count = array->size;
|
||||
arr->ids = array->ptr;
|
||||
}
|
||||
18
src/oidarray.h
Normal file
18
src/oidarray.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) the libgit2 contributors. All rights reserved.
|
||||
*
|
||||
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
||||
* a Linking Exception. For full terms see the included COPYING file.
|
||||
*/
|
||||
#ifndef INCLUDE_oidarray_h__
|
||||
#define INCLUDE_oidarray_h__
|
||||
|
||||
#include "common.h"
|
||||
#include "git2/oidarray.h"
|
||||
#include "array.h"
|
||||
|
||||
typedef git_array_t(git_oid) git_array_oid_t;
|
||||
|
||||
extern void git_oidarray__from_array(git_oidarray *arr, git_array_oid_t *array);
|
||||
|
||||
#endif
|
||||
@ -648,9 +648,6 @@ int git_packfile_unpack(
|
||||
base_type = elem->type;
|
||||
}
|
||||
|
||||
if (error < 0)
|
||||
goto cleanup;
|
||||
|
||||
switch (base_type) {
|
||||
case GIT_OBJ_COMMIT:
|
||||
case GIT_OBJ_TREE:
|
||||
|
||||
55
src/path.c
55
src/path.c
@ -750,6 +750,61 @@ int git_path_cmp(
|
||||
return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
|
||||
}
|
||||
|
||||
int git_path_make_relative(git_buf *path, const char *parent)
|
||||
{
|
||||
const char *p, *q, *p_dirsep, *q_dirsep;
|
||||
size_t plen = path->size, newlen, depth = 1, i;
|
||||
|
||||
for (p_dirsep = p = path->ptr, q_dirsep = q = parent; *p && *q; p++, q++) {
|
||||
if (*p == '/' && *q == '/') {
|
||||
p_dirsep = p;
|
||||
q_dirsep = q;
|
||||
}
|
||||
else if (*p != *q)
|
||||
break;
|
||||
}
|
||||
|
||||
/* need at least 1 common path segment */
|
||||
if ((p_dirsep == path->ptr || q_dirsep == parent) &&
|
||||
(*p_dirsep != '/' || *q_dirsep != '/')) {
|
||||
giterr_set(GITERR_INVALID,
|
||||
"%s is not a parent of %s", parent, path->ptr);
|
||||
return GIT_ENOTFOUND;
|
||||
}
|
||||
|
||||
if (*p == '/' && !*q)
|
||||
p++;
|
||||
else if (!*p && *q == '/')
|
||||
q++;
|
||||
else if (!*p && !*q)
|
||||
return git_buf_clear(path), 0;
|
||||
else {
|
||||
p = p_dirsep + 1;
|
||||
q = q_dirsep + 1;
|
||||
}
|
||||
|
||||
plen -= (p - path->ptr);
|
||||
|
||||
if (!*q)
|
||||
return git_buf_set(path, p, plen);
|
||||
|
||||
for (; (q = strchr(q, '/')) && *(q + 1); q++)
|
||||
depth++;
|
||||
|
||||
newlen = (depth * 3) + plen;
|
||||
|
||||
if (git_buf_try_grow(path, newlen + 1, 1, 0) < 0)
|
||||
return -1;
|
||||
|
||||
memmove(path->ptr + (depth * 3), p, plen + 1);
|
||||
|
||||
for (i = 0; i < depth; i++)
|
||||
memcpy(path->ptr + (i * 3), "../", 3);
|
||||
|
||||
path->size = newlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool git_path_has_non_ascii(const char *path, size_t pathlen)
|
||||
{
|
||||
const uint8_t *scan = (const uint8_t *)path, *end;
|
||||
|
||||
11
src/path.h
11
src/path.h
@ -196,6 +196,17 @@ extern bool git_path_contains(git_buf *dir, const char *item);
|
||||
*/
|
||||
extern bool git_path_contains_dir(git_buf *parent, const char *subdir);
|
||||
|
||||
/**
|
||||
* Make the path relative to the given parent path.
|
||||
*
|
||||
* @param path The path to make relative
|
||||
* @param parent The parent path to make path relative to
|
||||
* @return 0 if path was made relative, GIT_ENOTFOUND
|
||||
* if there was not common root between the paths,
|
||||
* or <0.
|
||||
*/
|
||||
extern int git_path_make_relative(git_buf *path, const char *parent);
|
||||
|
||||
/**
|
||||
* Check if the given path contains the given file.
|
||||
*
|
||||
|
||||
14
src/remote.c
14
src/remote.c
@ -1058,16 +1058,20 @@ static int update_tips_for_spec(
|
||||
if (autotag && !git_odb_exists(odb, &head->oid))
|
||||
continue;
|
||||
|
||||
if (git_vector_insert(&update_heads, head) < 0)
|
||||
if (!autotag && git_vector_insert(&update_heads, head) < 0)
|
||||
goto on_error;
|
||||
|
||||
error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
|
||||
if (error < 0 && error != GIT_ENOTFOUND)
|
||||
goto on_error;
|
||||
|
||||
if (error == GIT_ENOTFOUND)
|
||||
if (error == GIT_ENOTFOUND) {
|
||||
memset(&old, 0, GIT_OID_RAWSZ);
|
||||
|
||||
if (autotag && git_vector_insert(&update_heads, head) < 0)
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
if (!git_oid__cmp(&old, &head->oid))
|
||||
continue;
|
||||
|
||||
@ -1942,6 +1946,9 @@ int git_remote_default_branch(git_buf *out, git_remote *remote)
|
||||
if (heads_len == 0)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
if (strcmp(heads[0]->name, GIT_HEAD_FILE))
|
||||
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)
|
||||
@ -1958,6 +1965,9 @@ int git_remote_default_branch(git_buf *out, git_remote *remote)
|
||||
if (git_oid_cmp(head_id, &heads[i]->oid))
|
||||
continue;
|
||||
|
||||
if (git__prefixcmp(heads[i]->name, GIT_REFS_HEADS_DIR))
|
||||
continue;
|
||||
|
||||
if (!guess) {
|
||||
guess = heads[i];
|
||||
continue;
|
||||
|
||||
@ -994,7 +994,7 @@ static int repo_init_config(
|
||||
uint32_t mode)
|
||||
{
|
||||
int error = 0;
|
||||
git_buf cfg_path = GIT_BUF_INIT;
|
||||
git_buf cfg_path = GIT_BUF_INIT, worktree_path = GIT_BUF_INIT;
|
||||
git_config *config = NULL;
|
||||
bool is_bare = ((flags & GIT_REPOSITORY_INIT_BARE) != 0);
|
||||
bool is_reinit = ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0);
|
||||
@ -1019,9 +1019,16 @@ static int repo_init_config(
|
||||
if (!is_bare) {
|
||||
SET_REPO_CONFIG(bool, "core.logallrefupdates", true);
|
||||
|
||||
if (!(flags & GIT_REPOSITORY_INIT__NATURAL_WD))
|
||||
SET_REPO_CONFIG(string, "core.worktree", work_dir);
|
||||
else if (is_reinit) {
|
||||
if (!(flags & GIT_REPOSITORY_INIT__NATURAL_WD)) {
|
||||
if ((error = git_buf_sets(&worktree_path, work_dir)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if ((flags & GIT_REPOSITORY_INIT_RELATIVE_GITLINK))
|
||||
if ((error = git_path_make_relative(&worktree_path, repo_dir)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
SET_REPO_CONFIG(string, "core.worktree", worktree_path.ptr);
|
||||
} else if (is_reinit) {
|
||||
if (git_config_delete_entry(config, "core.worktree") < 0)
|
||||
giterr_clear();
|
||||
}
|
||||
@ -1038,6 +1045,7 @@ static int repo_init_config(
|
||||
|
||||
cleanup:
|
||||
git_buf_free(&cfg_path);
|
||||
git_buf_free(&worktree_path);
|
||||
git_config_free(config);
|
||||
|
||||
return error;
|
||||
@ -1126,10 +1134,11 @@ static int repo_write_template(
|
||||
}
|
||||
|
||||
static int repo_write_gitlink(
|
||||
const char *in_dir, const char *to_repo)
|
||||
const char *in_dir, const char *to_repo, bool use_relative_path)
|
||||
{
|
||||
int error;
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
git_buf path_to_repo = GIT_BUF_INIT;
|
||||
struct stat st;
|
||||
|
||||
git_path_dirname_r(&buf, to_repo);
|
||||
@ -1157,13 +1166,20 @@ static int repo_write_gitlink(
|
||||
|
||||
git_buf_clear(&buf);
|
||||
|
||||
error = git_buf_printf(&buf, "%s %s", GIT_FILE_CONTENT_PREFIX, to_repo);
|
||||
error = git_buf_sets(&path_to_repo, to_repo);
|
||||
|
||||
if (!error && use_relative_path)
|
||||
error = git_path_make_relative(&path_to_repo, in_dir);
|
||||
|
||||
if (!error)
|
||||
error = git_buf_join(&buf, ' ', GIT_FILE_CONTENT_PREFIX, path_to_repo.ptr);
|
||||
|
||||
if (!error)
|
||||
error = repo_write_template(in_dir, true, DOT_GIT, 0666, true, buf.ptr);
|
||||
|
||||
cleanup:
|
||||
git_buf_free(&buf);
|
||||
git_buf_free(&path_to_repo);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -1207,7 +1223,7 @@ static int repo_init_structure(
|
||||
if ((opts->flags & GIT_REPOSITORY_INIT_BARE) == 0 &&
|
||||
(opts->flags & GIT_REPOSITORY_INIT__NATURAL_WD) == 0)
|
||||
{
|
||||
if (repo_write_gitlink(work_dir, repo_dir) < 0)
|
||||
if (repo_write_gitlink(work_dir, repo_dir, opts->flags & GIT_REPOSITORY_INIT_RELATIVE_GITLINK) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1635,7 +1651,7 @@ int git_repository_set_workdir(
|
||||
if (git_repository_config__weakptr(&config, repo) < 0)
|
||||
return -1;
|
||||
|
||||
error = repo_write_gitlink(path.ptr, git_repository_path(repo));
|
||||
error = repo_write_gitlink(path.ptr, git_repository_path(repo), false);
|
||||
|
||||
/* passthrough error means gitlink is unnecessary */
|
||||
if (error == GIT_PASSTHROUGH)
|
||||
|
||||
@ -205,7 +205,6 @@ cleanup:
|
||||
static int retrieve_oid_from_reflog(git_oid *oid, git_reference *ref, size_t identifier)
|
||||
{
|
||||
git_reflog *reflog;
|
||||
int error = -1;
|
||||
size_t numentries;
|
||||
const git_reflog_entry *entry;
|
||||
bool search_by_pos = (identifier <= 100000000);
|
||||
@ -216,21 +215,11 @@ static int retrieve_oid_from_reflog(git_oid *oid, git_reference *ref, size_t ide
|
||||
numentries = git_reflog_entrycount(reflog);
|
||||
|
||||
if (search_by_pos) {
|
||||
if (numentries < identifier + 1) {
|
||||
giterr_set(
|
||||
GITERR_REFERENCE,
|
||||
"Reflog for '%s' has only %"PRIuZ" entries, asked for %"PRIuZ,
|
||||
git_reference_name(ref), numentries, identifier);
|
||||
|
||||
error = GIT_ENOTFOUND;
|
||||
goto cleanup;
|
||||
}
|
||||
if (numentries < identifier + 1)
|
||||
goto notfound;
|
||||
|
||||
entry = git_reflog_entry_byindex(reflog, identifier);
|
||||
git_oid_cpy(oid, git_reflog_entry_id_new(entry));
|
||||
error = 0;
|
||||
goto cleanup;
|
||||
|
||||
} else {
|
||||
size_t i;
|
||||
git_time commit_time;
|
||||
@ -243,16 +232,24 @@ static int retrieve_oid_from_reflog(git_oid *oid, git_reference *ref, size_t ide
|
||||
continue;
|
||||
|
||||
git_oid_cpy(oid, git_reflog_entry_id_new(entry));
|
||||
error = 0;
|
||||
goto cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
error = GIT_ENOTFOUND;
|
||||
if (i == numentries)
|
||||
goto notfound;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
git_reflog_free(reflog);
|
||||
return error;
|
||||
return 0;
|
||||
|
||||
notfound:
|
||||
giterr_set(
|
||||
GITERR_REFERENCE,
|
||||
"Reflog for '%s' has only %"PRIuZ" entries, asked for %"PRIuZ,
|
||||
git_reference_name(ref), numentries, identifier);
|
||||
|
||||
git_reflog_free(reflog);
|
||||
return GIT_ENOTFOUND;
|
||||
}
|
||||
|
||||
static int retrieve_revobject_from_reflog(git_object **out, git_reference **base_ref, git_repository *repo, const char *identifier, size_t position)
|
||||
|
||||
@ -70,9 +70,9 @@ int git_signature_new(git_signature **sig_out, const char *name, const char *ema
|
||||
if (p->name == NULL || p->email == NULL)
|
||||
return -1; /* oom */
|
||||
|
||||
if (p->name[0] == '\0') {
|
||||
if (p->name[0] == '\0' || p->email[0] == '\0') {
|
||||
git_signature_free(p);
|
||||
return signature_error("Signature cannot have an empty name");
|
||||
return signature_error("Signature cannot have an empty name or email");
|
||||
}
|
||||
|
||||
p->when.time = time;
|
||||
|
||||
@ -634,7 +634,8 @@ int git_stash_drop(
|
||||
entry = git_reflog_entry_byindex(reflog, 0);
|
||||
|
||||
git_reference_free(stash);
|
||||
if ((error = git_reference_create(&stash, repo, GIT_REFS_STASH_FILE, &entry->oid_cur, 1, NULL, NULL) < 0))
|
||||
error = git_reference_create(&stash, repo, GIT_REFS_STASH_FILE, &entry->oid_cur, 1, NULL, NULL);
|
||||
if (error < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* We need to undo the writing that we just did */
|
||||
|
||||
106
src/submodule.c
106
src/submodule.c
@ -306,6 +306,56 @@ void git_submodule_cache_free(git_repository *repo)
|
||||
submodule_cache_free(cache);
|
||||
}
|
||||
|
||||
static int submodule_repo_init(
|
||||
git_repository **out,
|
||||
git_repository *parent_repo,
|
||||
const char *path,
|
||||
const char *url,
|
||||
bool use_gitlink)
|
||||
{
|
||||
int error = 0;
|
||||
git_buf workdir = GIT_BUF_INIT, repodir = GIT_BUF_INIT;
|
||||
git_repository_init_options initopt = GIT_REPOSITORY_INIT_OPTIONS_INIT;
|
||||
git_repository *subrepo = NULL;
|
||||
|
||||
error = git_buf_joinpath(&workdir, git_repository_workdir(parent_repo), path);
|
||||
if (error < 0)
|
||||
goto cleanup;
|
||||
|
||||
initopt.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_NO_REINIT;
|
||||
initopt.origin_url = url;
|
||||
|
||||
/* init submodule repository and add origin remote as needed */
|
||||
|
||||
/* New style: sub-repo goes in <repo-dir>/modules/<name>/ with a
|
||||
* gitlink in the sub-repo workdir directory to that repository
|
||||
*
|
||||
* Old style: sub-repo goes directly into repo/<name>/.git/
|
||||
*/
|
||||
if (use_gitlink) {
|
||||
error = git_buf_join3(
|
||||
&repodir, '/', git_repository_path(parent_repo), "modules", path);
|
||||
if (error < 0)
|
||||
goto cleanup;
|
||||
|
||||
initopt.workdir_path = workdir.ptr;
|
||||
initopt.flags |=
|
||||
GIT_REPOSITORY_INIT_NO_DOTGIT_DIR |
|
||||
GIT_REPOSITORY_INIT_RELATIVE_GITLINK;
|
||||
|
||||
error = git_repository_init_ext(&subrepo, repodir.ptr, &initopt);
|
||||
} else
|
||||
error = git_repository_init_ext(&subrepo, workdir.ptr, &initopt);
|
||||
|
||||
cleanup:
|
||||
git_buf_free(&workdir);
|
||||
git_buf_free(&repodir);
|
||||
|
||||
*out = subrepo;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_submodule_add_setup(
|
||||
git_submodule **out,
|
||||
git_repository *repo,
|
||||
@ -317,7 +367,6 @@ int git_submodule_add_setup(
|
||||
git_config_backend *mods = NULL;
|
||||
git_submodule *sm = NULL;
|
||||
git_buf name = GIT_BUF_INIT, real_url = GIT_BUF_INIT;
|
||||
git_repository_init_options initopt = GIT_REPOSITORY_INIT_OPTIONS_INIT;
|
||||
git_repository *subrepo = NULL;
|
||||
|
||||
assert(repo && url && path);
|
||||
@ -371,41 +420,14 @@ int git_submodule_add_setup(
|
||||
if (error < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* New style: sub-repo goes in <repo-dir>/modules/<name>/ with a
|
||||
* gitlink in the sub-repo workdir directory to that repository
|
||||
*
|
||||
* Old style: sub-repo goes directly into repo/<name>/.git/
|
||||
/* if the repo does not already exist, then init a new repo and add it.
|
||||
* Otherwise, just add the existing repo.
|
||||
*/
|
||||
|
||||
initopt.flags = GIT_REPOSITORY_INIT_MKPATH |
|
||||
GIT_REPOSITORY_INIT_NO_REINIT;
|
||||
initopt.origin_url = real_url.ptr;
|
||||
|
||||
if (git_path_exists(name.ptr) &&
|
||||
git_path_contains(&name, DOT_GIT))
|
||||
{
|
||||
/* repo appears to already exist - reinit? */
|
||||
}
|
||||
else if (use_gitlink) {
|
||||
git_buf repodir = GIT_BUF_INIT;
|
||||
|
||||
error = git_buf_join3(
|
||||
&repodir, '/', git_repository_path(repo), "modules", path);
|
||||
if (error < 0)
|
||||
if (!(git_path_exists(name.ptr) &&
|
||||
git_path_contains(&name, DOT_GIT))) {
|
||||
if ((error = submodule_repo_init(&subrepo, repo, path, real_url.ptr, use_gitlink)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
initopt.workdir_path = name.ptr;
|
||||
initopt.flags |= GIT_REPOSITORY_INIT_NO_DOTGIT_DIR;
|
||||
|
||||
error = git_repository_init_ext(&subrepo, repodir.ptr, &initopt);
|
||||
|
||||
git_buf_free(&repodir);
|
||||
}
|
||||
else {
|
||||
error = git_repository_init_ext(&subrepo, name.ptr, &initopt);
|
||||
}
|
||||
if (error < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* add submodule to hash and "reload" it */
|
||||
|
||||
@ -437,6 +459,23 @@ cleanup:
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_submodule_repo_init(
|
||||
git_repository **out,
|
||||
const git_submodule *sm,
|
||||
int use_gitlink)
|
||||
{
|
||||
int error;
|
||||
git_repository *sub_repo = NULL;
|
||||
|
||||
assert(out && sm);
|
||||
|
||||
error = submodule_repo_init(&sub_repo, sm->repo, sm->path, sm->url, use_gitlink);
|
||||
|
||||
*out = sub_repo;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_submodule_add_finalize(git_submodule *sm)
|
||||
{
|
||||
int error;
|
||||
@ -1897,6 +1936,7 @@ static void submodule_get_index_status(unsigned int *status, git_submodule *sm)
|
||||
*status |= GIT_SUBMODULE_STATUS_INDEX_MODIFIED;
|
||||
}
|
||||
|
||||
|
||||
static void submodule_get_wd_status(
|
||||
unsigned int *status,
|
||||
git_submodule *sm,
|
||||
|
||||
@ -25,16 +25,13 @@ static git_smart_subtransport_definition ssh_subtransport_definition = { git_sma
|
||||
#endif
|
||||
|
||||
static transport_definition local_transport_definition = { "file://", git_transport_local, NULL };
|
||||
#ifdef GIT_SSH
|
||||
static transport_definition ssh_transport_definition = { "ssh://", git_transport_smart, &ssh_subtransport_definition };
|
||||
#else
|
||||
static transport_definition dummy_transport_definition = { NULL, git_transport_dummy, NULL };
|
||||
#endif
|
||||
|
||||
static transport_definition transports[] = {
|
||||
{ "git://", git_transport_smart, &git_subtransport_definition },
|
||||
{ "http://", git_transport_smart, &http_subtransport_definition },
|
||||
#if defined(GIT_SSL) || defined(GIT_WINHTTP)
|
||||
{ "https://", git_transport_smart, &http_subtransport_definition },
|
||||
#endif
|
||||
{ "file://", git_transport_local, NULL },
|
||||
#ifdef GIT_SSH
|
||||
{ "ssh://", git_transport_smart, &ssh_subtransport_definition },
|
||||
@ -95,11 +92,6 @@ static int transport_find_fn(
|
||||
if (!definition && strrchr(url, ':')) {
|
||||
// re-search transports again with ssh:// as url so that we can find a third party ssh transport
|
||||
definition = transport_find_by_url("ssh://");
|
||||
#ifndef GIT_SSH
|
||||
if (!definition) {
|
||||
definition = &dummy_transport_definition;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef GIT_WIN32
|
||||
@ -121,15 +113,6 @@ static int transport_find_fn(
|
||||
* Public API *
|
||||
**************/
|
||||
|
||||
int git_transport_dummy(git_transport **transport, git_remote *owner, void *param)
|
||||
{
|
||||
GIT_UNUSED(transport);
|
||||
GIT_UNUSED(owner);
|
||||
GIT_UNUSED(param);
|
||||
giterr_set(GITERR_NET, "This transport isn't implemented. Sorry");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int git_transport_new(git_transport **out, git_remote *owner, const char *url)
|
||||
{
|
||||
git_transport_cb fn;
|
||||
@ -229,24 +212,13 @@ done:
|
||||
return error;
|
||||
}
|
||||
|
||||
/* from remote.h */
|
||||
int git_remote_valid_url(const char *url)
|
||||
{
|
||||
git_transport_cb fn;
|
||||
void *param;
|
||||
|
||||
return !transport_find_fn(&fn, url, ¶m);
|
||||
}
|
||||
|
||||
int git_remote_supported_url(const char* url)
|
||||
{
|
||||
git_transport_cb fn;
|
||||
void *param;
|
||||
|
||||
if (transport_find_fn(&fn, url, ¶m) < 0)
|
||||
return 0;
|
||||
|
||||
return fn != &git_transport_dummy;
|
||||
/* The only error we expect is ENOTFOUND */
|
||||
return !transport_find_fn(&fn, url, ¶m);
|
||||
}
|
||||
|
||||
int git_transport_init(git_transport *opts, unsigned int version)
|
||||
|
||||
@ -314,7 +314,7 @@ static int wait_while_ack(gitno_buffer *buf)
|
||||
break;
|
||||
|
||||
if (pkt->type == GIT_PKT_ACK &&
|
||||
(pkt->status != GIT_ACK_CONTINUE ||
|
||||
(pkt->status != GIT_ACK_CONTINUE &&
|
||||
pkt->status != GIT_ACK_COMMON)) {
|
||||
git__free(pkt);
|
||||
return 0;
|
||||
|
||||
@ -292,6 +292,10 @@ static int ssh_agent_auth(LIBSSH2_SESSION *session, git_cred_ssh_key *c) {
|
||||
}
|
||||
|
||||
shutdown:
|
||||
|
||||
if (rc != LIBSSH2_ERROR_NONE)
|
||||
ssh_error(session, "error authenticating");
|
||||
|
||||
libssh2_agent_disconnect(agent);
|
||||
libssh2_agent_free(agent);
|
||||
|
||||
@ -305,6 +309,7 @@ static int _git_ssh_authenticate_session(
|
||||
int rc;
|
||||
|
||||
do {
|
||||
giterr_clear();
|
||||
switch (cred->credtype) {
|
||||
case GIT_CREDTYPE_USERPASS_PLAINTEXT: {
|
||||
git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred;
|
||||
@ -361,7 +366,8 @@ static int _git_ssh_authenticate_session(
|
||||
return GIT_EAUTH;
|
||||
|
||||
if (rc != LIBSSH2_ERROR_NONE) {
|
||||
ssh_error(session, "Failed to authenticate SSH session");
|
||||
if (!giterr_last())
|
||||
ssh_error(session, "Failed to authenticate SSH session");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@ -56,8 +56,8 @@ void test_commit_signature__create_empties(void)
|
||||
|
||||
cl_git_fail(try_build_signature("", "emeric.fermas@gmail.com", 1234567890, 60));
|
||||
cl_git_fail(try_build_signature(" ", "emeric.fermas@gmail.com", 1234567890, 60));
|
||||
cl_git_pass(try_build_signature("nulltoken", "", 1234567890, 60));
|
||||
cl_git_pass(try_build_signature("nulltoken", " ", 1234567890, 60));
|
||||
cl_git_fail(try_build_signature("nulltoken", "", 1234567890, 60));
|
||||
cl_git_fail(try_build_signature("nulltoken", " ", 1234567890, 60));
|
||||
}
|
||||
|
||||
void test_commit_signature__create_one_char(void)
|
||||
|
||||
@ -16,6 +16,11 @@
|
||||
"8f50ba15d49353813cc6e20298002c0d17b0a9ee\tnot-for-merge\ttag 'commit_tree' of git://github.com/libgit2/TestGitRepository\n" \
|
||||
"6e0c7bdb9b4ed93212491ee778ca1c65047cab4e\tnot-for-merge\ttag 'nearly-dangling' of git://github.com/libgit2/TestGitRepository\n"
|
||||
|
||||
#define FETCH_HEAD_WILDCARD_DATA2 \
|
||||
"49322bb17d3acc9146f98c97d078513228bbf3c0\t\tbranch 'master' of git://github.com/libgit2/TestGitRepository\n" \
|
||||
"0966a434eb1a025db6b71485ab63a3bfbea520b6\tnot-for-merge\tbranch 'first-merge' of git://github.com/libgit2/TestGitRepository\n" \
|
||||
"42e4e7c5e507e113ebbb7801b16b52cf867b7ce1\tnot-for-merge\tbranch 'no-parent' of git://github.com/libgit2/TestGitRepository\n" \
|
||||
|
||||
#define FETCH_HEAD_NO_MERGE_DATA \
|
||||
"0966a434eb1a025db6b71485ab63a3bfbea520b6\tnot-for-merge\tbranch 'first-merge' of git://github.com/libgit2/TestGitRepository\n" \
|
||||
"49322bb17d3acc9146f98c97d078513228bbf3c0\tnot-for-merge\tbranch 'master' of git://github.com/libgit2/TestGitRepository\n" \
|
||||
@ -25,6 +30,16 @@
|
||||
"8f50ba15d49353813cc6e20298002c0d17b0a9ee\tnot-for-merge\ttag 'commit_tree' of git://github.com/libgit2/TestGitRepository\n" \
|
||||
"6e0c7bdb9b4ed93212491ee778ca1c65047cab4e\tnot-for-merge\ttag 'nearly-dangling' of git://github.com/libgit2/TestGitRepository\n"
|
||||
|
||||
#define FETCH_HEAD_NO_MERGE_DATA2 \
|
||||
"0966a434eb1a025db6b71485ab63a3bfbea520b6\tnot-for-merge\tbranch 'first-merge' of git://github.com/libgit2/TestGitRepository\n" \
|
||||
"49322bb17d3acc9146f98c97d078513228bbf3c0\tnot-for-merge\tbranch 'master' of git://github.com/libgit2/TestGitRepository\n" \
|
||||
"42e4e7c5e507e113ebbb7801b16b52cf867b7ce1\tnot-for-merge\tbranch 'no-parent' of git://github.com/libgit2/TestGitRepository\n" \
|
||||
|
||||
#define FETCH_HEAD_NO_MERGE_DATA3 \
|
||||
"0966a434eb1a025db6b71485ab63a3bfbea520b6\tnot-for-merge\tbranch 'first-merge' of git://github.com/libgit2/TestGitRepository\n" \
|
||||
"49322bb17d3acc9146f98c97d078513228bbf3c0\tnot-for-merge\tbranch 'master' of git://github.com/libgit2/TestGitRepository\n" \
|
||||
"42e4e7c5e507e113ebbb7801b16b52cf867b7ce1\tnot-for-merge\tbranch 'no-parent' of git://github.com/libgit2/TestGitRepository\n" \
|
||||
"8f50ba15d49353813cc6e20298002c0d17b0a9ee\tnot-for-merge\ttag 'commit_tree' of git://github.com/libgit2/TestGitRepository\n" \
|
||||
|
||||
#define FETCH_HEAD_EXPLICIT_DATA \
|
||||
"0966a434eb1a025db6b71485ab63a3bfbea520b6\t\tbranch 'first-merge' of git://github.com/libgit2/TestGitRepository\n"
|
||||
|
||||
@ -48,3 +48,61 @@ 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");
|
||||
}
|
||||
|
||||
void test_network_remote_defaultbranch__no_default_branch(void)
|
||||
{
|
||||
git_remote *remote_b;
|
||||
const git_remote_head **heads;
|
||||
size_t len;
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
|
||||
cl_git_pass(git_remote_create(&remote_b, g_repo_b, "self", git_repository_path(g_repo_b)));
|
||||
cl_git_pass(git_remote_connect(remote_b, GIT_DIRECTION_FETCH));
|
||||
cl_git_pass(git_remote_ls(&heads, &len, remote_b));
|
||||
cl_assert_equal_i(0, len);
|
||||
|
||||
cl_git_fail_with(GIT_ENOTFOUND, git_remote_default_branch(&buf, remote_b));
|
||||
|
||||
git_remote_free(remote_b);
|
||||
}
|
||||
|
||||
void test_network_remote_defaultbranch__detached_sharing_nonbranch_id(void)
|
||||
{
|
||||
git_oid id, id_cloned;
|
||||
git_reference *ref;
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
git_repository *cloned_repo;
|
||||
|
||||
cl_git_pass(git_reference_name_to_id(&id, g_repo_a, "HEAD"));
|
||||
cl_git_pass(git_repository_detach_head(g_repo_a, NULL, NULL));
|
||||
cl_git_pass(git_reference_remove(g_repo_a, "refs/heads/master"));
|
||||
cl_git_pass(git_reference_remove(g_repo_a, "refs/heads/not-good"));
|
||||
cl_git_pass(git_reference_create(&ref, g_repo_a, "refs/foo/bar", &id, 1, NULL, NULL));
|
||||
git_reference_free(ref);
|
||||
|
||||
cl_git_pass(git_remote_connect(g_remote, GIT_DIRECTION_FETCH));
|
||||
cl_git_fail_with(GIT_ENOTFOUND, git_remote_default_branch(&buf, g_remote));
|
||||
|
||||
cl_git_pass(git_clone(&cloned_repo, git_repository_path(g_repo_a), "./local-detached", NULL));
|
||||
|
||||
cl_assert(git_repository_head_detached(cloned_repo));
|
||||
cl_git_pass(git_reference_name_to_id(&id_cloned, g_repo_a, "HEAD"));
|
||||
cl_assert(git_oid_equal(&id, &id_cloned));
|
||||
|
||||
git_repository_free(cloned_repo);
|
||||
}
|
||||
|
||||
void test_network_remote_defaultbranch__unborn_HEAD_with_branches(void)
|
||||
{
|
||||
git_reference *ref;
|
||||
git_repository *cloned_repo;
|
||||
|
||||
cl_git_pass(git_reference_symbolic_create(&ref, g_repo_a, "HEAD", "refs/heads/i-dont-exist", 1, NULL, NULL));
|
||||
git_reference_free(ref);
|
||||
|
||||
cl_git_pass(git_clone(&cloned_repo, git_repository_path(g_repo_a), "./semi-empty", NULL));
|
||||
|
||||
cl_assert(git_repository_head_unborn(cloned_repo));
|
||||
|
||||
git_repository_free(cloned_repo);
|
||||
}
|
||||
|
||||
@ -91,26 +91,24 @@ void test_network_remote_remotes__error_when_no_push_available(void)
|
||||
git_remote_free(r);
|
||||
}
|
||||
|
||||
void test_network_remote_remotes__parsing_ssh_remote(void)
|
||||
void test_network_remote_remotes__supported_urls(void)
|
||||
{
|
||||
cl_assert( git_remote_valid_url("git@github.com:libgit2/libgit2.git") );
|
||||
}
|
||||
int ssh_supported = 0, https_supported = 0;
|
||||
|
||||
void test_network_remote_remotes__parsing_local_path_fails_if_path_not_found(void)
|
||||
{
|
||||
cl_assert( !git_remote_valid_url("/home/git/repos/libgit2.git") );
|
||||
}
|
||||
|
||||
void test_network_remote_remotes__supported_transport_methods_are_supported(void)
|
||||
{
|
||||
cl_assert( git_remote_supported_url("git://github.com/libgit2/libgit2") );
|
||||
}
|
||||
|
||||
void test_network_remote_remotes__unsupported_transport_methods_are_unsupported(void)
|
||||
{
|
||||
#ifndef GIT_SSH
|
||||
cl_assert( !git_remote_supported_url("git@github.com:libgit2/libgit2.git") );
|
||||
#ifdef GIT_SSH
|
||||
ssh_supported = 1;
|
||||
#endif
|
||||
|
||||
#if defined(GIT_SSL) || defined(GIT_WINHTTP)
|
||||
https_supported = 1;
|
||||
#endif
|
||||
|
||||
cl_assert(git_remote_supported_url("git://github.com/libgit2/libgit2"));
|
||||
cl_assert(git_remote_supported_url("http://github.com/libgit2/libgit2"));
|
||||
|
||||
cl_assert_equal_i(ssh_supported, git_remote_supported_url("git@github.com:libgit2/libgit2.git"));
|
||||
cl_assert_equal_i(ssh_supported, git_remote_supported_url("ssh://git@github.com/libgit2/libgit2.git"));
|
||||
cl_assert_equal_i(https_supported, git_remote_supported_url("https://github.com/libgit2/libgit2.git"));
|
||||
}
|
||||
|
||||
void test_network_remote_remotes__refspec_parsing(void)
|
||||
@ -511,3 +509,53 @@ void test_network_remote_remotes__query_refspecs(void)
|
||||
|
||||
git_remote_free(remote);
|
||||
}
|
||||
|
||||
static int remote_single_branch(git_remote **out, git_repository *repo, const char *name, const char *url, void *payload)
|
||||
{
|
||||
char *fetch_refspecs[] = {
|
||||
"refs/heads/first-merge:refs/remotes/origin/first-merge",
|
||||
};
|
||||
git_strarray fetch_refspecs_strarray = {
|
||||
fetch_refspecs,
|
||||
1,
|
||||
};
|
||||
|
||||
GIT_UNUSED(payload);
|
||||
|
||||
cl_git_pass(git_remote_create(out, repo, name, url));
|
||||
cl_git_pass(git_remote_set_fetch_refspecs(*out, &fetch_refspecs_strarray));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_network_remote_remotes__single_branch(void)
|
||||
{
|
||||
git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
|
||||
git_repository *repo;
|
||||
git_strarray refs;
|
||||
size_t i, count = 0;
|
||||
|
||||
opts.remote_cb = remote_single_branch;
|
||||
opts.checkout_branch = "first-merge";
|
||||
|
||||
cl_git_pass(git_clone(&repo, "git://github.com/libgit2/TestGitRepository", "./single-branch", &opts));
|
||||
cl_git_pass(git_reference_list(&refs, repo));
|
||||
|
||||
for (i = 0; i < refs.count; i++) {
|
||||
if (!git__prefixcmp(refs.strings[i], "refs/heads/"))
|
||||
count++;
|
||||
}
|
||||
cl_assert_equal_i(1, count);
|
||||
|
||||
git_repository_free(repo);
|
||||
}
|
||||
|
||||
void test_network_remote_remotes__restricted_refspecs(void)
|
||||
{
|
||||
git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
|
||||
git_repository *repo;
|
||||
|
||||
opts.remote_cb = remote_single_branch;
|
||||
|
||||
cl_git_fail_with(GIT_EINVALIDSPEC, git_clone(&repo, "git://github.com/libgit2/TestGitRepository", "./restrict-refspec", &opts));
|
||||
}
|
||||
|
||||
@ -384,6 +384,9 @@ void test_online_clone__ssh_auth_methods(void)
|
||||
{
|
||||
int with_user;
|
||||
|
||||
#ifndef GIT_SSH
|
||||
clar__skip();
|
||||
#endif
|
||||
g_options.remote_callbacks.credentials = check_ssh_auth_methods;
|
||||
g_options.remote_callbacks.payload = &with_user;
|
||||
|
||||
@ -436,6 +439,9 @@ void test_online_clone__ssh_with_paths(void)
|
||||
const char *remote_url = cl_getenv("GITTEST_REMOTE_URL");
|
||||
const char *remote_user = cl_getenv("GITTEST_REMOTE_USER");
|
||||
|
||||
#ifndef GIT_SSH
|
||||
clar__skip();
|
||||
#endif
|
||||
if (!remote_url || !remote_user || strncmp(remote_url, "ssh://", 5) != 0)
|
||||
clar__skip();
|
||||
|
||||
@ -459,6 +465,9 @@ static int cred_foo_bar(git_cred **cred, const char *url, const char *username_f
|
||||
|
||||
void test_online_clone__ssh_cannot_change_username(void)
|
||||
{
|
||||
#ifndef GIT_SSH
|
||||
clar__skip();
|
||||
#endif
|
||||
g_options.remote_callbacks.credentials = cred_foo_bar;
|
||||
|
||||
cl_git_fail(git_clone(&g_repo, "ssh://git@github.com/libgit2/TestGitRepository", "./foo", &g_options));
|
||||
|
||||
@ -67,6 +67,11 @@ static void fetchhead_test_fetch(const char *fetchspec, const char *expected_fet
|
||||
void test_online_fetchhead__wildcard_spec(void)
|
||||
{
|
||||
fetchhead_test_clone();
|
||||
fetchhead_test_fetch(NULL, FETCH_HEAD_WILDCARD_DATA2);
|
||||
cl_git_pass(git_tag_delete(g_repo, "annotated_tag"));
|
||||
cl_git_pass(git_tag_delete(g_repo, "blob"));
|
||||
cl_git_pass(git_tag_delete(g_repo, "commit_tree"));
|
||||
cl_git_pass(git_tag_delete(g_repo, "nearly-dangling"));
|
||||
fetchhead_test_fetch(NULL, FETCH_HEAD_WILDCARD_DATA);
|
||||
}
|
||||
|
||||
@ -87,5 +92,12 @@ void test_online_fetchhead__no_merges(void)
|
||||
cl_git_pass(git_config_delete_entry(config, "branch.master.merge"));
|
||||
git_config_free(config);
|
||||
|
||||
fetchhead_test_fetch(NULL, FETCH_HEAD_NO_MERGE_DATA2);
|
||||
cl_git_pass(git_tag_delete(g_repo, "annotated_tag"));
|
||||
cl_git_pass(git_tag_delete(g_repo, "blob"));
|
||||
cl_git_pass(git_tag_delete(g_repo, "commit_tree"));
|
||||
cl_git_pass(git_tag_delete(g_repo, "nearly-dangling"));
|
||||
fetchhead_test_fetch(NULL, FETCH_HEAD_NO_MERGE_DATA);
|
||||
cl_git_pass(git_tag_delete(g_repo, "commit_tree"));
|
||||
fetchhead_test_fetch(NULL, FETCH_HEAD_NO_MERGE_DATA3);
|
||||
}
|
||||
|
||||
@ -864,7 +864,6 @@ void test_online_push__notes(void)
|
||||
push_status exp_stats[] = { { "refs/notes/commits", 1 } };
|
||||
expected_ref exp_refs[] = { { "refs/notes/commits", &expected_oid } };
|
||||
const char *specs_del[] = { ":refs/notes/commits" };
|
||||
expected_ref exp_refs_del[] = { };
|
||||
|
||||
git_oid_fromstr(&expected_oid, "8461a99b27b7043e58ff6e1f5d2cf07d282534fb");
|
||||
|
||||
@ -882,7 +881,7 @@ void test_online_push__notes(void)
|
||||
|
||||
do_push(specs_del, ARRAY_SIZE(specs_del),
|
||||
exp_stats, 1,
|
||||
exp_refs_del, ARRAY_SIZE(exp_refs_del), 0, 0, 0);
|
||||
NULL, 0, 0, 0, 0);
|
||||
|
||||
git_signature_free(signature);
|
||||
}
|
||||
|
||||
55
tests/path/core.c
Normal file
55
tests/path/core.c
Normal file
@ -0,0 +1,55 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "path.h"
|
||||
|
||||
static void test_make_relative(
|
||||
const char *expected_path,
|
||||
const char *path,
|
||||
const char *parent,
|
||||
int expected_status)
|
||||
{
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
git_buf_puts(&buf, path);
|
||||
cl_assert_equal_i(expected_status, git_path_make_relative(&buf, parent));
|
||||
cl_assert_equal_s(expected_path, buf.ptr);
|
||||
git_buf_free(&buf);
|
||||
}
|
||||
|
||||
void test_path_core__make_relative(void)
|
||||
{
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
|
||||
test_make_relative("foo.c", "/path/to/foo.c", "/path/to", 0);
|
||||
test_make_relative("bar/foo.c", "/path/to/bar/foo.c", "/path/to", 0);
|
||||
test_make_relative("foo.c", "/path/to/foo.c", "/path/to/", 0);
|
||||
|
||||
test_make_relative("", "/path/to", "/path/to", 0);
|
||||
test_make_relative("", "/path/to", "/path/to/", 0);
|
||||
|
||||
test_make_relative("../", "/path/to", "/path/to/foo", 0);
|
||||
|
||||
test_make_relative("../foo.c", "/path/to/foo.c", "/path/to/bar", 0);
|
||||
test_make_relative("../bar/foo.c", "/path/to/bar/foo.c", "/path/to/baz", 0);
|
||||
|
||||
test_make_relative("../../foo.c", "/path/to/foo.c", "/path/to/foo/bar", 0);
|
||||
test_make_relative("../../foo/bar.c", "/path/to/foo/bar.c", "/path/to/bar/foo", 0);
|
||||
|
||||
test_make_relative("../../foo.c", "/foo.c", "/bar/foo", 0);
|
||||
|
||||
test_make_relative("foo.c", "/path/to/foo.c", "/path/to/", 0);
|
||||
test_make_relative("../foo.c", "/path/to/foo.c", "/path/to/bar/", 0);
|
||||
|
||||
test_make_relative("foo.c", "d:/path/to/foo.c", "d:/path/to", 0);
|
||||
|
||||
test_make_relative("../foo", "/foo", "/bar", 0);
|
||||
test_make_relative("path/to/foo.c", "/path/to/foo.c", "/", 0);
|
||||
test_make_relative("../foo", "path/to/foo", "path/to/bar", 0);
|
||||
|
||||
test_make_relative("/path/to/foo.c", "/path/to/foo.c", "d:/path/to", GIT_ENOTFOUND);
|
||||
test_make_relative("d:/path/to/foo.c", "d:/path/to/foo.c", "/path/to", GIT_ENOTFOUND);
|
||||
|
||||
test_make_relative("/path/to/foo.c", "/path/to/foo.c", "not-a-rooted-path", GIT_ENOTFOUND);
|
||||
test_make_relative("not-a-rooted-path", "not-a-rooted-path", "/path/to", GIT_ENOTFOUND);
|
||||
|
||||
test_make_relative("/path", "/path", "pathtofoo", GIT_ENOTFOUND);
|
||||
test_make_relative("path", "path", "pathtofoo", GIT_ENOTFOUND);
|
||||
}
|
||||
@ -367,6 +367,84 @@ void test_repo_init__extended_1(void)
|
||||
cl_fixture_cleanup("root");
|
||||
}
|
||||
|
||||
void test_repo_init__relative_gitdir(void)
|
||||
{
|
||||
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
|
||||
git_config *cfg;
|
||||
const char *worktree_path;
|
||||
git_buf dot_git_content = GIT_BUF_INIT;
|
||||
|
||||
opts.workdir_path = "../c_wd";
|
||||
opts.flags =
|
||||
GIT_REPOSITORY_INIT_MKPATH |
|
||||
GIT_REPOSITORY_INIT_RELATIVE_GITLINK |
|
||||
GIT_REPOSITORY_INIT_NO_DOTGIT_DIR;
|
||||
|
||||
/* make the directory first, then it should succeed */
|
||||
cl_git_pass(git_repository_init_ext(&_repo, "root/b/my_repository", &opts));
|
||||
|
||||
cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "root/b/c_wd/"));
|
||||
cl_assert(!git__suffixcmp(git_repository_path(_repo), "root/b/my_repository/"));
|
||||
cl_assert(!git_repository_is_bare(_repo));
|
||||
cl_assert(git_repository_is_empty(_repo));
|
||||
|
||||
/* Verify that the gitlink and worktree entries are relative */
|
||||
|
||||
/* Verify worktree */
|
||||
cl_git_pass(git_repository_config(&cfg, _repo));
|
||||
cl_git_pass(git_config_get_string(&worktree_path, cfg, "core.worktree"));
|
||||
cl_assert_equal_s("../c_wd/", worktree_path);
|
||||
|
||||
/* Verify gitlink */
|
||||
cl_git_pass(git_futils_readbuffer(&dot_git_content, "root/b/c_wd/.git"));
|
||||
cl_assert_equal_s("gitdir: ../my_repository/", dot_git_content.ptr);
|
||||
|
||||
git_buf_free(&dot_git_content);
|
||||
git_config_free(cfg);
|
||||
cleanup_repository("root");
|
||||
}
|
||||
|
||||
void test_repo_init__relative_gitdir_2(void)
|
||||
{
|
||||
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
|
||||
git_config *cfg;
|
||||
const char *worktree_path;
|
||||
git_buf dot_git_content = GIT_BUF_INIT;
|
||||
git_buf full_path = GIT_BUF_INIT;
|
||||
|
||||
cl_git_pass(git_path_prettify(&full_path, ".", NULL));
|
||||
cl_git_pass(git_buf_joinpath(&full_path, full_path.ptr, "root/b/c_wd"));
|
||||
|
||||
opts.workdir_path = full_path.ptr;
|
||||
opts.flags =
|
||||
GIT_REPOSITORY_INIT_MKPATH |
|
||||
GIT_REPOSITORY_INIT_RELATIVE_GITLINK |
|
||||
GIT_REPOSITORY_INIT_NO_DOTGIT_DIR;
|
||||
|
||||
/* make the directory first, then it should succeed */
|
||||
cl_git_pass(git_repository_init_ext(&_repo, "root/b/my_repository", &opts));
|
||||
|
||||
cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "root/b/c_wd/"));
|
||||
cl_assert(!git__suffixcmp(git_repository_path(_repo), "root/b/my_repository/"));
|
||||
cl_assert(!git_repository_is_bare(_repo));
|
||||
cl_assert(git_repository_is_empty(_repo));
|
||||
|
||||
/* Verify that the gitlink and worktree entries are relative */
|
||||
|
||||
/* Verify worktree */
|
||||
cl_git_pass(git_repository_config(&cfg, _repo));
|
||||
cl_git_pass(git_config_get_string(&worktree_path, cfg, "core.worktree"));
|
||||
cl_assert_equal_s("../c_wd/", worktree_path);
|
||||
|
||||
/* Verify gitlink */
|
||||
cl_git_pass(git_futils_readbuffer(&dot_git_content, "root/b/c_wd/.git"));
|
||||
cl_assert_equal_s("gitdir: ../my_repository/", dot_git_content.ptr);
|
||||
|
||||
git_buf_free(&dot_git_content);
|
||||
git_config_free(cfg);
|
||||
cleanup_repository("root");
|
||||
}
|
||||
|
||||
#define CLEAR_FOR_CORE_FILEMODE(M) ((M) &= ~0177)
|
||||
|
||||
static void assert_hooks_match(
|
||||
|
||||
@ -135,6 +135,24 @@ void test_revwalk_mergebase__prefer_youngest_merge_base(void)
|
||||
cl_assert_equal_oid(&expected, &result);
|
||||
}
|
||||
|
||||
void test_revwalk_mergebase__multiple_merge_bases(void)
|
||||
{
|
||||
git_oid one, two, expected1, expected2;
|
||||
git_oidarray result = {NULL, 0};
|
||||
|
||||
cl_git_pass(git_oid_fromstr(&one, "a4a7dce85cf63874e984719f4fdd239f5145052f "));
|
||||
cl_git_pass(git_oid_fromstr(&two, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"));
|
||||
cl_git_pass(git_oid_fromstr(&expected1, "c47800c7266a2be04c571c04d5a6614691ea99bd"));
|
||||
cl_git_pass(git_oid_fromstr(&expected2, "9fd738e8f7967c078dceed8190330fc8648ee56a"));
|
||||
|
||||
cl_git_pass(git_merge_bases(&result, _repo, &one, &two));
|
||||
cl_assert_equal_i(2, result.count);
|
||||
cl_assert_equal_oid(&expected1, &result.ids[0]);
|
||||
cl_assert_equal_oid(&expected2, &result.ids[1]);
|
||||
|
||||
git_oidarray_free(&result);
|
||||
}
|
||||
|
||||
void test_revwalk_mergebase__no_off_by_one_missing(void)
|
||||
{
|
||||
git_oid result, one, two;
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#include "posix.h"
|
||||
#include "path.h"
|
||||
#include "submodule_helpers.h"
|
||||
#include "fileops.h"
|
||||
|
||||
static git_repository *g_repo = NULL;
|
||||
|
||||
@ -29,6 +30,10 @@ static void assert_submodule_url(const char* name, const char *url)
|
||||
void test_submodule_add__url_absolute(void)
|
||||
{
|
||||
git_submodule *sm;
|
||||
git_config *cfg;
|
||||
git_repository *repo;
|
||||
const char *worktree_path;
|
||||
git_buf dot_git_content = GIT_BUF_INIT;
|
||||
|
||||
g_repo = setup_fixture_submod2();
|
||||
|
||||
@ -51,6 +56,21 @@ void test_submodule_add__url_absolute(void)
|
||||
cl_assert(git_path_isfile("submod2/.git/modules/" "sm_libgit2" "/HEAD"));
|
||||
assert_submodule_url("sm_libgit2", "https://github.com/libgit2/libgit2.git");
|
||||
|
||||
cl_git_pass(git_repository_open(&repo, "submod2/" "sm_libgit2"));
|
||||
|
||||
/* Verify worktree path is relative */
|
||||
cl_git_pass(git_repository_config(&cfg, repo));
|
||||
cl_git_pass(git_config_get_string(&worktree_path, cfg, "core.worktree"));
|
||||
cl_assert_equal_s("../../../sm_libgit2/", worktree_path);
|
||||
|
||||
/* Verify gitdir path is relative */
|
||||
cl_git_pass(git_futils_readbuffer(&dot_git_content, "submod2/" "sm_libgit2" "/.git"));
|
||||
cl_assert_equal_s("gitdir: ../.git/modules/sm_libgit2/", dot_git_content.ptr);
|
||||
|
||||
git_config_free(cfg);
|
||||
git_repository_free(repo);
|
||||
git_buf_free(&dot_git_content);
|
||||
|
||||
/* add a submodule not using a gitlink */
|
||||
|
||||
cl_git_pass(
|
||||
|
||||
40
tests/submodule/repository_init.c
Normal file
40
tests/submodule/repository_init.c
Normal file
@ -0,0 +1,40 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "posix.h"
|
||||
#include "path.h"
|
||||
#include "submodule_helpers.h"
|
||||
#include "fileops.h"
|
||||
|
||||
static git_repository *g_repo = NULL;
|
||||
|
||||
void test_submodule_repository_init__basic(void)
|
||||
{
|
||||
git_submodule *sm;
|
||||
git_repository *repo;
|
||||
git_config *cfg;
|
||||
const char *worktree_path;
|
||||
git_buf dot_git_content = GIT_BUF_INIT;
|
||||
|
||||
g_repo = setup_fixture_submod2();
|
||||
|
||||
cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_gitmodules_only"));
|
||||
cl_git_pass(git_submodule_repo_init(&repo, sm, 1));
|
||||
|
||||
/* Verify worktree */
|
||||
cl_git_pass(git_repository_config(&cfg, repo));
|
||||
cl_git_pass(git_config_get_string(&worktree_path, cfg, "core.worktree"));
|
||||
cl_assert_equal_s("../../../sm_gitmodules_only/", worktree_path);
|
||||
|
||||
/* Verify gitlink */
|
||||
cl_git_pass(git_futils_readbuffer(&dot_git_content, "submod2/" "sm_gitmodules_only" "/.git"));
|
||||
cl_assert_equal_s("gitdir: ../.git/modules/sm_gitmodules_only/", dot_git_content.ptr);
|
||||
|
||||
cl_assert(git_path_isfile("submod2/" "sm_gitmodules_only" "/.git"));
|
||||
|
||||
cl_assert(git_path_isdir("submod2/.git/modules"));
|
||||
cl_assert(git_path_isdir("submod2/.git/modules/" "sm_gitmodules_only"));
|
||||
cl_assert(git_path_isfile("submod2/.git/modules/" "sm_gitmodules_only" "/HEAD"));
|
||||
|
||||
git_config_free(cfg);
|
||||
git_repository_free(repo);
|
||||
git_buf_free(&dot_git_content);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user