* `git_cert` descendent types now have a proper `parent` member
+* It is the responsibility fo the refdb backend to decide what to do
+ with the reflog on ref deletion. The file-based backend must delete
+ it, a database-backed one may wish to archive it.
+
v0.23
------
GIT_EEOF = -20, /**< Unexpected EOF */
GIT_EINVALID = -21, /**< Invalid operation or input */
GIT_EUNCOMMITTED = -22, /**< Uncommitted changes in index prevented operation */
+ GIT_EDIRECTORY = -23, /**< The operation is not valid for a directory */
GIT_PASSTHROUGH = -30, /**< Internal only */
GIT_ITEROVER = -31, /**< Signals end of iteration with iterator */
const git_signature *who, const char *message);
/**
- * Deletes the given reference from the refdb. A refdb implementation
- * must provide this function.
+ * Deletes the given reference (and if necessary its reflog)
+ * from the refdb. A refdb implementation must provide this
+ * function.
*/
int (*del)(git_refdb_backend *backend, const char *ref_name, const git_oid *old_id, const char *old_target);
(error = git_repository_odb(&odb, repo)) < 0)
goto done;
+ if (S_ISDIR(st.st_mode)) {
+ giterr_set(GITERR_ODB, "cannot create blob from '%s'; it is a directory", content_path);
+ error = GIT_EDIRECTORY;
+ goto done;
+ }
+
if (out_st)
memcpy(out_st, &st, sizeof(st));
git_reference_owner(branch), git_buf_cstr(&config_section), NULL) < 0)
goto on_error;
- if (git_reference_delete(branch) < 0)
- goto on_error;
-
- 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;
+ error = git_reference_delete(branch);
on_error:
git_buf_free(&config_section);
{
git_vector filter_streams = GIT_VECTOR_INIT;
git_writestream *stream_start;
- int error = 0;
+ int error = 0, close_error;
git_buf_sanitize(data);
- if ((error = stream_list_init(
- &stream_start, &filter_streams, filters, target)) == 0 &&
- (error =
- stream_start->write(stream_start, data->ptr, data->size)) == 0)
- error = stream_start->close(stream_start);
+ if ((error = stream_list_init(&stream_start, &filter_streams, filters, target)) < 0)
+ goto out;
+ error = stream_start->write(stream_start, data->ptr, data->size);
+
+out:
+ close_error = stream_start->close(stream_start);
stream_list_free(&filter_streams);
- return error;
+ /* propagate the stream init or write error */
+ return error < 0 ? error : close_error;
}
int git_filter_list_stream_blob(
{
int ret;
- pthread_once(&_once_init, init_once);
ret = git_atomic_inc(&git__n_inits);
+ pthread_once(&_once_init, init_once);
return init_error ? init_error : ret;
}
assert(index && path);
- if ((ret = index_entry_init(&entry, index, path)) < 0 ||
- (ret = index_insert(index, &entry, 1, false)) < 0)
+ if ((ret = index_entry_init(&entry, index, path)) == 0)
+ ret = index_insert(index, &entry, 1, false);
+
+ /* If we were given a directory, let's see if it's a submodule */
+ if (ret < 0 && ret != GIT_EDIRECTORY)
+ return ret;
+
+ if (ret == GIT_EDIRECTORY) {
+ git_submodule *sm;
+ git_error_state err;
+
+ giterr_capture(&err, ret);
+
+ ret = git_submodule_lookup(&sm, INDEX_OWNER(index), path);
+ if (ret == GIT_ENOTFOUND)
+ return giterr_restore(&err);
+ else
+ git__free(err.error_msg.message);
+
+ ret = git_submodule_add_to_index(sm, false);
+ git_submodule_free(sm);
return ret;
+ }
/* Adding implies conflict was resolved, move conflict entries to REUC */
if ((ret = index_conflict_to_reuc(index, path)) < 0 && ret != GIT_ENOTFOUND)
#include "win32/posix.h"
#include "win32/buffer.h"
#include "win32/w32_util.h"
+#include "win32/version.h"
#else
#include <dirent.h>
#endif
#if defined(GIT_WIN32) && !defined(__MINGW32__)
/* Using _FIND_FIRST_EX_LARGE_FETCH may increase performance in Windows 7
- * and better. Prior versions will ignore this.
+ * and better.
*/
#ifndef FIND_FIRST_EX_LARGE_FETCH
# define FIND_FIRST_EX_LARGE_FETCH 2
git_win32_path path_filter;
git_buf hack = {0};
+ static int is_win7_or_later = -1;
+ if (is_win7_or_later < 0)
+ is_win7_or_later = git_has_win32_version(6, 1, 0);
+
assert(diriter && path);
memset(diriter, 0, sizeof(git_path_diriter));
diriter->handle = FindFirstFileExW(
path_filter,
- FindExInfoBasic,
+ is_win7_or_later ? FindExInfoBasic : FindExInfoStandard,
&diriter->current,
FindExSearchNameMatch,
NULL,
- FIND_FIRST_EX_LARGE_FETCH);
+ is_win7_or_later ? FIND_FIRST_EX_LARGE_FETCH : 0);
if (diriter->handle == INVALID_HANDLE_VALUE) {
giterr_set(GITERR_OS, "Could not open directory '%s'", path);
return verify_component(repo, start, (c - start), flags);
}
+
+int git_path_normalize_slashes(git_buf *out, const char *path)
+{
+ int error;
+ char *p;
+
+ if ((error = git_buf_puts(out, path)) < 0)
+ return error;
+
+ for (p = out->ptr; *p; p++) {
+ if (*p == '\\')
+ *p = '/';
+ }
+
+ return 0;
+}
const char *path,
unsigned int flags);
+/**
+ * Convert any backslashes into slashes
+ */
+int git_path_normalize_slashes(git_buf *out, const char *path);
+
#endif
uint32_t direach_flags;
} refdb_fs_backend;
+static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name);
+
static int packref_cmp(const void *a_, const void *b_)
{
const struct packref *a = a_, *b = b_;
if ((error = loose_lock(&file, backend, ref_name)) < 0)
return error;
+ if ((error = refdb_reflog_fs__delete(_backend, ref_name)) < 0) {
+ git_filebuf_cleanup(&file);
+ return error;
+ }
+
return refdb_fs_backend__delete_tail(_backend, &file, ref_name, old_id, old_target);
}
int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *url)
{
int error = 0;
+ git_buf normalized = GIT_BUF_INIT;
assert(out && repo && url);
git_buf_sanitize(out);
+ /* We do this in all platforms in case someone on Windows created the .gitmodules */
+ if (strchr(url, '\\')) {
+ if ((error = git_path_normalize_slashes(&normalized, url)) < 0)
+ return error;
+
+ url = normalized.ptr;
+ }
+
+
if (git_path_is_relative(url)) {
if (!(error = get_url_base(out, repo)))
error = git_path_apply_relative(out, url);
error = -1;
}
+ git_buf_free(&normalized);
return error;
}
GITERR_CHECK_ALLOC(t->content_type);
}
}
- else if (!strcmp("WWW-Authenticate", git_buf_cstr(name))) {
+ else if (!strcasecmp("WWW-Authenticate", git_buf_cstr(name))) {
char *dup = git__strdup(git_buf_cstr(value));
GITERR_CHECK_ALLOC(dup);
--- /dev/null
+#include "clar_libgit2.h"
+#include "repository.h"
+#include "../submodule/submodule_helpers.h"
+
+static git_repository *g_repo;
+static git_index *g_idx;
+
+void test_index_bypath__initialize(void)
+{
+ g_repo = setup_fixture_submod2();
+ cl_git_pass(git_repository_index__weakptr(&g_idx, g_repo));
+}
+
+void test_index_bypath__cleanup(void)
+{
+ g_repo = NULL;
+ g_idx = NULL;
+}
+
+void test_index_bypath__add_directory(void)
+{
+ cl_git_fail_with(GIT_EDIRECTORY, git_index_add_bypath(g_idx, "just_a_dir"));
+}
+
+void test_index_bypath__add_submodule(void)
+{
+ unsigned int status;
+ const char *sm_name = "sm_changed_head";
+
+ cl_git_pass(git_submodule_status(&status, g_repo, sm_name, 0));
+ cl_assert_equal_i(GIT_SUBMODULE_STATUS_WD_MODIFIED, status & GIT_SUBMODULE_STATUS_WD_MODIFIED);
+ cl_git_pass(git_index_add_bypath(g_idx, sm_name));
+ cl_git_pass(git_submodule_status(&status, g_repo, sm_name, 0));
+ cl_assert_equal_i(0, status & GIT_SUBMODULE_STATUS_WD_MODIFIED);
+}
cl_git_pass(git_branch_delete(branch));
git_reference_free(branch);
+ cl_assert_equal_i(false, git_reference_has_log(repo, "refs/heads/track-local"));
+
/* Reading a nonexistant reflog creates it, but it should be empty */
cl_git_pass(git_reflog_read(&log, repo, "refs/heads/track-local"));
cl_assert_equal_i(0, git_reflog_entrycount(log));
#include "submodule_helpers.h"
#include "config/config_helpers.h"
#include "fileops.h"
+#include "repository.h"
static git_repository *g_repo = NULL;
test_submodule_lookup__simple_lookup(); /* baseline should still pass */
}
+void test_submodule_lookup__backslashes(void)
+{
+ git_config *cfg;
+ git_submodule *sm;
+ git_repository *subrepo;
+ git_buf buf = GIT_BUF_INIT;
+ const char *backslashed_path = "..\\submod2_target";
+
+ cl_git_pass(git_config_open_ondisk(&cfg, "submod2/.gitmodules"));
+ cl_git_pass(git_config_set_string(cfg, "submodule.sm_unchanged.url", backslashed_path));
+ git_config_free(cfg);
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
+ cl_assert_equal_s(backslashed_path, git_submodule_url(sm));
+ cl_git_pass(git_submodule_open(&subrepo, sm));
+
+ cl_git_pass(git_submodule_resolve_url(&buf, g_repo, backslashed_path));
+
+ git_buf_free(&buf);
+ git_submodule_free(sm);
+ git_repository_free(subrepo);
+}
+
static void baseline_tests(void)
{
/* small baseline that should work even if we change the index or make