mirror of
https://github.com/git/git.git
synced 2024-11-24 18:33:43 +08:00
Merge branch 'jn/maint-sequencer-fixes'
* jn/maint-sequencer-fixes: revert: stop creating and removing sequencer-old directory Revert "reset: Make reset remove the sequencer state" revert: do not remove state until sequence is finished revert: allow single-pick in the middle of cherry-pick sequence revert: pass around rev-list args in already-parsed form revert: allow cherry-pick --continue to commit before resuming revert: give --continue handling its own function
This commit is contained in:
commit
b8fc5abd73
2
branch.c
2
branch.c
@ -3,7 +3,6 @@
|
||||
#include "refs.h"
|
||||
#include "remote.h"
|
||||
#include "commit.h"
|
||||
#include "sequencer.h"
|
||||
|
||||
struct tracking {
|
||||
struct refspec spec;
|
||||
@ -280,5 +279,4 @@ void remove_branch_state(void)
|
||||
unlink(git_path("MERGE_MSG"));
|
||||
unlink(git_path("MERGE_MODE"));
|
||||
unlink(git_path("SQUASH_MSG"));
|
||||
remove_sequencer_state(0);
|
||||
}
|
||||
|
138
builtin/revert.c
138
builtin/revert.c
@ -60,13 +60,14 @@ struct replay_opts {
|
||||
int allow_rerere_auto;
|
||||
|
||||
int mainline;
|
||||
int commit_argc;
|
||||
const char **commit_argv;
|
||||
|
||||
/* Merge strategy */
|
||||
const char *strategy;
|
||||
const char **xopts;
|
||||
size_t xopts_nr, xopts_alloc;
|
||||
|
||||
/* Only used by REPLAY_NONE */
|
||||
struct rev_info *revs;
|
||||
};
|
||||
|
||||
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
|
||||
@ -169,9 +170,9 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
|
||||
die(_("program error"));
|
||||
}
|
||||
|
||||
opts->commit_argc = parse_options(argc, argv, NULL, options, usage_str,
|
||||
PARSE_OPT_KEEP_ARGV0 |
|
||||
PARSE_OPT_KEEP_UNKNOWN);
|
||||
argc = parse_options(argc, argv, NULL, options, usage_str,
|
||||
PARSE_OPT_KEEP_ARGV0 |
|
||||
PARSE_OPT_KEEP_UNKNOWN);
|
||||
|
||||
/* Check for incompatible subcommands */
|
||||
verify_opt_mutually_compatible(me,
|
||||
@ -213,9 +214,6 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
|
||||
NULL);
|
||||
}
|
||||
|
||||
else if (opts->commit_argc < 2)
|
||||
usage_with_options(usage_str, options);
|
||||
|
||||
if (opts->allow_ff)
|
||||
verify_opt_compatible(me, "--ff",
|
||||
"--signoff", opts->signoff,
|
||||
@ -223,7 +221,20 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
|
||||
"-x", opts->record_origin,
|
||||
"--edit", opts->edit,
|
||||
NULL);
|
||||
opts->commit_argv = argv;
|
||||
|
||||
if (opts->subcommand != REPLAY_NONE) {
|
||||
opts->revs = NULL;
|
||||
} else {
|
||||
opts->revs = xmalloc(sizeof(*opts->revs));
|
||||
init_revisions(opts->revs, NULL);
|
||||
opts->revs->no_walk = 1;
|
||||
if (argc < 2)
|
||||
usage_with_options(usage_str, options);
|
||||
argc = setup_revisions(argc, argv, opts->revs, NULL);
|
||||
}
|
||||
|
||||
if (argc > 1)
|
||||
usage_with_options(usage_str, options);
|
||||
}
|
||||
|
||||
struct commit_message {
|
||||
@ -631,23 +642,15 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
|
||||
return res;
|
||||
}
|
||||
|
||||
static void prepare_revs(struct rev_info *revs, struct replay_opts *opts)
|
||||
static void prepare_revs(struct replay_opts *opts)
|
||||
{
|
||||
int argc;
|
||||
|
||||
init_revisions(revs, NULL);
|
||||
revs->no_walk = 1;
|
||||
if (opts->action != REVERT)
|
||||
revs->reverse = 1;
|
||||
opts->revs->reverse ^= 1;
|
||||
|
||||
argc = setup_revisions(opts->commit_argc, opts->commit_argv, revs, NULL);
|
||||
if (argc > 1)
|
||||
usage(*revert_or_cherry_pick_usage(opts));
|
||||
|
||||
if (prepare_revision_walk(revs))
|
||||
if (prepare_revision_walk(opts->revs))
|
||||
die(_("revision walk setup failed"));
|
||||
|
||||
if (!revs->commits)
|
||||
if (!opts->revs->commits)
|
||||
die(_("empty commit set passed"));
|
||||
}
|
||||
|
||||
@ -844,14 +847,13 @@ static void read_populate_opts(struct replay_opts **opts_ptr)
|
||||
static void walk_revs_populate_todo(struct commit_list **todo_list,
|
||||
struct replay_opts *opts)
|
||||
{
|
||||
struct rev_info revs;
|
||||
struct commit *commit;
|
||||
struct commit_list **next;
|
||||
|
||||
prepare_revs(&revs, opts);
|
||||
prepare_revs(opts);
|
||||
|
||||
next = todo_list;
|
||||
while ((commit = get_revision(&revs)))
|
||||
while ((commit = get_revision(opts->revs)))
|
||||
next = commit_list_append(commit, next);
|
||||
}
|
||||
|
||||
@ -942,7 +944,7 @@ static int sequencer_rollback(struct replay_opts *opts)
|
||||
}
|
||||
if (reset_for_rollback(sha1))
|
||||
goto fail;
|
||||
remove_sequencer_state(1);
|
||||
remove_sequencer_state();
|
||||
strbuf_release(&buf);
|
||||
return 0;
|
||||
fail:
|
||||
@ -1016,33 +1018,64 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)
|
||||
for (cur = todo_list; cur; cur = cur->next) {
|
||||
save_todo(cur, opts);
|
||||
res = do_pick_commit(cur->item, opts);
|
||||
if (res) {
|
||||
if (!cur->next)
|
||||
/*
|
||||
* An error was encountered while
|
||||
* picking the last commit; the
|
||||
* sequencer state is useless now --
|
||||
* the user simply needs to resolve
|
||||
* the conflict and commit
|
||||
*/
|
||||
remove_sequencer_state(0);
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sequence of picks finished successfully; cleanup by
|
||||
* removing the .git/sequencer directory
|
||||
*/
|
||||
remove_sequencer_state(1);
|
||||
remove_sequencer_state();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int continue_single_pick(void)
|
||||
{
|
||||
const char *argv[] = { "commit", NULL };
|
||||
|
||||
if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
|
||||
!file_exists(git_path("REVERT_HEAD")))
|
||||
return error(_("no cherry-pick or revert in progress"));
|
||||
return run_command_v_opt(argv, RUN_GIT_CMD);
|
||||
}
|
||||
|
||||
static int sequencer_continue(struct replay_opts *opts)
|
||||
{
|
||||
struct commit_list *todo_list = NULL;
|
||||
|
||||
if (!file_exists(git_path(SEQ_TODO_FILE)))
|
||||
return continue_single_pick();
|
||||
read_populate_opts(&opts);
|
||||
read_populate_todo(&todo_list, opts);
|
||||
|
||||
/* Verify that the conflict has been resolved */
|
||||
if (file_exists(git_path("CHERRY_PICK_HEAD")) ||
|
||||
file_exists(git_path("REVERT_HEAD"))) {
|
||||
int ret = continue_single_pick();
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
if (index_differs_from("HEAD", 0))
|
||||
return error_dirty_index(opts);
|
||||
todo_list = todo_list->next;
|
||||
return pick_commits(todo_list, opts);
|
||||
}
|
||||
|
||||
static int single_pick(struct commit *cmit, struct replay_opts *opts)
|
||||
{
|
||||
setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
|
||||
return do_pick_commit(cmit, opts);
|
||||
}
|
||||
|
||||
static int pick_revisions(struct replay_opts *opts)
|
||||
{
|
||||
struct commit_list *todo_list = NULL;
|
||||
unsigned char sha1[20];
|
||||
|
||||
if (opts->subcommand == REPLAY_NONE)
|
||||
assert(opts->revs);
|
||||
|
||||
read_and_refresh_cache(opts);
|
||||
|
||||
/*
|
||||
@ -1051,21 +1084,32 @@ static int pick_revisions(struct replay_opts *opts)
|
||||
* one that is being continued
|
||||
*/
|
||||
if (opts->subcommand == REPLAY_REMOVE_STATE) {
|
||||
remove_sequencer_state(1);
|
||||
remove_sequencer_state();
|
||||
return 0;
|
||||
}
|
||||
if (opts->subcommand == REPLAY_ROLLBACK)
|
||||
return sequencer_rollback(opts);
|
||||
if (opts->subcommand == REPLAY_CONTINUE) {
|
||||
if (!file_exists(git_path(SEQ_TODO_FILE)))
|
||||
return error(_("No %s in progress"), action_name(opts));
|
||||
read_populate_opts(&opts);
|
||||
read_populate_todo(&todo_list, opts);
|
||||
if (opts->subcommand == REPLAY_CONTINUE)
|
||||
return sequencer_continue(opts);
|
||||
|
||||
/* Verify that the conflict has been resolved */
|
||||
if (!index_differs_from("HEAD", 0))
|
||||
todo_list = todo_list->next;
|
||||
return pick_commits(todo_list, opts);
|
||||
/*
|
||||
* If we were called as "git cherry-pick <commit>", just
|
||||
* cherry-pick/revert it, set CHERRY_PICK_HEAD /
|
||||
* REVERT_HEAD, and don't touch the sequencer state.
|
||||
* This means it is possible to cherry-pick in the middle
|
||||
* of a cherry-pick sequence.
|
||||
*/
|
||||
if (opts->revs->cmdline.nr == 1 &&
|
||||
opts->revs->cmdline.rev->whence == REV_CMD_REV &&
|
||||
opts->revs->no_walk &&
|
||||
!opts->revs->cmdline.rev->flags) {
|
||||
struct commit *cmit;
|
||||
if (prepare_revision_walk(opts->revs))
|
||||
die(_("revision walk setup failed"));
|
||||
cmit = get_revision(opts->revs);
|
||||
if (!cmit || get_revision(opts->revs))
|
||||
die("BUG: expected exactly one commit from walk");
|
||||
return single_pick(cmit, opts);
|
||||
}
|
||||
|
||||
/*
|
||||
|
10
sequencer.c
10
sequencer.c
@ -3,17 +3,11 @@
|
||||
#include "strbuf.h"
|
||||
#include "dir.h"
|
||||
|
||||
void remove_sequencer_state(int aggressive)
|
||||
void remove_sequencer_state(void)
|
||||
{
|
||||
struct strbuf seq_dir = STRBUF_INIT;
|
||||
struct strbuf seq_old_dir = STRBUF_INIT;
|
||||
|
||||
strbuf_addf(&seq_dir, "%s", git_path(SEQ_DIR));
|
||||
strbuf_addf(&seq_old_dir, "%s", git_path(SEQ_OLD_DIR));
|
||||
remove_dir_recursively(&seq_old_dir, 0);
|
||||
rename(git_path(SEQ_DIR), git_path(SEQ_OLD_DIR));
|
||||
if (aggressive)
|
||||
remove_dir_recursively(&seq_old_dir, 0);
|
||||
remove_dir_recursively(&seq_dir, 0);
|
||||
strbuf_release(&seq_dir);
|
||||
strbuf_release(&seq_old_dir);
|
||||
}
|
||||
|
12
sequencer.h
12
sequencer.h
@ -2,19 +2,11 @@
|
||||
#define SEQUENCER_H
|
||||
|
||||
#define SEQ_DIR "sequencer"
|
||||
#define SEQ_OLD_DIR "sequencer-old"
|
||||
#define SEQ_HEAD_FILE "sequencer/head"
|
||||
#define SEQ_TODO_FILE "sequencer/todo"
|
||||
#define SEQ_OPTS_FILE "sequencer/opts"
|
||||
|
||||
/*
|
||||
* Removes SEQ_OLD_DIR and renames SEQ_DIR to SEQ_OLD_DIR, ignoring
|
||||
* any errors. Intended to be used by 'git reset'.
|
||||
*
|
||||
* With the aggressive flag, it additionally removes SEQ_OLD_DIR,
|
||||
* ignoring any errors. Inteded to be used by the sequencer's
|
||||
* '--quit' subcommand.
|
||||
*/
|
||||
void remove_sequencer_state(int aggressive);
|
||||
/* Removes SEQ_DIR. */
|
||||
extern void remove_sequencer_state(void);
|
||||
|
||||
#endif
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
test_description='Test cherry-pick continuation features
|
||||
|
||||
+ conflicting: rewrites unrelated to conflicting
|
||||
+ yetanotherpick: rewrites foo to e
|
||||
+ anotherpick: rewrites foo to d
|
||||
+ picked: rewrites foo to c
|
||||
@ -27,6 +28,7 @@ test_cmp_rev () {
|
||||
}
|
||||
|
||||
test_expect_success setup '
|
||||
git config advice.detachedhead false
|
||||
echo unrelated >unrelated &&
|
||||
git add unrelated &&
|
||||
test_commit initial foo a &&
|
||||
@ -35,8 +37,8 @@ test_expect_success setup '
|
||||
test_commit picked foo c &&
|
||||
test_commit anotherpick foo d &&
|
||||
test_commit yetanotherpick foo e &&
|
||||
git config advice.detachedhead false
|
||||
|
||||
pristine_detach initial &&
|
||||
test_commit conflicting unrelated
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick persists data on failure' '
|
||||
@ -48,6 +50,18 @@ test_expect_success 'cherry-pick persists data on failure' '
|
||||
test_path_is_file .git/sequencer/opts
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick mid-cherry-pick-sequence' '
|
||||
pristine_detach initial &&
|
||||
test_must_fail git cherry-pick base..anotherpick &&
|
||||
test_cmp_rev picked CHERRY_PICK_HEAD &&
|
||||
# "oops, I forgot that these patches rely on the change from base"
|
||||
git checkout HEAD foo &&
|
||||
git cherry-pick base &&
|
||||
git cherry-pick picked &&
|
||||
git cherry-pick --continue &&
|
||||
git diff --exit-code anotherpick
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick persists opts correctly' '
|
||||
pristine_detach initial &&
|
||||
test_must_fail git cherry-pick -s -m 1 --strategy=recursive -X patience -X ours base..anotherpick &&
|
||||
@ -189,10 +203,10 @@ test_expect_success '--abort refuses to clobber unrelated change, harder case' '
|
||||
test_cmp_rev initial HEAD
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick cleans up sequencer state when one commit is left' '
|
||||
test_expect_success 'cherry-pick still writes sequencer state when one commit is left' '
|
||||
pristine_detach initial &&
|
||||
test_must_fail git cherry-pick base..picked &&
|
||||
test_path_is_missing .git/sequencer &&
|
||||
test_path_is_dir .git/sequencer &&
|
||||
echo "resolved" >foo &&
|
||||
git add foo &&
|
||||
git commit &&
|
||||
@ -213,7 +227,7 @@ test_expect_success 'cherry-pick cleans up sequencer state when one commit is le
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_failure '--abort after last commit in sequence' '
|
||||
test_expect_success '--abort after last commit in sequence' '
|
||||
pristine_detach initial &&
|
||||
test_must_fail git cherry-pick base..picked &&
|
||||
git cherry-pick --abort &&
|
||||
@ -243,7 +257,66 @@ test_expect_success '--continue complains when there are unresolved conflicts' '
|
||||
test_must_fail git cherry-pick --continue
|
||||
'
|
||||
|
||||
test_expect_success '--continue continues after conflicts are resolved' '
|
||||
test_expect_success '--continue of single cherry-pick' '
|
||||
pristine_detach initial &&
|
||||
echo c >expect &&
|
||||
test_must_fail git cherry-pick picked &&
|
||||
echo c >foo &&
|
||||
git add foo &&
|
||||
git cherry-pick --continue &&
|
||||
|
||||
test_cmp expect foo &&
|
||||
test_cmp_rev initial HEAD^ &&
|
||||
git diff --exit-code HEAD &&
|
||||
test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
|
||||
'
|
||||
|
||||
test_expect_success '--continue of single revert' '
|
||||
pristine_detach initial &&
|
||||
echo resolved >expect &&
|
||||
echo "Revert \"picked\"" >expect.msg &&
|
||||
test_must_fail git revert picked &&
|
||||
echo resolved >foo &&
|
||||
git add foo &&
|
||||
git cherry-pick --continue &&
|
||||
|
||||
git diff --exit-code HEAD &&
|
||||
test_cmp expect foo &&
|
||||
test_cmp_rev initial HEAD^ &&
|
||||
git diff-tree -s --pretty=tformat:%s HEAD >msg &&
|
||||
test_cmp expect.msg msg &&
|
||||
test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
|
||||
test_must_fail git rev-parse --verify REVERT_HEAD
|
||||
'
|
||||
|
||||
test_expect_success '--continue after resolving conflicts' '
|
||||
pristine_detach initial &&
|
||||
echo d >expect &&
|
||||
cat >expect.log <<-\EOF &&
|
||||
OBJID
|
||||
:100644 100644 OBJID OBJID M foo
|
||||
OBJID
|
||||
:100644 100644 OBJID OBJID M foo
|
||||
OBJID
|
||||
:100644 100644 OBJID OBJID M unrelated
|
||||
OBJID
|
||||
:000000 100644 OBJID OBJID A foo
|
||||
:000000 100644 OBJID OBJID A unrelated
|
||||
EOF
|
||||
test_must_fail git cherry-pick base..anotherpick &&
|
||||
echo c >foo &&
|
||||
git add foo &&
|
||||
git cherry-pick --continue &&
|
||||
{
|
||||
git rev-list HEAD |
|
||||
git diff-tree --root --stdin |
|
||||
sed "s/$_x40/OBJID/g"
|
||||
} >actual.log &&
|
||||
test_cmp expect foo &&
|
||||
test_cmp expect.log actual.log
|
||||
'
|
||||
|
||||
test_expect_success '--continue after resolving conflicts and committing' '
|
||||
pristine_detach initial &&
|
||||
test_must_fail git cherry-pick base..anotherpick &&
|
||||
echo "c" >foo &&
|
||||
@ -270,6 +343,29 @@ test_expect_success '--continue continues after conflicts are resolved' '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success '--continue asks for help after resolving patch to nil' '
|
||||
pristine_detach conflicting &&
|
||||
test_must_fail git cherry-pick initial..picked &&
|
||||
|
||||
test_cmp_rev unrelatedpick CHERRY_PICK_HEAD &&
|
||||
git checkout HEAD -- unrelated &&
|
||||
test_must_fail git cherry-pick --continue 2>msg &&
|
||||
test_i18ngrep "The previous cherry-pick is now empty" msg
|
||||
'
|
||||
|
||||
test_expect_success 'follow advice and skip nil patch' '
|
||||
pristine_detach conflicting &&
|
||||
test_must_fail git cherry-pick initial..picked &&
|
||||
|
||||
git checkout HEAD -- unrelated &&
|
||||
test_must_fail git cherry-pick --continue &&
|
||||
git reset &&
|
||||
git cherry-pick --continue &&
|
||||
|
||||
git rev-list initial..HEAD >commits &&
|
||||
test_line_count = 3 commits
|
||||
'
|
||||
|
||||
test_expect_success '--continue respects opts' '
|
||||
pristine_detach initial &&
|
||||
test_must_fail git cherry-pick -x base..anotherpick &&
|
||||
@ -288,6 +384,29 @@ test_expect_success '--continue respects opts' '
|
||||
grep "cherry picked from" anotherpick_msg
|
||||
'
|
||||
|
||||
test_expect_success '--continue of single-pick respects -x' '
|
||||
pristine_detach initial &&
|
||||
test_must_fail git cherry-pick -x picked &&
|
||||
echo c >foo &&
|
||||
git add foo &&
|
||||
git cherry-pick --continue &&
|
||||
test_path_is_missing .git/sequencer &&
|
||||
git cat-file commit HEAD >msg &&
|
||||
grep "cherry picked from" msg
|
||||
'
|
||||
|
||||
test_expect_success '--continue respects -x in first commit in multi-pick' '
|
||||
pristine_detach initial &&
|
||||
test_must_fail git cherry-pick -x picked anotherpick &&
|
||||
echo c >foo &&
|
||||
git add foo &&
|
||||
git cherry-pick --continue &&
|
||||
test_path_is_missing .git/sequencer &&
|
||||
git cat-file commit HEAD^ >msg &&
|
||||
picked=$(git rev-parse --verify picked) &&
|
||||
grep "cherry picked from.*$picked" msg
|
||||
'
|
||||
|
||||
test_expect_success '--signoff is not automatically propagated to resolved conflict' '
|
||||
pristine_detach initial &&
|
||||
test_must_fail git cherry-pick --signoff base..anotherpick &&
|
||||
@ -306,6 +425,32 @@ test_expect_success '--signoff is not automatically propagated to resolved confl
|
||||
grep "Signed-off-by:" anotherpick_msg
|
||||
'
|
||||
|
||||
test_expect_success '--signoff dropped for implicit commit of resolution, multi-pick case' '
|
||||
pristine_detach initial &&
|
||||
test_must_fail git cherry-pick -s picked anotherpick &&
|
||||
echo c >foo &&
|
||||
git add foo &&
|
||||
git cherry-pick --continue &&
|
||||
|
||||
git diff --exit-code HEAD &&
|
||||
test_cmp_rev initial HEAD^^ &&
|
||||
git cat-file commit HEAD^ >msg &&
|
||||
! grep Signed-off-by: msg
|
||||
'
|
||||
|
||||
test_expect_success 'sign-off needs to be reaffirmed after conflict resolution, single-pick case' '
|
||||
pristine_detach initial &&
|
||||
test_must_fail git cherry-pick -s picked &&
|
||||
echo c >foo &&
|
||||
git add foo &&
|
||||
git cherry-pick --continue &&
|
||||
|
||||
git diff --exit-code HEAD &&
|
||||
test_cmp_rev initial HEAD^ &&
|
||||
git cat-file commit HEAD >msg &&
|
||||
! grep Signed-off-by: msg
|
||||
'
|
||||
|
||||
test_expect_success 'malformed instruction sheet 1' '
|
||||
pristine_detach initial &&
|
||||
test_must_fail git cherry-pick base..anotherpick &&
|
||||
@ -328,4 +473,9 @@ test_expect_success 'malformed instruction sheet 2' '
|
||||
test_must_fail git cherry-pick --continue
|
||||
'
|
||||
|
||||
test_expect_success 'empty commit set' '
|
||||
pristine_detach initial &&
|
||||
test_expect_code 128 git cherry-pick base..base
|
||||
'
|
||||
|
||||
test_done
|
||||
|
@ -1,52 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='Test interaction of reset --hard with sequencer
|
||||
|
||||
+ anotherpick: rewrites foo to d
|
||||
+ picked: rewrites foo to c
|
||||
+ unrelatedpick: rewrites unrelated to reallyunrelated
|
||||
+ base: rewrites foo to b
|
||||
+ initial: writes foo as a, unrelated as unrelated
|
||||
'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
pristine_detach () {
|
||||
git cherry-pick --quit &&
|
||||
git checkout -f "$1^0" &&
|
||||
git read-tree -u --reset HEAD &&
|
||||
git clean -d -f -f -q -x
|
||||
}
|
||||
|
||||
test_expect_success setup '
|
||||
echo unrelated >unrelated &&
|
||||
git add unrelated &&
|
||||
test_commit initial foo a &&
|
||||
test_commit base foo b &&
|
||||
test_commit unrelatedpick unrelated reallyunrelated &&
|
||||
test_commit picked foo c &&
|
||||
test_commit anotherpick foo d &&
|
||||
git config advice.detachedhead false
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'reset --hard cleans up sequencer state, providing one-level undo' '
|
||||
pristine_detach initial &&
|
||||
test_must_fail git cherry-pick base..anotherpick &&
|
||||
test_path_is_dir .git/sequencer &&
|
||||
git reset --hard &&
|
||||
test_path_is_missing .git/sequencer &&
|
||||
test_path_is_dir .git/sequencer-old &&
|
||||
git reset --hard &&
|
||||
test_path_is_missing .git/sequencer-old
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick --abort does not leave sequencer-old dir' '
|
||||
pristine_detach initial &&
|
||||
test_must_fail git cherry-pick base..anotherpick &&
|
||||
git cherry-pick --abort &&
|
||||
test_path_is_missing .git/sequencer &&
|
||||
test_path_is_missing .git/sequencer-old
|
||||
'
|
||||
|
||||
test_done
|
Loading…
Reference in New Issue
Block a user