diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/checkout.c | 7 | ||||
-rw-r--r-- | src/commit.c | 10 | ||||
-rw-r--r-- | src/diff.c | 8 | ||||
-rw-r--r-- | src/index.c | 36 | ||||
-rw-r--r-- | src/iterator.c | 17 | ||||
-rw-r--r-- | src/iterator.h | 1 | ||||
-rw-r--r-- | src/merge.c | 14 | ||||
-rw-r--r-- | src/path.c | 7 | ||||
-rw-r--r-- | src/path.h | 18 | ||||
-rw-r--r-- | src/pathspec.c | 3 | ||||
-rw-r--r-- | src/rebase.c | 380 | ||||
-rw-r--r-- | src/refdb_fs.c | 4 | ||||
-rw-r--r-- | src/stash.c | 8 | ||||
-rw-r--r-- | src/submodule.c | 6 |
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(¤t_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(¤t_commit, rebase->repo, &operation->id)) < 0 || + (error = git_commit_tree(¤t_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(¤t_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(¤t_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; |