зеркало из https://github.com/microsoft/git.git
Merge branch 'pw/rebase-i-show-HEAD-to-reword'
"git rebase -i" showed a wrong HEAD while "reword" open the editor. * pw/rebase-i-show-HEAD-to-reword: sequencer: simplify root commit creation rebase -i: check for updated todo after squash and reword rebase -i: always update HEAD before rewording
This commit is contained in:
Коммит
4608a029b4
130
sequencer.c
130
sequencer.c
|
@ -869,34 +869,6 @@ static char *get_author(const char *message)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Read author-script and return an ident line (author <email> timestamp) */
|
||||
static const char *read_author_ident(struct strbuf *buf)
|
||||
{
|
||||
struct strbuf out = STRBUF_INIT;
|
||||
char *name, *email, *date;
|
||||
|
||||
if (read_author_script(rebase_path_author_script(),
|
||||
&name, &email, &date, 0))
|
||||
return NULL;
|
||||
|
||||
/* validate date since fmt_ident() will die() on bad value */
|
||||
if (parse_date(date, &out)){
|
||||
warning(_("invalid date format '%s' in '%s'"),
|
||||
date, rebase_path_author_script());
|
||||
strbuf_release(&out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strbuf_reset(&out);
|
||||
strbuf_addstr(&out, fmt_ident(name, email, WANT_AUTHOR_IDENT, date, 0));
|
||||
strbuf_swap(buf, &out);
|
||||
strbuf_release(&out);
|
||||
free(name);
|
||||
free(email);
|
||||
free(date);
|
||||
return buf->buf;
|
||||
}
|
||||
|
||||
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"
|
||||
|
@ -954,47 +926,6 @@ static int run_git_commit(struct repository *r,
|
|||
{
|
||||
struct child_process cmd = CHILD_PROCESS_INIT;
|
||||
|
||||
if ((flags & CREATE_ROOT_COMMIT) && !(flags & AMEND_MSG)) {
|
||||
struct strbuf msg = STRBUF_INIT, script = STRBUF_INIT;
|
||||
const char *author = NULL;
|
||||
struct object_id root_commit, *cache_tree_oid;
|
||||
int res = 0;
|
||||
|
||||
if (is_rebase_i(opts)) {
|
||||
author = read_author_ident(&script);
|
||||
if (!author) {
|
||||
strbuf_release(&script);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!defmsg)
|
||||
BUG("root commit without message");
|
||||
|
||||
if (!(cache_tree_oid = get_cache_tree_oid(r->index)))
|
||||
res = -1;
|
||||
|
||||
if (!res)
|
||||
res = strbuf_read_file(&msg, defmsg, 0);
|
||||
|
||||
if (res <= 0)
|
||||
res = error_errno(_("could not read '%s'"), defmsg);
|
||||
else
|
||||
res = commit_tree(msg.buf, msg.len, cache_tree_oid,
|
||||
NULL, &root_commit, author,
|
||||
opts->gpg_sign);
|
||||
|
||||
strbuf_release(&msg);
|
||||
strbuf_release(&script);
|
||||
if (!res) {
|
||||
update_ref(NULL, "CHERRY_PICK_HEAD", &root_commit, NULL,
|
||||
REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR);
|
||||
res = update_ref(NULL, "HEAD", &root_commit, NULL, 0,
|
||||
UPDATE_REFS_MSG_ON_ERR);
|
||||
}
|
||||
return res < 0 ? error(_("writing root commit")) : 0;
|
||||
}
|
||||
|
||||
cmd.git_cmd = 1;
|
||||
|
||||
if (is_rebase_i(opts) && read_env_script(&cmd.env_array)) {
|
||||
|
@ -1378,7 +1309,7 @@ static int try_to_commit(struct repository *r,
|
|||
struct object_id *oid)
|
||||
{
|
||||
struct object_id tree;
|
||||
struct commit *current_head;
|
||||
struct commit *current_head = NULL;
|
||||
struct commit_list *parents = NULL;
|
||||
struct commit_extra_header *extra = NULL;
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
|
@ -1413,7 +1344,8 @@ static int try_to_commit(struct repository *r,
|
|||
}
|
||||
parents = copy_commit_list(current_head->parents);
|
||||
extra = read_commit_extra_headers(current_head, exclude_gpgsig);
|
||||
} else if (current_head) {
|
||||
} else if (current_head &&
|
||||
(!(flags & CREATE_ROOT_COMMIT) || (flags & AMEND_MSG))) {
|
||||
commit_list_insert(current_head, &parents);
|
||||
}
|
||||
|
||||
|
@ -1490,8 +1422,7 @@ static int do_commit(struct repository *r,
|
|||
{
|
||||
int res = 1;
|
||||
|
||||
if (!(flags & EDIT_MSG) && !(flags & VERIFY_MSG) &&
|
||||
!(flags & CREATE_ROOT_COMMIT)) {
|
||||
if (!(flags & EDIT_MSG) && !(flags & VERIFY_MSG)) {
|
||||
struct object_id oid;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
|
@ -1775,7 +1706,7 @@ static int do_pick_commit(struct repository *r,
|
|||
enum todo_command command,
|
||||
struct commit *commit,
|
||||
struct replay_opts *opts,
|
||||
int final_fixup)
|
||||
int final_fixup, int *check_todo)
|
||||
{
|
||||
unsigned int flags = opts->edit ? EDIT_MSG : 0;
|
||||
const char *msg_file = opts->edit ? NULL : git_path_merge_msg(r);
|
||||
|
@ -1785,7 +1716,7 @@ static int do_pick_commit(struct repository *r,
|
|||
char *author = NULL;
|
||||
struct commit_message msg = { NULL, NULL, NULL, NULL };
|
||||
struct strbuf msgbuf = STRBUF_INIT;
|
||||
int res, unborn = 0, allow;
|
||||
int res, unborn = 0, reword = 0, allow;
|
||||
|
||||
if (opts->no_commit) {
|
||||
/*
|
||||
|
@ -1855,7 +1786,7 @@ static int do_pick_commit(struct repository *r,
|
|||
opts);
|
||||
if (res || command != TODO_REWORD)
|
||||
goto leave;
|
||||
flags |= EDIT_MSG | AMEND_MSG | VERIFY_MSG;
|
||||
reword = 1;
|
||||
msg_file = NULL;
|
||||
goto fast_forward_edit;
|
||||
}
|
||||
|
@ -1913,7 +1844,7 @@ static int do_pick_commit(struct repository *r,
|
|||
}
|
||||
|
||||
if (command == TODO_REWORD)
|
||||
flags |= EDIT_MSG | VERIFY_MSG;
|
||||
reword = 1;
|
||||
else if (is_fixup(command)) {
|
||||
if (update_squash_messages(r, command, commit, opts))
|
||||
return -1;
|
||||
|
@ -1997,12 +1928,20 @@ static int do_pick_commit(struct repository *r,
|
|||
} else if (allow)
|
||||
flags |= ALLOW_EMPTY;
|
||||
if (!opts->no_commit) {
|
||||
fast_forward_edit:
|
||||
if (author || command == TODO_REVERT || (flags & AMEND_MSG))
|
||||
res = do_commit(r, msg_file, author, opts, flags);
|
||||
else
|
||||
res = error(_("unable to parse commit author"));
|
||||
*check_todo = !!(flags & EDIT_MSG);
|
||||
if (!res && reword) {
|
||||
fast_forward_edit:
|
||||
res = run_git_commit(r, NULL, opts, EDIT_MSG |
|
||||
VERIFY_MSG | AMEND_MSG |
|
||||
(flags & ALLOW_EMPTY));
|
||||
*check_todo = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!res && final_fixup) {
|
||||
unlink(rebase_path_fixup_msg());
|
||||
|
@ -3828,6 +3767,7 @@ static int pick_commits(struct repository *r,
|
|||
while (todo_list->current < todo_list->nr) {
|
||||
struct todo_item *item = todo_list->items + todo_list->current;
|
||||
const char *arg = todo_item_get_arg(todo_list, item);
|
||||
int check_todo = 0;
|
||||
|
||||
if (save_todo(todo_list, opts))
|
||||
return -1;
|
||||
|
@ -3866,7 +3806,8 @@ static int pick_commits(struct repository *r,
|
|||
command_to_string(item->command), NULL),
|
||||
1);
|
||||
res = do_pick_commit(r, item->command, item->commit,
|
||||
opts, is_final_fixup(todo_list));
|
||||
opts, is_final_fixup(todo_list),
|
||||
&check_todo);
|
||||
if (is_rebase_i(opts) && res < 0) {
|
||||
/* Reschedule */
|
||||
advise(_(rescheduled_advice),
|
||||
|
@ -3923,7 +3864,6 @@ static int pick_commits(struct repository *r,
|
|||
} else if (item->command == TODO_EXEC) {
|
||||
char *end_of_arg = (char *)(arg + item->arg_len);
|
||||
int saved = *end_of_arg;
|
||||
struct stat st;
|
||||
|
||||
if (!opts->verbose)
|
||||
term_clear_line();
|
||||
|
@ -3934,17 +3874,8 @@ static int pick_commits(struct repository *r,
|
|||
if (res) {
|
||||
if (opts->reschedule_failed_exec)
|
||||
reschedule = 1;
|
||||
} else if (stat(get_todo_path(opts), &st))
|
||||
res = error_errno(_("could not stat '%s'"),
|
||||
get_todo_path(opts));
|
||||
else if (match_stat_data(&todo_list->stat, &st)) {
|
||||
/* Reread the todo file if it has changed. */
|
||||
todo_list_release(todo_list);
|
||||
if (read_populate_todo(r, todo_list, opts))
|
||||
res = -1; /* message was printed */
|
||||
/* `current` will be incremented below */
|
||||
todo_list->current = -1;
|
||||
}
|
||||
check_todo = 1;
|
||||
} else if (item->command == TODO_LABEL) {
|
||||
if ((res = do_label(r, arg, item->arg_len)))
|
||||
reschedule = 1;
|
||||
|
@ -3980,6 +3911,20 @@ static int pick_commits(struct repository *r,
|
|||
item->commit,
|
||||
arg, item->arg_len,
|
||||
opts, res, 0);
|
||||
} else if (check_todo && !res) {
|
||||
struct stat st;
|
||||
|
||||
if (stat(get_todo_path(opts), &st)) {
|
||||
res = error_errno(_("could not stat '%s'"),
|
||||
get_todo_path(opts));
|
||||
} else if (match_stat_data(&todo_list->stat, &st)) {
|
||||
/* Reread the todo file if it has changed. */
|
||||
todo_list_release(todo_list);
|
||||
if (read_populate_todo(r, todo_list, opts))
|
||||
res = -1; /* message was printed */
|
||||
/* `current` will be incremented below */
|
||||
todo_list->current = -1;
|
||||
}
|
||||
}
|
||||
|
||||
todo_list->current++;
|
||||
|
@ -4306,9 +4251,12 @@ static int single_pick(struct repository *r,
|
|||
struct commit *cmit,
|
||||
struct replay_opts *opts)
|
||||
{
|
||||
int check_todo;
|
||||
|
||||
setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
|
||||
return do_pick_commit(r, opts->action == REPLAY_PICK ?
|
||||
TODO_PICK : TODO_REVERT, cmit, opts, 0);
|
||||
TODO_PICK : TODO_REVERT, cmit, opts, 0,
|
||||
&check_todo);
|
||||
}
|
||||
|
||||
int sequencer_pick_revisions(struct repository *r,
|
||||
|
|
|
@ -1014,9 +1014,9 @@ test_expect_success 'rebase -i --root fixup root commit' '
|
|||
test 0 = $(git cat-file commit HEAD | grep -c ^parent\ )
|
||||
'
|
||||
|
||||
test_expect_success 'rebase -i --root reword root commit' '
|
||||
test_expect_success 'rebase -i --root reword original root commit' '
|
||||
test_when_finished "test_might_fail git rebase --abort" &&
|
||||
git checkout -b reword-root-branch master &&
|
||||
git checkout -b reword-original-root-branch master &&
|
||||
set_fake_editor &&
|
||||
FAKE_LINES="reword 1 2" FAKE_COMMIT_MESSAGE="A changed" \
|
||||
git rebase -i --root &&
|
||||
|
@ -1024,6 +1024,16 @@ test_expect_success 'rebase -i --root reword root commit' '
|
|||
test -z "$(git show -s --format=%p HEAD^)"
|
||||
'
|
||||
|
||||
test_expect_success 'rebase -i --root reword new root commit' '
|
||||
test_when_finished "test_might_fail git rebase --abort" &&
|
||||
git checkout -b reword-now-root-branch master &&
|
||||
set_fake_editor &&
|
||||
FAKE_LINES="reword 3 1" FAKE_COMMIT_MESSAGE="C changed" \
|
||||
git rebase -i --root &&
|
||||
git show HEAD^ | grep "C changed" &&
|
||||
test -z "$(git show -s --format=%p HEAD^)"
|
||||
'
|
||||
|
||||
test_expect_success 'rebase -i --root when root has untracked file conflict' '
|
||||
test_when_finished "reset_rebase" &&
|
||||
git checkout -b failing-root-pick A &&
|
||||
|
@ -1052,7 +1062,7 @@ test_expect_success 'rebase -i --root reword root when root has untracked file c
|
|||
'
|
||||
|
||||
test_expect_success C_LOCALE_OUTPUT 'rebase --edit-todo does not work on non-interactive rebase' '
|
||||
git checkout reword-root-branch &&
|
||||
git checkout reword-original-root-branch &&
|
||||
git reset --hard &&
|
||||
git checkout conflict-branch &&
|
||||
set_fake_editor &&
|
||||
|
|
|
@ -3,9 +3,15 @@
|
|||
test_description='rebase should reread the todo file if an exec modifies it'
|
||||
|
||||
. ./test-lib.sh
|
||||
. "$TEST_DIRECTORY"/lib-rebase.sh
|
||||
|
||||
test_expect_success 'setup' '
|
||||
test_commit first file &&
|
||||
test_commit second file &&
|
||||
test_commit third file
|
||||
'
|
||||
|
||||
test_expect_success 'rebase exec modifies rebase-todo' '
|
||||
test_commit initial &&
|
||||
todo=.git/rebase-merge/git-rebase-todo &&
|
||||
git rebase HEAD -x "echo exec touch F >>$todo" &&
|
||||
test -e F
|
||||
|
@ -33,4 +39,17 @@ test_expect_success SHA1 'loose object cache vs re-reading todo list' '
|
|||
git rebase HEAD -x "./append-todo.sh 5 6"
|
||||
'
|
||||
|
||||
test_expect_success 'todo is re-read after reword and squash' '
|
||||
write_script reword-editor.sh <<-\EOS &&
|
||||
GIT_SEQUENCE_EDITOR="echo \"exec echo $(cat file) >>actual\" >>" \
|
||||
git rebase --edit-todo
|
||||
EOS
|
||||
|
||||
test_write_lines first third >expected &&
|
||||
set_fake_editor &&
|
||||
GIT_SEQUENCE_EDITOR="$EDITOR" FAKE_LINES="reword 1 squash 2 fixup 3" \
|
||||
GIT_EDITOR=./reword-editor.sh git rebase -i --root third &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
@ -241,13 +241,7 @@ test_rebase () {
|
|||
git add b &&
|
||||
git rebase --continue
|
||||
) &&
|
||||
if test "$mode" = -p # reword amended after pick
|
||||
then
|
||||
n=18
|
||||
else
|
||||
n=17
|
||||
fi &&
|
||||
git log --pretty=%s -g -n$n HEAD@{1} >actual &&
|
||||
git log --pretty=%s -g -n18 HEAD@{1} >actual &&
|
||||
test_cmp "$TEST_DIRECTORY/t7505/expected-rebase${mode:--i}" actual
|
||||
'
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@ message (no editor) [edit rebase-10]
|
|||
message [fixup rebase-9]
|
||||
message (no editor) [fixup rebase-8]
|
||||
message (no editor) [squash rebase-7]
|
||||
message [reword rebase-6]
|
||||
HEAD [reword rebase-6]
|
||||
message (no editor) [reword rebase-6]
|
||||
message [squash rebase-5]
|
||||
message (no editor) [fixup rebase-4]
|
||||
message (no editor) [pick rebase-3]
|
||||
|
|
Загрузка…
Ссылка в новой задаче