summaryrefslogtreecommitdiff
path: root/src/libgit2/rebase.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libgit2/rebase.c')
-rw-r--r--src/libgit2/rebase.c156
1 files changed, 72 insertions, 84 deletions
diff --git a/src/libgit2/rebase.c b/src/libgit2/rebase.c
index 1970d5ddc..77e442e98 100644
--- a/src/libgit2/rebase.c
+++ b/src/libgit2/rebase.c
@@ -65,6 +65,9 @@ struct git_rebase {
git_rebase_t type;
char *state_path;
+ /* Temporary buffer for paths within the state path. */
+ git_str state_filename;
+
unsigned int head_detached:1,
inmemory:1,
quiet:1,
@@ -134,33 +137,42 @@ done:
GIT_INLINE(int) rebase_readfile(
git_str *out,
- git_str *state_path,
+ git_rebase *rebase,
const char *filename)
{
- size_t state_path_len = state_path->size;
+ /*
+ * `rebase->state_filename` is a temporary buffer to avoid
+ * unnecessary allocations and copies of `rebase->state_path`.
+ * At the start and end of this function it always contains the
+ * contents of `rebase->state_path` itself.
+ */
+ size_t state_path_len = rebase->state_filename.size;
int error;
git_str_clear(out);
- if ((error = git_str_joinpath(state_path, state_path->ptr, filename)) < 0 ||
- (error = git_futils_readbuffer(out, state_path->ptr)) < 0)
+ if ((error = git_str_joinpath(&rebase->state_filename, rebase->state_filename.ptr, filename)) < 0 ||
+ (error = git_futils_readbuffer(out, rebase->state_filename.ptr)) < 0)
goto done;
git_str_rtrim(out);
done:
- git_str_truncate(state_path, state_path_len);
+ git_str_truncate(&rebase->state_filename, state_path_len);
return error;
}
GIT_INLINE(int) rebase_readint(
- size_t *out, git_str *asc_out, git_str *state_path, const char *filename)
+ size_t *out,
+ git_str *asc_out,
+ git_rebase *rebase,
+ const char *filename)
{
int32_t num;
const char *eol;
int error = 0;
- if ((error = rebase_readfile(asc_out, state_path, filename)) < 0)
+ if ((error = rebase_readfile(asc_out, rebase, filename)) < 0)
return error;
if (git__strntol32(&num, asc_out->ptr, asc_out->size, &eol, 10) < 0 || num < 0 || *eol) {
@@ -174,15 +186,18 @@ GIT_INLINE(int) rebase_readint(
}
GIT_INLINE(int) rebase_readoid(
- git_oid *out, git_str *str_out, git_str *state_path, const char *filename)
+ git_oid *out,
+ git_str *str_out,
+ git_rebase *rebase,
+ const char *filename)
{
int error;
- if ((error = rebase_readfile(str_out, state_path, filename)) < 0)
+ if ((error = rebase_readfile(str_out, rebase, filename)) < 0)
return error;
- if (str_out->size != GIT_OID_SHA1_HEXSIZE ||
- git_oid__fromstr(out, str_out->ptr, GIT_OID_SHA1) < 0) {
+ if (str_out->size != git_oid_hexsize(rebase->repo->oid_type) ||
+ git_oid__fromstr(out, str_out->ptr, rebase->repo->oid_type) < 0) {
git_error_set(GIT_ERROR_REBASE, "the file '%s' contains an invalid object ID", filename);
return -1;
}
@@ -213,17 +228,14 @@ static git_rebase_operation *rebase_operation_alloc(
static int rebase_open_merge(git_rebase *rebase)
{
- git_str state_path = GIT_STR_INIT, buf = GIT_STR_INIT, cmt = GIT_STR_INIT;
+ git_str buf = GIT_STR_INIT, cmt = GIT_STR_INIT;
git_oid id;
git_rebase_operation *operation;
size_t i, msgnum = 0, end;
int error;
- if ((error = git_str_puts(&state_path, rebase->state_path)) < 0)
- goto done;
-
/* Read 'msgnum' if it exists (otherwise, let msgnum = 0) */
- if ((error = rebase_readint(&msgnum, &buf, &state_path, MSGNUM_FILE)) < 0 &&
+ if ((error = rebase_readint(&msgnum, &buf, rebase, MSGNUM_FILE)) < 0 &&
error != GIT_ENOTFOUND)
goto done;
@@ -233,11 +245,11 @@ static int rebase_open_merge(git_rebase *rebase)
}
/* Read 'end' */
- if ((error = rebase_readint(&end, &buf, &state_path, END_FILE)) < 0)
+ if ((error = rebase_readint(&end, &buf, rebase, END_FILE)) < 0)
goto done;
/* Read 'current' if it exists */
- if ((error = rebase_readoid(&id, &buf, &state_path, CURRENT_FILE)) < 0 &&
+ if ((error = rebase_readoid(&id, &buf, rebase, CURRENT_FILE)) < 0 &&
error != GIT_ENOTFOUND)
goto done;
@@ -249,7 +261,7 @@ static int rebase_open_merge(git_rebase *rebase)
git_str_clear(&cmt);
if ((error = git_str_printf(&cmt, "cmt.%" PRIuZ, (i+1))) < 0 ||
- (error = rebase_readoid(&id, &buf, &state_path, cmt.ptr)) < 0)
+ (error = rebase_readoid(&id, &buf, rebase, cmt.ptr)) < 0)
goto done;
operation = rebase_operation_alloc(rebase, GIT_REBASE_OPERATION_PICK, &id, NULL);
@@ -257,14 +269,13 @@ static int rebase_open_merge(git_rebase *rebase)
}
/* Read 'onto_name' */
- if ((error = rebase_readfile(&buf, &state_path, ONTO_NAME_FILE)) < 0)
+ if ((error = rebase_readfile(&buf, rebase, ONTO_NAME_FILE)) < 0)
goto done;
rebase->onto_name = git_str_detach(&buf);
done:
git_str_dispose(&cmt);
- git_str_dispose(&state_path);
git_str_dispose(&buf);
return error;
@@ -308,9 +319,9 @@ int git_rebase_open(
const git_rebase_options *given_opts)
{
git_rebase *rebase;
- git_str path = GIT_STR_INIT, orig_head_name = GIT_STR_INIT,
- orig_head_id = GIT_STR_INIT, onto_id = GIT_STR_INIT;
- size_t state_path_len;
+ git_str orig_head_name = GIT_STR_INIT,
+ orig_head_id = GIT_STR_INIT,
+ onto_id = GIT_STR_INIT;
int error;
GIT_ASSERT_ARG(repo);
@@ -332,13 +343,10 @@ int git_rebase_open(
goto done;
}
- if ((error = git_str_puts(&path, rebase->state_path)) < 0)
+ if ((error = git_str_puts(&rebase->state_filename, rebase->state_path)) < 0)
goto done;
- state_path_len = git_str_len(&path);
-
- if ((error = git_str_joinpath(&path, path.ptr, HEAD_NAME_FILE)) < 0 ||
- (error = git_futils_readbuffer(&orig_head_name, path.ptr)) < 0)
+ if ((error = rebase_readfile(&orig_head_name, rebase, HEAD_NAME_FILE)) < 0)
goto done;
git_str_rtrim(&orig_head_name);
@@ -346,36 +354,16 @@ int git_rebase_open(
if (strcmp(ORIG_DETACHED_HEAD, orig_head_name.ptr) == 0)
rebase->head_detached = 1;
- git_str_truncate(&path, state_path_len);
-
- if ((error = git_str_joinpath(&path, path.ptr, ORIG_HEAD_FILE)) < 0)
- goto done;
-
- if (!git_fs_path_isfile(path.ptr)) {
+ if ((error = rebase_readoid(&rebase->orig_head_id, &orig_head_id, rebase, ORIG_HEAD_FILE)) < 0) {
/* Previous versions of git.git used 'head' here; support that. */
- git_str_truncate(&path, state_path_len);
+ if (error == GIT_ENOTFOUND)
+ error = rebase_readoid(&rebase->orig_head_id, &orig_head_id, rebase, HEAD_FILE);
- if ((error = git_str_joinpath(&path, path.ptr, HEAD_FILE)) < 0)
+ if (error < 0)
goto done;
}
- if ((error = git_futils_readbuffer(&orig_head_id, path.ptr)) < 0)
- goto done;
-
- git_str_rtrim(&orig_head_id);
-
- if ((error = git_oid__fromstr(&rebase->orig_head_id, orig_head_id.ptr, GIT_OID_SHA1)) < 0)
- goto done;
-
- git_str_truncate(&path, state_path_len);
-
- if ((error = git_str_joinpath(&path, path.ptr, ONTO_FILE)) < 0 ||
- (error = git_futils_readbuffer(&onto_id, path.ptr)) < 0)
- goto done;
-
- git_str_rtrim(&onto_id);
-
- if ((error = git_oid__fromstr(&rebase->onto_id, onto_id.ptr, GIT_OID_SHA1)) < 0)
+ if ((error = rebase_readoid(&rebase->onto_id, &onto_id, rebase, ONTO_FILE)) < 0)
goto done;
if (!rebase->head_detached)
@@ -403,7 +391,6 @@ done:
else
git_rebase_free(rebase);
- git_str_dispose(&path);
git_str_dispose(&orig_head_name);
git_str_dispose(&orig_head_id);
git_str_dispose(&onto_id);
@@ -453,13 +440,13 @@ static const char *rebase_onto_name(const git_annotated_commit *onto)
static int rebase_setupfiles_merge(git_rebase *rebase)
{
git_str commit_filename = GIT_STR_INIT;
- char id_str[GIT_OID_SHA1_HEXSIZE];
+ char id_str[GIT_OID_MAX_HEXSIZE + 1];
git_rebase_operation *operation;
size_t i;
int error = 0;
if ((error = rebase_setupfile(rebase, END_FILE, 0, "%" PRIuZ "\n", git_array_size(rebase->operations))) < 0 ||
- (error = rebase_setupfile(rebase, ONTO_NAME_FILE, 0, "%s\n", rebase->onto_name)) < 0)
+ (error = rebase_setupfile(rebase, ONTO_NAME_FILE, 0, "%s\n", rebase->onto_name)) < 0)
goto done;
for (i = 0; i < git_array_size(rebase->operations); i++) {
@@ -468,10 +455,9 @@ static int rebase_setupfiles_merge(git_rebase *rebase)
git_str_clear(&commit_filename);
git_str_printf(&commit_filename, CMT_FILE_FMT, i+1);
- git_oid_fmt(id_str, &operation->id);
+ git_oid_tostr(id_str, GIT_OID_MAX_HEXSIZE + 1, &operation->id);
- if ((error = rebase_setupfile(rebase, commit_filename.ptr, 0,
- "%.*s\n", GIT_OID_SHA1_HEXSIZE, id_str)) < 0)
+ if ((error = rebase_setupfile(rebase, commit_filename.ptr, 0, "%s\n", id_str)) < 0)
goto done;
}
@@ -482,11 +468,11 @@ done:
static int rebase_setupfiles(git_rebase *rebase)
{
- char onto[GIT_OID_SHA1_HEXSIZE], orig_head[GIT_OID_SHA1_HEXSIZE];
+ char onto[GIT_OID_MAX_HEXSIZE + 1], orig_head[GIT_OID_MAX_HEXSIZE + 1];
const char *orig_head_name;
- git_oid_fmt(onto, &rebase->onto_id);
- git_oid_fmt(orig_head, &rebase->orig_head_id);
+ git_oid_tostr(onto, GIT_OID_MAX_HEXSIZE + 1, &rebase->onto_id);
+ git_oid_tostr(orig_head, GIT_OID_MAX_HEXSIZE + 1, &rebase->orig_head_id);
if (p_mkdir(rebase->state_path, REBASE_DIR_MODE) < 0) {
git_error_set(GIT_ERROR_OS, "failed to create rebase directory '%s'", rebase->state_path);
@@ -498,8 +484,8 @@ static int rebase_setupfiles(git_rebase *rebase)
if (git_repository__set_orig_head(rebase->repo, &rebase->orig_head_id) < 0 ||
rebase_setupfile(rebase, HEAD_NAME_FILE, 0, "%s\n", orig_head_name) < 0 ||
- rebase_setupfile(rebase, ONTO_FILE, 0, "%.*s\n", GIT_OID_SHA1_HEXSIZE, onto) < 0 ||
- rebase_setupfile(rebase, ORIG_HEAD_FILE, 0, "%.*s\n", GIT_OID_SHA1_HEXSIZE, orig_head) < 0 ||
+ rebase_setupfile(rebase, ONTO_FILE, 0, "%s\n", onto) < 0 ||
+ rebase_setupfile(rebase, ORIG_HEAD_FILE, 0, "%s\n", orig_head) < 0 ||
rebase_setupfile(rebase, QUIET_FILE, 0, rebase->quiet ? "t\n" : "\n") < 0)
return -1;
@@ -644,7 +630,8 @@ static int rebase_init_merge(
GIT_UNUSED(upstream);
- if ((error = git_str_joinpath(&state_path, repo->gitdir, REBASE_MERGE_DIR)) < 0)
+ if ((error = git_str_joinpath(&state_path, repo->gitdir, REBASE_MERGE_DIR)) < 0 ||
+ (error = git_str_put(&rebase->state_filename, state_path.ptr, state_path.size)) < 0)
goto done;
rebase->state_path = git_str_detach(&state_path);
@@ -814,7 +801,7 @@ static int rebase_next_merge(
git_indexwriter indexwriter = GIT_INDEXWRITER_INIT;
git_rebase_operation *operation;
git_checkout_options checkout_opts;
- char current_idstr[GIT_OID_SHA1_HEXSIZE];
+ char current_idstr[GIT_OID_MAX_HEXSIZE + 1];
unsigned int parent_count;
int error;
@@ -837,13 +824,13 @@ static int rebase_next_merge(
goto done;
}
- git_oid_fmt(current_idstr, &operation->id);
+ git_oid_tostr(current_idstr, GIT_OID_MAX_HEXSIZE + 1, &operation->id);
normalize_checkout_options_for_apply(&checkout_opts, rebase, current_commit);
if ((error = git_indexwriter_init_for_operation(&indexwriter, rebase->repo, &checkout_opts.checkout_strategy)) < 0 ||
(error = rebase_setupfile(rebase, MSGNUM_FILE, 0, "%" PRIuZ "\n", rebase->current+1)) < 0 ||
- (error = rebase_setupfile(rebase, CURRENT_FILE, 0, "%.*s\n", GIT_OID_SHA1_HEXSIZE, current_idstr)) < 0 ||
+ (error = rebase_setupfile(rebase, CURRENT_FILE, 0, "%s\n", current_idstr)) < 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 ||
@@ -1103,7 +1090,7 @@ static int rebase_commit_merge(
git_reference *head = NULL;
git_commit *head_commit = NULL, *commit = NULL;
git_index *index = NULL;
- char old_idstr[GIT_OID_SHA1_HEXSIZE], new_idstr[GIT_OID_SHA1_HEXSIZE];
+ char old_idstr[GIT_OID_MAX_HEXSIZE + 1], new_idstr[GIT_OID_MAX_HEXSIZE + 1];
int error;
operation = git_array_get(rebase->operations, rebase->current);
@@ -1119,11 +1106,11 @@ static int rebase_commit_merge(
rebase->repo, NULL, "HEAD", git_commit_id(commit), "rebase")) < 0)
goto done;
- git_oid_fmt(old_idstr, &operation->id);
- git_oid_fmt(new_idstr, git_commit_id(commit));
+ git_oid_tostr(old_idstr, GIT_OID_MAX_HEXSIZE + 1, &operation->id);
+ git_oid_tostr(new_idstr, GIT_OID_MAX_HEXSIZE + 1, git_commit_id(commit));
if ((error = rebase_setupfile(rebase, REWRITTEN_FILE, O_CREAT|O_WRONLY|O_APPEND,
- "%.*s %.*s\n", GIT_OID_SHA1_HEXSIZE, old_idstr, GIT_OID_SHA1_HEXSIZE, new_idstr)) < 0)
+ "%s %s\n", old_idstr, new_idstr)) < 0)
goto done;
git_oid_cpy(commit_id, git_commit_id(commit));
@@ -1306,7 +1293,9 @@ static int rebase_copy_notes(
git_rebase *rebase,
const git_signature *committer)
{
- git_str path = GIT_STR_INIT, rewritten = GIT_STR_INIT, notes_ref = GIT_STR_INIT;
+ git_str path = GIT_STR_INIT,
+ rewritten = GIT_STR_INIT,
+ notes_ref = GIT_STR_INIT;
char *pair_list, *fromstr, *tostr, *end;
git_oid from, to;
unsigned int linenum = 1;
@@ -1342,10 +1331,10 @@ static int rebase_copy_notes(
tostr = end+1;
*end = '\0';
- if (strlen(fromstr) != GIT_OID_SHA1_HEXSIZE ||
- strlen(tostr) != GIT_OID_SHA1_HEXSIZE ||
- git_oid__fromstr(&from, fromstr, GIT_OID_SHA1) < 0 ||
- git_oid__fromstr(&to, tostr, GIT_OID_SHA1) < 0)
+ if (strlen(fromstr) != git_oid_hexsize(rebase->repo->oid_type) ||
+ strlen(tostr) != git_oid_hexsize(rebase->repo->oid_type) ||
+ git_oid__fromstr(&from, fromstr, rebase->repo->oid_type) < 0 ||
+ git_oid__fromstr(&to, tostr, rebase->repo->oid_type) < 0)
goto on_error;
if ((error = rebase_copy_note(rebase, notes_ref.ptr, &from, &to, committer)) < 0)
@@ -1373,17 +1362,15 @@ static int return_to_orig_head(git_rebase *rebase)
git_reference *terminal_ref = NULL, *branch_ref = NULL, *head_ref = NULL;
git_commit *terminal_commit = NULL;
git_str branch_msg = GIT_STR_INIT, head_msg = GIT_STR_INIT;
- char onto[GIT_OID_SHA1_HEXSIZE];
+ char onto[GIT_OID_MAX_HEXSIZE + 1];
int error = 0;
- git_oid_fmt(onto, &rebase->onto_id);
+ git_oid_tostr(onto, GIT_OID_MAX_HEXSIZE + 1, &rebase->onto_id);
if ((error = git_str_printf(&branch_msg,
- "rebase finished: %s onto %.*s",
- rebase->orig_head_name, GIT_OID_SHA1_HEXSIZE, onto)) == 0 &&
+ "rebase finished: %s onto %s", rebase->orig_head_name, onto)) == 0 &&
(error = git_str_printf(&head_msg,
- "rebase finished: returning to %s",
- rebase->orig_head_name)) == 0 &&
+ "rebase finished: returning to %s", rebase->orig_head_name)) == 0 &&
(error = git_repository_head(&terminal_ref, rebase->repo)) == 0 &&
(error = git_reference_peel((git_object **)&terminal_commit,
terminal_ref, GIT_OBJECT_COMMIT)) == 0 &&
@@ -1475,6 +1462,7 @@ void git_rebase_free(git_rebase *rebase)
git__free(rebase->onto_name);
git__free(rebase->orig_head_name);
git__free(rebase->state_path);
+ git_str_dispose(&rebase->state_filename);
git_array_clear(rebase->operations);
git__free((char *)rebase->options.rewrite_notes_ref);
git__free(rebase);