#include "rerere.h"
#include "merge-recursive.h"
#include "refs.h"
-#include "argv-array.h"
+#include "strvec.h"
#include "quote.h"
#include "trailer.h"
#include "log-tree.h"
#include "alias.h"
#include "commit-reach.h"
#include "rebase-interactive.h"
+#include "reset.h"
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
* command-line.
*/
static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt")
+static GIT_PATH_FUNC(rebase_path_cdate_is_adate, "rebase-merge/cdate_is_adate")
+static GIT_PATH_FUNC(rebase_path_ignore_date, "rebase-merge/ignore_date")
static GIT_PATH_FUNC(rebase_path_orig_head, "rebase-merge/orig-head")
static GIT_PATH_FUNC(rebase_path_verbose, "rebase-merge/verbose")
static GIT_PATH_FUNC(rebase_path_quiet, "rebase-merge/quiet")
}
}
+ free(opts->committer_name);
+ free(opts->committer_email);
free(opts->gpg_sign);
free(opts->strategy);
for (i = 0; i < opts->xopts_nr; i++)
subject_len = find_commit_subject(out->message, &subject);
out->subject = xmemdupz(subject, subject_len);
- out->label = xstrfmt("%s... %s", abbrev, out->subject);
+ out->label = xstrfmt("%s (%s)", abbrev, out->subject);
out->parent_label = xstrfmt("parent of %s", out->label);
return 0;
* (typically rebase --interactive) wants to take care
* of the commit itself so remove CHERRY_PICK_HEAD
*/
- unlink(git_path_cherry_pick_head(r));
+ refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD",
+ NULL, 0);
return;
}
return 0;
}
-/*
- * Reads a file that was presumably written by a shell script, i.e. with an
- * end-of-line marker that needs to be stripped.
- *
- * Note that only the last end-of-line marker is stripped, consistent with the
- * behavior of "$(cat path)" in a shell script.
- *
- * Returns 1 if the file was read, 0 if it could not be read or does not exist.
- */
-static int read_oneliner(struct strbuf *buf,
- const char *path, int skip_if_empty)
+int read_oneliner(struct strbuf *buf,
+ const char *path, unsigned flags)
{
int orig_len = buf->len;
- if (!file_exists(path))
- return 0;
-
if (strbuf_read_file(buf, path, 0) < 0) {
- warning_errno(_("could not read '%s'"), path);
+ if ((flags & READ_ONELINER_WARN_MISSING) ||
+ (errno != ENOENT && errno != ENOTDIR))
+ warning_errno(_("could not read '%s'"), path);
return 0;
}
buf->buf[buf->len] = '\0';
}
- if (skip_if_empty && buf->len == orig_len)
+ if ((flags & READ_ONELINER_SKIP_IF_EMPTY) && buf->len == orig_len)
return 0;
return 1;
/*
* Read a GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL AND GIT_AUTHOR_DATE from a
- * file with shell quoting into struct argv_array. Returns -1 on
+ * file with shell quoting into struct strvec. Returns -1 on
* error, 0 otherwise.
*/
-static int read_env_script(struct argv_array *env)
+static int read_env_script(struct strvec *env)
{
char *name, *email, *date;
&name, &email, &date, 0))
return -1;
- argv_array_pushf(env, "GIT_AUTHOR_NAME=%s", name);
- argv_array_pushf(env, "GIT_AUTHOR_EMAIL=%s", email);
- argv_array_pushf(env, "GIT_AUTHOR_DATE=%s", date);
+ strvec_pushf(env, "GIT_AUTHOR_NAME=%s", name);
+ strvec_pushf(env, "GIT_AUTHOR_EMAIL=%s", email);
+ strvec_pushf(env, "GIT_AUTHOR_DATE=%s", date);
free(name);
free(email);
free(date);
return NULL;
}
+static const char *author_date_from_env_array(const struct strvec *env)
+{
+ int i;
+ const char *date;
+
+ for (i = 0; i < env->nr; i++)
+ if (skip_prefix(env->v[i],
+ "GIT_AUTHOR_DATE=", &date))
+ return date;
+ /*
+ * If GIT_AUTHOR_DATE is missing we should have already errored out when
+ * reading the script
+ */
+ BUG("GIT_AUTHOR_DATE missing from author script");
+}
+
static const char staged_changes_advice[] =
N_("you have staged changes in your working tree\n"
"If these changes are meant to be squashed into the previous commit, run:\n"
gpg_opt, gpg_opt);
}
- argv_array_push(&cmd.args, "commit");
+ if (opts->committer_date_is_author_date)
+ strvec_pushf(&cmd.env_array, "GIT_COMMITTER_DATE=%s",
+ opts->ignore_date ?
+ "" :
+ author_date_from_env_array(&cmd.env_array));
+ if (opts->ignore_date)
+ strvec_push(&cmd.env_array, "GIT_AUTHOR_DATE=");
+
+ strvec_push(&cmd.args, "commit");
if (!(flags & VERIFY_MSG))
- argv_array_push(&cmd.args, "-n");
+ strvec_push(&cmd.args, "-n");
if ((flags & AMEND_MSG))
- argv_array_push(&cmd.args, "--amend");
+ strvec_push(&cmd.args, "--amend");
if (opts->gpg_sign)
- argv_array_pushf(&cmd.args, "-S%s", opts->gpg_sign);
+ strvec_pushf(&cmd.args, "-S%s", opts->gpg_sign);
+ else
+ strvec_push(&cmd.args, "--no-gpg-sign");
if (defmsg)
- argv_array_pushl(&cmd.args, "-F", defmsg, NULL);
+ strvec_pushl(&cmd.args, "-F", defmsg, NULL);
else if (!(flags & EDIT_MSG))
- argv_array_pushl(&cmd.args, "-C", "HEAD", NULL);
+ strvec_pushl(&cmd.args, "-C", "HEAD", NULL);
if ((flags & CLEANUP_MSG))
- argv_array_push(&cmd.args, "--cleanup=strip");
+ strvec_push(&cmd.args, "--cleanup=strip");
if ((flags & EDIT_MSG))
- argv_array_push(&cmd.args, "-e");
+ strvec_push(&cmd.args, "-e");
else if (!(flags & CLEANUP_MSG) &&
!opts->signoff && !opts->record_origin &&
!opts->explicit_cleanup)
- argv_array_push(&cmd.args, "--cleanup=verbatim");
+ strvec_push(&cmd.args, "--cleanup=verbatim");
if ((flags & ALLOW_EMPTY))
- argv_array_push(&cmd.args, "--allow-empty");
+ strvec_push(&cmd.args, "--allow-empty");
if (!(flags & EDIT_MSG))
- argv_array_push(&cmd.args, "--allow-empty-message");
+ strvec_push(&cmd.args, "--allow-empty-message");
if (is_rebase_i(opts) && !(flags & EDIT_MSG))
return run_command_silent_on_success(&cmd);
struct strbuf err = STRBUF_INIT;
struct strbuf commit_msg = STRBUF_INIT;
char *amend_author = NULL;
+ const char *committer = NULL;
const char *hook_commit = NULL;
enum commit_msg_cleanup_mode cleanup;
int res = 0;
goto out;
}
- reset_ident_date();
+ if (opts->committer_date_is_author_date) {
+ struct ident_split id;
+ struct strbuf date = STRBUF_INIT;
+
+ if (!opts->ignore_date) {
+ if (split_ident_line(&id, author, (int)strlen(author)) < 0) {
+ res = error(_("invalid author identity '%s'"),
+ author);
+ goto out;
+ }
+ if (!id.date_begin) {
+ res = error(_(
+ "corrupt author: missing date information"));
+ goto out;
+ }
+ strbuf_addf(&date, "@%.*s %.*s",
+ (int)(id.date_end - id.date_begin),
+ id.date_begin,
+ (int)(id.tz_end - id.tz_begin),
+ id.tz_begin);
+ } else {
+ reset_ident_date();
+ }
+ committer = fmt_ident(opts->committer_name,
+ opts->committer_email,
+ WANT_COMMITTER_IDENT,
+ opts->ignore_date ? NULL : date.buf,
+ IDENT_STRICT);
+ strbuf_release(&date);
+ } else {
+ reset_ident_date();
+ }
+
+ if (opts->ignore_date) {
+ struct ident_split id;
+ char *name, *email;
+
+ if (split_ident_line(&id, author, strlen(author)) < 0) {
+ error(_("invalid author identity '%s'"), author);
+ goto out;
+ }
+ name = xmemdupz(id.name_begin, id.name_end - id.name_begin);
+ email = xmemdupz(id.mail_begin, id.mail_end - id.mail_begin);
+ author = fmt_ident(name, email, WANT_AUTHOR_IDENT, NULL,
+ IDENT_STRICT);
+ free(name);
+ free(email);
+ }
if (commit_tree_extended(msg->buf, msg->len, &tree, parents, oid,
- author, NULL, opts->gpg_sign, extra)) {
+ author, committer, opts->gpg_sign, extra)) {
res = error(_("failed to write commit object"));
goto out;
}
author, opts, flags, &oid);
strbuf_release(&sb);
if (!res) {
- unlink(git_path_cherry_pick_head(r));
+ refs_delete_ref(get_main_ref_store(r), "",
+ "CHERRY_PICK_HEAD", NULL, 0);
unlink(git_path_merge_msg(r));
if (!is_rebase_i(opts))
print_commit_summary(r, NULL, &oid,
static char command_to_char(const enum todo_command command)
{
- if (command < TODO_COMMENT && todo_command_info[command].c)
+ if (command < TODO_COMMENT)
return todo_command_info[command].c;
return comment_line_char;
}
flags |= ALLOW_EMPTY;
} else if (allow == 2) {
drop_commit = 1;
- unlink(git_path_cherry_pick_head(r));
+ refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD",
+ NULL, 0);
unlink(git_path_merge_msg(r));
fprintf(stderr,
_("dropping %s %s -- patch contents already upstream\n"),
struct replay_opts opts = REPLAY_OPTS_INIT;
int need_cleanup = 0;
- if (file_exists(git_path_cherry_pick_head(r))) {
- if (!unlink(git_path_cherry_pick_head(r)) && verbose)
+ if (refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD")) {
+ if (!refs_delete_ref(get_main_ref_store(r), "",
+ "CHERRY_PICK_HEAD", NULL, 0) &&
+ verbose)
warning(_("cancelling a cherry picking in progress"));
opts.action = REPLAY_PICK;
need_cleanup = 1;
}
- if (file_exists(git_path_revert_head(r))) {
- if (!unlink(git_path_revert_head(r)) && verbose)
+ if (refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD")) {
+ if (!refs_delete_ref(get_main_ref_store(r), "", "REVERT_HEAD",
+ NULL, 0) &&
+ verbose)
warning(_("cancelling a revert in progress"));
opts.action = REPLAY_REVERT;
need_cleanup = 1;
{
if (is_rebase_i(opts)) {
struct strbuf buf = STRBUF_INIT;
+ int ret = 0;
- if (read_oneliner(&buf, rebase_path_gpg_sign_opt(), 1)) {
+ if (read_oneliner(&buf, rebase_path_gpg_sign_opt(),
+ READ_ONELINER_SKIP_IF_EMPTY)) {
if (!starts_with(buf.buf, "-S"))
strbuf_reset(&buf);
else {
strbuf_reset(&buf);
}
- if (read_oneliner(&buf, rebase_path_allow_rerere_autoupdate(), 1)) {
+ if (read_oneliner(&buf, rebase_path_allow_rerere_autoupdate(),
+ READ_ONELINER_SKIP_IF_EMPTY)) {
if (!strcmp(buf.buf, "--rerere-autoupdate"))
opts->allow_rerere_auto = RERERE_AUTOUPDATE;
else if (!strcmp(buf.buf, "--no-rerere-autoupdate"))
opts->signoff = 1;
}
+ if (file_exists(rebase_path_cdate_is_adate())) {
+ opts->allow_ff = 0;
+ opts->committer_date_is_author_date = 1;
+ }
+
+ if (file_exists(rebase_path_ignore_date())) {
+ opts->allow_ff = 0;
+ opts->ignore_date = 1;
+ }
+
if (file_exists(rebase_path_reschedule_failed_exec()))
opts->reschedule_failed_exec = 1;
opts->keep_redundant_commits = 1;
read_strategy_opts(opts, &buf);
- strbuf_release(&buf);
+ strbuf_reset(&buf);
if (read_oneliner(&opts->current_fixups,
- rebase_path_current_fixups(), 1)) {
+ rebase_path_current_fixups(),
+ READ_ONELINER_SKIP_IF_EMPTY)) {
const char *p = opts->current_fixups.buf;
opts->current_fixup_count = 1;
while ((p = strchr(p, '\n'))) {
}
if (read_oneliner(&buf, rebase_path_squash_onto(), 0)) {
- if (get_oid_hex(buf.buf, &opts->squash_onto) < 0)
- return error(_("unusable squash-onto"));
+ if (get_oid_hex(buf.buf, &opts->squash_onto) < 0) {
+ ret = error(_("unusable squash-onto"));
+ goto done_rebase_i;
+ }
opts->have_squash_onto = 1;
}
- return 0;
+done_rebase_i:
+ strbuf_release(&buf);
+ return ret;
}
if (!file_exists(git_path_opts_file()))
write_file(rebase_path_drop_redundant_commits(), "%s", "");
if (opts->keep_redundant_commits)
write_file(rebase_path_keep_redundant_commits(), "%s", "");
+ if (opts->committer_date_is_author_date)
+ write_file(rebase_path_cdate_is_adate(), "%s", "");
+ if (opts->ignore_date)
+ write_file(rebase_path_ignore_date(), "%s", "");
if (opts->reschedule_failed_exec)
write_file(rebase_path_reschedule_failed_exec(), "%s", "");
enum replay_action action;
const char *in_progress_error = NULL;
const char *in_progress_advice = NULL;
- unsigned int advise_skip = file_exists(git_path_revert_head(r)) ||
- file_exists(git_path_cherry_pick_head(r));
+ unsigned int advise_skip =
+ refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD") ||
+ refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD");
if (!sequencer_get_last_command(r, &action)) {
switch (action) {
static int reset_merge(const struct object_id *oid)
{
int ret;
- struct argv_array argv = ARGV_ARRAY_INIT;
+ struct strvec argv = STRVEC_INIT;
- argv_array_pushl(&argv, "reset", "--merge", NULL);
+ strvec_pushl(&argv, "reset", "--merge", NULL);
if (!is_null_oid(oid))
- argv_array_push(&argv, oid_to_hex(oid));
+ strvec_push(&argv, oid_to_hex(oid));
- ret = run_command_v_opt(argv.argv, RUN_GIT_CMD);
- argv_array_clear(&argv);
+ ret = run_command_v_opt(argv.v, RUN_GIT_CMD);
+ strvec_clear(&argv);
return ret;
}
{
struct object_id head_oid;
- if (!file_exists(git_path_cherry_pick_head(r)) &&
- !file_exists(git_path_revert_head(r)))
+ if (!refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD") &&
+ !refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD"))
return error(_("no cherry-pick or revert in progress"));
if (read_ref_full("HEAD", 0, &head_oid, NULL))
return error(_("cannot resolve HEAD"));
*/
switch (opts->action) {
case REPLAY_REVERT:
- if (!file_exists(git_path_revert_head(r))) {
+ if (!refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD")) {
if (action != REPLAY_REVERT)
return error(_("no revert in progress"));
if (!rollback_is_safe())
}
break;
case REPLAY_PICK:
- if (!file_exists(git_path_cherry_pick_head(r))) {
+ if (!refs_ref_exists(get_main_ref_store(r),
+ "CHERRY_PICK_HEAD")) {
if (action != REPLAY_PICK)
return error(_("no cherry-pick in progress"));
if (!rollback_is_safe())
static int do_exec(struct repository *r, const char *command_line)
{
- struct argv_array child_env = ARGV_ARRAY_INIT;
+ struct strvec child_env = STRVEC_INIT;
const char *child_argv[] = { NULL, NULL };
int dirty, status;
- fprintf(stderr, "Executing: %s\n", command_line);
+ fprintf(stderr, _("Executing: %s\n"), command_line);
child_argv[0] = command_line;
- argv_array_pushf(&child_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
- argv_array_pushf(&child_env, "GIT_WORK_TREE=%s",
- absolute_path(get_git_work_tree()));
+ strvec_pushf(&child_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+ strvec_pushf(&child_env, "GIT_WORK_TREE=%s",
+ absolute_path(get_git_work_tree()));
status = run_command_v_opt_cd_env(child_argv, RUN_USING_SHELL, NULL,
- child_env.argv);
+ child_env.v);
/* force re-reading of the cache */
if (discard_index(r->index) < 0 || repo_read_index(r) < 0)
status = 1;
}
- argv_array_clear(&child_env);
+ strvec_clear(&child_env);
return status;
}
goto leave_merge;
}
+ if (opts->committer_date_is_author_date)
+ strvec_pushf(&cmd.env_array, "GIT_COMMITTER_DATE=%s",
+ opts->ignore_date ?
+ "" :
+ author_date_from_env_array(&cmd.env_array));
+ if (opts->ignore_date)
+ strvec_push(&cmd.env_array, "GIT_AUTHOR_DATE=");
+
cmd.git_cmd = 1;
- argv_array_push(&cmd.args, "merge");
- argv_array_push(&cmd.args, "-s");
+ strvec_push(&cmd.args, "merge");
+ strvec_push(&cmd.args, "-s");
if (!strategy)
- argv_array_push(&cmd.args, "octopus");
+ strvec_push(&cmd.args, "octopus");
else {
- argv_array_push(&cmd.args, strategy);
+ strvec_push(&cmd.args, strategy);
for (k = 0; k < opts->xopts_nr; k++)
- argv_array_pushf(&cmd.args,
- "-X%s", opts->xopts[k]);
+ strvec_pushf(&cmd.args,
+ "-X%s", opts->xopts[k]);
}
- argv_array_push(&cmd.args, "--no-edit");
- argv_array_push(&cmd.args, "--no-ff");
- argv_array_push(&cmd.args, "--no-log");
- argv_array_push(&cmd.args, "--no-stat");
- argv_array_push(&cmd.args, "-F");
- argv_array_push(&cmd.args, git_path_merge_msg(r));
+ strvec_push(&cmd.args, "--no-edit");
+ strvec_push(&cmd.args, "--no-ff");
+ strvec_push(&cmd.args, "--no-log");
+ strvec_push(&cmd.args, "--no-stat");
+ strvec_push(&cmd.args, "-F");
+ strvec_push(&cmd.args, git_path_merge_msg(r));
if (opts->gpg_sign)
- argv_array_push(&cmd.args, opts->gpg_sign);
+ strvec_push(&cmd.args, opts->gpg_sign);
/* Add the tips to be merged */
for (j = to_merge; j; j = j->next)
- argv_array_push(&cmd.args,
- oid_to_hex(&j->item->object.oid));
+ strvec_push(&cmd.args,
+ oid_to_hex(&j->item->object.oid));
strbuf_release(&ref_name);
- unlink(git_path_cherry_pick_head(r));
+ refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD",
+ NULL, 0);
rollback_lock_file(&lock);
rollback_lock_file(&lock);
return -1;
}
-static int apply_autostash(struct replay_opts *opts)
+void create_autostash(struct repository *r, const char *path,
+ const char *default_reflog_action)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct lock_file lock_file = LOCK_INIT;
+ int fd;
+
+ fd = repo_hold_locked_index(r, &lock_file, 0);
+ refresh_index(r->index, REFRESH_QUIET, NULL, NULL, NULL);
+ if (0 <= fd)
+ repo_update_index_if_able(r, &lock_file);
+ rollback_lock_file(&lock_file);
+
+ if (has_unstaged_changes(r, 1) ||
+ has_uncommitted_changes(r, 1)) {
+ struct child_process stash = CHILD_PROCESS_INIT;
+ struct object_id oid;
+
+ strvec_pushl(&stash.args,
+ "stash", "create", "autostash", NULL);
+ stash.git_cmd = 1;
+ stash.no_stdin = 1;
+ strbuf_reset(&buf);
+ if (capture_command(&stash, &buf, GIT_MAX_HEXSZ))
+ die(_("Cannot autostash"));
+ strbuf_trim_trailing_newline(&buf);
+ if (get_oid(buf.buf, &oid))
+ die(_("Unexpected stash response: '%s'"),
+ buf.buf);
+ strbuf_reset(&buf);
+ strbuf_add_unique_abbrev(&buf, &oid, DEFAULT_ABBREV);
+
+ if (safe_create_leading_directories_const(path))
+ die(_("Could not create directory for '%s'"),
+ path);
+ write_file(path, "%s", oid_to_hex(&oid));
+ printf(_("Created autostash: %s\n"), buf.buf);
+ if (reset_head(r, NULL, "reset --hard",
+ NULL, RESET_HEAD_HARD, NULL, NULL,
+ default_reflog_action) < 0)
+ die(_("could not reset --hard"));
+
+ if (discard_index(r->index) < 0 ||
+ repo_read_index(r) < 0)
+ die(_("could not read index"));
+ }
+ strbuf_release(&buf);
+}
+
+static int apply_save_autostash_oid(const char *stash_oid, int attempt_apply)
{
- struct strbuf stash_sha1 = STRBUF_INIT;
struct child_process child = CHILD_PROCESS_INIT;
int ret = 0;
- if (!read_oneliner(&stash_sha1, rebase_path_autostash(), 1)) {
- strbuf_release(&stash_sha1);
- return 0;
+ if (attempt_apply) {
+ child.git_cmd = 1;
+ child.no_stdout = 1;
+ child.no_stderr = 1;
+ strvec_push(&child.args, "stash");
+ strvec_push(&child.args, "apply");
+ strvec_push(&child.args, stash_oid);
+ ret = run_command(&child);
}
- strbuf_trim(&stash_sha1);
- child.git_cmd = 1;
- child.no_stdout = 1;
- child.no_stderr = 1;
- argv_array_push(&child.args, "stash");
- argv_array_push(&child.args, "apply");
- argv_array_push(&child.args, stash_sha1.buf);
- if (!run_command(&child))
+ if (attempt_apply && !ret)
fprintf(stderr, _("Applied autostash.\n"));
else {
struct child_process store = CHILD_PROCESS_INIT;
store.git_cmd = 1;
- argv_array_push(&store.args, "stash");
- argv_array_push(&store.args, "store");
- argv_array_push(&store.args, "-m");
- argv_array_push(&store.args, "autostash");
- argv_array_push(&store.args, "-q");
- argv_array_push(&store.args, stash_sha1.buf);
+ strvec_push(&store.args, "stash");
+ strvec_push(&store.args, "store");
+ strvec_push(&store.args, "-m");
+ strvec_push(&store.args, "autostash");
+ strvec_push(&store.args, "-q");
+ strvec_push(&store.args, stash_oid);
if (run_command(&store))
- ret = error(_("cannot store %s"), stash_sha1.buf);
+ ret = error(_("cannot store %s"), stash_oid);
else
fprintf(stderr,
- _("Applying autostash resulted in conflicts.\n"
+ _("%s\n"
"Your changes are safe in the stash.\n"
"You can run \"git stash pop\" or"
- " \"git stash drop\" at any time.\n"));
+ " \"git stash drop\" at any time.\n"),
+ attempt_apply ?
+ _("Applying autostash resulted in conflicts.") :
+ _("Autostash exists; creating a new stash entry."));
+ }
+
+ return ret;
+}
+
+static int apply_save_autostash(const char *path, int attempt_apply)
+{
+ struct strbuf stash_oid = STRBUF_INIT;
+ int ret = 0;
+
+ if (!read_oneliner(&stash_oid, path,
+ READ_ONELINER_SKIP_IF_EMPTY)) {
+ strbuf_release(&stash_oid);
+ return 0;
}
+ strbuf_trim(&stash_oid);
+
+ ret = apply_save_autostash_oid(stash_oid.buf, attempt_apply);
- strbuf_release(&stash_sha1);
+ unlink(path);
+ strbuf_release(&stash_oid);
return ret;
}
+int save_autostash(const char *path)
+{
+ return apply_save_autostash(path, 0);
+}
+
+int apply_autostash(const char *path)
+{
+ return apply_save_autostash(path, 1);
+}
+
+int apply_autostash_oid(const char *stash_oid)
+{
+ return apply_save_autostash_oid(stash_oid, 1);
+}
+
static const char *reflog_message(struct replay_opts *opts,
const char *sub_action, const char *fmt, ...)
{
va_list ap;
static struct strbuf buf = STRBUF_INIT;
+ char *reflog_action = getenv(GIT_REFLOG_ACTION);
va_start(ap, fmt);
strbuf_reset(&buf);
- strbuf_addstr(&buf, action_name(opts));
+ strbuf_addstr(&buf, reflog_action ? reflog_action : action_name(opts));
if (sub_action)
strbuf_addf(&buf, " (%s)", sub_action);
if (fmt) {
cmd.git_cmd = 1;
- argv_array_push(&cmd.args, "checkout");
- argv_array_push(&cmd.args, commit);
- argv_array_pushf(&cmd.env_array, GIT_REFLOG_ACTION "=%s", action);
+ strvec_push(&cmd.args, "checkout");
+ strvec_push(&cmd.args, commit);
+ strvec_pushf(&cmd.env_array, GIT_REFLOG_ACTION "=%s", action);
if (opts->verbose)
ret = run_command(&cmd);
return error(_("%s: not a valid OID"), orig_head);
if (run_git_checkout(r, opts, oid_to_hex(onto), action)) {
- apply_autostash(opts);
+ apply_autostash(rebase_path_autostash());
sequencer_remove_state(opts);
return error(_("could not detach HEAD"));
}
struct replay_opts *opts)
{
int res = 0, reschedule = 0;
+ char *prev_reflog_action;
+ /* Note that 0 for 3rd parameter of setenv means set only if not set */
setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
+ prev_reflog_action = xstrdup(getenv(GIT_REFLOG_ACTION));
if (opts->allow_ff)
assert(!(opts->signoff || opts->no_commit ||
- opts->record_origin || opts->edit));
+ opts->record_origin || opts->edit ||
+ opts->committer_date_is_author_date ||
+ opts->ignore_date));
if (read_and_refresh_cache(r, opts))
return -1;
fclose(f);
}
if (!opts->quiet)
- fprintf(stderr, "Rebasing (%d/%d)%s",
+ fprintf(stderr, _("Rebasing (%d/%d)%s"),
todo_list->done_nr,
todo_list->total_nr,
opts->verbose ? "\n" : "\r");
}
if (item->command <= TODO_SQUASH) {
if (is_rebase_i(opts))
- setenv("GIT_REFLOG_ACTION", reflog_message(opts,
+ setenv(GIT_REFLOG_ACTION, reflog_message(opts,
command_to_string(item->command), NULL),
1);
res = do_pick_commit(r, item->command, item->commit,
opts, is_final_fixup(todo_list),
&check_todo);
+ if (is_rebase_i(opts))
+ setenv(GIT_REFLOG_ACTION, prev_reflog_action, 1);
if (is_rebase_i(opts) && res < 0) {
/* Reschedule */
advise(_(rescheduled_advice),
child.in = open(rebase_path_rewritten_list(), O_RDONLY);
child.git_cmd = 1;
- argv_array_push(&child.args, "notes");
- argv_array_push(&child.args, "copy");
- argv_array_push(&child.args, "--for-rewrite=rebase");
+ strvec_push(&child.args, "notes");
+ strvec_push(&child.args, "copy");
+ strvec_push(&child.args, "--for-rewrite=rebase");
/* we don't care if this copying failed */
run_command(&child);
O_RDONLY);
hook.stdout_to_stderr = 1;
hook.trace2_hook_name = "post-rewrite";
- argv_array_push(&hook.args, post_rewrite_hook);
- argv_array_push(&hook.args, "rebase");
+ strvec_push(&hook.args, post_rewrite_hook);
+ strvec_push(&hook.args, "rebase");
/* we don't care if this hook failed */
run_command(&hook);
}
}
- apply_autostash(opts);
+ apply_autostash(rebase_path_autostash());
if (!opts->quiet) {
if (!opts->verbose)
term_clear_line();
fprintf(stderr,
- "Successfully rebased and updated %s.\n",
+ _("Successfully rebased and updated %s.\n"),
head_ref.buf);
}
{
const char *argv[] = { "commit", NULL };
- if (!file_exists(git_path_cherry_pick_head(r)) &&
- !file_exists(git_path_revert_head(r)))
+ if (!refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD") &&
+ !refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD"))
return error(_("no cherry-pick or revert in progress"));
return run_command_v_opt(argv, RUN_GIT_CMD);
}
}
if (is_clean) {
- const char *cherry_pick_head = git_path_cherry_pick_head(r);
-
- if (file_exists(cherry_pick_head) && unlink(cherry_pick_head))
+ if (refs_ref_exists(get_main_ref_store(r),
+ "CHERRY_PICK_HEAD") &&
+ refs_delete_ref(get_main_ref_store(r), "",
+ "CHERRY_PICK_HEAD", NULL, 0))
return error(_("could not remove CHERRY_PICK_HEAD"));
if (!final_fixup)
return 0;
return 0;
}
+static int init_committer(struct replay_opts *opts)
+{
+ struct ident_split id;
+ const char *committer;
+
+ committer = git_committer_info(IDENT_STRICT);
+ if (split_ident_line(&id, committer, strlen(committer)) < 0)
+ return error(_("invalid committer '%s'"), committer);
+ opts->committer_name =
+ xmemdupz(id.name_begin, id.name_end - id.name_begin);
+ opts->committer_email =
+ xmemdupz(id.mail_begin, id.mail_end - id.mail_end);
+
+ return 0;
+}
+
int sequencer_continue(struct repository *r, struct replay_opts *opts)
{
struct todo_list todo_list = TODO_LIST_INIT;
if (read_populate_opts(opts))
return -1;
if (is_rebase_i(opts)) {
+ if (opts->committer_date_is_author_date && init_committer(opts))
+ return -1;
+
if ((res = read_populate_todo(r, &todo_list, opts)))
goto release_todo_list;
if (!is_rebase_i(opts)) {
/* Verify that the conflict has been resolved */
- if (file_exists(git_path_cherry_pick_head(r)) ||
- file_exists(git_path_revert_head(r))) {
+ if (refs_ref_exists(get_main_ref_store(r),
+ "CHERRY_PICK_HEAD") ||
+ refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD")) {
res = continue_single_pick(r);
if (res)
goto release_todo_list;
struct strbuf buf = STRBUF_INIT;
struct object_id oid;
- if (read_oneliner(&buf, rebase_path_stopped_sha(), 1) &&
+ if (read_oneliner(&buf, rebase_path_stopped_sha(),
+ READ_ONELINER_SKIP_IF_EMPTY) &&
!get_oid_committish(buf.buf, &oid))
record_in_rewritten(&oid, peek_command(&todo_list, 0));
strbuf_release(&buf);
struct rev_info *revs, struct strbuf *out,
unsigned flags)
{
+ int keep_empty = flags & TODO_LIST_KEEP_EMPTY;
int rebase_cousins = flags & TODO_LIST_REBASE_COUSINS;
int root_with_onto = flags & TODO_LIST_ROOT_WITH_ONTO;
struct strbuf buf = STRBUF_INIT, oneline = STRBUF_INIT;
is_empty = is_original_commit_empty(commit);
if (!is_empty && (commit->object.flags & PATCHSAME))
continue;
+ if (is_empty && !keep_empty)
+ continue;
strbuf_reset(&oneline);
pretty_print_commit(pp, commit, &oneline);
strbuf_addf(&buf, "%s %s %s", cmd_pick,
oid_to_hex(&commit->object.oid),
oneline.buf);
+ if (is_empty)
+ strbuf_addf(&buf, " %c empty",
+ comment_line_char);
FLEX_ALLOC_STR(entry, string, buf.buf);
oidcpy(&entry->entry.oid, &commit->object.oid);
struct pretty_print_context pp = {0};
struct rev_info revs;
struct commit *commit;
+ int keep_empty = flags & TODO_LIST_KEEP_EMPTY;
const char *insn = flags & TODO_LIST_ABBREVIATE_CMDS ? "p" : "pick";
int rebase_merges = flags & TODO_LIST_REBASE_MERGES;
+ int reapply_cherry_picks = flags & TODO_LIST_REAPPLY_CHERRY_PICKS;
repo_init_revisions(r, &revs, NULL);
revs.verbose_header = 1;
if (!rebase_merges)
revs.max_parents = 1;
- revs.cherry_mark = 1;
+ revs.cherry_mark = !reapply_cherry_picks;
revs.limited = 1;
revs.reverse = 1;
revs.right_only = 1;
if (!is_empty && (commit->object.flags & PATCHSAME))
continue;
+ if (is_empty && !keep_empty)
+ continue;
strbuf_addf(out, "%s %s ", insn,
oid_to_hex(&commit->object.oid));
pretty_print_commit(&pp, commit, out);
+ if (is_empty)
+ strbuf_addf(out, " %c empty", comment_line_char);
strbuf_addch(out, '\n');
}
return 0;
max = num;
for (item = todo_list->items, i = 0; i < max; i++, item++) {
+ char cmd;
+
/* if the item is not a command write it and continue */
if (item->command >= TODO_COMMENT) {
strbuf_addf(buf, "%.*s\n", item->arg_len,
}
/* add command to the buffer */
- if (flags & TODO_LIST_ABBREVIATE_CMDS)
- strbuf_addch(buf, command_to_char(item->command));
+ cmd = command_to_char(item->command);
+ if ((flags & TODO_LIST_ABBREVIATE_CMDS) && cmd)
+ strbuf_addch(buf, cmd);
else
strbuf_addstr(buf, command_to_string(item->command));
struct string_list *commands, unsigned autosquash,
struct todo_list *todo_list)
{
- const char *shortonto, *todo_file = rebase_path_todo();
+ char shortonto[GIT_MAX_HEXSZ + 1];
+ const char *todo_file = rebase_path_todo();
struct todo_list new_todo = TODO_LIST_INIT;
struct strbuf *buf = &todo_list->buf, buf2 = STRBUF_INIT;
struct object_id oid = onto->object.oid;
int res;
- shortonto = find_unique_abbrev(&oid, DEFAULT_ABBREV);
+ find_unique_abbrev_r(shortonto, &oid, DEFAULT_ABBREV);
if (buf->len == 0) {
struct todo_item *item = append_new_todo(todo_list);
todo_list_add_exec_commands(todo_list, commands);
if (count_commands(todo_list) == 0) {
- apply_autostash(opts);
+ apply_autostash(rebase_path_autostash());
sequencer_remove_state(opts);
return error(_("nothing to do"));
if (res == -1)
return -1;
else if (res == -2) {
- apply_autostash(opts);
+ apply_autostash(rebase_path_autostash());
sequencer_remove_state(opts);
return -1;
} else if (res == -3) {
- apply_autostash(opts);
+ apply_autostash(rebase_path_autostash());
sequencer_remove_state(opts);
todo_list_release(&new_todo);
res = -1;
+ if (opts->committer_date_is_author_date && init_committer(opts))
+ goto cleanup;
+
if (checkout_onto(r, opts, onto_name, &oid, orig_head))
goto cleanup;
todo_list->items[i].command =
starts_with(subject, "fixup!") ?
TODO_FIXUP : TODO_SQUASH;
- if (next[i2] < 0)
+ if (tail[i2] < 0) {
+ next[i] = next[i2];
next[i2] = i;
- else
+ } else {
+ next[i] = next[tail[i2]];
next[tail[i2]] = i;
+ }
tail[i2] = i;
} else if (!hashmap_get_from_hash(&subject2item,
strhash(subject), subject)) {
int sequencer_determine_whence(struct repository *r, enum commit_whence *whence)
{
- if (file_exists(git_path_cherry_pick_head(r))) {
+ if (refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD")) {
struct object_id cherry_pick_head, rebase_head;
if (file_exists(git_path_seq_dir()))