teach log --no-walk=unsorted, which avoids sorting

When 'git log' is passed the --no-walk option, no revision walk takes place, naturally. Perhaps somewhat surprisingly, however, the provided revisions still get sorted by commit date. So e.g 'git log --no-walk HEAD HEAD~1' and 'git log --no-walk HEAD~1 HEAD' give the same result (unless the two revisions share the commit date, in which case they will retain the order given on the command line). As the commit that introduced --no-walk (8e64006 (Teach revision machinery about --no-walk, 2007-07-24)) points out, the sorting is intentional, to allow things like git log --abbrev-commit --pretty=oneline --decorate --all --no-walk to show all refs in order by commit date. But there are also other cases where the sorting is not wanted, such as <command producing revisions in order> | git log --oneline --no-walk --stdin To accomodate both cases, leave the decision of whether or not to sort up to the caller, by allowing --no-walk={sorted,unsorted}, defaulting to 'sorted' for backward-compatibility reasons. Signed-off-by: Martin von Zweigbergk <martinvonz@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Martin von Zweigbergk committed Aug 28, 2012 at 23:15 UTC ca92e59e30b503ff8861b6cd4d431d38738a7ee8
6 files changed +40 -9
Documentation/rev-list-options.txt
+8 -3
@@ -619,9 +619,14 @@ These options are mostly targeted for packing of git repositories.
619 Only useful with '--objects'; print the object IDs that are not
620 in packs.
621
622 ---no-walk::
623 -
624 - Only show the given revs, but do not traverse their ancestors.
622 +--no-walk[=(sorted|unsorted)]::
623 +
624 + Only show the given commits, but do not traverse their ancestors.
625 + This has no effect if a range is specified. If the argument
626 + "unsorted" is given, the commits are show in the order they were
627 + given on the command line. Otherwise (if "sorted" or no argument
628 + was given), the commits are show in reverse chronological order
629 + by commit time.
630
631 --do-walk::
632
builtin/log.c
+1 -1
@@ -454,7 +454,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
454 init_revisions(&rev, prefix);
455 rev.diff = 1;
456 rev.always_show_header = 1;
457 - rev.no_walk = 1;
457 + rev.no_walk = REVISION_WALK_NO_WALK_SORTED;
458 rev.diffopt.stat_width = -1; /* Scale to real terminal size */
459
460 memset(&opt, 0, sizeof(opt));
builtin/revert.c
+1 -1
@@ -193,7 +193,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
193 struct setup_revision_opt s_r_opt;
194 opts->revs = xmalloc(sizeof(*opts->revs));
195 init_revisions(opts->revs, NULL);
196 - opts->revs->no_walk = 1;
196 + opts->revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
197 if (argc < 2)
198 usage_with_options(usage_str, options);
199 memset(&s_r_opt, 0, sizeof(s_r_opt));
revision.c
+15 -3
@@ -1294,7 +1294,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
1294 !strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") ||
1295 !strcmp(arg, "--bisect") || !prefixcmp(arg, "--glob=") ||
1296 !prefixcmp(arg, "--branches=") || !prefixcmp(arg, "--tags=") ||
1297 - !prefixcmp(arg, "--remotes="))
1297 + !prefixcmp(arg, "--remotes=") || !prefixcmp(arg, "--no-walk="))
1298 {
1299 unkv[(*unkc)++] = arg;
1300 return 1;
@@ -1687,7 +1687,18 @@ static int handle_revision_pseudo_opt(const char *submodule,
1687 } else if (!strcmp(arg, "--not")) {
1688 *flags ^= UNINTERESTING;
1689 } else if (!strcmp(arg, "--no-walk")) {
1690 - revs->no_walk = 1;
1690 + revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
1691 + } else if (!prefixcmp(arg, "--no-walk=")) {
1692 + /*
1693 + * Detached form ("--no-walk X" as opposed to "--no-walk=X")
1694 + * not allowed, since the argument is optional.
1695 + */
1696 + if (!strcmp(arg + 10, "sorted"))
1697 + revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
1698 + else if (!strcmp(arg + 10, "unsorted"))
1699 + revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED;
1700 + else
1701 + return error("invalid argument to --no-walk");
1702 } else if (!strcmp(arg, "--do-walk")) {
1703 revs->no_walk = 0;
1704 } else {
@@ -2091,10 +2102,11 @@ int prepare_revision_walk(struct rev_info *revs)
2102 }
2103 e++;
2104 }
2094 - commit_list_sort_by_date(&revs->commits);
2105 if (!revs->leak_pending)
2106 free(list);
2107
2108 + if (revs->no_walk != REVISION_WALK_NO_WALK_UNSORTED)
2109 + commit_list_sort_by_date(&revs->commits);
2110 if (revs->no_walk)
2111 return 0;
2112 if (revs->limited)
revision.h
+5 -1
@@ -41,6 +41,10 @@ struct rev_cmdline_info {
41 } *rev;
42 };
43
44 +#define REVISION_WALK_WALK 0
45 +#define REVISION_WALK_NO_WALK_SORTED 1
46 +#define REVISION_WALK_NO_WALK_UNSORTED 2
47 +
48 struct rev_info {
49 /* Starting list */
50 struct commit_list *commits;
@@ -62,7 +66,7 @@ struct rev_info {
66 /* Traversal flags */
67 unsigned int dense:1,
68 prune:1,
65 - no_walk:1,
69 + no_walk:2,
70 show_all:1,
71 remove_empty_trees:1,
72 simplify_history:1,
t/t4202-log.sh
+10
@@ -178,11 +178,21 @@ test_expect_success 'git log --no-walk <commits> sorts by commit time' '
178 test_cmp expect actual
179 '
180
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 +
186 cat > expect << EOF
187 5d31159 fourth
188 804a787 sixth
189 394ef78 fifth
190 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 +
196 test_expect_success 'git show <commits> leaves list of commits as given' '
197 git show --oneline -s 5d31159 804a787 394ef78 > actual &&
198 test_cmp expect actual