Commit 0fef3899 by Carlos Martín Nieto

Merge remote-tracking branch 'upstream/master' into cmn/host-cert-info

parents bf8756d6 910cd2da
; 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"
......@@ -321,6 +322,21 @@ GIT_EXTERN(int) git_merge_base(
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
*
* @param out the OID of a merge base considering all the commits
......
/*
* 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;
/**
......
......@@ -471,6 +471,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.
*
* This copies the information about the submodules URL into the checked out
......
......@@ -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);
......
......@@ -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);
}
cleanup:
git_buf_free(&remote_master_name);
git_buf_free(&branch);
return error;
}
......
......@@ -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;
}
......
/*
* 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;
}
/*
* 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:
......
......@@ -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;
......
......@@ -197,6 +197,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.
*
* @param dir Directory path that might contain file
......
......@@ -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 */
......
......@@ -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, &param);
}
int git_remote_supported_url(const char* url)
{
git_transport_cb fn;
void *param;
if (transport_find_fn(&fn, url, &param) < 0)
return 0;
return fn != &git_transport_dummy;
/* The only error we expect is ENOTFOUND */
return !transport_find_fn(&fn, url, &param);
}
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,6 +366,7 @@ static int _git_ssh_authenticate_session(
return GIT_EAUTH;
if (rc != LIBSSH2_ERROR_NONE) {
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") );
}
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") );
}
int ssh_supported = 0, https_supported = 0;
void test_network_remote_remotes__supported_transport_methods_are_supported(void)
{
cl_assert( git_remote_supported_url("git://github.com/libgit2/libgit2") );
}
#ifdef GIT_SSH
ssh_supported = 1;
#endif
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") );
#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);
}
#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(
......
#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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment