summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
14 files changed, 353 insertions, 166 deletions
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;