Skip to content

Commit c40f0b7

Browse files
pks-tgitster
authored andcommitted
revision: handle pseudo-opts in --stdin mode
While both git-rev-list(1) and git-log(1) support `--stdin`, it only accepts commits and files. Most notably, it is impossible to pass any of the pseudo-opts like `--all`, `--glob=` or others via stdin. This makes it hard to use this function in certain scripted scenarios, like when one wants to support queries against specific revisions, but also against reference patterns. While this is theoretically possible by using arguments, this may run into issues once we hit platform limits with sufficiently large queries. And because `--stdin` cannot handle pseudo-opts, the only alternative would be to use a mixture of arguments and standard input, which is cumbersome. Implement support for handling pseudo-opts in both commands to support this usecase better. One notable restriction here is that `--stdin` only supports "stuck" arguments in the form of `--glob=foo`. This is because "unstuck" arguments would also require us to read the next line, which would add quite some complexity to the code. This restriction should be fine for scripted usage though. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent af37a20 commit c40f0b7

File tree

3 files changed

+72
-9
lines changed

3 files changed

+72
-9
lines changed

Documentation/rev-list-options.txt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,11 @@ ifndef::git-rev-list[]
236236
endif::git-rev-list[]
237237

238238
--stdin::
239-
In addition to the '<commit>' listed on the command
240-
line, read them from the standard input. If a `--` separator is
241-
seen, stop reading commits and start reading paths to limit the
242-
result.
239+
In addition to getting arguments from the command line, read
240+
them for standard input as well. This accepts commits and
241+
pseudo-options like `--all` and `--glob=`. When a `--` separator
242+
is seen, the following input is treated as paths and used to
243+
limit the result.
243244

244245
ifdef::git-rev-list[]
245246
--quiet::

revision.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2784,10 +2784,12 @@ static int handle_revision_pseudo_opt(struct rev_info *revs,
27842784
}
27852785

27862786
static void read_revisions_from_stdin(struct rev_info *revs,
2787-
struct strvec *prune)
2787+
struct strvec *prune,
2788+
int *flags)
27882789
{
27892790
struct strbuf sb;
27902791
int seen_dashdash = 0;
2792+
int seen_end_of_options = 0;
27912793
int save_warning;
27922794

27932795
save_warning = warn_on_object_refname_ambiguity;
@@ -2803,8 +2805,19 @@ static void read_revisions_from_stdin(struct rev_info *revs,
28032805
break;
28042806
}
28052807

2806-
if (sb.buf[0] == '-')
2807-
die("options not supported in --stdin mode");
2808+
if (!seen_end_of_options && sb.buf[0] == '-') {
2809+
const char *argv[] = { sb.buf, NULL };
2810+
2811+
if (!strcmp(sb.buf, "--end-of-options")) {
2812+
seen_end_of_options = 1;
2813+
continue;
2814+
}
2815+
2816+
if (handle_revision_pseudo_opt(revs, argv, flags) > 0)
2817+
continue;
2818+
2819+
die(_("invalid option '%s' in --stdin mode"), sb.buf);
2820+
}
28082821

28092822
if (handle_revision_arg(sb.buf, revs, 0,
28102823
REVARG_CANNOT_BE_FILENAME))
@@ -2889,7 +2902,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
28892902
}
28902903
if (revs->read_from_stdin++)
28912904
die("--stdin given twice?");
2892-
read_revisions_from_stdin(revs, &prune_data);
2905+
read_revisions_from_stdin(revs, &prune_data, &flags);
28932906
continue;
28942907
}
28952908

t/t6017-rev-list-stdin.sh

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ test_expect_success setup '
4848
git add file-$i &&
4949
test_tick &&
5050
git commit -m side-$i || exit
51-
done
51+
done &&
52+
53+
git update-ref refs/heads/-dashed-branch HEAD
5254
)
5355
'
5456

@@ -60,6 +62,12 @@ check side-1 ^side-7 -- file-2
6062
check side-3 ^side-4 -- file-3
6163
check side-3 ^side-2
6264
check side-3 ^side-2 -- file-1
65+
check --all
66+
check --all --not --branches
67+
check --glob=refs/heads
68+
check --glob=refs/heads --
69+
check --glob=refs/heads -- file-1
70+
check --end-of-options -dashed-branch
6371

6472
test_expect_success 'not only --stdin' '
6573
cat >expect <<-EOF &&
@@ -78,4 +86,45 @@ test_expect_success 'not only --stdin' '
7886
test_cmp expect actual
7987
'
8088

89+
test_expect_success 'pseudo-opt with missing value' '
90+
cat >input <<-EOF &&
91+
--glob
92+
refs/heads
93+
EOF
94+
95+
cat >expect <<-EOF &&
96+
fatal: Option ${SQ}--glob${SQ} requires a value
97+
EOF
98+
99+
test_must_fail git rev-list --stdin <input 2>error &&
100+
test_cmp expect error
101+
'
102+
103+
test_expect_success 'pseudo-opt with invalid value' '
104+
cat >input <<-EOF &&
105+
--no-walk=garbage
106+
EOF
107+
108+
cat >expect <<-EOF &&
109+
error: invalid argument to --no-walk
110+
fatal: invalid option ${SQ}--no-walk=garbage${SQ} in --stdin mode
111+
EOF
112+
113+
test_must_fail git rev-list --stdin <input 2>error &&
114+
test_cmp expect error
115+
'
116+
117+
test_expect_success 'unknown option without --end-of-options' '
118+
cat >input <<-EOF &&
119+
-dashed-branch
120+
EOF
121+
122+
cat >expect <<-EOF &&
123+
fatal: invalid option ${SQ}-dashed-branch${SQ} in --stdin mode
124+
EOF
125+
126+
test_must_fail git rev-list --stdin <input 2>error &&
127+
test_cmp expect error
128+
'
129+
81130
test_done

0 commit comments

Comments
 (0)