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>
This commit is contained in:
Shawn Pearce 2006-02-28 21:43:33 -05:00 committed by Junio C Hamano
parent 858cbfbabe
commit 9debe63d10
2 changed files with 59 additions and 2 deletions

View File

@ -10,7 +10,9 @@ SYNOPSIS
-------- --------
[verse] [verse]
'git-checkout-index' [-u] [-q] [-a] [-f] [-n] [--prefix=<string>] 'git-checkout-index' [-u] [-q] [-a] [-f] [-n] [--prefix=<string>]
[--stage=<number>] [--] <file>... [--stage=<number>]
[-z] [--stdin]
[--] [<file>]\*
DESCRIPTION DESCRIPTION
----------- -----------
@ -45,6 +47,15 @@ OPTIONS
Instead of checking out unmerged entries, copy out the Instead of checking out unmerged entries, copy out the
files from named stage. <number> must be between 1 and 3. files from named stage. <number> must be between 1 and 3.
--stdin::
Instead of taking list of paths from the command line,
read list of paths from the standard input. Paths are
separated by LF (i.e. one path per line) by default.
-z::
Only meaningful with `--stdin`; paths are separated with
NUL character instead of LF.
--:: --::
Do not interpret any more arguments as options. Do not interpret any more arguments as options.
@ -64,7 +75,12 @@ $ find . -name '*.h' -print0 | xargs -0 git-checkout-index -f --
which will force all existing `*.h` files to be replaced with their which will force all existing `*.h` files to be replaced with their
cached copies. If an empty command line implied "all", then this would cached copies. If an empty command line implied "all", then this would
force-refresh everything in the index, which was not the point. force-refresh everything in the index, which was not the point. But
since git-checkout-index accepts --stdin it would be faster to use:
----------------
$ find . -name '*.h' -print0 | git-checkout-index -f -z --stdin
----------------
The `--` is just a good idea when you know the rest will be filenames; The `--` is just a good idea when you know the rest will be filenames;
it will prevent problems with a filename of, for example, `-a`. it will prevent problems with a filename of, for example, `-a`.

View File

@ -22,6 +22,10 @@
* *
* find . -name '*.h' -print0 | xargs -0 git-checkout-index -f -- * find . -name '*.h' -print0 | xargs -0 git-checkout-index -f --
* *
* or:
*
* find . -name '*.h' -print0 | git-checkout-index -f -z --stdin
*
* which will force all existing *.h files to be replaced with * which will force all existing *.h files to be replaced with
* their cached copies. If an empty command line implied "all", * their cached copies. If an empty command line implied "all",
* then this would force-refresh everything in the cache, which * then this would force-refresh everything in the cache, which
@ -33,6 +37,8 @@
* but get used to it in scripting!). * but get used to it in scripting!).
*/ */
#include "cache.h" #include "cache.h"
#include "strbuf.h"
#include "quote.h"
static const char *prefix; static const char *prefix;
static int prefix_length; static int prefix_length;
@ -114,6 +120,8 @@ int main(int argc, char **argv)
int i; int i;
int newfd = -1; int newfd = -1;
int all = 0; int all = 0;
int read_from_stdin = 0;
int line_termination = '\n';
prefix = setup_git_directory(); prefix = setup_git_directory();
git_config(git_default_config); git_config(git_default_config);
@ -156,6 +164,17 @@ int main(int argc, char **argv)
die("cannot open index.lock file."); die("cannot open index.lock file.");
continue; continue;
} }
if (!strcmp(arg, "-z")) {
line_termination = 0;
continue;
}
if (!strcmp(arg, "--stdin")) {
if (i != argc - 1)
die("--stdin must be at the end");
read_from_stdin = 1;
i++; /* do not consider arg as a file name */
break;
}
if (!strncmp(arg, "--prefix=", 9)) { if (!strncmp(arg, "--prefix=", 9)) {
state.base_dir = arg+9; state.base_dir = arg+9;
state.base_dir_len = strlen(state.base_dir); state.base_dir_len = strlen(state.base_dir);
@ -191,9 +210,31 @@ int main(int argc, char **argv)
if (all) if (all)
die("git-checkout-index: don't mix '--all' and explicit filenames"); die("git-checkout-index: don't mix '--all' and explicit filenames");
if (read_from_stdin)
die("git-checkout-index: don't mix '--stdin' and explicit filenames");
checkout_file(prefix_path(prefix, prefix_length, arg)); checkout_file(prefix_path(prefix, prefix_length, arg));
} }
if (read_from_stdin) {
struct strbuf buf;
if (all)
die("git-checkout-index: don't mix '--all' and '--stdin'");
strbuf_init(&buf);
while (1) {
char *path_name;
read_line(&buf, stdin, line_termination);
if (buf.eof)
break;
if (line_termination && buf.buf[0] == '"')
path_name = unquote_c_style(buf.buf, NULL);
else
path_name = buf.buf;
checkout_file(prefix_path(prefix, prefix_length, path_name));
if (path_name != buf.buf)
free(path_name);
}
}
if (all) if (all)
checkout_all(); checkout_all();