summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2015-03-24 16:47:26 +0100
committerCarlos Martín Nieto <cmn@dwim.me>2015-03-24 16:47:26 +0100
commit928b4cad520fa87dd192d6363182145a91fcedea (patch)
tree33763aa2c58761694ced3947b54ab62b69c5321c
parent79010d09df45ed8cbe1b64fb12786db2ba98f7cd (diff)
parent1f726d05d382e7f797e9a77dfec8f4383f1000c1 (diff)
downloadlibgit2-928b4cad520fa87dd192d6363182145a91fcedea.tar.gz
Merge pull request #3005 from libgit2/cmn/maint-update
Backports for the maint branch
-rw-r--r--CMakeLists.txt6
-rw-r--r--include/git2/repository.h4
-rw-r--r--include/git2/sys/repository.h5
-rw-r--r--src/branch.c7
-rw-r--r--src/buf_text.c5
-rw-r--r--src/checkout.c1
-rw-r--r--src/config_file.c1
-rw-r--r--src/diff_patch.c3
-rw-r--r--src/fileops.c29
-rw-r--r--src/index.c3
-rw-r--r--src/indexer.c1
-rw-r--r--src/openssl_stream.c3
-rw-r--r--src/pack.c11
-rw-r--r--src/rebase.c4
-rw-r--r--src/refdb_fs.c9
-rw-r--r--src/remote.c6
-rw-r--r--src/repository.c2
-rw-r--r--src/stream.h5
-rw-r--r--src/transports/git.c1
-rw-r--r--src/transports/http.c8
-rw-r--r--src/win32/posix_w32.c8
-rw-r--r--tests/checkout/icase.c2
-rw-r--r--tests/core/buffer.c2
-rw-r--r--tests/core/stat.c17
-rw-r--r--tests/online/fetch.c6
-rw-r--r--tests/refs/branches/create.c104
-rw-r--r--tests/repo/init.c26
27 files changed, 243 insertions, 36 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b4d42e060..77a591f8d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -42,7 +42,6 @@ OPTION( VALGRIND "Configure build for valgrind" OFF )
IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
SET( USE_ICONV ON )
- ADD_DEFINITIONS(-DGIT_COMMON_CRYPTO)
ENDIF()
IF(MSVC)
@@ -172,6 +171,8 @@ ENDIF()
IF (WIN32 AND NOT MINGW AND NOT SHA1_TYPE STREQUAL "builtin")
ADD_DEFINITIONS(-DWIN32_SHA1)
FILE(GLOB SRC_SHA1 src/hash/hash_win32.c)
+ELSEIF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ ADD_DEFINITIONS(-DGIT_COMMON_CRYPTO)
ELSEIF (OPENSSL_FOUND AND NOT SHA1_TYPE STREQUAL "builtin")
ADD_DEFINITIONS(-DOPENSSL_SHA1)
IF (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
@@ -217,7 +218,8 @@ IF (USE_SSH)
ENDIF()
IF (LIBSSH2_FOUND)
ADD_DEFINITIONS(-DGIT_SSH)
- INCLUDE_DIRECTORIES(${LIBSSH2_INCLUDE_DIR})
+ INCLUDE_DIRECTORIES(${LIBSSH2_INCLUDE_DIRS})
+ LINK_DIRECTORIES(${LIBSSH2_LIBRARY_DIRS})
SET(LIBGIT2_PC_REQUIRES "${LIBGIT2_PC_REQUIRES} libssh2")
SET(SSH_LIBRARIES ${LIBSSH2_LIBRARIES})
ENDIF()
diff --git a/include/git2/repository.h b/include/git2/repository.h
index 124aa67e6..2fb381316 100644
--- a/include/git2/repository.h
+++ b/include/git2/repository.h
@@ -342,8 +342,8 @@ GIT_EXTERN(int) git_repository_head_unborn(git_repository *repo);
/**
* Check if a repository is empty
*
- * An empty repository has just been initialized and contains
- * no references.
+ * An empty repository has just been initialized and contains no references
+ * apart from HEAD, which must be pointing to the unborn master branch.
*
* @param repo Repo to test
* @return 1 if the repository is empty, 0 if it isn't, error code
diff --git a/include/git2/sys/repository.h b/include/git2/sys/repository.h
index dd7b22e06..800396c86 100644
--- a/include/git2/sys/repository.h
+++ b/include/git2/sys/repository.h
@@ -7,6 +7,9 @@
#ifndef INCLUDE_sys_git_repository_h__
#define INCLUDE_sys_git_repository_h__
+#include "git2/common.h"
+#include "git2/types.h"
+
/**
* @file git2/sys/repository.h
* @brief Git repository custom implementation routines
@@ -53,7 +56,7 @@ GIT_EXTERN(void) git_repository__cleanup(git_repository *repo);
*
* @param repo A repository object
* @param recurse_submodules Should submodules be updated recursively
- * @returrn 0 on success, < 0 on error
+ * @return 0 on success, < 0 on error
*/
GIT_EXTERN(int) git_repository_reinit_filesystem(
git_repository *repo,
diff --git a/src/branch.c b/src/branch.c
index b4e4b0564..b39d74749 100644
--- a/src/branch.c
+++ b/src/branch.c
@@ -138,8 +138,13 @@ int git_branch_delete(git_reference *branch)
if (git_reference_delete(branch) < 0)
goto on_error;
- if (git_reflog_delete(git_reference_owner(branch), git_reference_name(branch)) < 0)
+ if ((error = git_reflog_delete(git_reference_owner(branch), git_reference_name(branch))) < 0) {
+ if (error == GIT_ENOTFOUND) {
+ giterr_clear();
+ error = 0;
+ }
goto on_error;
+ }
error = 0;
diff --git a/src/buf_text.c b/src/buf_text.c
index cead599f4..cb3661edb 100644
--- a/src/buf_text.c
+++ b/src/buf_text.c
@@ -191,7 +191,10 @@ bool git_buf_text_is_binary(const git_buf *buf)
while (scan < end) {
unsigned char c = *scan++;
- if (c > 0x1F && c < 0x7F)
+ /* Printable characters are those above SPACE (0x1F) excluding DEL,
+ * and including BS, ESC and FF.
+ */
+ if ((c > 0x1F && c != 127) || c == '\b' || c == '\033' || c == '\014')
printable++;
else if (c == '\0')
return true;
diff --git a/src/checkout.c b/src/checkout.c
index 7b683bbda..6357579cc 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -2212,6 +2212,7 @@ static void checkout_data_clear(checkout_data *data)
git__free(data->pfx);
data->pfx = NULL;
+ git_buf_free(&data->last_mkdir);
git_buf_free(&data->path);
git_buf_free(&data->tmp);
diff --git a/src/config_file.c b/src/config_file.c
index 4f041e7e3..268cced09 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -1284,6 +1284,7 @@ static int config_parse(git_strmap *values, diskfile_backend *cfg_file, struct r
if (result == 0) {
result = config_parse(values, cfg_file, r, level, depth+1);
r = git_array_get(cfg_file->readers, index);
+ reader = git_array_get(cfg_file->readers, reader_idx);
}
else if (result == GIT_ENOTFOUND) {
giterr_clear();
diff --git a/src/diff_patch.c b/src/diff_patch.c
index 317dbeabb..7cdf6f39b 100644
--- a/src/diff_patch.c
+++ b/src/diff_patch.c
@@ -822,7 +822,8 @@ int git_patch__invoke_callbacks(
for (i = 0; !error && i < git_array_size(patch->hunks); ++i) {
diff_patch_hunk *h = git_array_get(patch->hunks, i);
- error = hunk_cb(patch->delta, &h->hunk, payload);
+ if (hunk_cb)
+ error = hunk_cb(patch->delta, &h->hunk, payload);
if (!line_cb)
continue;
diff --git a/src/fileops.c b/src/fileops.c
index 59882a968..4b49fa85c 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -330,7 +330,7 @@ int git_futils_mkdir_withperf(
{
int error = -1;
git_buf make_path = GIT_BUF_INIT;
- ssize_t root = 0, min_root_len;
+ ssize_t root = 0, min_root_len, root_len;
char lastch = '/', *tail;
struct stat st;
@@ -343,22 +343,29 @@ int git_futils_mkdir_withperf(
goto done;
}
- /* remove trailing slashes on path */
- while (make_path.ptr[make_path.size - 1] == '/') {
- make_path.size--;
- make_path.ptr[make_path.size] = '\0';
- }
+ /* Trim trailing slashes (except the root) */
+ if ((root_len = git_path_root(make_path.ptr)) < 0)
+ root_len = 0;
+ else
+ root_len++;
+
+ while (make_path.size > (size_t)root_len &&
+ make_path.ptr[make_path.size - 1] == '/')
+ make_path.ptr[--make_path.size] = '\0';
/* if we are not supposed to made the last element, truncate it */
if ((flags & GIT_MKDIR_SKIP_LAST2) != 0) {
- git_buf_rtruncate_at_char(&make_path, '/');
+ git_path_dirname_r(&make_path, make_path.ptr);
flags |= GIT_MKDIR_SKIP_LAST;
}
- if ((flags & GIT_MKDIR_SKIP_LAST) != 0)
- git_buf_rtruncate_at_char(&make_path, '/');
+ if ((flags & GIT_MKDIR_SKIP_LAST) != 0) {
+ git_path_dirname_r(&make_path, make_path.ptr);
+ }
- /* if nothing left after truncation, then we're done! */
- if (!make_path.size) {
+ /* We were either given the root path (or trimmed it to
+ * the root), we don't have anything to do.
+ */
+ if (make_path.size <= (size_t)root_len) {
error = 0;
goto done;
}
diff --git a/src/index.c b/src/index.c
index 079b0cb65..cbace3606 100644
--- a/src/index.c
+++ b/src/index.c
@@ -292,6 +292,9 @@ static void index_entry_reuc_free(git_index_reuc_entry *reuc)
static void index_entry_free(git_index_entry *entry)
{
+ if (!entry)
+ return;
+
memset(&entry->id, 0, sizeof(entry->id));
git__free(entry);
}
diff --git a/src/indexer.c b/src/indexer.c
index 92f85c167..f328025fd 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -289,6 +289,7 @@ static int store_object(git_indexer *idx)
k = kh_put(oid, idx->pack->idx_cache, &pentry->sha1, &error);
if (!error) {
git__free(pentry);
+ giterr_set(GITERR_INDEXER, "cannot handle duplicate objects in pack");
goto on_error;
}
diff --git a/src/openssl_stream.c b/src/openssl_stream.c
index 108ccfef2..c02df0b7a 100644
--- a/src/openssl_stream.c
+++ b/src/openssl_stream.c
@@ -8,6 +8,9 @@
#ifdef GIT_SSL
#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
#include "global.h"
#include "posix.h"
diff --git a/src/pack.c b/src/pack.c
index 47ce854c4..6891a7d03 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -56,6 +56,7 @@ static git_pack_cache_entry *new_cache_object(git_rawobj *source)
if (!e)
return NULL;
+ git_atomic_inc(&e->refcount);
memcpy(&e->raw, source, sizeof(git_rawobj));
return e;
@@ -145,7 +146,11 @@ static void free_lowest_entry(git_pack_cache *cache)
}
}
-static int cache_add(git_pack_cache *cache, git_rawobj *base, git_off_t offset)
+static int cache_add(
+ git_pack_cache_entry **cached_out,
+ git_pack_cache *cache,
+ git_rawobj *base,
+ git_off_t offset)
{
git_pack_cache_entry *entry;
int error, exists = 0;
@@ -171,6 +176,8 @@ static int cache_add(git_pack_cache *cache, git_rawobj *base, git_off_t offset)
assert(error != 0);
kh_value(cache->entries, k) = entry;
cache->memory_used += entry->raw.len;
+
+ *cached_out = entry;
}
git_mutex_unlock(&cache->lock);
/* Somebody beat us to adding it into the cache */
@@ -699,7 +706,7 @@ int git_packfile_unpack(
* long as it's not already the cached one.
*/
if (!cached)
- free_base = !!cache_add(&p->bases, obj, elem->base_key);
+ free_base = !!cache_add(&cached, &p->bases, obj, elem->base_key);
elem = &stack[elem_pos - 1];
curpos = elem->offset;
diff --git a/src/rebase.c b/src/rebase.c
index ceb74d39f..2e805929e 100644
--- a/src/rebase.c
+++ b/src/rebase.c
@@ -634,7 +634,7 @@ int git_rebase_init(
*out = NULL;
- GITERR_CHECK_VERSION(given_opts, GIT_MERGE_OPTIONS_VERSION, "git_merge_options");
+ GITERR_CHECK_VERSION(given_opts, GIT_REBASE_OPTIONS_VERSION, "git_rebase_options");
if (!onto)
onto = upstream;
@@ -1058,6 +1058,8 @@ int git_rebase_finish(
assert(rebase);
+ GITERR_CHECK_VERSION(given_opts, GIT_REBASE_OPTIONS_VERSION, "git_rebase_options");
+
if ((error = rebase_normalize_opts(rebase->repo, &opts, given_opts)) < 0)
goto done;
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index fc41a95d7..5cd2112fc 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -1771,6 +1771,15 @@ static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, co
goto cleanup;
}
+ /* If the new branch matches part of the namespace of a previously deleted branch,
+ * there maybe an obsolete/unused directory (or directory hierarchy) in the way.
+ */
+ if (git_path_isdir(git_buf_cstr(&path)) &&
+ (git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0)) {
+ error = -1;
+ goto cleanup;
+ }
+
error = git_futils_writebuffer(&buf, git_buf_cstr(&path), O_WRONLY|O_CREAT|O_APPEND, GIT_REFLOG_FILE_MODE);
cleanup:
diff --git a/src/remote.c b/src/remote.c
index 5ba7735ae..af5ebdfa6 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -1459,7 +1459,7 @@ int git_remote_update_tips(
const char *reflog_message)
{
git_refspec *spec, tagspec;
- git_vector refs;
+ git_vector refs = GIT_VECTOR_INIT;
int error;
size_t i;
@@ -2330,6 +2330,10 @@ int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const gi
(error = git_remote_connect(remote, GIT_DIRECTION_PUSH)) < 0)
goto cleanup;
+ free_refspecs(&remote->active_refspecs);
+ if (dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs) < 0)
+ goto cleanup;
+
if (remote->push) {
git_push_free(remote->push);
remote->push = NULL;
diff --git a/src/repository.c b/src/repository.c
index 5d5b3e5ea..fe2a2a677 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -1724,7 +1724,7 @@ int git_repository_set_bare(git_repository *repo)
if ((error = git_repository_config__weakptr(&config, repo)) < 0)
return error;
- if ((error = git_config_set_bool(config, "core.bare", false)) < 0)
+ if ((error = git_config_set_bool(config, "core.bare", true)) < 0)
return error;
if ((error = git_config__update_entry(config, "core.worktree", NULL, true, true)) < 0)
diff --git a/src/stream.h b/src/stream.h
index 3a7ef9514..d810e704d 100644
--- a/src/stream.h
+++ b/src/stream.h
@@ -15,6 +15,11 @@ GIT_INLINE(int) git_stream_connect(git_stream *st)
return st->connect(st);
}
+GIT_INLINE(int) git_stream_is_encrypted(git_stream *st)
+{
+ return st->encrypted;
+}
+
GIT_INLINE(int) git_stream_certificate(git_cert **out, git_stream *st)
{
if (!st->encrypted) {
diff --git a/src/transports/git.c b/src/transports/git.c
index 6f25736b1..8ab809117 100644
--- a/src/transports/git.c
+++ b/src/transports/git.c
@@ -136,6 +136,7 @@ static void git_proto_stream_free(git_smart_subtransport_stream *stream)
t->current_stream = NULL;
+ git_stream_close(s->io);
git_stream_free(s->io);
git__free(s->url);
git__free(s);
diff --git a/src/transports/http.c b/src/transports/http.c
index 807e08044..0cd33002f 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -350,6 +350,11 @@ static int on_headers_complete(http_parser *parser)
} else {
assert(t->cred);
+ if (!(t->cred->credtype & allowed_auth_types)) {
+ giterr_set(GITERR_NET, "credentials callback returned an invalid cred type");
+ return t->parse_error = PARSE_ERROR_GENERIC;
+ }
+
/* Successfully acquired a credential. */
t->parse_error = PARSE_ERROR_REPLAY;
return 0;
@@ -553,7 +558,8 @@ static int http_connect(http_subtransport *t)
error = git_stream_connect(t->io);
#ifdef GIT_SSL
- if ((!error || error == GIT_ECERTIFICATE) && t->owner->certificate_check_cb != NULL) {
+ if ((!error || error == GIT_ECERTIFICATE) && t->owner->certificate_check_cb != NULL &&
+ git_stream_is_encrypted(t->io)) {
git_cert *cert;
int is_valid;
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index e446ccab0..346f537e4 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -448,12 +448,8 @@ int p_stat(const char* path, struct stat* buf)
git_win32_path path_w;
int len;
- if ((len = git_win32_path_from_utf8(path_w, path)) < 0)
- return -1;
-
- git_win32__path_trim_end(path_w, len);
-
- if (lstat_w(path_w, buf, false) < 0)
+ if ((len = git_win32_path_from_utf8(path_w, path)) < 0 ||
+ lstat_w(path_w, buf, false) < 0)
return -1;
/* The item is a symbolic link or mount point. No need to iterate
diff --git a/tests/checkout/icase.c b/tests/checkout/icase.c
index 3a6ce2078..211738070 100644
--- a/tests/checkout/icase.c
+++ b/tests/checkout/icase.c
@@ -4,7 +4,7 @@
#include "path.h"
#ifdef GIT_WIN32
-# include <Windows.h>
+# include <windows.h>
#endif
static git_repository *repo;
diff --git a/tests/core/buffer.c b/tests/core/buffer.c
index 87dec4607..d28aa218f 100644
--- a/tests/core/buffer.c
+++ b/tests/core/buffer.c
@@ -830,7 +830,7 @@ void test_core_buffer__classify_with_utf8(void)
cl_assert(!git_buf_text_contains_nul(&b));
b.ptr = data1; b.size = b.asize = data1len;
- cl_assert(git_buf_text_is_binary(&b));
+ cl_assert(!git_buf_text_is_binary(&b));
cl_assert(!git_buf_text_contains_nul(&b));
b.ptr = data2; b.size = b.asize = data2len;
diff --git a/tests/core/stat.c b/tests/core/stat.c
index 2e4abfb79..bd9b990e3 100644
--- a/tests/core/stat.c
+++ b/tests/core/stat.c
@@ -95,3 +95,20 @@ void test_core_stat__0(void)
cl_assert_error(ENOTDIR);
}
+void test_core_stat__root(void)
+{
+ const char *sandbox = clar_sandbox_path();
+ git_buf root = GIT_BUF_INIT;
+ int root_len;
+ struct stat st;
+
+ root_len = git_path_root(sandbox);
+ cl_assert(root_len >= 0);
+
+ git_buf_set(&root, sandbox, root_len+1);
+
+ cl_must_pass(p_stat(root.ptr, &st));
+ cl_assert(S_ISDIR(st.st_mode));
+
+ git_buf_free(&root);
+}
diff --git a/tests/online/fetch.c b/tests/online/fetch.c
index 848b87410..484f4b57d 100644
--- a/tests/online/fetch.c
+++ b/tests/online/fetch.c
@@ -58,17 +58,17 @@ static void do_fetch(const char *url, git_remote_autotag_option_t flag, int n)
void test_online_fetch__default_git(void)
{
- do_fetch("git://github.com/libgit2/TestGitRepository.git", GIT_REMOTE_DOWNLOAD_TAGS_AUTO, 5);
+ do_fetch("git://github.com/libgit2/TestGitRepository.git", GIT_REMOTE_DOWNLOAD_TAGS_AUTO, 6);
}
void test_online_fetch__default_http(void)
{
- do_fetch("http://github.com/libgit2/TestGitRepository.git", GIT_REMOTE_DOWNLOAD_TAGS_AUTO, 5);
+ do_fetch("http://github.com/libgit2/TestGitRepository.git", GIT_REMOTE_DOWNLOAD_TAGS_AUTO, 6);
}
void test_online_fetch__default_https(void)
{
- do_fetch("https://github.com/libgit2/TestGitRepository.git", GIT_REMOTE_DOWNLOAD_TAGS_AUTO, 5);
+ do_fetch("https://github.com/libgit2/TestGitRepository.git", GIT_REMOTE_DOWNLOAD_TAGS_AUTO, 6);
}
void test_online_fetch__no_tags_git(void)
diff --git a/tests/refs/branches/create.c b/tests/refs/branches/create.c
index 3a4f33b6e..af9963bde 100644
--- a/tests/refs/branches/create.c
+++ b/tests/refs/branches/create.c
@@ -196,3 +196,107 @@ void test_refs_branches_create__can_create_branch_with_unicode(void)
branch = NULL;
}
}
+
+/**
+ * Verify that we can create a branch with a name that matches the
+ * namespace of a previously delete branch.
+ *
+ * git branch level_one/level_two
+ * git branch -D level_one/level_two
+ * git branch level_one
+ *
+ * We expect the delete to have deleted the files:
+ * ".git/refs/heads/level_one/level_two"
+ * ".git/logs/refs/heads/level_one/level_two"
+ * It may or may not have deleted the (now empty)
+ * containing directories. To match git.git behavior,
+ * the second create needs to implicilty delete the
+ * directories and create the new files.
+ * "refs/heads/level_one"
+ * "logs/refs/heads/level_one"
+ *
+ * We should not fail to create the branch or its
+ * reflog because of an obsolete namespace container
+ * directory.
+ */
+void test_refs_branches_create__name_vs_namespace(void)
+{
+ const char * name;
+ struct item {
+ const char *first;
+ const char *second;
+ };
+ static const struct item item[] = {
+ { "level_one/level_two", "level_one" },
+ { "a/b/c/d/e", "a/b/c/d" },
+ { "ss/tt/uu/vv/ww", "ss" },
+ /* And one test case that is deeper. */
+ { "xx1/xx2/xx3/xx4", "xx1/xx2/xx3/xx4/xx5/xx6" },
+ { NULL, NULL },
+ };
+ const struct item *p;
+
+ retrieve_known_commit(&target, repo);
+
+ for (p=item; p->first; p++) {
+ cl_git_pass(git_branch_create(&branch, repo, p->first, target, 0, NULL, NULL));
+ cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target)));
+ cl_git_pass(git_branch_name(&name, branch));
+ cl_assert_equal_s(name, p->first);
+
+ cl_git_pass(git_branch_delete(branch));
+ git_reference_free(branch);
+ branch = NULL;
+
+ cl_git_pass(git_branch_create(&branch, repo, p->second, target, 0, NULL, NULL));
+ git_reference_free(branch);
+ branch = NULL;
+ }
+}
+
+/**
+ * We still need to fail if part of the namespace is
+ * still in use.
+ */
+void test_refs_branches_create__name_vs_namespace_fail(void)
+{
+ const char * name;
+ struct item {
+ const char *first;
+ const char *first_alternate;
+ const char *second;
+ };
+ static const struct item item[] = {
+ { "level_one/level_two", "level_one/alternate", "level_one" },
+ { "a/b/c/d/e", "a/b/c/d/alternate", "a/b/c/d" },
+ { "ss/tt/uu/vv/ww", "ss/alternate", "ss" },
+ { NULL, NULL, NULL },
+ };
+ const struct item *p;
+
+ retrieve_known_commit(&target, repo);
+
+ for (p=item; p->first; p++) {
+ cl_git_pass(git_branch_create(&branch, repo, p->first, target, 0, NULL, NULL));
+ cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target)));
+ cl_git_pass(git_branch_name(&name, branch));
+ cl_assert_equal_s(name, p->first);
+
+ cl_git_pass(git_branch_delete(branch));
+ git_reference_free(branch);
+ branch = NULL;
+
+ cl_git_pass(git_branch_create(&branch, repo, p->first_alternate, target, 0, NULL, NULL));
+ cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target)));
+ cl_git_pass(git_branch_name(&name, branch));
+ cl_assert_equal_s(name, p->first_alternate);
+
+ /* we do not delete the alternate. */
+ git_reference_free(branch);
+ branch = NULL;
+
+ cl_git_fail(git_branch_create(&branch, repo, p->second, target, 0, NULL, NULL));
+ git_reference_free(branch);
+ branch = NULL;
+ }
+}
diff --git a/tests/repo/init.c b/tests/repo/init.c
index ed86f6e4f..91747c9f5 100644
--- a/tests/repo/init.c
+++ b/tests/repo/init.c
@@ -714,3 +714,29 @@ void test_repo_init__init_with_initial_commit(void)
git_index_free(index);
}
+
+void test_repo_init__at_filesystem_root(void)
+{
+ git_repository *repo;
+ const char *sandbox = clar_sandbox_path();
+ git_buf root = GIT_BUF_INIT;
+ int root_len;
+
+ if (!cl_getenv("GITTEST_INVASIVE_FILESYSTEM"))
+ cl_skip();
+
+ root_len = git_path_root(sandbox);
+ cl_assert(root_len >= 0);
+
+ git_buf_put(&root, sandbox, root_len+1);
+ git_buf_joinpath(&root, root.ptr, "libgit2_test_dir");
+
+ cl_assert(!git_path_exists(root.ptr));
+
+ cl_git_pass(git_repository_init(&repo, root.ptr, 0));
+ cl_assert(git_path_isdir(root.ptr));
+ cl_git_pass(git_futils_rmdir_r(root.ptr, NULL, GIT_RMDIR_REMOVE_FILES));
+
+ git_buf_free(&root);
+ git_repository_free(repo);
+}