#include "rerere.h"
#include "prompt.h"
#include "mailinfo.h"
+#include "apply.h"
#include "string-list.h"
/**
size_t msg_len;
/* when --rebasing, records the original commit the patch came from */
- unsigned char orig_commit[GIT_SHA1_RAWSZ];
+ struct object_id orig_commit;
/* number of digits in patch filename */
int prec;
};
/**
- * Initializes am_state with the default values. The state directory is set to
- * dir.
+ * Initializes am_state with the default values.
*/
-static void am_state_init(struct am_state *state, const char *dir)
+static void am_state_init(struct am_state *state)
{
int gpgsign;
memset(state, 0, sizeof(*state));
- assert(dir);
- state->dir = xstrdup(dir);
+ state->dir = git_pathdup("rebase-apply");
state->prec = 4;
read_commit_msg(state);
if (read_state_file(&sb, state, "original-commit", 1) < 0)
- hashclr(state->orig_commit);
- else if (get_sha1_hex(sb.buf, state->orig_commit) < 0)
+ oidclr(&state->orig_commit);
+ else if (get_oid_hex(sb.buf, &state->orig_commit) < 0)
die(_("could not parse %s"), am_path(state, "original-commit"));
read_state_file(&sb, state, "threeway", 1);
fp = xfopen(am_path(state, "rewritten"), "r");
while (!strbuf_getline_lf(&sb, fp)) {
- unsigned char from_obj[GIT_SHA1_RAWSZ], to_obj[GIT_SHA1_RAWSZ];
+ struct object_id from_obj, to_obj;
if (sb.len != GIT_SHA1_HEXSZ * 2 + 1) {
ret = error(invalid_line, sb.buf);
goto finish;
}
- if (get_sha1_hex(sb.buf, from_obj)) {
+ if (get_oid_hex(sb.buf, &from_obj)) {
ret = error(invalid_line, sb.buf);
goto finish;
}
goto finish;
}
- if (get_sha1_hex(sb.buf + GIT_SHA1_HEXSZ + 1, to_obj)) {
+ if (get_oid_hex(sb.buf + GIT_SHA1_HEXSZ + 1, &to_obj)) {
ret = error(invalid_line, sb.buf);
goto finish;
}
- if (copy_note_for_rewrite(c, from_obj, to_obj))
+ if (copy_note_for_rewrite(c, from_obj.hash, to_obj.hash))
ret = error(_("Failed to copy notes from '%s' to '%s'"),
- sha1_to_hex(from_obj), sha1_to_hex(to_obj));
+ oid_to_hex(&from_obj), oid_to_hex(&to_obj));
}
finish:
mail = mkpath("%s/%0*d", state->dir, state->prec, i + 1);
out = fopen(mail, "w");
- if (!out)
+ if (!out) {
+ if (in != stdin)
+ fclose(in);
return error_errno(_("could not open '%s' for writing"),
mail);
+ }
ret = fn(out, in, keep_cr);
fclose(out);
- fclose(in);
+ if (in != stdin)
+ fclose(in);
if (ret)
return error(_("could not parse patch '%s'"), *paths);
if (skip_prefix(sb.buf, "# User ", &str))
fprintf(out, "From: %s\n", str);
else if (skip_prefix(sb.buf, "# Date ", &str)) {
- unsigned long timestamp;
+ timestamp_t timestamp;
long tz, tz2;
char *end;
errno = 0;
- timestamp = strtoul(str, &end, 10);
+ timestamp = parse_timestamp(str, &end, 10);
if (errno)
return error(_("invalid timestamp"));
static void am_setup(struct am_state *state, enum patch_format patch_format,
const char **paths, int keep_cr)
{
- unsigned char curr_head[GIT_SHA1_RAWSZ];
+ struct object_id curr_head;
const char *str;
struct strbuf sb = STRBUF_INIT;
else
write_state_text(state, "applying", "");
- if (!get_sha1("HEAD", curr_head)) {
- write_state_text(state, "abort-safety", sha1_to_hex(curr_head));
+ if (!get_oid("HEAD", &curr_head)) {
+ write_state_text(state, "abort-safety", oid_to_hex(&curr_head));
if (!state->rebasing)
- update_ref("am", "ORIG_HEAD", curr_head, NULL, 0,
+ update_ref_oid("am", "ORIG_HEAD", &curr_head, NULL, 0,
UPDATE_REFS_DIE_ON_ERR);
} else {
write_state_text(state, "abort-safety", "");
if (!state->rebasing)
- delete_ref("ORIG_HEAD", NULL, 0);
+ delete_ref(NULL, "ORIG_HEAD", NULL, 0);
}
/*
*/
static void am_next(struct am_state *state)
{
- unsigned char head[GIT_SHA1_RAWSZ];
+ struct object_id head;
free(state->author_name);
state->author_name = NULL;
unlink(am_path(state, "author-script"));
unlink(am_path(state, "final-commit"));
- hashclr(state->orig_commit);
+ oidclr(&state->orig_commit);
unlink(am_path(state, "original-commit"));
- if (!get_sha1("HEAD", head))
- write_state_text(state, "abort-safety", sha1_to_hex(head));
+ if (!get_oid("HEAD", &head))
+ write_state_text(state, "abort-safety", oid_to_hex(&head));
else
write_state_text(state, "abort-safety", "");
{
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
- hold_locked_index(lock_file, 1);
+ hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
refresh_cache(REFRESH_QUIET);
if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
die(_("unable to write index file"));
*/
static int index_has_changes(struct strbuf *sb)
{
- unsigned char head[GIT_SHA1_RAWSZ];
+ struct object_id head;
int i;
- if (!get_sha1_tree("HEAD", head)) {
+ if (!get_sha1_tree("HEAD", head.hash)) {
struct diff_options opt;
diff_setup(&opt);
DIFF_OPT_SET(&opt, EXIT_WITH_STATUS);
if (!sb)
DIFF_OPT_SET(&opt, QUICK);
- do_diff_cache(head, &opt);
+ do_diff_cache(&head, &opt);
diffcore_std(&opt);
for (i = 0; sb && i < diff_queued_diff.nr; i++) {
if (i)
exit(128);
}
-static void am_signoff(struct strbuf *sb)
+/**
+ * Appends signoff to the "msg" field of the am_state.
+ */
+static void am_append_signoff(struct am_state *state)
{
char *cp;
struct strbuf mine = STRBUF_INIT;
+ struct strbuf sb = STRBUF_INIT;
- /* Does it end with our own sign-off? */
+ strbuf_attach(&sb, state->msg, state->msg_len, state->msg_len);
+
+ /* our sign-off */
strbuf_addf(&mine, "\n%s%s\n",
sign_off_header,
fmt_name(getenv("GIT_COMMITTER_NAME"),
getenv("GIT_COMMITTER_EMAIL")));
- if (mine.len < sb->len &&
- !strcmp(mine.buf, sb->buf + sb->len - mine.len))
+
+ /* Does sb end with it already? */
+ if (mine.len < sb.len &&
+ !strcmp(mine.buf, sb.buf + sb.len - mine.len))
goto exit; /* no need to duplicate */
/* Does it have any Signed-off-by: in the text */
- for (cp = sb->buf;
+ for (cp = sb.buf;
cp && *cp && (cp = strstr(cp, sign_off_header)) != NULL;
cp = strchr(cp, '\n')) {
- if (sb->buf == cp || cp[-1] == '\n')
+ if (sb.buf == cp || cp[-1] == '\n')
break;
}
- strbuf_addstr(sb, mine.buf + !!cp);
+ strbuf_addstr(&sb, mine.buf + !!cp);
exit:
strbuf_release(&mine);
-}
-
-/**
- * Appends signoff to the "msg" field of the am_state.
- */
-static void am_append_signoff(struct am_state *state)
-{
- struct strbuf sb = STRBUF_INIT;
-
- strbuf_attach(&sb, state->msg, state->msg_len, state->msg_len);
- am_signoff(&sb);
state->msg = strbuf_detach(&sb, &state->msg_len);
}
}
if (is_empty_file(am_path(state, "patch"))) {
- printf_ln(_("Patch is empty. Was it split wrong?"));
+ printf_ln(_("Patch is empty."));
die_user_resolve(state);
}
strbuf_addbuf(&msg, &mi.log_message);
strbuf_stripspace(&msg, 0);
- if (state->signoff)
- am_signoff(&msg);
-
assert(!state->author_name);
state->author_name = strbuf_detach(&author_name, NULL);
* Sets commit_id to the commit hash where the mail was generated from.
* Returns 0 on success, -1 on failure.
*/
-static int get_mail_commit_sha1(unsigned char *commit_id, const char *mail)
+static int get_mail_commit_oid(struct object_id *commit_id, const char *mail)
{
struct strbuf sb = STRBUF_INIT;
FILE *fp = xfopen(mail, "r");
const char *x;
+ int ret = 0;
- if (strbuf_getline_lf(&sb, fp))
- return -1;
-
- if (!skip_prefix(sb.buf, "From ", &x))
- return -1;
-
- if (get_sha1_hex(x, commit_id) < 0)
- return -1;
+ if (strbuf_getline_lf(&sb, fp) ||
+ !skip_prefix(sb.buf, "From ", &x) ||
+ get_oid_hex(x, commit_id) < 0)
+ ret = -1;
strbuf_release(&sb);
fclose(fp);
- return 0;
+ return ret;
}
/**
*/
static void get_commit_info(struct am_state *state, struct commit *commit)
{
- const char *buffer, *ident_line, *author_date, *msg;
+ const char *buffer, *ident_line, *msg;
size_t ident_len;
- struct ident_split ident_split;
- struct strbuf sb = STRBUF_INIT;
+ struct ident_split id;
buffer = logmsg_reencode(commit, NULL, get_commit_output_encoding());
ident_line = find_commit_header(buffer, "author", &ident_len);
- if (split_ident_line(&ident_split, ident_line, ident_len) < 0) {
- strbuf_add(&sb, ident_line, ident_len);
- die(_("invalid ident line: %s"), sb.buf);
- }
+ if (split_ident_line(&id, ident_line, ident_len) < 0)
+ die(_("invalid ident line: %.*s"), (int)ident_len, ident_line);
assert(!state->author_name);
- if (ident_split.name_begin) {
- strbuf_add(&sb, ident_split.name_begin,
- ident_split.name_end - ident_split.name_begin);
- state->author_name = strbuf_detach(&sb, NULL);
- } else
+ if (id.name_begin)
+ state->author_name =
+ xmemdupz(id.name_begin, id.name_end - id.name_begin);
+ else
state->author_name = xstrdup("");
assert(!state->author_email);
- if (ident_split.mail_begin) {
- strbuf_add(&sb, ident_split.mail_begin,
- ident_split.mail_end - ident_split.mail_begin);
- state->author_email = strbuf_detach(&sb, NULL);
- } else
+ if (id.mail_begin)
+ state->author_email =
+ xmemdupz(id.mail_begin, id.mail_end - id.mail_begin);
+ else
state->author_email = xstrdup("");
- author_date = show_ident_date(&ident_split, DATE_MODE(NORMAL));
- strbuf_addstr(&sb, author_date);
assert(!state->author_date);
- state->author_date = strbuf_detach(&sb, NULL);
+ state->author_date = xstrdup(show_ident_date(&id, DATE_MODE(NORMAL)));
assert(!state->msg);
msg = strstr(buffer, "\n\n");
die(_("unable to parse commit %s"), oid_to_hex(&commit->object.oid));
state->msg = xstrdup(msg + 2);
state->msg_len = strlen(state->msg);
+ unuse_commit_buffer(commit, buffer);
}
/**
static void write_index_patch(const struct am_state *state)
{
struct tree *tree;
- unsigned char head[GIT_SHA1_RAWSZ];
+ struct object_id head;
struct rev_info rev_info;
FILE *fp;
- if (!get_sha1_tree("HEAD", head))
- tree = lookup_tree(head);
+ if (!get_sha1_tree("HEAD", head.hash))
+ tree = lookup_tree(&head);
else
- tree = lookup_tree(EMPTY_TREE_SHA1_BIN);
+ tree = lookup_tree(&empty_tree_oid);
fp = xfopen(am_path(state, "patch"), "w");
init_revisions(&rev_info, NULL);
static int parse_mail_rebase(struct am_state *state, const char *mail)
{
struct commit *commit;
- unsigned char commit_sha1[GIT_SHA1_RAWSZ];
+ struct object_id commit_oid;
- if (get_mail_commit_sha1(commit_sha1, mail) < 0)
+ if (get_mail_commit_oid(&commit_oid, mail) < 0)
die(_("could not parse %s"), mail);
- commit = lookup_commit_or_die(commit_sha1, mail);
+ commit = lookup_commit_or_die(&commit_oid, mail);
get_commit_info(state, commit);
write_commit_patch(state, commit);
- hashcpy(state->orig_commit, commit_sha1);
- write_state_text(state, "original-commit", sha1_to_hex(commit_sha1));
+ oidcpy(&state->orig_commit, &commit_oid);
+ write_state_text(state, "original-commit", oid_to_hex(&commit_oid));
return 0;
}
*/
static int run_apply(const struct am_state *state, const char *index_file)
{
- struct child_process cp = CHILD_PROCESS_INIT;
-
- cp.git_cmd = 1;
-
- if (index_file)
- argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s", index_file);
+ struct argv_array apply_paths = ARGV_ARRAY_INIT;
+ struct argv_array apply_opts = ARGV_ARRAY_INIT;
+ struct apply_state apply_state;
+ int res, opts_left;
+ static struct lock_file lock_file;
+ int force_apply = 0;
+ int options = 0;
+
+ if (init_apply_state(&apply_state, NULL, &lock_file))
+ die("BUG: init_apply_state() failed");
+
+ argv_array_push(&apply_opts, "apply");
+ argv_array_pushv(&apply_opts, state->git_apply_opts.argv);
+
+ opts_left = apply_parse_options(apply_opts.argc, apply_opts.argv,
+ &apply_state, &force_apply, &options,
+ NULL);
+
+ if (opts_left != 0)
+ die("unknown option passed through to git apply");
+
+ if (index_file) {
+ apply_state.index_file = index_file;
+ apply_state.cached = 1;
+ } else
+ apply_state.check_index = 1;
/*
* If we are allowed to fall back on 3-way merge, don't give false
* errors during the initial attempt.
*/
- if (state->threeway && !index_file) {
- cp.no_stdout = 1;
- cp.no_stderr = 1;
- }
+ if (state->threeway && !index_file)
+ apply_state.apply_verbosity = verbosity_silent;
- argv_array_push(&cp.args, "apply");
+ if (check_apply_state(&apply_state, force_apply))
+ die("BUG: check_apply_state() failed");
- argv_array_pushv(&cp.args, state->git_apply_opts.argv);
+ argv_array_push(&apply_paths, am_path(state, "patch"));
- if (index_file)
- argv_array_push(&cp.args, "--cached");
- else
- argv_array_push(&cp.args, "--index");
+ res = apply_all_patches(&apply_state, apply_paths.argc, apply_paths.argv, options);
- argv_array_push(&cp.args, am_path(state, "patch"));
+ argv_array_clear(&apply_paths);
+ argv_array_clear(&apply_opts);
+ clear_apply_state(&apply_state);
- if (run_command(&cp))
- return -1;
+ if (res)
+ return res;
- /* Reload index as git-apply will have modified it. */
- discard_cache();
- read_cache_from(index_file ? index_file : get_index_file());
+ if (index_file) {
+ /* Reload index as apply_all_patches() will have modified it. */
+ discard_cache();
+ read_cache_from(index_file);
+ }
return 0;
}
init_revisions(&rev_info, NULL);
rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS;
diff_opt_parse(&rev_info.diffopt, &diff_filter_str, 1, rev_info.prefix);
- add_pending_sha1(&rev_info, "HEAD", our_tree.hash, 0);
+ add_pending_oid(&rev_info, "HEAD", &our_tree, 0);
diff_setup_done(&rev_info.diffopt);
run_diff_index(&rev_info, 1);
}
*/
static void do_commit(const struct am_state *state)
{
- unsigned char tree[GIT_SHA1_RAWSZ], parent[GIT_SHA1_RAWSZ],
- commit[GIT_SHA1_RAWSZ];
- unsigned char *ptr;
+ struct object_id tree, parent, commit;
+ const struct object_id *old_oid;
struct commit_list *parents = NULL;
const char *reflog_msg, *author;
struct strbuf sb = STRBUF_INIT;
if (run_hook_le(NULL, "pre-applypatch", NULL))
exit(1);
- if (write_cache_as_tree(tree, 0, NULL))
+ if (write_cache_as_tree(tree.hash, 0, NULL))
die(_("git write-tree failed to write a tree"));
- if (!get_sha1_commit("HEAD", parent)) {
- ptr = parent;
- commit_list_insert(lookup_commit(parent), &parents);
+ if (!get_sha1_commit("HEAD", parent.hash)) {
+ old_oid = &parent;
+ commit_list_insert(lookup_commit(&parent), &parents);
} else {
- ptr = NULL;
+ old_oid = NULL;
say(state, stderr, _("applying to an empty history"));
}
setenv("GIT_COMMITTER_DATE",
state->ignore_date ? "" : state->author_date, 1);
- if (commit_tree(state->msg, state->msg_len, tree, parents, commit,
+ if (commit_tree(state->msg, state->msg_len, tree.hash, parents, commit.hash,
author, state->sign_commit))
die(_("failed to write commit object"));
strbuf_addf(&sb, "%s: %.*s", reflog_msg, linelen(state->msg),
state->msg);
- update_ref(sb.buf, "HEAD", commit, ptr, 0, UPDATE_REFS_DIE_ON_ERR);
+ update_ref_oid(sb.buf, "HEAD", &commit, old_oid, 0,
+ UPDATE_REFS_DIE_ON_ERR);
if (state->rebasing) {
FILE *fp = xfopen(am_path(state, "rewritten"), "a");
- assert(!is_null_sha1(state->orig_commit));
- fprintf(fp, "%s ", sha1_to_hex(state->orig_commit));
- fprintf(fp, "%s\n", sha1_to_hex(commit));
+ assert(!is_null_oid(&state->orig_commit));
+ fprintf(fp, "%s ", oid_to_hex(&state->orig_commit));
+ fprintf(fp, "%s\n", oid_to_hex(&commit));
fclose(fp);
}
if (skip)
goto next; /* mail should be skipped */
+ if (state->signoff)
+ am_append_signoff(state);
+
write_author_script(state);
write_commit_msg(state);
}
if (unmerged_cache()) {
printf_ln(_("You still have unmerged paths in your index.\n"
- "Did you forget to use 'git add'?"));
+ "You should 'git add' each file with resolved conflicts to mark them as such.\n"
+ "You might run `git rm` on a file to accept \"deleted by them\" for it."));
die_user_resolve(state);
}
return -1;
lock_file = xcalloc(1, sizeof(struct lock_file));
- hold_locked_index(lock_file, 1);
+ hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
refresh_cache(REFRESH_QUIET);
return -1;
lock_file = xcalloc(1, sizeof(struct lock_file));
- hold_locked_index(lock_file, 1);
+ hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
memset(&opts, 0, sizeof(opts));
opts.head_idx = 1;
* Clean the index without touching entries that are not modified between
* `head` and `remote`.
*/
-static int clean_index(const unsigned char *head, const unsigned char *remote)
+static int clean_index(const struct object_id *head, const struct object_id *remote)
{
struct tree *head_tree, *remote_tree, *index_tree;
- unsigned char index[GIT_SHA1_RAWSZ];
+ struct object_id index;
head_tree = parse_tree_indirect(head);
if (!head_tree)
- return error(_("Could not parse object '%s'."), sha1_to_hex(head));
+ return error(_("Could not parse object '%s'."), oid_to_hex(head));
remote_tree = parse_tree_indirect(remote);
if (!remote_tree)
- return error(_("Could not parse object '%s'."), sha1_to_hex(remote));
+ return error(_("Could not parse object '%s'."), oid_to_hex(remote));
read_cache_unmerged();
if (fast_forward_to(head_tree, head_tree, 1))
return -1;
- if (write_cache_as_tree(index, 0, NULL))
+ if (write_cache_as_tree(index.hash, 0, NULL))
return -1;
- index_tree = parse_tree_indirect(index);
+ index_tree = parse_tree_indirect(&index);
if (!index_tree)
- return error(_("Could not parse object '%s'."), sha1_to_hex(index));
+ return error(_("Could not parse object '%s'."), oid_to_hex(&index));
if (fast_forward_to(index_tree, remote_tree, 0))
return -1;
*/
static void am_skip(struct am_state *state)
{
- unsigned char head[GIT_SHA1_RAWSZ];
+ struct object_id head;
am_rerere_clear();
- if (get_sha1("HEAD", head))
- hashcpy(head, EMPTY_TREE_SHA1_BIN);
+ if (get_oid("HEAD", &head))
+ hashcpy(head.hash, EMPTY_TREE_SHA1_BIN);
- if (clean_index(head, head))
+ if (clean_index(&head, &head))
die(_("failed to clean index"));
am_next(state);
static int safe_to_abort(const struct am_state *state)
{
struct strbuf sb = STRBUF_INIT;
- unsigned char abort_safety[GIT_SHA1_RAWSZ], head[GIT_SHA1_RAWSZ];
+ struct object_id abort_safety, head;
if (file_exists(am_path(state, "dirtyindex")))
return 0;
if (read_state_file(&sb, state, "abort-safety", 1) > 0) {
- if (get_sha1_hex(sb.buf, abort_safety))
- die(_("could not parse %s"), am_path(state, "abort_safety"));
+ if (get_oid_hex(sb.buf, &abort_safety))
+ die(_("could not parse %s"), am_path(state, "abort-safety"));
} else
- hashclr(abort_safety);
+ oidclr(&abort_safety);
- if (get_sha1("HEAD", head))
- hashclr(head);
+ if (get_oid("HEAD", &head))
+ oidclr(&head);
- if (!hashcmp(head, abort_safety))
+ if (!oidcmp(&head, &abort_safety))
return 1;
- error(_("You seem to have moved HEAD since the last 'am' failure.\n"
+ warning(_("You seem to have moved HEAD since the last 'am' failure.\n"
"Not rewinding to ORIG_HEAD"));
return 0;
*/
static void am_abort(struct am_state *state)
{
- unsigned char curr_head[GIT_SHA1_RAWSZ], orig_head[GIT_SHA1_RAWSZ];
+ struct object_id curr_head, orig_head;
int has_curr_head, has_orig_head;
char *curr_branch;
am_rerere_clear();
- curr_branch = resolve_refdup("HEAD", 0, curr_head, NULL);
- has_curr_head = !is_null_sha1(curr_head);
+ curr_branch = resolve_refdup("HEAD", 0, curr_head.hash, NULL);
+ has_curr_head = curr_branch && !is_null_oid(&curr_head);
if (!has_curr_head)
- hashcpy(curr_head, EMPTY_TREE_SHA1_BIN);
+ hashcpy(curr_head.hash, EMPTY_TREE_SHA1_BIN);
- has_orig_head = !get_sha1("ORIG_HEAD", orig_head);
+ has_orig_head = !get_oid("ORIG_HEAD", &orig_head);
if (!has_orig_head)
- hashcpy(orig_head, EMPTY_TREE_SHA1_BIN);
+ hashcpy(orig_head.hash, EMPTY_TREE_SHA1_BIN);
- clean_index(curr_head, orig_head);
+ clean_index(&curr_head, &orig_head);
if (has_orig_head)
- update_ref("am --abort", "HEAD", orig_head,
- has_curr_head ? curr_head : NULL, 0,
+ update_ref_oid("am --abort", "HEAD", &orig_head,
+ has_curr_head ? &curr_head : NULL, 0,
UPDATE_REFS_DIE_ON_ERR);
else if (curr_branch)
- delete_ref(curr_branch, NULL, REF_NODEREF);
+ delete_ref(NULL, curr_branch, NULL, REF_NODEREF);
free(curr_branch);
am_destroy(state);
git_config(git_am_config, NULL);
- am_state_init(&state, git_path("rebase-apply"));
+ am_state_init(&state);
in_progress = am_in_progress(&state);
if (in_progress)