Merge branch 'pw/advise-rebase-skip'
The mechanism to prevent "git commit" from making an empty commit or amending during an interrupted cherry-pick was broken during the rewrite of "git rebase" in C, which has been corrected. * pw/advise-rebase-skip: commit: give correct advice for empty commit during a rebase commit: encapsulate determine_whence() for sequencer commit: use enum value for multiple cherry-picks sequencer: write CHERRY_PICK_HEAD for reword and edit cherry-pick: check commit error messages cherry-pick: add test for `--skip` advice in `git commit` t3404: use test_cmp_rev
This commit is contained in:
commit
f085189f14
@ -59,6 +59,9 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\
|
|||||||
" git commit --allow-empty\n"
|
" git commit --allow-empty\n"
|
||||||
"\n");
|
"\n");
|
||||||
|
|
||||||
|
static const char empty_rebase_pick_advice[] =
|
||||||
|
N_("Otherwise, please use 'git rebase --skip'\n");
|
||||||
|
|
||||||
static const char empty_cherry_pick_advice_single[] =
|
static const char empty_cherry_pick_advice_single[] =
|
||||||
N_("Otherwise, please use 'git cherry-pick --skip'\n");
|
N_("Otherwise, please use 'git cherry-pick --skip'\n");
|
||||||
|
|
||||||
@ -122,7 +125,6 @@ static enum commit_msg_cleanup_mode cleanup_mode;
|
|||||||
static const char *cleanup_arg;
|
static const char *cleanup_arg;
|
||||||
|
|
||||||
static enum commit_whence whence;
|
static enum commit_whence whence;
|
||||||
static int sequencer_in_use;
|
|
||||||
static int use_editor = 1, include_status = 1;
|
static int use_editor = 1, include_status = 1;
|
||||||
static int have_option_m;
|
static int have_option_m;
|
||||||
static struct strbuf message = STRBUF_INIT;
|
static struct strbuf message = STRBUF_INIT;
|
||||||
@ -179,12 +181,7 @@ static void determine_whence(struct wt_status *s)
|
|||||||
{
|
{
|
||||||
if (file_exists(git_path_merge_head(the_repository)))
|
if (file_exists(git_path_merge_head(the_repository)))
|
||||||
whence = FROM_MERGE;
|
whence = FROM_MERGE;
|
||||||
else if (file_exists(git_path_cherry_pick_head(the_repository))) {
|
else if (!sequencer_determine_whence(the_repository, &whence))
|
||||||
whence = FROM_CHERRY_PICK;
|
|
||||||
if (file_exists(git_path_seq_dir()))
|
|
||||||
sequencer_in_use = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
whence = FROM_COMMIT;
|
whence = FROM_COMMIT;
|
||||||
if (s)
|
if (s)
|
||||||
s->whence = whence;
|
s->whence = whence;
|
||||||
@ -477,8 +474,10 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
|
|||||||
if (whence != FROM_COMMIT) {
|
if (whence != FROM_COMMIT) {
|
||||||
if (whence == FROM_MERGE)
|
if (whence == FROM_MERGE)
|
||||||
die(_("cannot do a partial commit during a merge."));
|
die(_("cannot do a partial commit during a merge."));
|
||||||
else if (whence == FROM_CHERRY_PICK)
|
else if (is_from_cherry_pick(whence))
|
||||||
die(_("cannot do a partial commit during a cherry-pick."));
|
die(_("cannot do a partial commit during a cherry-pick."));
|
||||||
|
else if (is_from_rebase(whence))
|
||||||
|
die(_("cannot do a partial commit during a rebase."));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list_paths(&partial, !current_head ? NULL : "HEAD", &pathspec))
|
if (list_paths(&partial, !current_head ? NULL : "HEAD", &pathspec))
|
||||||
@ -795,7 +794,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
|
|||||||
*/
|
*/
|
||||||
else if (whence == FROM_MERGE)
|
else if (whence == FROM_MERGE)
|
||||||
hook_arg1 = "merge";
|
hook_arg1 = "merge";
|
||||||
else if (whence == FROM_CHERRY_PICK) {
|
else if (is_from_cherry_pick(whence) || whence == FROM_REBASE_PICK) {
|
||||||
hook_arg1 = "commit";
|
hook_arg1 = "commit";
|
||||||
hook_arg2 = "CHERRY_PICK_HEAD";
|
hook_arg2 = "CHERRY_PICK_HEAD";
|
||||||
}
|
}
|
||||||
@ -973,12 +972,15 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
|
|||||||
run_status(stdout, index_file, prefix, 0, s);
|
run_status(stdout, index_file, prefix, 0, s);
|
||||||
if (amend)
|
if (amend)
|
||||||
fputs(_(empty_amend_advice), stderr);
|
fputs(_(empty_amend_advice), stderr);
|
||||||
else if (whence == FROM_CHERRY_PICK) {
|
else if (is_from_cherry_pick(whence) ||
|
||||||
|
whence == FROM_REBASE_PICK) {
|
||||||
fputs(_(empty_cherry_pick_advice), stderr);
|
fputs(_(empty_cherry_pick_advice), stderr);
|
||||||
if (!sequencer_in_use)
|
if (whence == FROM_CHERRY_PICK_SINGLE)
|
||||||
fputs(_(empty_cherry_pick_advice_single), stderr);
|
fputs(_(empty_cherry_pick_advice_single), stderr);
|
||||||
else
|
else if (whence == FROM_CHERRY_PICK_MULTI)
|
||||||
fputs(_(empty_cherry_pick_advice_multi), stderr);
|
fputs(_(empty_cherry_pick_advice_multi), stderr);
|
||||||
|
else
|
||||||
|
fputs(_(empty_rebase_pick_advice), stderr);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1181,8 +1183,10 @@ static int parse_and_validate_options(int argc, const char *argv[],
|
|||||||
if (amend && whence != FROM_COMMIT) {
|
if (amend && whence != FROM_COMMIT) {
|
||||||
if (whence == FROM_MERGE)
|
if (whence == FROM_MERGE)
|
||||||
die(_("You are in the middle of a merge -- cannot amend."));
|
die(_("You are in the middle of a merge -- cannot amend."));
|
||||||
else if (whence == FROM_CHERRY_PICK)
|
else if (is_from_cherry_pick(whence))
|
||||||
die(_("You are in the middle of a cherry-pick -- cannot amend."));
|
die(_("You are in the middle of a cherry-pick -- cannot amend."));
|
||||||
|
else if (whence == FROM_REBASE_PICK)
|
||||||
|
die(_("You are in the middle of a rebase -- cannot amend."));
|
||||||
}
|
}
|
||||||
if (fixup_message && squash_message)
|
if (fixup_message && squash_message)
|
||||||
die(_("Options --squash and --fixup cannot be used together"));
|
die(_("Options --squash and --fixup cannot be used together"));
|
||||||
@ -1204,7 +1208,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
|
|||||||
use_message = edit_message;
|
use_message = edit_message;
|
||||||
if (amend && !use_message && !fixup_message)
|
if (amend && !use_message && !fixup_message)
|
||||||
use_message = "HEAD";
|
use_message = "HEAD";
|
||||||
if (!use_message && whence != FROM_CHERRY_PICK && renew_authorship)
|
if (!use_message && !is_from_cherry_pick(whence) &&
|
||||||
|
!is_from_rebase(whence) && renew_authorship)
|
||||||
die(_("--reset-author can be used only with -C, -c or --amend."));
|
die(_("--reset-author can be used only with -C, -c or --amend."));
|
||||||
if (use_message) {
|
if (use_message) {
|
||||||
use_message_buffer = read_commit_message(use_message);
|
use_message_buffer = read_commit_message(use_message);
|
||||||
@ -1213,7 +1218,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
|
|||||||
author_message_buffer = use_message_buffer;
|
author_message_buffer = use_message_buffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (whence == FROM_CHERRY_PICK && !renew_authorship) {
|
if ((is_from_cherry_pick(whence) || whence == FROM_REBASE_PICK) &&
|
||||||
|
!renew_authorship) {
|
||||||
author_message = "CHERRY_PICK_HEAD";
|
author_message = "CHERRY_PICK_HEAD";
|
||||||
author_message_buffer = read_commit_message(author_message);
|
author_message_buffer = read_commit_message(author_message);
|
||||||
}
|
}
|
||||||
@ -1631,8 +1637,10 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
|||||||
reduce_heads_replace(&parents);
|
reduce_heads_replace(&parents);
|
||||||
} else {
|
} else {
|
||||||
if (!reflog_msg)
|
if (!reflog_msg)
|
||||||
reflog_msg = (whence == FROM_CHERRY_PICK)
|
reflog_msg = is_from_cherry_pick(whence)
|
||||||
? "commit (cherry-pick)"
|
? "commit (cherry-pick)"
|
||||||
|
: is_from_rebase(whence)
|
||||||
|
? "commit (rebase)"
|
||||||
: "commit";
|
: "commit";
|
||||||
commit_list_insert(current_head, &parents);
|
commit_list_insert(current_head, &parents);
|
||||||
}
|
}
|
||||||
|
52
sequencer.c
52
sequencer.c
@ -40,7 +40,7 @@ static const char cherry_picked_prefix[] = "(cherry picked from commit ";
|
|||||||
|
|
||||||
GIT_PATH_FUNC(git_path_commit_editmsg, "COMMIT_EDITMSG")
|
GIT_PATH_FUNC(git_path_commit_editmsg, "COMMIT_EDITMSG")
|
||||||
|
|
||||||
GIT_PATH_FUNC(git_path_seq_dir, "sequencer")
|
static GIT_PATH_FUNC(git_path_seq_dir, "sequencer")
|
||||||
|
|
||||||
static GIT_PATH_FUNC(git_path_todo_file, "sequencer/todo")
|
static GIT_PATH_FUNC(git_path_todo_file, "sequencer/todo")
|
||||||
static GIT_PATH_FUNC(git_path_opts_file, "sequencer/opts")
|
static GIT_PATH_FUNC(git_path_opts_file, "sequencer/opts")
|
||||||
@ -1433,9 +1433,19 @@ out:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int write_rebase_head(struct object_id *oid)
|
||||||
|
{
|
||||||
|
if (update_ref("rebase", "REBASE_HEAD", oid,
|
||||||
|
NULL, REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
|
||||||
|
return error(_("could not update %s"), "REBASE_HEAD");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int do_commit(struct repository *r,
|
static int do_commit(struct repository *r,
|
||||||
const char *msg_file, const char *author,
|
const char *msg_file, const char *author,
|
||||||
struct replay_opts *opts, unsigned int flags)
|
struct replay_opts *opts, unsigned int flags,
|
||||||
|
struct object_id *oid)
|
||||||
{
|
{
|
||||||
int res = 1;
|
int res = 1;
|
||||||
|
|
||||||
@ -1460,8 +1470,12 @@ static int do_commit(struct repository *r,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (res == 1)
|
if (res == 1) {
|
||||||
|
if (is_rebase_i(opts) && oid)
|
||||||
|
if (write_rebase_head(oid))
|
||||||
|
return -1;
|
||||||
return run_git_commit(r, msg_file, opts, flags);
|
return run_git_commit(r, msg_file, opts, flags);
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -1929,7 +1943,9 @@ static int do_pick_commit(struct repository *r,
|
|||||||
* However, if the merge did not even start, then we don't want to
|
* However, if the merge did not even start, then we don't want to
|
||||||
* write it at all.
|
* write it at all.
|
||||||
*/
|
*/
|
||||||
if (command == TODO_PICK && !opts->no_commit && (res == 0 || res == 1) &&
|
if ((command == TODO_PICK || command == TODO_REWORD ||
|
||||||
|
command == TODO_EDIT) && !opts->no_commit &&
|
||||||
|
(res == 0 || res == 1) &&
|
||||||
update_ref(NULL, "CHERRY_PICK_HEAD", &commit->object.oid, NULL,
|
update_ref(NULL, "CHERRY_PICK_HEAD", &commit->object.oid, NULL,
|
||||||
REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
|
REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
|
||||||
res = -1;
|
res = -1;
|
||||||
@ -1965,7 +1981,8 @@ static int do_pick_commit(struct repository *r,
|
|||||||
} /* else allow == 0 and there's nothing special to do */
|
} /* else allow == 0 and there's nothing special to do */
|
||||||
if (!opts->no_commit && !drop_commit) {
|
if (!opts->no_commit && !drop_commit) {
|
||||||
if (author || command == TODO_REVERT || (flags & AMEND_MSG))
|
if (author || command == TODO_REVERT || (flags & AMEND_MSG))
|
||||||
res = do_commit(r, msg_file, author, opts, flags);
|
res = do_commit(r, msg_file, author, opts, flags,
|
||||||
|
commit? &commit->object.oid : NULL);
|
||||||
else
|
else
|
||||||
res = error(_("unable to parse commit author"));
|
res = error(_("unable to parse commit author"));
|
||||||
*check_todo = !!(flags & EDIT_MSG);
|
*check_todo = !!(flags & EDIT_MSG);
|
||||||
@ -3000,9 +3017,7 @@ static int make_patch(struct repository *r,
|
|||||||
p = short_commit_name(commit);
|
p = short_commit_name(commit);
|
||||||
if (write_message(p, strlen(p), rebase_path_stopped_sha(), 1) < 0)
|
if (write_message(p, strlen(p), rebase_path_stopped_sha(), 1) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (update_ref("rebase", "REBASE_HEAD", &commit->object.oid,
|
res |= write_rebase_head(&commit->object.oid);
|
||||||
NULL, REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
|
|
||||||
res |= error(_("could not update %s"), "REBASE_HEAD");
|
|
||||||
|
|
||||||
strbuf_addf(&buf, "%s/patch", get_dir(opts));
|
strbuf_addf(&buf, "%s/patch", get_dir(opts));
|
||||||
memset(&log_tree_opt, 0, sizeof(log_tree_opt));
|
memset(&log_tree_opt, 0, sizeof(log_tree_opt));
|
||||||
@ -5315,3 +5330,24 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sequencer_determine_whence(struct repository *r, enum commit_whence *whence)
|
||||||
|
{
|
||||||
|
if (file_exists(git_path_cherry_pick_head(r))) {
|
||||||
|
struct object_id cherry_pick_head, rebase_head;
|
||||||
|
|
||||||
|
if (file_exists(git_path_seq_dir()))
|
||||||
|
*whence = FROM_CHERRY_PICK_MULTI;
|
||||||
|
if (file_exists(rebase_path()) &&
|
||||||
|
!get_oid("REBASE_HEAD", &rebase_head) &&
|
||||||
|
!get_oid("CHERRY_PICK_HEAD", &cherry_pick_head) &&
|
||||||
|
oideq(&rebase_head, &cherry_pick_head))
|
||||||
|
*whence = FROM_REBASE_PICK;
|
||||||
|
else
|
||||||
|
*whence = FROM_CHERRY_PICK_SINGLE;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
|
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "strbuf.h"
|
#include "strbuf.h"
|
||||||
|
#include "wt-status.h"
|
||||||
|
|
||||||
struct commit;
|
struct commit;
|
||||||
struct repository;
|
struct repository;
|
||||||
|
|
||||||
const char *git_path_commit_editmsg(void);
|
const char *git_path_commit_editmsg(void);
|
||||||
const char *git_path_seq_dir(void);
|
|
||||||
const char *rebase_path_todo(void);
|
const char *rebase_path_todo(void);
|
||||||
const char *rebase_path_todo_backup(void);
|
const char *rebase_path_todo_backup(void);
|
||||||
const char *rebase_path_dropped(void);
|
const char *rebase_path_dropped(void);
|
||||||
@ -206,4 +206,5 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,
|
|||||||
void sequencer_post_commit_cleanup(struct repository *r, int verbose);
|
void sequencer_post_commit_cleanup(struct repository *r, int verbose);
|
||||||
int sequencer_get_last_command(struct repository* r,
|
int sequencer_get_last_command(struct repository* r,
|
||||||
enum replay_action *action);
|
enum replay_action *action);
|
||||||
|
int sequencer_determine_whence(struct repository *r, enum commit_whence *whence);
|
||||||
#endif /* SEQUENCER_H */
|
#endif /* SEQUENCER_H */
|
||||||
|
@ -29,6 +29,13 @@ test_expect_success setup '
|
|||||||
test_tick &&
|
test_tick &&
|
||||||
git commit -m reverted-goodbye &&
|
git commit -m reverted-goodbye &&
|
||||||
git tag reverted-goodbye &&
|
git tag reverted-goodbye &&
|
||||||
|
git checkout goodbye &&
|
||||||
|
test_tick &&
|
||||||
|
GIT_AUTHOR_NAME="Another Author" \
|
||||||
|
GIT_AUTHOR_EMAIL="another.author@example.com" \
|
||||||
|
git commit --amend --no-edit -m amended-goodbye &&
|
||||||
|
test_tick &&
|
||||||
|
git tag amended-goodbye &&
|
||||||
|
|
||||||
git checkout -f skip-reference &&
|
git checkout -f skip-reference &&
|
||||||
echo moo > hello &&
|
echo moo > hello &&
|
||||||
@ -85,6 +92,78 @@ test_expect_success 'moved back to branch correctly' '
|
|||||||
|
|
||||||
test_debug 'gitk --all & sleep 1'
|
test_debug 'gitk --all & sleep 1'
|
||||||
|
|
||||||
|
test_expect_success 'correct advice upon picking empty commit' '
|
||||||
|
test_when_finished "git rebase --abort" &&
|
||||||
|
test_must_fail git rebase -i --onto goodbye \
|
||||||
|
amended-goodbye^ amended-goodbye 2>err &&
|
||||||
|
test_i18ngrep "previous cherry-pick is now empty" err &&
|
||||||
|
test_i18ngrep "git rebase --skip" err &&
|
||||||
|
test_must_fail git commit &&
|
||||||
|
test_i18ngrep "git rebase --skip" err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'correct authorship when committing empty pick' '
|
||||||
|
test_when_finished "git rebase --abort" &&
|
||||||
|
test_must_fail git rebase -i --onto goodbye \
|
||||||
|
amended-goodbye^ amended-goodbye &&
|
||||||
|
git commit --allow-empty &&
|
||||||
|
git log --pretty=format:"%an <%ae>%n%ad%B" -1 amended-goodbye >expect &&
|
||||||
|
git log --pretty=format:"%an <%ae>%n%ad%B" -1 HEAD >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'correct advice upon rewording empty commit' '
|
||||||
|
test_when_finished "git rebase --abort" &&
|
||||||
|
(
|
||||||
|
set_fake_editor &&
|
||||||
|
test_must_fail env FAKE_LINES="reword 1" git rebase -i \
|
||||||
|
--onto goodbye amended-goodbye^ amended-goodbye 2>err
|
||||||
|
) &&
|
||||||
|
test_i18ngrep "previous cherry-pick is now empty" err &&
|
||||||
|
test_i18ngrep "git rebase --skip" err &&
|
||||||
|
test_must_fail git commit &&
|
||||||
|
test_i18ngrep "git rebase --skip" err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'correct advice upon editing empty commit' '
|
||||||
|
test_when_finished "git rebase --abort" &&
|
||||||
|
(
|
||||||
|
set_fake_editor &&
|
||||||
|
test_must_fail env FAKE_LINES="edit 1" git rebase -i \
|
||||||
|
--onto goodbye amended-goodbye^ amended-goodbye 2>err
|
||||||
|
) &&
|
||||||
|
test_i18ngrep "previous cherry-pick is now empty" err &&
|
||||||
|
test_i18ngrep "git rebase --skip" err &&
|
||||||
|
test_must_fail git commit &&
|
||||||
|
test_i18ngrep "git rebase --skip" err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'correct advice upon cherry-picking an empty commit during a rebase' '
|
||||||
|
test_when_finished "git rebase --abort" &&
|
||||||
|
(
|
||||||
|
set_fake_editor &&
|
||||||
|
test_must_fail env FAKE_LINES="1 exec_git_cherry-pick_amended-goodbye" \
|
||||||
|
git rebase -i goodbye^ goodbye 2>err
|
||||||
|
) &&
|
||||||
|
test_i18ngrep "previous cherry-pick is now empty" err &&
|
||||||
|
test_i18ngrep "git cherry-pick --skip" err &&
|
||||||
|
test_must_fail git commit 2>err &&
|
||||||
|
test_i18ngrep "git cherry-pick --skip" err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'correct advice upon multi cherry-pick picking an empty commit during a rebase' '
|
||||||
|
test_when_finished "git rebase --abort" &&
|
||||||
|
(
|
||||||
|
set_fake_editor &&
|
||||||
|
test_must_fail env FAKE_LINES="1 exec_git_cherry-pick_goodbye_amended-goodbye" \
|
||||||
|
git rebase -i goodbye^^ goodbye 2>err
|
||||||
|
) &&
|
||||||
|
test_i18ngrep "previous cherry-pick is now empty" err &&
|
||||||
|
test_i18ngrep "git cherry-pick --skip" err &&
|
||||||
|
test_must_fail git commit 2>err &&
|
||||||
|
test_i18ngrep "git cherry-pick --skip" err
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'fixup that empties commit fails' '
|
test_expect_success 'fixup that empties commit fails' '
|
||||||
test_when_finished "git rebase --abort" &&
|
test_when_finished "git rebase --abort" &&
|
||||||
(
|
(
|
||||||
|
@ -187,7 +187,7 @@ test_expect_success 'no changes are a nop' '
|
|||||||
git checkout branch2 &&
|
git checkout branch2 &&
|
||||||
git rebase -i F &&
|
git rebase -i F &&
|
||||||
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" &&
|
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" &&
|
||||||
test $(git rev-parse I) = $(git rev-parse HEAD)
|
test_cmp_rev I HEAD
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'test the [branch] option' '
|
test_expect_success 'test the [branch] option' '
|
||||||
@ -196,16 +196,16 @@ test_expect_success 'test the [branch] option' '
|
|||||||
git commit -m "stop here" &&
|
git commit -m "stop here" &&
|
||||||
git rebase -i F branch2 &&
|
git rebase -i F branch2 &&
|
||||||
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" &&
|
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" &&
|
||||||
test $(git rev-parse I) = $(git rev-parse branch2) &&
|
test_cmp_rev I branch2 &&
|
||||||
test $(git rev-parse I) = $(git rev-parse HEAD)
|
test_cmp_rev I HEAD
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'test --onto <branch>' '
|
test_expect_success 'test --onto <branch>' '
|
||||||
git checkout -b test-onto branch2 &&
|
git checkout -b test-onto branch2 &&
|
||||||
git rebase -i --onto branch1 F &&
|
git rebase -i --onto branch1 F &&
|
||||||
test "$(git symbolic-ref -q HEAD)" = "refs/heads/test-onto" &&
|
test "$(git symbolic-ref -q HEAD)" = "refs/heads/test-onto" &&
|
||||||
test $(git rev-parse HEAD^) = $(git rev-parse branch1) &&
|
test_cmp_rev HEAD^ branch1 &&
|
||||||
test $(git rev-parse I) = $(git rev-parse branch2)
|
test_cmp_rev I branch2
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'rebase on top of a non-conflicting commit' '
|
test_expect_success 'rebase on top of a non-conflicting commit' '
|
||||||
@ -214,12 +214,12 @@ test_expect_success 'rebase on top of a non-conflicting commit' '
|
|||||||
git rebase -i branch2 &&
|
git rebase -i branch2 &&
|
||||||
test file6 = $(git diff --name-only original-branch1) &&
|
test file6 = $(git diff --name-only original-branch1) &&
|
||||||
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch1" &&
|
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch1" &&
|
||||||
test $(git rev-parse I) = $(git rev-parse branch2) &&
|
test_cmp_rev I branch2 &&
|
||||||
test $(git rev-parse I) = $(git rev-parse HEAD~2)
|
test_cmp_rev I HEAD~2
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'reflog for the branch shows state before rebase' '
|
test_expect_success 'reflog for the branch shows state before rebase' '
|
||||||
test $(git rev-parse branch1@{1}) = $(git rev-parse original-branch1)
|
test_cmp_rev branch1@{1} original-branch1
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'reflog for the branch shows correct finish message' '
|
test_expect_success 'reflog for the branch shows correct finish message' '
|
||||||
@ -279,7 +279,7 @@ test_expect_success 'show conflicted patch' '
|
|||||||
|
|
||||||
test_expect_success 'abort' '
|
test_expect_success 'abort' '
|
||||||
git rebase --abort &&
|
git rebase --abort &&
|
||||||
test $(git rev-parse new-branch1) = $(git rev-parse HEAD) &&
|
test_cmp_rev new-branch1 HEAD &&
|
||||||
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch1" &&
|
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch1" &&
|
||||||
test_path_is_missing .git/rebase-merge
|
test_path_is_missing .git/rebase-merge
|
||||||
'
|
'
|
||||||
@ -322,7 +322,7 @@ test_expect_success 'retain authorship w/ conflicts' '
|
|||||||
echo resolved >conflict &&
|
echo resolved >conflict &&
|
||||||
git add conflict &&
|
git add conflict &&
|
||||||
git rebase --continue &&
|
git rebase --continue &&
|
||||||
test $(git rev-parse conflict-a^0) = $(git rev-parse HEAD^) &&
|
test_cmp_rev conflict-a^0 HEAD^ &&
|
||||||
git show >out &&
|
git show >out &&
|
||||||
grep AttributeMe out
|
grep AttributeMe out
|
||||||
'
|
'
|
||||||
@ -339,7 +339,7 @@ test_expect_success 'squash' '
|
|||||||
git rebase -i --onto master HEAD~2
|
git rebase -i --onto master HEAD~2
|
||||||
) &&
|
) &&
|
||||||
test B = $(cat file7) &&
|
test B = $(cat file7) &&
|
||||||
test $(git rev-parse HEAD^) = $(git rev-parse master)
|
test_cmp_rev HEAD^ master
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'retain authorship when squashing' '
|
test_expect_success 'retain authorship when squashing' '
|
||||||
@ -398,9 +398,9 @@ test_expect_success REBASE_P 'preserve merges with -p' '
|
|||||||
git update-index --refresh &&
|
git update-index --refresh &&
|
||||||
git diff-files --quiet &&
|
git diff-files --quiet &&
|
||||||
git diff-index --quiet --cached HEAD -- &&
|
git diff-index --quiet --cached HEAD -- &&
|
||||||
test $(git rev-parse HEAD~6) = $(git rev-parse branch1) &&
|
test_cmp_rev HEAD~6 branch1 &&
|
||||||
test $(git rev-parse HEAD~4^2) = $(git rev-parse to-be-preserved) &&
|
test_cmp_rev HEAD~4^2 to-be-preserved &&
|
||||||
test $(git rev-parse HEAD^^2^) = $(git rev-parse HEAD^^^) &&
|
test_cmp_rev HEAD^^2^ HEAD^^^ &&
|
||||||
test $(git show HEAD~5:file1) = B &&
|
test $(git show HEAD~5:file1) = B &&
|
||||||
test $(git show HEAD~3:file1) = C &&
|
test $(git show HEAD~3:file1) = C &&
|
||||||
test $(git show HEAD:file1) = E &&
|
test $(git show HEAD:file1) = E &&
|
||||||
@ -432,7 +432,7 @@ test_expect_success '--continue tries to commit' '
|
|||||||
git add file1 &&
|
git add file1 &&
|
||||||
FAKE_COMMIT_MESSAGE="chouette!" git rebase --continue
|
FAKE_COMMIT_MESSAGE="chouette!" git rebase --continue
|
||||||
) &&
|
) &&
|
||||||
test $(git rev-parse HEAD^) = $(git rev-parse new-branch1) &&
|
test_cmp_rev HEAD^ new-branch1 &&
|
||||||
git show HEAD | grep chouette
|
git show HEAD | grep chouette
|
||||||
'
|
'
|
||||||
|
|
||||||
@ -739,7 +739,7 @@ test_expect_success 'do "noop" when there is nothing to cherry-pick' '
|
|||||||
--author="Somebody else <somebody@else.com>" &&
|
--author="Somebody else <somebody@else.com>" &&
|
||||||
test $(git rev-parse branch3) != $(git rev-parse branch4) &&
|
test $(git rev-parse branch3) != $(git rev-parse branch4) &&
|
||||||
git rebase -i branch3 &&
|
git rebase -i branch3 &&
|
||||||
test $(git rev-parse branch3) = $(git rev-parse branch4)
|
test_cmp_rev branch3 branch4
|
||||||
|
|
||||||
'
|
'
|
||||||
|
|
||||||
@ -798,7 +798,7 @@ test_expect_success 'rebase -i continue with unstaged submodule' '
|
|||||||
test_must_fail git rebase -i submodule-base &&
|
test_must_fail git rebase -i submodule-base &&
|
||||||
git reset &&
|
git reset &&
|
||||||
git rebase --continue &&
|
git rebase --continue &&
|
||||||
test $(git rev-parse submodule-base) = $(git rev-parse HEAD)
|
test_cmp_rev submodule-base HEAD
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'avoid unnecessary reset' '
|
test_expect_success 'avoid unnecessary reset' '
|
||||||
@ -821,7 +821,7 @@ test_expect_success 'reword' '
|
|||||||
git rebase -i A &&
|
git rebase -i A &&
|
||||||
git show HEAD | grep "E changed" &&
|
git show HEAD | grep "E changed" &&
|
||||||
test $(git rev-parse master) != $(git rev-parse HEAD) &&
|
test $(git rev-parse master) != $(git rev-parse HEAD) &&
|
||||||
test $(git rev-parse master^) = $(git rev-parse HEAD^) &&
|
test_cmp_rev master^ HEAD^ &&
|
||||||
FAKE_LINES="1 2 reword 3 4" FAKE_COMMIT_MESSAGE="D changed" \
|
FAKE_LINES="1 2 reword 3 4" FAKE_COMMIT_MESSAGE="D changed" \
|
||||||
git rebase -i A &&
|
git rebase -i A &&
|
||||||
git show HEAD^ | grep "D changed" &&
|
git show HEAD^ | grep "D changed" &&
|
||||||
@ -885,7 +885,7 @@ test_expect_success 'always cherry-pick with --no-ff' '
|
|||||||
git diff HEAD~$p original-no-ff-branch~$p > out &&
|
git diff HEAD~$p original-no-ff-branch~$p > out &&
|
||||||
test_must_be_empty out
|
test_must_be_empty out
|
||||||
done &&
|
done &&
|
||||||
test $(git rev-parse HEAD~3) = $(git rev-parse original-no-ff-branch~3) &&
|
test_cmp_rev HEAD~3 original-no-ff-branch~3 &&
|
||||||
git diff HEAD~3 original-no-ff-branch~3 > out &&
|
git diff HEAD~3 original-no-ff-branch~3 > out &&
|
||||||
test_must_be_empty out
|
test_must_be_empty out
|
||||||
'
|
'
|
||||||
@ -1734,6 +1734,32 @@ test_expect_success 'post-commit hook is called' '
|
|||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'correct error message for partial commit after empty pick' '
|
||||||
|
test_when_finished "git rebase --abort" &&
|
||||||
|
(
|
||||||
|
set_fake_editor &&
|
||||||
|
FAKE_LINES="2 1 1" &&
|
||||||
|
export FAKE_LINES &&
|
||||||
|
test_must_fail git rebase -i A D
|
||||||
|
) &&
|
||||||
|
echo x >file1 &&
|
||||||
|
test_must_fail git commit file1 2>err &&
|
||||||
|
test_i18ngrep "cannot do a partial commit during a rebase." err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'correct error message for commit --amend after empty pick' '
|
||||||
|
test_when_finished "git rebase --abort" &&
|
||||||
|
(
|
||||||
|
set_fake_editor &&
|
||||||
|
FAKE_LINES="1 1" &&
|
||||||
|
export FAKE_LINES &&
|
||||||
|
test_must_fail git rebase -i A D
|
||||||
|
) &&
|
||||||
|
echo x>file1 &&
|
||||||
|
test_must_fail git commit -a --amend 2>err &&
|
||||||
|
test_i18ngrep "middle of a rebase -- cannot amend." err
|
||||||
|
'
|
||||||
|
|
||||||
# This must be the last test in this file
|
# This must be the last test in this file
|
||||||
test_expect_success '$EDITOR and friends are unchanged' '
|
test_expect_success '$EDITOR and friends are unchanged' '
|
||||||
test_editor_unchanged
|
test_editor_unchanged
|
||||||
|
@ -161,6 +161,29 @@ test_expect_success 'successful commit clears CHERRY_PICK_HEAD' '
|
|||||||
|
|
||||||
test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
|
test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'partial commit of cherry-pick fails' '
|
||||||
|
pristine_detach initial &&
|
||||||
|
|
||||||
|
test_must_fail git cherry-pick picked &&
|
||||||
|
echo resolved >foo &&
|
||||||
|
git add foo &&
|
||||||
|
test_must_fail git commit foo 2>err &&
|
||||||
|
|
||||||
|
test_i18ngrep "cannot do a partial commit during a cherry-pick." err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'commit --amend of cherry-pick fails' '
|
||||||
|
pristine_detach initial &&
|
||||||
|
|
||||||
|
test_must_fail git cherry-pick picked &&
|
||||||
|
echo resolved >foo &&
|
||||||
|
git add foo &&
|
||||||
|
test_must_fail git commit --amend 2>err &&
|
||||||
|
|
||||||
|
test_i18ngrep "in the middle of a cherry-pick -- cannot amend." err
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'successful final commit clears cherry-pick state' '
|
test_expect_success 'successful final commit clears cherry-pick state' '
|
||||||
pristine_detach initial &&
|
pristine_detach initial &&
|
||||||
|
|
||||||
|
@ -123,7 +123,8 @@ test_expect_success 'revert --skip to skip commit' '
|
|||||||
test_expect_success 'skip "empty" commit' '
|
test_expect_success 'skip "empty" commit' '
|
||||||
pristine_detach picked &&
|
pristine_detach picked &&
|
||||||
test_commit dummy foo d &&
|
test_commit dummy foo d &&
|
||||||
test_must_fail git cherry-pick anotherpick &&
|
test_must_fail git cherry-pick anotherpick 2>err &&
|
||||||
|
test_i18ngrep "git cherry-pick --skip" err &&
|
||||||
git cherry-pick --skip &&
|
git cherry-pick --skip &&
|
||||||
test_cmp_rev dummy HEAD
|
test_cmp_rev dummy HEAD
|
||||||
'
|
'
|
||||||
|
15
wt-status.h
15
wt-status.h
@ -38,9 +38,22 @@ enum show_ignored_type {
|
|||||||
enum commit_whence {
|
enum commit_whence {
|
||||||
FROM_COMMIT, /* normal */
|
FROM_COMMIT, /* normal */
|
||||||
FROM_MERGE, /* commit came from merge */
|
FROM_MERGE, /* commit came from merge */
|
||||||
FROM_CHERRY_PICK /* commit came from cherry-pick */
|
FROM_CHERRY_PICK_SINGLE, /* commit came from cherry-pick */
|
||||||
|
FROM_CHERRY_PICK_MULTI, /* commit came from a sequence of cherry-picks */
|
||||||
|
FROM_REBASE_PICK /* commit came from a pick/reword/edit */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline int is_from_cherry_pick(enum commit_whence whence)
|
||||||
|
{
|
||||||
|
return whence == FROM_CHERRY_PICK_SINGLE ||
|
||||||
|
whence == FROM_CHERRY_PICK_MULTI;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int is_from_rebase(enum commit_whence whence)
|
||||||
|
{
|
||||||
|
return whence == FROM_REBASE_PICK;
|
||||||
|
}
|
||||||
|
|
||||||
struct wt_status_change_data {
|
struct wt_status_change_data {
|
||||||
int worktree_status;
|
int worktree_status;
|
||||||
int index_status;
|
int index_status;
|
||||||
|
Loading…
Reference in New Issue
Block a user