summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--PROJECTS.md6
-rw-r--r--include/git2/commit.h6
-rw-r--r--include/git2/rebase.h32
-rwxr-xr-xscript/coverity.sh5
-rw-r--r--script/user_nodefs.h8
-rw-r--r--src/checkout.c7
-rw-r--r--src/commit.c10
-rw-r--r--src/diff.c8
-rw-r--r--src/index.c36
-rw-r--r--src/iterator.c17
-rw-r--r--src/iterator.h1
-rw-r--r--src/merge.c14
-rw-r--r--src/path.c7
-rw-r--r--src/path.h18
-rw-r--r--src/pathspec.c3
-rw-r--r--src/rebase.c380
-rw-r--r--src/refdb_fs.c4
-rw-r--r--src/stash.c8
-rw-r--r--src/submodule.c6
-rw-r--r--tests/commit/parse.c18
-rw-r--r--tests/diff/iterator.c4
-rw-r--r--tests/path/core.c12
-rw-r--r--tests/rebase/inmemory.c116
-rw-r--r--tests/rebase/iterator.c50
-rw-r--r--tests/rebase/merge.c30
-rw-r--r--tests/repo/iterator.c50
-rw-r--r--tests/resources/win32-forbidden/.gitted/HEAD1
-rw-r--r--tests/resources/win32-forbidden/.gitted/config7
-rw-r--r--tests/resources/win32-forbidden/.gitted/indexbin0 -> 577 bytes
-rw-r--r--tests/resources/win32-forbidden/.gitted/info/exclude6
-rw-r--r--tests/resources/win32-forbidden/.gitted/objects/10/68072702a28a82c78902cf5bf82c3864cf4356bin0 -> 143 bytes
-rw-r--r--tests/resources/win32-forbidden/.gitted/objects/17/6a458f94e0ea5272ce67c36bf30b6be9caf623bin0 -> 28 bytes
-rw-r--r--tests/resources/win32-forbidden/.gitted/objects/2d/7445a749d25269f32724aa621cb70b196bcc40bin0 -> 105 bytes
-rw-r--r--tests/resources/win32-forbidden/.gitted/objects/34/96991d72d500af36edef68bbfcccd1661d88db3
-rw-r--r--tests/resources/win32-forbidden/.gitted/objects/8f/45aad6f23b9509f8786c617e19c127ae76609a2
-rw-r--r--tests/resources/win32-forbidden/.gitted/objects/da/623abd956bb2fd8052c708c7ed43f05d192d37bin0 -> 59 bytes
-rw-r--r--tests/resources/win32-forbidden/.gitted/objects/ea/c7621a652e5261ef1c1d3e7ae31b0d84fcbaba3
-rw-r--r--tests/resources/win32-forbidden/.gitted/refs/heads/master1
-rw-r--r--tests/win32/forbidden.c183
39 files changed, 847 insertions, 215 deletions
diff --git a/PROJECTS.md b/PROJECTS.md
index 4f200b7f9..87ce78f02 100644
--- a/PROJECTS.md
+++ b/PROJECTS.md
@@ -48,7 +48,7 @@ These are good small projects to get started with libgit2.
a new example that mirrors the behavior. Examples don't have to be
perfect emulations, but should demonstrate how to use the libgit2 APIs
to get results that are similar to Git commands. This lets you (and us)
- easily exercise a particular facet of the API and measure compatability
+ easily exercise a particular facet of the API and measure compatibility
and feature parity with core git.
* Submit a PR to clarify documentation! While we do try to document all of
the APIs, your fresh eyes on the documentation will find areas that are
@@ -75,8 +75,6 @@ might make good smaller projects by themselves.
* Extract the Git tests that exercise that command
* Convert the tests to call our emulation
* These tests could go in examples/tests/...
-* Fix symlink support for files in the .git directory (i.e. don't overwrite
- the symlinks when writing the file contents back out)
* Add hooks API to enumerate and manage hooks (not run them at this point)
* Enumeration of available hooks
* Lookup API to see which hooks have a script and get the script
@@ -85,8 +83,6 @@ might make good smaller projects by themselves.
executes the action in question
* Isolate logic of ignore evaluation into a standalone API
* Upgrade internal libxdiff code to latest from core Git
-* Improve index internals with hashtable lookup for files instead of
- using binary search every time
* Tree builder improvements:
* Extend to allow building a tree hierarchy
* Apply-patch API
diff --git a/include/git2/commit.h b/include/git2/commit.h
index a92277417..3488c7440 100644
--- a/include/git2/commit.h
+++ b/include/git2/commit.h
@@ -266,12 +266,18 @@ GIT_EXTERN(int) git_commit_header_field(git_buf *out, const git_commit *commit,
/**
* Extract the signature from a commit
*
+ * If the id is not for a commit, the error class will be
+ * `GITERR_INVALID`. If the commit does not have a signature, the
+ * error class will be `GITERR_OBJECT`.
+ *
* @param signature the signature block
* @param signed_data signed data; this is the commit contents minus the signature block
* @param repo the repository in which the commit exists
* @param commit_id the commit from which to extract the data
* @param field the name of the header field containing the signature
* block; pass `NULL` to extract the default 'gpgsig'
+ * @return 0 on success, GIT_ENOTFOUND if the id is not for a commit
+ * or the commit does not have a signature.
*/
GIT_EXTERN(int) git_commit_extract_signature(git_buf *signature, git_buf *signed_data, git_repository *repo, git_oid *commit_id, const char *field);
diff --git a/include/git2/rebase.h b/include/git2/rebase.h
index cf1b00fd9..ece8b3664 100644
--- a/include/git2/rebase.h
+++ b/include/git2/rebase.h
@@ -39,6 +39,15 @@ typedef struct {
int quiet;
/**
+ * Used by `git_rebase_init`, this will begin an in-memory rebase,
+ * which will allow callers to step through the rebase operations and
+ * commit the rebased changes, but will not rewind HEAD or update the
+ * repository to be in a rebasing state. This will not interfere with
+ * the working directory (if there is one).
+ */
+ int inmemory;
+
+ /**
* Used by `git_rebase_finish`, this is the name of the notes reference
* used to rewrite notes for rebased commits when finishing the rebase;
* if NULL, the contents of the configuration option `notes.rewriteRef`
@@ -49,6 +58,11 @@ typedef struct {
const char *rewrite_notes_ref;
/**
+ * Options to control how trees are merged during `git_rebase_next`.
+ */
+ git_merge_options merge_options;
+
+ /**
* Options to control how files are written during `git_rebase_init`,
* `git_checkout_next` and `git_checkout_abort`. Note that a minimum
* strategy of `GIT_CHECKOUT_SAFE` is defaulted in `init` and `next`,
@@ -101,7 +115,8 @@ typedef enum {
#define GIT_REBASE_OPTIONS_VERSION 1
#define GIT_REBASE_OPTIONS_INIT \
- {GIT_REBASE_OPTIONS_VERSION, 0, NULL, GIT_CHECKOUT_OPTIONS_INIT}
+ { GIT_REBASE_OPTIONS_VERSION, 0, 0, NULL, GIT_MERGE_OPTIONS_INIT, \
+ GIT_CHECKOUT_OPTIONS_INIT}
/** Indicates that a rebase operation is not (yet) in progress. */
#define GIT_REBASE_NO_OPERATION SIZE_MAX
@@ -227,6 +242,21 @@ GIT_EXTERN(int) git_rebase_next(
git_rebase *rebase);
/**
+ * Gets the index produced by the last operation, which is the result
+ * of `git_rebase_next` and which will be committed by the next
+ * invocation of `git_rebase_commit`. This is useful for resolving
+ * conflicts in an in-memory rebase before committing them. You must
+ * call `git_index_free` when you are finished with this.
+ *
+ * This is only applicable for in-memory rebases; for rebases within
+ * a working directory, the changes were applied to the repository's
+ * index.
+ */
+GIT_EXTERN(int) git_rebase_inmemory_index(
+ git_index **index,
+ git_rebase *rebase);
+
+/**
* Commits the current patch. You must have resolved any conflicts that
* were introduced during the patch application from the `git_rebase_next`
* invocation.
diff --git a/script/coverity.sh b/script/coverity.sh
index dcfeffc1d..8c826892f 100755
--- a/script/coverity.sh
+++ b/script/coverity.sh
@@ -33,6 +33,8 @@ if [ ! -d "$TOOL_BASE" ]; then
ln -s "$TOOL_DIR" "$TOOL_BASE"/cov-analysis
fi
+cp script/user_nodefs.h "$TOOL_BASE"/cov-analysis/config/user_nodefs.h
+
COV_BUILD="$TOOL_BASE/cov-analysis/bin/cov-build"
# Configure and build
@@ -48,10 +50,9 @@ COVERITY_UNSUPPORTED=1 \
tar czf libgit2.tgz cov-int
SHA=$(git rev-parse --short HEAD)
curl \
- --form project=libgit2 \
--form token="$COVERITY_TOKEN" \
--form email=bs@github.com \
--form file=@libgit2.tgz \
--form version="$SHA" \
--form description="Travis build" \
- http://scan5.coverity.com/cgi-bin/upload.py
+ https://scan.coverity.com/builds?project=libgit2
diff --git a/script/user_nodefs.h b/script/user_nodefs.h
new file mode 100644
index 000000000..110f76851
--- /dev/null
+++ b/script/user_nodefs.h
@@ -0,0 +1,8 @@
+/*
+ * 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.
+ */
+
+#nodef GITERR_CHECK_ALLOC(ptr) if (ptr == NULL) { __coverity_panic__(); }
diff --git a/src/checkout.c b/src/checkout.c
index fd8e2c443..deeee62e0 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -1226,7 +1226,7 @@ static int checkout_verify_paths(
int action,
git_diff_delta *delta)
{
- unsigned int flags = GIT_PATH_REJECT_DEFAULTS | GIT_PATH_REJECT_DOT_GIT;
+ unsigned int flags = GIT_PATH_REJECT_WORKDIR_DEFAULTS;
if (action & CHECKOUT_ACTION__REMOVE) {
if (!git_path_isvalid(repo, delta->old_file.path, flags)) {
@@ -2521,7 +2521,8 @@ int git_checkout_iterator(
if (data.opts.baseline_index) {
if ((error = git_iterator_for_index(
- &baseline, data.opts.baseline_index, &baseline_opts)) < 0)
+ &baseline, git_index_owner(data.opts.baseline_index),
+ data.opts.baseline_index, &baseline_opts)) < 0)
goto cleanup;
} else {
if ((error = git_iterator_for_tree(
@@ -2633,7 +2634,7 @@ int git_checkout_index(
return error;
GIT_REFCOUNT_INC(index);
- if (!(error = git_iterator_for_index(&index_i, index, NULL)))
+ if (!(error = git_iterator_for_index(&index_i, repo, index, NULL)))
error = git_checkout_iterator(index_i, index, opts);
if (owned)
diff --git a/src/commit.c b/src/commit.c
index 453506d2f..5a0509803 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -568,7 +568,7 @@ int git_commit_header_field(git_buf *out, const git_commit *commit, const char *
git_buf_sanitize(out);
- while ((eol = strchr(buf, '\n')) && eol[1] != '\0') {
+ while ((eol = strchr(buf, '\n'))) {
/* We can skip continuations here */
if (buf[0] == ' ') {
buf = eol + 1;
@@ -642,6 +642,12 @@ int git_commit_extract_signature(git_buf *signature, git_buf *signed_data, git_r
if ((error = git_odb_read(&obj, odb, commit_id)) < 0)
return error;
+ if (obj->cached.type != GIT_OBJ_COMMIT) {
+ giterr_set(GITERR_INVALID, "the requested type does not match the type in ODB");
+ error = GIT_ENOTFOUND;
+ goto cleanup;
+ }
+
buf = git_odb_object_data(obj);
while ((h = strchr(buf, '\n')) && h[1] != '\0' && h[1] != '\n') {
@@ -688,7 +694,7 @@ int git_commit_extract_signature(git_buf *signature, git_buf *signed_data, git_r
return git_buf_puts(signed_data, eol+1);
}
- giterr_set(GITERR_INVALID, "this commit is not signed");
+ giterr_set(GITERR_OBJECT, "this commit is not signed");
error = GIT_ENOTFOUND;
goto cleanup;
diff --git a/src/diff.c b/src/diff.c
index 67fab0763..9ac5b9250 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -1371,7 +1371,7 @@ int git_diff_tree_to_index(
DIFF_FROM_ITERATORS(
git_iterator_for_tree(&a, old_tree, &a_opts), iflag,
- git_iterator_for_index(&b, index, &b_opts), iflag
+ git_iterator_for_index(&b, repo, index, &b_opts), iflag
);
/* if index is in case-insensitive order, re-sort deltas to match */
@@ -1395,7 +1395,7 @@ int git_diff_index_to_workdir(
return error;
DIFF_FROM_ITERATORS(
- git_iterator_for_index(&a, index, &a_opts),
+ git_iterator_for_index(&a, repo, index, &a_opts),
GIT_ITERATOR_INCLUDE_CONFLICTS,
git_iterator_for_workdir(&b, repo, index, NULL, &b_opts),
@@ -1472,8 +1472,8 @@ int git_diff_index_to_index(
assert(diff && old_index && new_index);
DIFF_FROM_ITERATORS(
- git_iterator_for_index(&a, old_index, &a_opts), GIT_ITERATOR_DONT_IGNORE_CASE,
- git_iterator_for_index(&b, new_index, &b_opts), GIT_ITERATOR_DONT_IGNORE_CASE
+ git_iterator_for_index(&a, repo, old_index, &a_opts), GIT_ITERATOR_DONT_IGNORE_CASE,
+ git_iterator_for_index(&b, repo, new_index, &b_opts), GIT_ITERATOR_DONT_IGNORE_CASE
);
/* if index is in case-insensitive order, re-sort deltas to match */
diff --git a/src/index.c b/src/index.c
index bfa9fc849..d0a0da2c5 100644
--- a/src/index.c
+++ b/src/index.c
@@ -853,17 +853,31 @@ static void index_entry_adjust_namemask(
entry->flags |= GIT_IDXENTRY_NAMEMASK;
}
+/* When `from_workdir` is true, we will validate the paths to avoid placing
+ * paths that are invalid for the working directory on the current filesystem
+ * (eg, on Windows, we will disallow `GIT~1`, `AUX`, `COM1`, etc). This
+ * function will *always* prevent `.git` and directory traversal `../` from
+ * being added to the index.
+ */
static int index_entry_create(
git_index_entry **out,
git_repository *repo,
- const char *path)
+ const char *path,
+ bool from_workdir)
{
size_t pathlen = strlen(path), alloclen;
struct entry_internal *entry;
+ unsigned int path_valid_flags = GIT_PATH_REJECT_INDEX_DEFAULTS;
+
+ /* always reject placing `.git` in the index and directory traversal.
+ * when requested, disallow platform-specific filenames and upgrade to
+ * the platform-specific `.git` tests (eg, `git~1`, etc).
+ */
+ if (from_workdir)
+ path_valid_flags |= GIT_PATH_REJECT_WORKDIR_DEFAULTS;
- if (!git_path_isvalid(repo, path,
- GIT_PATH_REJECT_DEFAULTS | GIT_PATH_REJECT_DOT_GIT)) {
- giterr_set(GITERR_INDEX, "Invalid path: '%s'", path);
+ if (!git_path_isvalid(repo, path, path_valid_flags)) {
+ giterr_set(GITERR_INDEX, "invalid path: '%s'", path);
return -1;
}
@@ -895,7 +909,7 @@ static int index_entry_init(
"Could not initialize index entry. "
"Index is not backed up by an existing repository.");
- if (index_entry_create(&entry, INDEX_OWNER(index), rel_path) < 0)
+ if (index_entry_create(&entry, INDEX_OWNER(index), rel_path, true) < 0)
return -1;
/* write the blob to disk and get the oid and stat info */
@@ -975,7 +989,7 @@ static int index_entry_dup(
git_index *index,
const git_index_entry *src)
{
- if (index_entry_create(out, INDEX_OWNER(index), src->path) < 0)
+ if (index_entry_create(out, INDEX_OWNER(index), src->path, false) < 0)
return -1;
index_entry_cpy(*out, src);
@@ -997,7 +1011,7 @@ static int index_entry_dup_nocache(
git_index *index,
const git_index_entry *src)
{
- if (index_entry_create(out, INDEX_OWNER(index), src->path) < 0)
+ if (index_entry_create(out, INDEX_OWNER(index), src->path, false) < 0)
return -1;
index_entry_cpy_nocache(*out, src);
@@ -1402,7 +1416,7 @@ static int add_repo_as_submodule(git_index_entry **out, git_index *index, const
struct stat st;
int error;
- if (index_entry_create(&entry, INDEX_OWNER(index), path) < 0)
+ if (index_entry_create(&entry, INDEX_OWNER(index), path, true) < 0)
return -1;
if ((error = git_buf_joinpath(&abspath, git_repository_workdir(repo), path)) < 0)
@@ -2788,7 +2802,7 @@ static int read_tree_cb(
if (git_buf_joinpath(&path, root, tentry->filename) < 0)
return -1;
- if (index_entry_create(&entry, INDEX_OWNER(data->index), path.ptr) < 0)
+ if (index_entry_create(&entry, INDEX_OWNER(data->index), path.ptr, false) < 0)
return -1;
entry->mode = tentry->attr;
@@ -2907,8 +2921,8 @@ int git_index_read_index(
opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;
- if ((error = git_iterator_for_index(&index_iterator, index, &opts)) < 0 ||
- (error = git_iterator_for_index(&new_iterator, (git_index *)new_index, &opts)) < 0)
+ if ((error = git_iterator_for_index(&index_iterator, git_index_owner(index), index, &opts)) < 0 ||
+ (error = git_iterator_for_index(&new_iterator, git_index_owner(new_index), (git_index *)new_index, &opts)) < 0)
goto done;
if (((error = git_iterator_current(&old_entry, index_iterator)) < 0 &&
diff --git a/src/iterator.c b/src/iterator.c
index ee348de6e..024a97573 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -558,6 +558,8 @@ static bool tree_iterator__pop_frame(tree_iterator *ti, bool final)
{
tree_iterator_frame *tf = ti->head;
+ assert(tf);
+
if (!tf->up)
return false;
@@ -581,6 +583,8 @@ static void tree_iterator__pop_all(tree_iterator *ti, bool to_end, bool final)
while (tree_iterator__pop_frame(ti, final)) /* pop to root */;
if (!final) {
+ assert(ti->head);
+
ti->head->current = to_end ? ti->head->n_entries : 0;
ti->path_ambiguities = 0;
git_buf_clear(&ti->path);
@@ -773,10 +777,12 @@ static void tree_iterator__free(git_iterator *self)
{
tree_iterator *ti = (tree_iterator *)self;
- tree_iterator__pop_all(ti, true, false);
+ if (ti->head) {
+ tree_iterator__pop_all(ti, true, false);
+ git_tree_free(ti->head->entries[0]->tree);
+ git__free(ti->head);
+ }
- git_tree_free(ti->head->entries[0]->tree);
- git__free(ti->head);
git_pool_clear(&ti->pool);
git_buf_free(&ti->path);
}
@@ -1080,6 +1086,7 @@ static void index_iterator__free(git_iterator *self)
int git_iterator_for_index(
git_iterator **iter,
+ git_repository *repo,
git_index *index,
git_iterator_options *options)
{
@@ -1093,7 +1100,7 @@ int git_iterator_for_index(
}
ii->index = index;
- ITERATOR_BASE_INIT(ii, index, INDEX, git_index_owner(index));
+ ITERATOR_BASE_INIT(ii, index, INDEX, repo);
if ((error = iterator__update_ignore_case((git_iterator *)ii, options ? options->flags : 0)) < 0) {
git_iterator_free((git_iterator *)ii);
@@ -2071,7 +2078,7 @@ int git_iterator_advance_over_with_status(
if (!error)
continue;
-
+
else if (error == GIT_ENOTFOUND) {
/* we entered this directory only hoping to find child matches to
* our pathlist (eg, this is `foo` and we had a pathlist entry for
diff --git a/src/iterator.h b/src/iterator.h
index 59f87e9de..ac17d2970 100644
--- a/src/iterator.h
+++ b/src/iterator.h
@@ -95,6 +95,7 @@ extern int git_iterator_for_tree(
*/
extern int git_iterator_for_index(
git_iterator **out,
+ git_repository *repo,
git_index *index,
git_iterator_options *options);
diff --git a/src/merge.c b/src/merge.c
index 70c705af6..d2f92ccce 100644
--- a/src/merge.c
+++ b/src/merge.c
@@ -2083,9 +2083,9 @@ static int iterator_for_annotated_commit(
opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;
if (commit == NULL) {
- error = git_iterator_for_nothing(out, &opts);
+ error = git_iterator_for_nothing(out, &opts);
} else if (commit->type == GIT_ANNOTATED_COMMIT_VIRTUAL) {
- error = git_iterator_for_index(out, commit->index, &opts);
+ error = git_iterator_for_index(out, git_index_owner(commit->index), commit->index, &opts);
} else {
if (!commit->tree &&
(error = git_commit_tree(&commit->tree, commit->commit)) < 0)
@@ -2427,7 +2427,7 @@ static int write_merge_msg(
assert(repo && heads);
entries = git__calloc(heads_len, sizeof(struct merge_msg_entry));
- GITERR_CHECK_ALLOC(entries);
+ GITERR_CHECK_ALLOC(entries);
if (git_vector_init(&matching, heads_len, NULL) < 0) {
git__free(entries);
@@ -2481,7 +2481,7 @@ static int write_merge_msg(
if (matching.length)
sep =',';
-
+
if ((error = merge_msg_entries(&matching, entries, heads_len, msg_entry_is_tag)) < 0 ||
(error = merge_msg_write_tags(&file, &matching, sep)) < 0)
goto cleanup;
@@ -2682,8 +2682,8 @@ static int merge_check_index(size_t *conflicts, git_repository *repo, git_index
iter_opts.pathlist.strings = (char **)staged_paths.contents;
iter_opts.pathlist.count = staged_paths.length;
- if ((error = git_iterator_for_index(&iter_repo, index_repo, &iter_opts)) < 0 ||
- (error = git_iterator_for_index(&iter_new, index_new, &iter_opts)) < 0 ||
+ if ((error = git_iterator_for_index(&iter_repo, repo, index_repo, &iter_opts)) < 0 ||
+ (error = git_iterator_for_index(&iter_new, repo, index_new, &iter_opts)) < 0 ||
(error = git_diff__from_iterators(&index_diff_list, repo, iter_repo, iter_new, &opts)) < 0)
goto done;
@@ -2759,7 +2759,7 @@ int git_merge__check_result(git_repository *repo, git_index *index_new)
if ((error = git_repository_head_tree(&head_tree, repo)) < 0 ||
(error = git_iterator_for_tree(&iter_head, head_tree, &iter_opts)) < 0 ||
- (error = git_iterator_for_index(&iter_new, index_new, &iter_opts)) < 0 ||
+ (error = git_iterator_for_index(&iter_new, repo, index_new, &iter_opts)) < 0 ||
(error = git_diff__from_iterators(&merged_list, repo, iter_head, iter_new, &opts)) < 0)
goto done;
diff --git a/src/path.c b/src/path.c
index 18b4f03fd..852ef576a 100644
--- a/src/path.c
+++ b/src/path.c
@@ -1630,9 +1630,12 @@ static bool verify_component(
!verify_dotgit_ntfs(repo, component, len))
return false;
+ /* don't bother rerunning the `.git` test if we ran the HFS or NTFS
+ * specific tests, they would have already rejected `.git`.
+ */
if ((flags & GIT_PATH_REJECT_DOT_GIT_HFS) == 0 &&
(flags & GIT_PATH_REJECT_DOT_GIT_NTFS) == 0 &&
- (flags & GIT_PATH_REJECT_DOT_GIT) &&
+ (flags & GIT_PATH_REJECT_DOT_GIT_LITERAL) &&
len == 4 &&
component[0] == '.' &&
(component[1] == 'g' || component[1] == 'G') &&
@@ -1649,6 +1652,8 @@ GIT_INLINE(unsigned int) dotgit_flags(
{
int protectHFS = 0, protectNTFS = 0;
+ flags |= GIT_PATH_REJECT_DOT_GIT_LITERAL;
+
#ifdef __APPLE__
protectHFS = 1;
#endif
diff --git a/src/path.h b/src/path.h
index 7e156fce8..875c8cb7e 100644
--- a/src/path.h
+++ b/src/path.h
@@ -564,15 +564,16 @@ extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or
#define GIT_PATH_REJECT_TRAILING_COLON (1 << 6)
#define GIT_PATH_REJECT_DOS_PATHS (1 << 7)
#define GIT_PATH_REJECT_NT_CHARS (1 << 8)
-#define GIT_PATH_REJECT_DOT_GIT_HFS (1 << 9)
-#define GIT_PATH_REJECT_DOT_GIT_NTFS (1 << 10)
+#define GIT_PATH_REJECT_DOT_GIT_LITERAL (1 << 9)
+#define GIT_PATH_REJECT_DOT_GIT_HFS (1 << 10)
+#define GIT_PATH_REJECT_DOT_GIT_NTFS (1 << 11)
/* Default path safety for writing files to disk: since we use the
* Win32 "File Namespace" APIs ("\\?\") we need to protect from
* paths that the normal Win32 APIs would not write.
*/
#ifdef GIT_WIN32
-# define GIT_PATH_REJECT_DEFAULTS \
+# define GIT_PATH_REJECT_FILESYSTEM_DEFAULTS \
GIT_PATH_REJECT_TRAVERSAL | \
GIT_PATH_REJECT_BACKSLASH | \
GIT_PATH_REJECT_TRAILING_DOT | \
@@ -581,9 +582,18 @@ extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or
GIT_PATH_REJECT_DOS_PATHS | \
GIT_PATH_REJECT_NT_CHARS
#else
-# define GIT_PATH_REJECT_DEFAULTS GIT_PATH_REJECT_TRAVERSAL
+# define GIT_PATH_REJECT_FILESYSTEM_DEFAULTS \
+ GIT_PATH_REJECT_TRAVERSAL
#endif
+ /* Paths that should never be written into the working directory. */
+#define GIT_PATH_REJECT_WORKDIR_DEFAULTS \
+ GIT_PATH_REJECT_FILESYSTEM_DEFAULTS | GIT_PATH_REJECT_DOT_GIT
+
+/* Paths that should never be written to the index. */
+#define GIT_PATH_REJECT_INDEX_DEFAULTS \
+ GIT_PATH_REJECT_TRAVERSAL | GIT_PATH_REJECT_DOT_GIT
+
/*
* Determine whether a path is a valid git path or not - this must not contain
* a '.' or '..' component, or a component that is ".git" (in any case).
diff --git a/src/pathspec.c b/src/pathspec.c
index 5bb69ec4b..8a93cdd50 100644
--- a/src/pathspec.c
+++ b/src/pathspec.c
@@ -550,7 +550,7 @@ int git_pathspec_match_index(
iter_opts.flags = pathspec_match_iter_flags(flags);
- if (!(error = git_iterator_for_index(&iter, index, &iter_opts))) {
+ if (!(error = git_iterator_for_index(&iter, git_index_owner(index), index, &iter_opts))) {
error = pathspec_match_from_iterator(out, iter, flags, ps);
git_iterator_free(iter);
}
@@ -718,4 +718,3 @@ const char * git_pathspec_match_list_failed_entry(
return entry ? *entry : NULL;
}
-
diff --git a/src/rebase.c b/src/rebase.c
index 17536c030..b9d1d4fc5 100644
--- a/src/rebase.c
+++ b/src/rebase.c
@@ -63,17 +63,23 @@ struct git_rebase {
char *state_path;
int head_detached : 1,
+ inmemory : 1,
quiet : 1,
started : 1;
- char *orig_head_name;
+ git_array_t(git_rebase_operation) operations;
+ size_t current;
+
+ /* Used by in-memory rebase */
+ git_index *index;
+ git_commit *last_commit;
+
+ /* Used by regular (not in-memory) merge-style rebase */
git_oid orig_head_id;
+ char *orig_head_name;
git_oid onto_id;
char *onto_name;
-
- git_array_t(git_rebase_operation) operations;
- size_t current;
};
#define GIT_REBASE_STATE_INIT {0}
@@ -393,6 +399,9 @@ done:
static int rebase_cleanup(git_rebase *rebase)
{
+ if (!rebase || rebase->inmemory)
+ return 0;
+
return git_path_isdir(rebase->state_path) ?
git_futils_rmdir_r(rebase->state_path, NULL, GIT_RMDIR_REMOVE_FILES) :
0;
@@ -601,61 +610,65 @@ static int rebase_init_merge(
const git_annotated_commit *upstream,
const git_annotated_commit *onto)
{
- if (rebase_init_operations(rebase, repo, branch, upstream, onto) < 0)
- return -1;
-
- rebase->onto_name = git__strdup(rebase_onto_name(onto));
- GITERR_CHECK_ALLOC(rebase->onto_name);
-
- return 0;
-}
-
-static int rebase_init(
- git_rebase *rebase,
- git_repository *repo,
- const git_annotated_commit *branch,
- const git_annotated_commit *upstream,
- const git_annotated_commit *onto)
-{
git_reference *head_ref = NULL;
- git_annotated_commit *head_branch = NULL;
+ git_commit *onto_commit = NULL;
+ git_buf reflog = GIT_BUF_INIT;
git_buf state_path = GIT_BUF_INIT;
int error;
+ GIT_UNUSED(upstream);
+
if ((error = git_buf_joinpath(&state_path, repo->path_repository, REBASE_MERGE_DIR)) < 0)
goto done;
- if (!branch) {
- if ((error = git_repository_head(&head_ref, repo)) < 0 ||
- (error = git_annotated_commit_from_ref(&head_branch, repo, head_ref)) < 0)
- goto done;
-
- branch = head_branch;
- }
-
- rebase->repo = repo;
- rebase->type = GIT_REBASE_TYPE_MERGE;
rebase->state_path = git_buf_detach(&state_path);
+ GITERR_CHECK_ALLOC(rebase->state_path);
+
rebase->orig_head_name = git__strdup(branch->ref_name ? branch->ref_name : ORIG_DETACHED_HEAD);
+ GITERR_CHECK_ALLOC(rebase->orig_head_name);
+
+ rebase->onto_name = git__strdup(rebase_onto_name(onto));
+ GITERR_CHECK_ALLOC(rebase->onto_name);
+
rebase->quiet = rebase->options.quiet;
git_oid_cpy(&rebase->orig_head_id, git_annotated_commit_id(branch));
git_oid_cpy(&rebase->onto_id, git_annotated_commit_id(onto));
- if (!rebase->orig_head_name || !rebase->state_path)
- return -1;
-
- error = rebase_init_merge(rebase, repo, branch, upstream, onto);
-
- git_buf_free(&state_path);
+ if ((error = rebase_setupfiles(rebase)) < 0 ||
+ (error = git_buf_printf(&reflog,
+ "rebase: checkout %s", rebase_onto_name(onto))) < 0 ||
+ (error = git_commit_lookup(
+ &onto_commit, repo, git_annotated_commit_id(onto))) < 0 ||
+ (error = git_checkout_tree(repo,
+ (git_object *)onto_commit, &rebase->options.checkout_options)) < 0 ||
+ (error = git_reference_create(&head_ref, repo, GIT_HEAD_FILE,
+ git_annotated_commit_id(onto), 1, reflog.ptr)) < 0)
+ goto done;
done:
git_reference_free(head_ref);
- git_annotated_commit_free(head_branch);
+ git_commit_free(onto_commit);
+ git_buf_free(&reflog);
+ git_buf_free(&state_path);
return error;
}
+static int rebase_init_inmemory(
+ git_rebase *rebase,
+ git_repository *repo,
+ const git_annotated_commit *branch,
+ const git_annotated_commit *upstream,
+ const git_annotated_commit *onto)
+{
+ GIT_UNUSED(branch);
+ GIT_UNUSED(upstream);
+
+ return git_commit_lookup(
+ &rebase->last_commit, repo, git_annotated_commit_id(onto));
+}
+
int git_rebase_init(
git_rebase **out,
git_repository *repo,
@@ -665,9 +678,9 @@ int git_rebase_init(
const git_rebase_options *given_opts)
{
git_rebase *rebase = NULL;
- git_buf reflog = GIT_BUF_INIT;
- git_commit *onto_commit = NULL;
+ git_annotated_commit *head_branch = NULL;
git_reference *head_ref = NULL;
+ bool inmemory = (given_opts && given_opts->inmemory);
int error;
assert(repo && (upstream || onto));
@@ -677,39 +690,51 @@ int git_rebase_init(
if (!onto)
onto = upstream;
- if ((error = rebase_check_versions(given_opts)) < 0 ||
- (error = git_repository__ensure_not_bare(repo, "rebase")) < 0 ||
- (error = rebase_ensure_not_in_progress(repo)) < 0 ||
- (error = rebase_ensure_not_dirty(repo, true, true, GIT_ERROR)) < 0 ||
- (error = git_commit_lookup(
- &onto_commit, repo, git_annotated_commit_id(onto))) < 0)
- return error;
+ if ((error = rebase_check_versions(given_opts)) < 0)
+ goto done;
+
+ if (!inmemory) {
+ if ((error = git_repository__ensure_not_bare(repo, "rebase")) < 0 ||
+ (error = rebase_ensure_not_in_progress(repo)) < 0 ||
+ (error = rebase_ensure_not_dirty(repo, true, true, GIT_ERROR)) < 0)
+ goto done;
+ }
+
+ if (!branch) {
+ if ((error = git_repository_head(&head_ref, repo)) < 0 ||
+ (error = git_annotated_commit_from_ref(&head_branch, repo, head_ref)) < 0)
+ goto done;
+
+ branch = head_branch;
+ }
rebase = rebase_alloc(given_opts);
+ GITERR_CHECK_ALLOC(rebase);
- if ((error = rebase_init(
- rebase, repo, branch, upstream, onto)) < 0 ||
- (error = rebase_setupfiles(rebase)) < 0 ||
- (error = git_buf_printf(&reflog,
- "rebase: checkout %s", rebase_onto_name(onto))) < 0 ||
- (error = git_checkout_tree(
- repo, (git_object *)onto_commit, &rebase->options.checkout_options)) < 0 ||
- (error = git_reference_create(&head_ref, repo, GIT_HEAD_FILE,
- git_annotated_commit_id(onto), 1, reflog.ptr)) < 0)
+ rebase->repo = repo;
+ rebase->inmemory = inmemory;
+ rebase->type = GIT_REBASE_TYPE_MERGE;
+
+ if ((error = rebase_init_operations(rebase, repo, branch, upstream, onto)) < 0)
goto done;
- *out = rebase;
+ if (inmemory)
+ error = rebase_init_inmemory(rebase, repo, branch, upstream, onto);
+ else
+ rebase_init_merge(rebase, repo, branch ,upstream, onto);
+
+ if (error == 0)
+ *out = rebase;
done:
git_reference_free(head_ref);
+ git_annotated_commit_free(head_branch);
+
if (error < 0) {
rebase_cleanup(rebase);
git_rebase_free(rebase);
}
- git_commit_free(onto_commit);
- git_buf_free(&reflog);
-
return error;
}
@@ -764,9 +789,6 @@ static int rebase_next_merge(
*out = NULL;
- if ((error = rebase_movenext(rebase)) < 0)
- goto done;
-
operation = git_array_get(rebase->operations, rebase->current);
if ((error = git_commit_lookup(&current_commit, rebase->repo, &operation->id)) < 0 ||
@@ -791,7 +813,7 @@ static int rebase_next_merge(
if ((error = git_indexwriter_init_for_operation(&indexwriter, rebase->repo, &checkout_opts.checkout_strategy)) < 0 ||
(error = rebase_setupfile(rebase, MSGNUM_FILE, -1, "%" PRIuZ "\n", rebase->current+1)) < 0 ||
(error = rebase_setupfile(rebase, CURRENT_FILE, -1, "%.*s\n", GIT_OID_HEXSZ, current_idstr)) < 0 ||
- (error = git_merge_trees(&index, rebase->repo, parent_tree, head_tree, current_tree, NULL)) < 0 ||
+ (error = git_merge_trees(&index, rebase->repo, parent_tree, head_tree, current_tree, &rebase->options.merge_options)) < 0 ||
(error = git_merge__check_result(rebase->repo, index)) < 0 ||
(error = git_checkout_index(rebase->repo, index, &checkout_opts)) < 0 ||
(error = git_indexwriter_commit(&indexwriter)) < 0)
@@ -812,6 +834,49 @@ done:
return error;
}
+static int rebase_next_inmemory(
+ git_rebase_operation **out,
+ git_rebase *rebase)
+{
+ git_commit *current_commit = NULL, *parent_commit = NULL;
+ git_tree *current_tree = NULL, *head_tree = NULL, *parent_tree = NULL;
+ git_rebase_operation *operation;
+ git_index *index = NULL;
+ int error;
+
+ *out = NULL;
+
+ operation = git_array_get(rebase->operations, rebase->current);
+
+ if ((error = git_commit_lookup(&current_commit, rebase->repo, &operation->id)) < 0 ||
+ (error = git_commit_tree(&current_tree, current_commit)) < 0 ||
+ (error = git_commit_parent(&parent_commit, current_commit, 0)) < 0 ||
+ (error = git_commit_tree(&parent_tree, parent_commit)) < 0 ||
+ (error = git_commit_tree(&head_tree, rebase->last_commit)) < 0 ||
+ (error = git_merge_trees(&index, rebase->repo, parent_tree, head_tree, current_tree, &rebase->options.merge_options)) < 0)
+ goto done;
+
+ if (!rebase->index) {
+ rebase->index = index;
+ index = NULL;
+ } else {
+ if ((error = git_index_read_index(rebase->index, index)) < 0)
+ goto done;
+ }
+
+ *out = operation;
+
+done:
+ git_commit_free(current_commit);
+ git_commit_free(parent_commit);
+ git_tree_free(current_tree);
+ git_tree_free(head_tree);
+ git_tree_free(parent_tree);
+ git_index_free(index);
+
+ return error;
+}
+
int git_rebase_next(
git_rebase_operation **out,
git_rebase *rebase)
@@ -820,66 +885,67 @@ int git_rebase_next(
assert(out && rebase);
- switch (rebase->type) {
- case GIT_REBASE_TYPE_MERGE:
+ if ((error = rebase_movenext(rebase)) < 0)
+ return error;
+
+ if (rebase->inmemory)
+ error = rebase_next_inmemory(out, rebase);
+ else if (rebase->type == GIT_REBASE_TYPE_MERGE)
error = rebase_next_merge(out, rebase);
- break;
- default:
+ else
abort();
- }
return error;
}
-static int rebase_commit_merge(
- git_oid *commit_id,
+int git_rebase_inmemory_index(
+ git_index **out,
+ git_rebase *rebase)
+{
+ assert(out && rebase && rebase->index);
+
+ GIT_REFCOUNT_INC(rebase->index);
+ *out = rebase->index;
+
+ return 0;
+}
+
+static int rebase_commit__create(
+ git_commit **out,
git_rebase *rebase,
+ git_index *index,
+ git_commit *parent_commit,
const git_signature *author,
const git_signature *committer,
const char *message_encoding,
const char *message)
{
- git_index *index = NULL;
- git_reference *head = NULL;
- git_commit *current_commit = NULL, *head_commit = NULL, *commit = NULL;
git_rebase_operation *operation;
- git_tree *head_tree = NULL, *tree = NULL;
- git_diff *diff = NULL;
- git_oid tree_id;
- git_buf reflog_msg = GIT_BUF_INIT;
- char old_idstr[GIT_OID_HEXSZ], new_idstr[GIT_OID_HEXSZ];
+ git_commit *current_commit = NULL, *commit = NULL;
+ git_tree *parent_tree = NULL, *tree = NULL;
+ git_oid tree_id, commit_id;
int error;
operation = git_array_get(rebase->operations, rebase->current);
- assert(operation);
-
- if ((error = git_repository_index(&index, rebase->repo)) < 0)
- goto done;
if (git_index_has_conflicts(index)) {
- giterr_set(GITERR_REBASE, "Conflicts have not been resolved");
+ giterr_set(GITERR_REBASE, "conflicts have not been resolved");
error = GIT_EUNMERGED;
goto done;
}
- if ((error = rebase_ensure_not_dirty(rebase->repo, false, true, GIT_EUNMERGED)) < 0 ||
- (error = git_commit_lookup(&current_commit, rebase->repo, &operation->id)) < 0 ||
- (error = git_repository_head(&head, rebase->repo)) < 0 ||
- (error = git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT)) < 0 ||
- (error = git_commit_tree(&head_tree, head_commit)) < 0 ||
- (error = git_diff_tree_to_index(&diff, rebase->repo, head_tree, index, NULL)) < 0)
+ if ((error = git_commit_lookup(&current_commit, rebase->repo, &operation->id)) < 0 ||
+ (error = git_commit_tree(&parent_tree, parent_commit)) < 0 ||
+ (error = git_index_write_tree_to(&tree_id, index, rebase->repo)) < 0 ||
+ (error = git_tree_lookup(&tree, rebase->repo, &tree_id)) < 0)
goto done;
- if (git_diff_num_deltas(diff) == 0) {
- giterr_set(GITERR_REBASE, "This patch has already been applied");
+ if (git_oid_equal(&tree_id, git_tree_id(parent_tree))) {
+ giterr_set(GITERR_REBASE, "this patch has already been applied");
error = GIT_EAPPLIED;
goto done;
}
- if ((error = git_index_write_tree(&tree_id, index)) < 0 ||
- (error = git_tree_lookup(&tree, rebase->repo, &tree_id)) < 0)
- goto done;
-
if (!author)
author = git_commit_author(current_commit);
@@ -888,30 +954,100 @@ static int rebase_commit_merge(
message = git_commit_message(current_commit);
}
- if ((error = git_commit_create(commit_id, rebase->repo, NULL, author,
- committer, message_encoding, message, tree, 1,
- (const git_commit **)&head_commit)) < 0 ||
- (error = git_commit_lookup(&commit, rebase->repo, commit_id)) < 0 ||
+ if ((error = git_commit_create(&commit_id, rebase->repo, NULL, author,
+ committer, message_encoding, message, tree, 1,
+ (const git_commit **)&parent_commit)) < 0 ||
+ (error = git_commit_lookup(&commit, rebase->repo, &commit_id)) < 0)
+ goto done;
+
+ *out = commit;
+
+done:
+ if (error < 0)
+ git_commit_free(commit);
+
+ git_commit_free(current_commit);
+ git_tree_free(parent_tree);
+ git_tree_free(tree);
+
+ return error;
+}
+
+static int rebase_commit_merge(
+ git_oid *commit_id,
+ git_rebase *rebase,
+ const git_signature *author,
+ const git_signature *committer,
+ const char *message_encoding,
+ const char *message)
+{
+ git_rebase_operation *operation;
+ git_reference *head = NULL;
+ git_commit *head_commit = NULL, *commit = NULL;
+ git_index *index = NULL;
+ char old_idstr[GIT_OID_HEXSZ], new_idstr[GIT_OID_HEXSZ];
+ int error;
+
+ operation = git_array_get(rebase->operations, rebase->current);
+ assert(operation);
+
+ if ((error = rebase_ensure_not_dirty(rebase->repo, false, true, GIT_EUNMERGED)) < 0 ||
+ (error = git_repository_head(&head, rebase->repo)) < 0 ||
+ (error = git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT)) < 0 ||
+ (error = git_repository_index(&index, rebase->repo)) < 0 ||
+ (error = rebase_commit__create(&commit, rebase, index, head_commit,
+ author, committer, message_encoding, message)) < 0 ||
(error = git_reference__update_for_commit(
- rebase->repo, NULL, "HEAD", commit_id, "rebase")) < 0)
+ rebase->repo, NULL, "HEAD", git_commit_id(commit), "rebase")) < 0)
goto done;
- git_oid_fmt(old_idstr, git_commit_id(current_commit));
- git_oid_fmt(new_idstr, commit_id);
+ git_oid_fmt(old_idstr, &operation->id);
+ git_oid_fmt(new_idstr, git_commit_id(commit));
- error = rebase_setupfile(rebase, REWRITTEN_FILE, O_CREAT|O_WRONLY|O_APPEND,
- "%.*s %.*s\n", GIT_OID_HEXSZ, old_idstr, GIT_OID_HEXSZ, new_idstr);
+ if ((error = rebase_setupfile(rebase, REWRITTEN_FILE, O_CREAT|O_WRONLY|O_APPEND,
+ "%.*s %.*s\n", GIT_OID_HEXSZ, old_idstr, GIT_OID_HEXSZ, new_idstr)) < 0)
+ goto done;
+
+ git_oid_cpy(commit_id, git_commit_id(commit));
done:
- git_buf_free(&reflog_msg);
- git_commit_free(commit);
- git_diff_free(diff);
- git_tree_free(tree);
- git_tree_free(head_tree);
- git_commit_free(head_commit);
- git_commit_free(current_commit);
- git_reference_free(head);
git_index_free(index);
+ git_reference_free(head);
+ git_commit_free(head_commit);
+ git_commit_free(commit);
+ return error;
+}
+
+static int rebase_commit_inmemory(
+ git_oid *commit_id,
+ git_rebase *rebase,
+ const git_signature *author,
+ const git_signature *committer,
+ const char *message_encoding,
+ const char *message)
+{
+ git_rebase_operation *operation;
+ git_commit *commit = NULL;
+ int error = 0;
+
+ operation = git_array_get(rebase->operations, rebase->current);
+
+ assert(operation);
+ assert(rebase->index);
+ assert(rebase->last_commit);
+
+ if ((error = rebase_commit__create(&commit, rebase, rebase->index,
+ rebase->last_commit, author, committer, message_encoding, message)) < 0)
+ goto done;
+
+ git_commit_free(rebase->last_commit);
+ rebase->last_commit = commit;
+
+ git_oid_cpy(commit_id, git_commit_id(commit));
+
+done:
+ if (error < 0)
+ git_commit_free(commit);
return error;
}
@@ -928,14 +1064,14 @@ int git_rebase_commit(
assert(rebase && committer);
- switch (rebase->type) {
- case GIT_REBASE_TYPE_MERGE:
+ if (rebase->inmemory)
+ error = rebase_commit_inmemory(
+ id, rebase, author, committer, message_encoding, message);
+ else if (rebase->type == GIT_REBASE_TYPE_MERGE)
error = rebase_commit_merge(
id, rebase, author, committer, message_encoding, message);
- break;
- default:
+ else
abort();
- }
return error;
}
@@ -948,6 +1084,9 @@ int git_rebase_abort(git_rebase *rebase)
assert(rebase);
+ if (rebase->inmemory)
+ return 0;
+
error = rebase->head_detached ?
git_reference_create(&orig_head_ref, rebase->repo, GIT_HEAD_FILE,
&rebase->orig_head_id, 1, "rebase: aborting") :
@@ -1125,6 +1264,9 @@ int git_rebase_finish(
assert(rebase);
+ if (rebase->inmemory)
+ return 0;
+
git_oid_fmt(onto, &rebase->onto_id);
if ((error = git_buf_printf(&branch_msg, "rebase finished: %s onto %.*s",
@@ -1182,6 +1324,8 @@ void git_rebase_free(git_rebase *rebase)
if (rebase == NULL)
return;
+ git_index_free(rebase->index);
+ git_commit_free(rebase->last_commit);
git__free(rebase->onto_name);
git__free(rebase->orig_head_name);
git__free(rebase->state_path);
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index 85b5034d6..1348c67a1 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -717,7 +717,7 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *
assert(file && backend && name);
- if (!git_path_isvalid(backend->repo, name, GIT_PATH_REJECT_DEFAULTS)) {
+ if (!git_path_isvalid(backend->repo, name, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
giterr_set(GITERR_INVALID, "Invalid reference name '%s'.", name);
return GIT_EINVALIDSPEC;
}
@@ -1672,7 +1672,7 @@ static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char
repo = backend->repo;
- if (!git_path_isvalid(backend->repo, refname, GIT_PATH_REJECT_DEFAULTS)) {
+ if (!git_path_isvalid(backend->repo, refname, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
giterr_set(GITERR_INVALID, "Invalid reference name '%s'.", refname);
return GIT_EINVALIDSPEC;
}
diff --git a/src/stash.c b/src/stash.c
index 35824659a..43a464e64 100644
--- a/src/stash.c
+++ b/src/stash.c
@@ -685,8 +685,8 @@ static int merge_indexes(
iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;
if ((error = git_iterator_for_tree(&ancestor, ancestor_tree, &iter_opts)) < 0 ||
- (error = git_iterator_for_index(&ours, ours_index, &iter_opts)) < 0 ||
- (error = git_iterator_for_index(&theirs, theirs_index, &iter_opts)) < 0)
+ (error = git_iterator_for_index(&ours, repo, ours_index, &iter_opts)) < 0 ||
+ (error = git_iterator_for_index(&theirs, repo, theirs_index, &iter_opts)) < 0)
goto done;
error = git_merge__iterators(out, repo, ancestor, ours, theirs, NULL);
@@ -712,7 +712,7 @@ static int merge_index_and_tree(
iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;
if ((error = git_iterator_for_tree(&ancestor, ancestor_tree, &iter_opts)) < 0 ||
- (error = git_iterator_for_index(&ours, ours_index, &iter_opts)) < 0 ||
+ (error = git_iterator_for_index(&ours, repo, ours_index, &iter_opts)) < 0 ||
(error = git_iterator_for_tree(&theirs, theirs_tree, &iter_opts)) < 0)
goto done;
@@ -728,7 +728,7 @@ done:
static void normalize_apply_options(
git_stash_apply_options *opts,
const git_stash_apply_options *given_apply_opts)
-{
+{
if (given_apply_opts != NULL) {
memcpy(opts, given_apply_opts, sizeof(git_stash_apply_options));
} else {
diff --git a/src/submodule.c b/src/submodule.c
index cdae3dddf..38db41529 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -327,7 +327,7 @@ static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cf
const git_index_entry *entry;
git_buf name = GIT_BUF_INIT;
- if ((error = git_iterator_for_index(&i, idx, NULL)) < 0)
+ if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0)
return error;
while (!(error = git_iterator_advance(&entry, i))) {
@@ -1037,7 +1037,7 @@ static int submodule_repo_create(
/**
* Repodir: path to the sub-repo. sub-repo goes in:
- * <repo-dir>/modules/<name>/ with a gitlink in the
+ * <repo-dir>/modules/<name>/ with a gitlink in the
* sub-repo workdir directory to that repository.
*/
error = git_buf_join3(
@@ -1154,7 +1154,7 @@ int git_submodule_update(git_submodule *sm, int init, git_submodule_update_optio
clone_options.repository_cb_payload = sm;
/*
- * Do not perform checkout as part of clone, instead we
+ * Do not perform checkout as part of clone, instead we
* will checkout the specific commit manually.
*/
clone_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE;
diff --git a/tests/commit/parse.c b/tests/commit/parse.c
index 733fbae82..838cfb467 100644
--- a/tests/commit/parse.c
+++ b/tests/commit/parse.c
@@ -453,10 +453,17 @@ cpxtDQQMGYFpXK/71stq\n\
cl_git_pass(git_commit_header_field(&buf, commit, "gpgsig"));
cl_assert_equal_s(gpgsig, buf.ptr);
+ git_buf_clear(&buf);
cl_git_fail_with(GIT_ENOTFOUND, git_commit_header_field(&buf, commit, "awesomeness"));
cl_git_fail_with(GIT_ENOTFOUND, git_commit_header_field(&buf, commit, "par"));
+ git_commit__free(commit);
+ cl_git_pass(parse_commit(&commit, passing_commit_cases[0]));
+
+ cl_git_pass(git_commit_header_field(&buf, commit, "committer"));
+ cl_assert_equal_s("Vicent Marti <tanoku@gmail.com> 1273848544 +0200", buf.ptr);
+
git_buf_free(&buf);
git_commit__free(commit);
}
@@ -506,6 +513,17 @@ a simple commit which works\n";
cl_assert_equal_s(gpgsig, signature.ptr);
cl_assert_equal_s(data, signed_data.ptr);
+ /* Try to parse a tree */
+ cl_git_pass(git_oid_fromstr(&commit_id, "45dd856fdd4d89b884c340ba0e047752d9b085d6"));
+ cl_git_fail_with(GIT_ENOTFOUND, git_commit_extract_signature(&signature, &signed_data, g_repo, &commit_id, NULL));
+ cl_assert_equal_i(GITERR_INVALID, giterr_last()->klass);
+
+ /* Try to parse an unsigned commit */
+ cl_git_pass(git_odb_write(&commit_id, odb, passing_commit_cases[1], strlen(passing_commit_cases[1]), GIT_OBJ_COMMIT));
+ cl_git_fail_with(GIT_ENOTFOUND, git_commit_extract_signature(&signature, &signed_data, g_repo, &commit_id, NULL));
+ cl_assert_equal_i(GITERR_OBJECT, giterr_last()->klass);
+
git_buf_free(&signature);
git_buf_free(&signed_data);
+
}
diff --git a/tests/diff/iterator.c b/tests/diff/iterator.c
index eafb1b9da..8417e8ed4 100644
--- a/tests/diff/iterator.c
+++ b/tests/diff/iterator.c
@@ -380,7 +380,7 @@ static void index_iterator_test(
iter_opts.start = start;
iter_opts.end = end;
- cl_git_pass(git_iterator_for_index(&i, index, &iter_opts));
+ cl_git_pass(git_iterator_for_index(&i, repo, index, &iter_opts));
while (!(error = git_iterator_advance(&entry, i))) {
cl_assert(entry);
@@ -974,7 +974,7 @@ static void check_index_range(
i_opts.start = start;
i_opts.end = end;
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, repo, index, &i_opts));
cl_assert(git_iterator_ignore_case(i) == ignore_case);
diff --git a/tests/path/core.c b/tests/path/core.c
index 064f1492a..3dccfe5fb 100644
--- a/tests/path/core.c
+++ b/tests/path/core.c
@@ -105,12 +105,12 @@ void test_path_core__isvalid_dot_git(void)
cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.GIT/bar", 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/.Git", 0));
- cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", GIT_PATH_REJECT_DOT_GIT));
- cl_assert_equal_b(false, git_path_isvalid(NULL, ".git/foo", GIT_PATH_REJECT_DOT_GIT));
- cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git", GIT_PATH_REJECT_DOT_GIT));
- cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git/bar", GIT_PATH_REJECT_DOT_GIT));
- cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.GIT/bar", GIT_PATH_REJECT_DOT_GIT));
- cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar/.Git", GIT_PATH_REJECT_DOT_GIT));
+ cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", GIT_PATH_REJECT_DOT_GIT_LITERAL));
+ cl_assert_equal_b(false, git_path_isvalid(NULL, ".git/foo", GIT_PATH_REJECT_DOT_GIT_LITERAL));
+ cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git", GIT_PATH_REJECT_DOT_GIT_LITERAL));
+ cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git/bar", GIT_PATH_REJECT_DOT_GIT_LITERAL));
+ cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.GIT/bar", GIT_PATH_REJECT_DOT_GIT_LITERAL));
+ cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar/.Git", GIT_PATH_REJECT_DOT_GIT_LITERAL));
cl_assert_equal_b(true, git_path_isvalid(NULL, "!git", 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/!git", 0));
diff --git a/tests/rebase/inmemory.c b/tests/rebase/inmemory.c
new file mode 100644
index 000000000..d5d89c719
--- /dev/null
+++ b/tests/rebase/inmemory.c
@@ -0,0 +1,116 @@
+#include "clar_libgit2.h"
+#include "git2/rebase.h"
+#include "posix.h"
+
+#include <fcntl.h>
+
+static git_repository *repo;
+
+// Fixture setup and teardown
+void test_rebase_inmemory__initialize(void)
+{
+ repo = cl_git_sandbox_init("rebase");
+}
+
+void test_rebase_inmemory__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
+void test_rebase_inmemory__not_in_rebase_state(void)
+{
+ git_rebase *rebase;
+ git_reference *branch_ref, *upstream_ref;
+ git_annotated_commit *branch_head, *upstream_head;
+ git_rebase_options opts = GIT_REBASE_OPTIONS_INIT;
+
+ opts.inmemory = true;
+
+ cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef"));
+ cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master"));
+
+ cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref));
+ cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref));
+
+ cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, &opts));
+
+ cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo));
+
+ git_rebase_free(rebase);
+
+ git_annotated_commit_free(branch_head);
+ git_annotated_commit_free(upstream_head);
+
+ git_reference_free(branch_ref);
+ git_reference_free(upstream_ref);
+}
+
+void test_rebase_inmemory__can_resolve_conflicts(void)
+{
+ git_rebase *rebase;
+ git_reference *branch_ref, *upstream_ref;
+ git_annotated_commit *branch_head, *upstream_head;
+ git_rebase_operation *rebase_operation;
+ git_status_list *status_list;
+ git_oid pick_id, commit_id, expected_commit_id;
+ git_signature *signature;
+ git_index *rebase_index, *repo_index;
+ git_index_entry resolution = {{0}};
+ git_rebase_options opts = GIT_REBASE_OPTIONS_INIT;
+
+ cl_git_pass(git_signature_new(&signature,
+ "Rebaser", "rebaser@rebaser.rb", 1405694510, 0));
+
+ opts.inmemory = true;
+
+ cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/asparagus"));
+ cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master"));
+
+ cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref));
+ cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref));
+
+ cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, &opts));
+
+ cl_git_pass(git_rebase_next(&rebase_operation, rebase));
+
+ git_oid_fromstr(&pick_id, "33f915f9e4dbd9f4b24430e48731a59b45b15500");
+
+ cl_assert_equal_i(GIT_REBASE_OPERATION_PICK, rebase_operation->type);
+ cl_assert_equal_oid(&pick_id, &rebase_operation->id);
+
+ /* ensure that we did not do anything stupid to the workdir or repo index */
+ cl_git_pass(git_repository_index(&repo_index, repo));
+ cl_assert(!git_index_has_conflicts(repo_index));
+
+ cl_git_pass(git_status_list_new(&status_list, repo, NULL));
+ cl_assert_equal_i(0, git_status_list_entrycount(status_list));
+
+ /* but that the index returned from rebase does have conflicts */
+ cl_git_pass(git_rebase_inmemory_index(&rebase_index, rebase));
+ cl_assert(git_index_has_conflicts(rebase_index));
+
+ cl_git_fail_with(GIT_EUNMERGED, git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL));
+
+ /* ensure that we can work with the in-memory index to resolve the conflict */
+ resolution.path = "asparagus.txt";
+ resolution.mode = GIT_FILEMODE_BLOB;
+ git_oid_fromstr(&resolution.id, "414dfc71ead79c07acd4ea47fecf91f289afc4b9");
+ cl_git_pass(git_index_conflict_remove(rebase_index, "asparagus.txt"));
+ cl_git_pass(git_index_add(rebase_index, &resolution));
+
+ /* and finally create a commit for the resolved rebase operation */
+ cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL));
+
+ cl_git_pass(git_oid_fromstr(&expected_commit_id, "db7af47222181e548810da2ab5fec0e9357c5637"));
+ cl_assert_equal_oid(&commit_id, &expected_commit_id);
+
+ git_signature_free(signature);
+ git_status_list_free(status_list);
+ git_annotated_commit_free(branch_head);
+ git_annotated_commit_free(upstream_head);
+ git_reference_free(branch_ref);
+ git_reference_free(upstream_ref);
+ git_index_free(repo_index);
+ git_index_free(rebase_index);
+ git_rebase_free(rebase);
+}
diff --git a/tests/rebase/iterator.c b/tests/rebase/iterator.c
index acf2a92db..db57b0a83 100644
--- a/tests/rebase/iterator.c
+++ b/tests/rebase/iterator.c
@@ -13,7 +13,8 @@ void test_rebase_iterator__initialize(void)
{
repo = cl_git_sandbox_init("rebase");
cl_git_pass(git_repository_index(&_index, repo));
- cl_git_pass(git_signature_now(&signature, "Rebaser", "rebaser@rebaser.rb"));
+ cl_git_pass(git_signature_new(&signature, "Rebaser",
+ "rebaser@rebaser.rb", 1405694510, 0));
}
void test_rebase_iterator__cleanup(void)
@@ -46,54 +47,77 @@ static void test_operations(git_rebase *rebase, size_t expected_current)
}
}
-void test_rebase_iterator__iterates(void)
+void test_iterator(bool inmemory)
{
git_rebase *rebase;
+ git_rebase_options opts = GIT_REBASE_OPTIONS_INIT;
git_reference *branch_ref, *upstream_ref;
git_annotated_commit *branch_head, *upstream_head;
git_rebase_operation *rebase_operation;
- git_oid commit_id;
+ git_oid commit_id, expected_id;
int error;
+ opts.inmemory = inmemory;
+
cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef"));
cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master"));
cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref));
cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref));
- cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL));
+ cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, &opts));
test_operations(rebase, GIT_REBASE_NO_OPERATION);
- git_rebase_free(rebase);
- cl_git_pass(git_rebase_open(&rebase, repo, NULL));
+ if (!inmemory) {
+ git_rebase_free(rebase);
+ cl_git_pass(git_rebase_open(&rebase, repo, NULL));
+ }
+
cl_git_pass(git_rebase_next(&rebase_operation, rebase));
cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature,
NULL, NULL));
test_operations(rebase, 0);
+ git_oid_fromstr(&expected_id, "776e4c48922799f903f03f5f6e51da8b01e4cce0");
+ cl_assert_equal_oid(&expected_id, &commit_id);
+
cl_git_pass(git_rebase_next(&rebase_operation, rebase));
cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature,
NULL, NULL));
test_operations(rebase, 1);
+ git_oid_fromstr(&expected_id, "ba1f9b4fd5cf8151f7818be2111cc0869f1eb95a");
+ cl_assert_equal_oid(&expected_id, &commit_id);
+
cl_git_pass(git_rebase_next(&rebase_operation, rebase));
cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature,
NULL, NULL));
test_operations(rebase, 2);
- git_rebase_free(rebase);
- cl_git_pass(git_rebase_open(&rebase, repo, NULL));
+ git_oid_fromstr(&expected_id, "948b12fe18b84f756223a61bece4c307787cd5d4");
+ cl_assert_equal_oid(&expected_id, &commit_id);
+
+ if (!inmemory) {
+ git_rebase_free(rebase);
+ cl_git_pass(git_rebase_open(&rebase, repo, NULL));
+ }
cl_git_pass(git_rebase_next(&rebase_operation, rebase));
cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature,
NULL, NULL));
test_operations(rebase, 3);
+ git_oid_fromstr(&expected_id, "d9d5d59d72c9968687f9462578d79878cd80e781");
+ cl_assert_equal_oid(&expected_id, &commit_id);
+
cl_git_pass(git_rebase_next(&rebase_operation, rebase));
cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature,
NULL, NULL));
test_operations(rebase, 4);
+ git_oid_fromstr(&expected_id, "9cf383c0a125d89e742c5dec58ed277dd07588b3");
+ cl_assert_equal_oid(&expected_id, &commit_id);
+
cl_git_fail(error = git_rebase_next(&rebase_operation, rebase));
cl_assert_equal_i(GIT_ITEROVER, error);
test_operations(rebase, 4);
@@ -104,3 +128,13 @@ void test_rebase_iterator__iterates(void)
git_reference_free(upstream_ref);
git_rebase_free(rebase);
}
+
+void test_rebase_iterator__iterates(void)
+{
+ test_iterator(false);
+}
+
+void test_rebase_iterator__iterates_inmemory(void)
+{
+ test_iterator(true);
+}
diff --git a/tests/rebase/merge.c b/tests/rebase/merge.c
index 33eadb7ed..c60113b64 100644
--- a/tests/rebase/merge.c
+++ b/tests/rebase/merge.c
@@ -565,3 +565,33 @@ void test_rebase_merge__custom_checkout_options(void)
git_reference_free(upstream_ref);
git_rebase_free(rebase);
}
+
+void test_rebase_merge__custom_merge_options(void)
+{
+ git_rebase *rebase;
+ git_reference *branch_ref, *upstream_ref;
+ git_annotated_commit *branch_head, *upstream_head;
+ git_rebase_options rebase_options = GIT_REBASE_OPTIONS_INIT;
+ git_rebase_operation *rebase_operation;
+
+ rebase_options.merge_options.flags |=
+ GIT_MERGE_FAIL_ON_CONFLICT |
+ GIT_MERGE_SKIP_REUC;
+
+ cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/asparagus"));
+ cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master"));
+
+ cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref));
+ cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref));
+
+ cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, &rebase_options));
+
+ cl_git_fail_with(GIT_EMERGECONFLICT, git_rebase_next(&rebase_operation, rebase));
+
+ git_annotated_commit_free(branch_head);
+ git_annotated_commit_free(upstream_head);
+ git_reference_free(branch_ref);
+ git_reference_free(upstream_ref);
+ git_rebase_free(rebase);
+}
+
diff --git a/tests/repo/iterator.c b/tests/repo/iterator.c
index 83b824691..c18e24a4f 100644
--- a/tests/repo/iterator.c
+++ b/tests/repo/iterator.c
@@ -134,19 +134,19 @@ void test_repo_iterator__index(void)
cl_git_pass(git_repository_index(&index, g_repo));
/* autoexpand with no tree entries for index */
- cl_git_pass(git_iterator_for_index(&i, index, NULL));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, NULL));
expect_iterator_items(i, 20, NULL, 20, NULL);
git_iterator_free(i);
/* auto expand with tree entries */
i_opts.flags = GIT_ITERATOR_INCLUDE_TREES;
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 22, NULL, 22, NULL);
git_iterator_free(i);
/* no auto expand (implies trees included) */
i_opts.flags = GIT_ITERATOR_DONT_AUTOEXPAND;
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 12, NULL, 22, NULL);
git_iterator_free(i);
@@ -171,13 +171,13 @@ void test_repo_iterator__index_icase(void)
/* autoexpand with no tree entries over range */
i_opts.start = "c";
i_opts.end = "k/D";
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 7, NULL, 7, NULL);
git_iterator_free(i);
i_opts.start = "k";
i_opts.end = "k/Z";
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 3, NULL, 3, NULL);
git_iterator_free(i);
@@ -186,13 +186,13 @@ void test_repo_iterator__index_icase(void)
i_opts.start = "c";
i_opts.end = "k/D";
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 8, NULL, 8, NULL);
git_iterator_free(i);
i_opts.start = "k";
i_opts.end = "k/Z";
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 4, NULL, 4, NULL);
git_iterator_free(i);
@@ -201,13 +201,13 @@ void test_repo_iterator__index_icase(void)
i_opts.start = "c";
i_opts.end = "k/D";
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 5, NULL, 8, NULL);
git_iterator_free(i);
i_opts.start = "k";
i_opts.end = "k/Z";
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 1, NULL, 4, NULL);
git_iterator_free(i);
@@ -219,13 +219,13 @@ void test_repo_iterator__index_icase(void)
i_opts.start = "c";
i_opts.end = "k/D";
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 13, NULL, 13, NULL);
git_iterator_free(i);
i_opts.start = "k";
i_opts.end = "k/Z";
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 5, NULL, 5, NULL);
git_iterator_free(i);
@@ -234,13 +234,13 @@ void test_repo_iterator__index_icase(void)
i_opts.start = "c";
i_opts.end = "k/D";
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 14, NULL, 14, NULL);
git_iterator_free(i);
i_opts.start = "k";
i_opts.end = "k/Z";
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 6, NULL, 6, NULL);
git_iterator_free(i);
@@ -249,13 +249,13 @@ void test_repo_iterator__index_icase(void)
i_opts.start = "c";
i_opts.end = "k/D";
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 9, NULL, 14, NULL);
git_iterator_free(i);
i_opts.start = "k";
i_opts.end = "k/Z";
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 1, NULL, 6, NULL);
git_iterator_free(i);
@@ -1108,14 +1108,14 @@ void test_repo_iterator__indexfilelist(void)
/* All indexfilelist iterator tests are "autoexpand with no tree entries" */
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 8, NULL, 8, NULL);
git_iterator_free(i);
i_opts.start = "c";
i_opts.end = NULL;
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
/* (c D e k/1 k/a L ==> 6) vs (c e k/1 k/a ==> 4) */
expect = ((default_icase) ? 6 : 4);
expect_iterator_items(i, expect, NULL, expect, NULL);
@@ -1124,7 +1124,7 @@ void test_repo_iterator__indexfilelist(void)
i_opts.start = NULL;
i_opts.end = "e";
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
/* (a B c D e ==> 5) vs (B D L/1 a c e ==> 6) */
expect = ((default_icase) ? 5 : 6);
expect_iterator_items(i, expect, NULL, expect, NULL);
@@ -1166,7 +1166,7 @@ void test_repo_iterator__indexfilelist_2(void)
/* (c D e k/1 k/a ==> 5) vs (c e k/1 ==> 3) */
expect = default_icase ? 5 : 3;
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, expect, NULL, expect, NULL);
git_iterator_free(i);
@@ -1208,7 +1208,7 @@ void test_repo_iterator__indexfilelist_3(void)
/* (c D e k/1 k/a k/B k/c k/D) vs (c e k/1 k/B k/D) */
expect = default_icase ? 8 : 5;
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, expect, NULL, expect, NULL);
git_iterator_free(i);
@@ -1250,7 +1250,7 @@ void test_repo_iterator__indexfilelist_4(void)
/* (c D e k/1 k/a k/B k/c k/D) vs (c e k/1 k/B k/D) */
expect = default_icase ? 8 : 5;
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, expect, NULL, expect, NULL);
git_iterator_free(i);
@@ -1291,13 +1291,13 @@ void test_repo_iterator__indexfilelist_icase(void)
i_opts.start = "c";
i_opts.end = "k/D";
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 3, NULL, 3, NULL);
git_iterator_free(i);
i_opts.start = "k";
i_opts.end = "k/Z";
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 1, NULL, 1, NULL);
git_iterator_free(i);
@@ -1306,13 +1306,13 @@ void test_repo_iterator__indexfilelist_icase(void)
i_opts.start = "c";
i_opts.end = "k/D";
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 5, NULL, 5, NULL);
git_iterator_free(i);
i_opts.start = "k";
i_opts.end = "k/Z";
- cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ cl_git_pass(git_iterator_for_index(&i, g_repo, index, &i_opts));
expect_iterator_items(i, 2, NULL, 2, NULL);
git_iterator_free(i);
diff --git a/tests/resources/win32-forbidden/.gitted/HEAD b/tests/resources/win32-forbidden/.gitted/HEAD
new file mode 100644
index 000000000..cb089cd89
--- /dev/null
+++ b/tests/resources/win32-forbidden/.gitted/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests/resources/win32-forbidden/.gitted/config b/tests/resources/win32-forbidden/.gitted/config
new file mode 100644
index 000000000..6c9406b7d
--- /dev/null
+++ b/tests/resources/win32-forbidden/.gitted/config
@@ -0,0 +1,7 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ ignorecase = true
+ precomposeunicode = true
diff --git a/tests/resources/win32-forbidden/.gitted/index b/tests/resources/win32-forbidden/.gitted/index
new file mode 100644
index 000000000..1202dd9f4
--- /dev/null
+++ b/tests/resources/win32-forbidden/.gitted/index
Binary files differ
diff --git a/tests/resources/win32-forbidden/.gitted/info/exclude b/tests/resources/win32-forbidden/.gitted/info/exclude
new file mode 100644
index 000000000..a5196d1be
--- /dev/null
+++ b/tests/resources/win32-forbidden/.gitted/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests/resources/win32-forbidden/.gitted/objects/10/68072702a28a82c78902cf5bf82c3864cf4356 b/tests/resources/win32-forbidden/.gitted/objects/10/68072702a28a82c78902cf5bf82c3864cf4356
new file mode 100644
index 000000000..2d3b31adc
--- /dev/null
+++ b/tests/resources/win32-forbidden/.gitted/objects/10/68072702a28a82c78902cf5bf82c3864cf4356
Binary files differ
diff --git a/tests/resources/win32-forbidden/.gitted/objects/17/6a458f94e0ea5272ce67c36bf30b6be9caf623 b/tests/resources/win32-forbidden/.gitted/objects/17/6a458f94e0ea5272ce67c36bf30b6be9caf623
new file mode 100644
index 000000000..ef8316670
--- /dev/null
+++ b/tests/resources/win32-forbidden/.gitted/objects/17/6a458f94e0ea5272ce67c36bf30b6be9caf623
Binary files differ
diff --git a/tests/resources/win32-forbidden/.gitted/objects/2d/7445a749d25269f32724aa621cb70b196bcc40 b/tests/resources/win32-forbidden/.gitted/objects/2d/7445a749d25269f32724aa621cb70b196bcc40
new file mode 100644
index 000000000..baddb1fc6
--- /dev/null
+++ b/tests/resources/win32-forbidden/.gitted/objects/2d/7445a749d25269f32724aa621cb70b196bcc40
Binary files differ
diff --git a/tests/resources/win32-forbidden/.gitted/objects/34/96991d72d500af36edef68bbfcccd1661d88db b/tests/resources/win32-forbidden/.gitted/objects/34/96991d72d500af36edef68bbfcccd1661d88db
new file mode 100644
index 000000000..71b6172c6
--- /dev/null
+++ b/tests/resources/win32-forbidden/.gitted/objects/34/96991d72d500af36edef68bbfcccd1661d88db
@@ -0,0 +1,3 @@
+x
+![whӢ}/8B*8N~@gu՜S ͡7a
+f2"s e.%Q ؽ຾m[kjmGq_N3LBJŔFG:B VRO ͿҖj!= \ No newline at end of file
diff --git a/tests/resources/win32-forbidden/.gitted/objects/8f/45aad6f23b9509f8786c617e19c127ae76609a b/tests/resources/win32-forbidden/.gitted/objects/8f/45aad6f23b9509f8786c617e19c127ae76609a
new file mode 100644
index 000000000..8bcd980c4
--- /dev/null
+++ b/tests/resources/win32-forbidden/.gitted/objects/8f/45aad6f23b9509f8786c617e19c127ae76609a
@@ -0,0 +1,2 @@
+xA
+ ֝/k. ]`h޾"= ˕e* U+M%O4c˱ \ No newline at end of file
diff --git a/tests/resources/win32-forbidden/.gitted/objects/da/623abd956bb2fd8052c708c7ed43f05d192d37 b/tests/resources/win32-forbidden/.gitted/objects/da/623abd956bb2fd8052c708c7ed43f05d192d37
new file mode 100644
index 000000000..923462306
--- /dev/null
+++ b/tests/resources/win32-forbidden/.gitted/objects/da/623abd956bb2fd8052c708c7ed43f05d192d37
Binary files differ
diff --git a/tests/resources/win32-forbidden/.gitted/objects/ea/c7621a652e5261ef1c1d3e7ae31b0d84fcbaba b/tests/resources/win32-forbidden/.gitted/objects/ea/c7621a652e5261ef1c1d3e7ae31b0d84fcbaba
new file mode 100644
index 000000000..32b3f02ec
--- /dev/null
+++ b/tests/resources/win32-forbidden/.gitted/objects/ea/c7621a652e5261ef1c1d3e7ae31b0d84fcbaba
@@ -0,0 +1,3 @@
+xM
+B!F;BoW}BDۀ
+>_m?BgqVJ =FdJTqDdBN'6Rp S+kpGrAR*Tz! vVGn5l_;U>H \ No newline at end of file
diff --git a/tests/resources/win32-forbidden/.gitted/refs/heads/master b/tests/resources/win32-forbidden/.gitted/refs/heads/master
new file mode 100644
index 000000000..47fce0fe3
--- /dev/null
+++ b/tests/resources/win32-forbidden/.gitted/refs/heads/master
@@ -0,0 +1 @@
+3496991d72d500af36edef68bbfcccd1661d88db
diff --git a/tests/win32/forbidden.c b/tests/win32/forbidden.c
new file mode 100644
index 000000000..e02f41179
--- /dev/null
+++ b/tests/win32/forbidden.c
@@ -0,0 +1,183 @@
+#include "clar_libgit2.h"
+
+#include "repository.h"
+#include "buffer.h"
+#include "submodule.h"
+
+static const char *repo_name = "win32-forbidden";
+static git_repository *repo;
+
+void test_win32_forbidden__initialize(void)
+{
+ repo = cl_git_sandbox_init(repo_name);
+}
+
+void test_win32_forbidden__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
+void test_win32_forbidden__can_open_index(void)
+{
+ git_index *index;
+ cl_git_pass(git_repository_index(&index, repo));
+ cl_assert_equal_i(7, git_index_entrycount(index));
+
+ /* ensure we can even write the unmodified index */
+ cl_git_pass(git_index_write(index));
+
+ git_index_free(index);
+}
+
+void test_win32_forbidden__can_add_forbidden_filename_with_entry(void)
+{
+ git_index *index;
+ git_index_entry entry = {{0}};
+
+ cl_git_pass(git_repository_index(&index, repo));
+
+ entry.path = "aux";
+ entry.mode = GIT_FILEMODE_BLOB;
+ git_oid_fromstr(&entry.id, "da623abd956bb2fd8052c708c7ed43f05d192d37");
+
+ cl_git_pass(git_index_add(index, &entry));
+
+ git_index_free(index);
+}
+
+void test_win32_forbidden__cannot_add_dot_git_even_with_entry(void)
+{
+ git_index *index;
+ git_index_entry entry = {{0}};
+
+ cl_git_pass(git_repository_index(&index, repo));
+
+ entry.path = "foo/.git";
+ entry.mode = GIT_FILEMODE_BLOB;
+ git_oid_fromstr(&entry.id, "da623abd956bb2fd8052c708c7ed43f05d192d37");
+
+ cl_git_fail(git_index_add(index, &entry));
+
+ git_index_free(index);
+}
+
+void test_win32_forbidden__cannot_add_forbidden_filename_from_filesystem(void)
+{
+ git_index *index;
+
+ /* since our function calls are very low-level, we can create `aux.`,
+ * but we should not be able to add it to the index
+ */
+ cl_git_pass(git_repository_index(&index, repo));
+ cl_git_write2file("win32-forbidden/aux.", "foo\n", 4, O_RDWR | O_CREAT, 0666);
+
+#ifdef GIT_WIN32
+ cl_git_fail(git_index_add_bypath(index, "aux."));
+#else
+ cl_git_pass(git_index_add_bypath(index, "aux."));
+#endif
+
+ cl_must_pass(p_unlink("win32-forbidden/aux."));
+ git_index_free(index);
+}
+
+static int dummy_submodule_cb(
+ git_submodule *sm, const char *name, void *payload)
+{
+ GIT_UNUSED(sm);
+ GIT_UNUSED(name);
+ GIT_UNUSED(payload);
+ return 0;
+}
+
+void test_win32_forbidden__can_diff_tree_to_index(void)
+{
+ git_diff *diff;
+ git_tree *tree;
+
+ cl_git_pass(git_repository_head_tree(&tree, repo));
+ cl_git_pass(git_diff_tree_to_index(&diff, repo, tree, NULL, NULL));
+ cl_assert_equal_i(0, git_diff_num_deltas(diff));
+ git_diff_free(diff);
+ git_tree_free(tree);
+}
+
+void test_win32_forbidden__can_diff_tree_to_tree(void)
+{
+ git_diff *diff;
+ git_tree *tree;
+
+ cl_git_pass(git_repository_head_tree(&tree, repo));
+ cl_git_pass(git_diff_tree_to_tree(&diff, repo, tree, tree, NULL));
+ cl_assert_equal_i(0, git_diff_num_deltas(diff));
+ git_diff_free(diff);
+ git_tree_free(tree);
+}
+
+void test_win32_forbidden__can_diff_index_to_workdir(void)
+{
+ git_index *index;
+ git_diff *diff;
+ const git_diff_delta *delta;
+ git_tree *tree;
+ size_t i;
+
+ cl_git_pass(git_repository_index(&index, repo));
+ cl_git_pass(git_repository_head_tree(&tree, repo));
+ cl_git_pass(git_diff_index_to_workdir(&diff, repo, index, NULL));
+
+ for (i = 0; i < git_diff_num_deltas(diff); i++) {
+ delta = git_diff_get_delta(diff, i);
+ cl_assert_equal_i(GIT_DELTA_DELETED, delta->status);
+ }
+
+ git_diff_free(diff);
+ git_tree_free(tree);
+ git_index_free(index);
+}
+
+void test_win32_forbidden__checking_out_forbidden_index_fails(void)
+{
+#ifdef GIT_WIN32
+ git_index *index;
+ git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+ git_diff *diff;
+ const git_diff_delta *delta;
+ git_tree *tree;
+ size_t num_deltas, i;
+
+ opts.checkout_strategy = GIT_CHECKOUT_FORCE;
+
+ cl_git_pass(git_repository_index(&index, repo));
+ cl_git_fail(git_checkout_index(repo, index, &opts));
+
+ cl_git_pass(git_repository_head_tree(&tree, repo));
+ cl_git_pass(git_diff_index_to_workdir(&diff, repo, index, NULL));
+
+ num_deltas = git_diff_num_deltas(diff);
+
+ cl_assert(num_deltas > 0);
+
+ for (i = 0; i < num_deltas; i++) {
+ delta = git_diff_get_delta(diff, i);
+ cl_assert_equal_i(GIT_DELTA_DELETED, delta->status);
+ }
+
+ git_diff_free(diff);
+ git_tree_free(tree);
+ git_index_free(index);
+#endif
+}
+
+void test_win32_forbidden__can_query_submodules(void)
+{
+ cl_git_pass(git_submodule_foreach(repo, dummy_submodule_cb, NULL));
+}
+
+void test_win32_forbidden__can_blame_file(void)
+{
+ git_blame *blame;
+
+ cl_git_pass(git_blame_file(&blame, repo, "aux", NULL));
+ git_blame_free(blame);
+}