Skip to content

Commit 9debe63

Browse files
spearceJunio C Hamano
authored andcommitted
Teach git-checkout-index to read filenames from stdin.
Since git-checkout-index is often used from scripts which may have a stream of filenames they wish to checkout it is more convenient to use --stdin than xargs. On platforms where fork performance is currently sub-optimal and the length of a command line is limited (*cough* Cygwin *cough*) running a single git-checkout-index process for a large number of files beats spawning it multiple times from xargs. File names are still accepted on the command line if --stdin is not supplied. Nothing is performed if no files are supplied on the command line or by stdin. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
1 parent 858cbfb commit 9debe63

File tree

2 files changed

+59
-2
lines changed

2 files changed

+59
-2
lines changed

Documentation/git-checkout-index.txt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ SYNOPSIS
1010
--------
1111
[verse]
1212
'git-checkout-index' [-u] [-q] [-a] [-f] [-n] [--prefix=<string>]
13-
[--stage=<number>] [--] <file>...
13+
[--stage=<number>]
14+
[-z] [--stdin]
15+
[--] [<file>]\*
1416

1517
DESCRIPTION
1618
-----------
@@ -45,6 +47,15 @@ OPTIONS
4547
Instead of checking out unmerged entries, copy out the
4648
files from named stage. <number> must be between 1 and 3.
4749

50+
--stdin::
51+
Instead of taking list of paths from the command line,
52+
read list of paths from the standard input. Paths are
53+
separated by LF (i.e. one path per line) by default.
54+
55+
-z::
56+
Only meaningful with `--stdin`; paths are separated with
57+
NUL character instead of LF.
58+
4859
--::
4960
Do not interpret any more arguments as options.
5061

@@ -64,7 +75,12 @@ $ find . -name '*.h' -print0 | xargs -0 git-checkout-index -f --
6475

6576
which will force all existing `*.h` files to be replaced with their
6677
cached copies. If an empty command line implied "all", then this would
67-
force-refresh everything in the index, which was not the point.
78+
force-refresh everything in the index, which was not the point. But
79+
since git-checkout-index accepts --stdin it would be faster to use:
80+
81+
----------------
82+
$ find . -name '*.h' -print0 | git-checkout-index -f -z --stdin
83+
----------------
6884

6985
The `--` is just a good idea when you know the rest will be filenames;
7086
it will prevent problems with a filename of, for example, `-a`.

checkout-index.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
*
2323
* find . -name '*.h' -print0 | xargs -0 git-checkout-index -f --
2424
*
25+
* or:
26+
*
27+
* find . -name '*.h' -print0 | git-checkout-index -f -z --stdin
28+
*
2529
* which will force all existing *.h files to be replaced with
2630
* their cached copies. If an empty command line implied "all",
2731
* then this would force-refresh everything in the cache, which
@@ -33,6 +37,8 @@
3337
* but get used to it in scripting!).
3438
*/
3539
#include "cache.h"
40+
#include "strbuf.h"
41+
#include "quote.h"
3642

3743
static const char *prefix;
3844
static int prefix_length;
@@ -114,6 +120,8 @@ int main(int argc, char **argv)
114120
int i;
115121
int newfd = -1;
116122
int all = 0;
123+
int read_from_stdin = 0;
124+
int line_termination = '\n';
117125

118126
prefix = setup_git_directory();
119127
git_config(git_default_config);
@@ -156,6 +164,17 @@ int main(int argc, char **argv)
156164
die("cannot open index.lock file.");
157165
continue;
158166
}
167+
if (!strcmp(arg, "-z")) {
168+
line_termination = 0;
169+
continue;
170+
}
171+
if (!strcmp(arg, "--stdin")) {
172+
if (i != argc - 1)
173+
die("--stdin must be at the end");
174+
read_from_stdin = 1;
175+
i++; /* do not consider arg as a file name */
176+
break;
177+
}
159178
if (!strncmp(arg, "--prefix=", 9)) {
160179
state.base_dir = arg+9;
161180
state.base_dir_len = strlen(state.base_dir);
@@ -191,9 +210,31 @@ int main(int argc, char **argv)
191210

192211
if (all)
193212
die("git-checkout-index: don't mix '--all' and explicit filenames");
213+
if (read_from_stdin)
214+
die("git-checkout-index: don't mix '--stdin' and explicit filenames");
194215
checkout_file(prefix_path(prefix, prefix_length, arg));
195216
}
196217

218+
if (read_from_stdin) {
219+
struct strbuf buf;
220+
if (all)
221+
die("git-checkout-index: don't mix '--all' and '--stdin'");
222+
strbuf_init(&buf);
223+
while (1) {
224+
char *path_name;
225+
read_line(&buf, stdin, line_termination);
226+
if (buf.eof)
227+
break;
228+
if (line_termination && buf.buf[0] == '"')
229+
path_name = unquote_c_style(buf.buf, NULL);
230+
else
231+
path_name = buf.buf;
232+
checkout_file(prefix_path(prefix, prefix_length, path_name));
233+
if (path_name != buf.buf)
234+
free(path_name);
235+
}
236+
}
237+
197238
if (all)
198239
checkout_all();
199240

0 commit comments

Comments
 (0)