Skip to content

Commit c2b9279

Browse files
committed
Merge branch 'mz/cherry-pick-cmdline-order'
"git cherry-pick A C B" used to replay changes in A and then B and then C if these three commits had committer timestamps in that order, which is not what the user who said "A C B" naturally expects. * mz/cherry-pick-cmdline-order: cherry-pick/revert: respect order of revisions to pick demonstrate broken 'git cherry-pick three one two' teach log --no-walk=unsorted, which avoids sorting
2 parents 1c0712d + a73e22e commit c2b9279

File tree

8 files changed

+60
-11
lines changed

8 files changed

+60
-11
lines changed

Documentation/rev-list-options.txt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -636,10 +636,14 @@ These options are mostly targeted for packing of git repositories.
636636
Only useful with '--objects'; print the object IDs that are not
637637
in packs.
638638

639-
--no-walk::
640-
641-
Only show the given revs, but do not traverse their ancestors.
642-
This has no effect if a range is specified.
639+
--no-walk[=(sorted|unsorted)]::
640+
641+
Only show the given commits, but do not traverse their ancestors.
642+
This has no effect if a range is specified. If the argument
643+
"unsorted" is given, the commits are show in the order they were
644+
given on the command line. Otherwise (if "sorted" or no argument
645+
was given), the commits are show in reverse chronological order
646+
by commit time.
643647

644648
--do-walk::
645649

builtin/log.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
456456
init_revisions(&rev, prefix);
457457
rev.diff = 1;
458458
rev.always_show_header = 1;
459-
rev.no_walk = 1;
459+
rev.no_walk = REVISION_WALK_NO_WALK_SORTED;
460460
rev.diffopt.stat_width = -1; /* Scale to real terminal size */
461461

462462
memset(&opt, 0, sizeof(opt));

builtin/revert.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
195195
struct setup_revision_opt s_r_opt;
196196
opts->revs = xmalloc(sizeof(*opts->revs));
197197
init_revisions(opts->revs, NULL);
198-
opts->revs->no_walk = 1;
198+
opts->revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED;
199199
if (argc < 2)
200200
usage_with_options(usage_str, options);
201201
memset(&s_r_opt, 0, sizeof(s_r_opt));

revision.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,7 +1312,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
13121312
!strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") ||
13131313
!strcmp(arg, "--bisect") || !prefixcmp(arg, "--glob=") ||
13141314
!prefixcmp(arg, "--branches=") || !prefixcmp(arg, "--tags=") ||
1315-
!prefixcmp(arg, "--remotes="))
1315+
!prefixcmp(arg, "--remotes=") || !prefixcmp(arg, "--no-walk="))
13161316
{
13171317
unkv[(*unkc)++] = arg;
13181318
return 1;
@@ -1707,7 +1707,18 @@ static int handle_revision_pseudo_opt(const char *submodule,
17071707
} else if (!strcmp(arg, "--not")) {
17081708
*flags ^= UNINTERESTING;
17091709
} else if (!strcmp(arg, "--no-walk")) {
1710-
revs->no_walk = 1;
1710+
revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
1711+
} else if (!prefixcmp(arg, "--no-walk=")) {
1712+
/*
1713+
* Detached form ("--no-walk X" as opposed to "--no-walk=X")
1714+
* not allowed, since the argument is optional.
1715+
*/
1716+
if (!strcmp(arg + 10, "sorted"))
1717+
revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
1718+
else if (!strcmp(arg + 10, "unsorted"))
1719+
revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED;
1720+
else
1721+
return error("invalid argument to --no-walk");
17111722
} else if (!strcmp(arg, "--do-walk")) {
17121723
revs->no_walk = 0;
17131724
} else {
@@ -2129,10 +2140,11 @@ int prepare_revision_walk(struct rev_info *revs)
21292140
}
21302141
e++;
21312142
}
2132-
commit_list_sort_by_date(&revs->commits);
21332143
if (!revs->leak_pending)
21342144
free(list);
21352145

2146+
if (revs->no_walk != REVISION_WALK_NO_WALK_UNSORTED)
2147+
commit_list_sort_by_date(&revs->commits);
21362148
if (revs->no_walk)
21372149
return 0;
21382150
if (revs->limited)

revision.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ struct rev_cmdline_info {
4141
} *rev;
4242
};
4343

44+
#define REVISION_WALK_WALK 0
45+
#define REVISION_WALK_NO_WALK_SORTED 1
46+
#define REVISION_WALK_NO_WALK_UNSORTED 2
47+
4448
struct rev_info {
4549
/* Starting list */
4650
struct commit_list *commits;
@@ -62,7 +66,7 @@ struct rev_info {
6266
/* Traversal flags */
6367
unsigned int dense:1,
6468
prune:1,
65-
no_walk:1,
69+
no_walk:2,
6670
show_all:1,
6771
remove_empty_trees:1,
6872
simplify_history:1,

sequencer.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,11 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
546546

547547
static void prepare_revs(struct replay_opts *opts)
548548
{
549-
if (opts->action != REPLAY_REVERT)
549+
/*
550+
* picking (but not reverting) ranges (but not individual revisions)
551+
* should be done in reverse
552+
*/
553+
if (opts->action == REPLAY_PICK && !opts->revs->no_walk)
550554
opts->revs->reverse ^= 1;
551555

552556
if (prepare_revision_walk(opts->revs))

t/t3508-cherry-pick-many-commits.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,21 @@ test_expect_success 'cherry-pick first..fourth works' '
4444
check_head_differs_from fourth
4545
'
4646

47+
test_expect_success 'cherry-pick three one two works' '
48+
git checkout -f first &&
49+
test_commit one &&
50+
test_commit two &&
51+
test_commit three &&
52+
git checkout -f master &&
53+
git reset --hard first &&
54+
git cherry-pick three one two &&
55+
git diff --quiet three &&
56+
git diff --quiet HEAD three &&
57+
test "$(git log --reverse --format=%s first..)" = "three
58+
one
59+
two"
60+
'
61+
4762
test_expect_success 'output to keep user entertained during multi-pick' '
4863
cat <<-\EOF >expected &&
4964
[master OBJID] second

t/t4202-log.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,21 @@ test_expect_success 'git log --no-walk <commits> sorts by commit time' '
178178
test_cmp expect actual
179179
'
180180

181+
test_expect_success 'git log --no-walk=sorted <commits> sorts by commit time' '
182+
git log --no-walk=sorted --oneline 5d31159 804a787 394ef78 > actual &&
183+
test_cmp expect actual
184+
'
185+
181186
cat > expect << EOF
182187
5d31159 fourth
183188
804a787 sixth
184189
394ef78 fifth
185190
EOF
191+
test_expect_success 'git log --no-walk=unsorted <commits> leaves list of commits as given' '
192+
git log --no-walk=unsorted --oneline 5d31159 804a787 394ef78 > actual &&
193+
test_cmp expect actual
194+
'
195+
186196
test_expect_success 'git show <commits> leaves list of commits as given' '
187197
git show --oneline -s 5d31159 804a787 394ef78 > actual &&
188198
test_cmp expect actual

0 commit comments

Comments
 (0)