diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index bf66116d61..b44fdd9f01 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -243,12 +243,14 @@ endif::git-rev-list[] Pretend as if all the refs in `$GIT_DIR/refs/remotes` are listed on the command line as ''. -ifdef::git-rev-list[] --stdin:: In addition to the '' listed on the command - line, read them from the standard input. + line, read them from the standard input. If a '--' separator is + seen, stop reading commits and start reading paths to limit the + result. +ifdef::git-rev-list[] --quiet:: Don't print anything to standard output. This form diff --git a/builtin-blame.c b/builtin-blame.c index dd16b22297..d4e25a595d 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -2358,6 +2358,7 @@ parse_done: die_errno("cannot stat path '%s'", path); } + revs.disable_stdin = 1; setup_revisions(argc, argv, &revs, NULL); memset(&sb, 0, sizeof(sb)); diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c index 79cedb72c4..2380c21951 100644 --- a/builtin-diff-tree.c +++ b/builtin-diff-tree.c @@ -104,6 +104,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix) git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ opt->abbrev = 0; opt->diff = 1; + opt->disable_stdin = 1; argc = setup_revisions(argc, argv, opt, NULL); while (--argc > 0) { diff --git a/builtin-rev-list.c b/builtin-rev-list.c index ac1136a3f5..91b604289d 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -306,7 +306,6 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) struct rev_info revs; struct rev_list_info info; int i; - int read_from_stdin = 0; int bisect_list = 0; int bisect_show_vars = 0; int bisect_find_all = 0; @@ -351,12 +350,6 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) bisect_show_vars = 1; continue; } - if (!strcmp(arg, "--stdin")) { - if (read_from_stdin++) - die("--stdin given twice?"); - read_revisions_from_stdin(&revs); - continue; - } usage(rev_list_usage); } diff --git a/bundle.c b/bundle.c index 717a712e9a..ff97adcb89 100644 --- a/bundle.c +++ b/bundle.c @@ -204,7 +204,6 @@ int create_bundle(struct bundle_header *header, const char *path, int i, ref_count = 0; char buffer[1024]; struct rev_info revs; - int read_from_stdin = 0; struct child_process rls; FILE *rls_fout; @@ -256,15 +255,8 @@ int create_bundle(struct bundle_header *header, const char *path, /* write references */ argc = setup_revisions(argc, argv, &revs, NULL); - for (i = 1; i < argc; i++) { - if (!strcmp(argv[i], "--stdin")) { - if (read_from_stdin++) - die("--stdin given twice?"); - read_revisions_from_stdin(&revs); - continue; - } - return error("unrecognized argument: %s'", argv[i]); - } + if (argc > 1) + return error("unrecognized argument: %s'", argv[1]); object_array_remove_duplicates(&revs.pending); diff --git a/revision.c b/revision.c index a36c0d9bcd..a8a3c3a4bd 100644 --- a/revision.c +++ b/revision.c @@ -953,21 +953,59 @@ int handle_revision_arg(const char *arg, struct rev_info *revs, return 0; } -void read_revisions_from_stdin(struct rev_info *revs) +static void read_pathspec_from_stdin(struct rev_info *revs, struct strbuf *sb, const char ***prune_data) { - char line[1000]; + const char **prune = *prune_data; + int prune_nr; + int prune_alloc; - while (fgets(line, sizeof(line), stdin) != NULL) { - int len = strlen(line); - if (len && line[len - 1] == '\n') - line[--len] = '\0'; + /* count existing ones */ + if (!prune) + prune_nr = 0; + else + for (prune_nr = 0; prune[prune_nr]; prune_nr++) + ; + prune_alloc = prune_nr; /* not really, but we do not know */ + + while (strbuf_getwholeline(sb, stdin, '\n') != EOF) { + int len = sb->len; + if (len && sb->buf[len - 1] == '\n') + sb->buf[--len] = '\0'; + ALLOC_GROW(prune, prune_nr+1, prune_alloc); + prune[prune_nr++] = xstrdup(sb->buf); + } + if (prune) { + ALLOC_GROW(prune, prune_nr+1, prune_alloc); + prune[prune_nr] = NULL; + } + *prune_data = prune; +} + +static void read_revisions_from_stdin(struct rev_info *revs, const char ***prune) +{ + struct strbuf sb; + int seen_dashdash = 0; + + strbuf_init(&sb, 1000); + while (strbuf_getwholeline(&sb, stdin, '\n') != EOF) { + int len = sb.len; + if (len && sb.buf[len - 1] == '\n') + sb.buf[--len] = '\0'; if (!len) break; - if (line[0] == '-') + if (sb.buf[0] == '-') { + if (len == 2 && sb.buf[1] == '-') { + seen_dashdash = 1; + break; + } die("options not supported in --stdin mode"); - if (handle_revision_arg(line, revs, 0, 1)) - die("bad revision '%s'", line); + } + if (handle_revision_arg(sb.buf, revs, 0, 1)) + die("bad revision '%s'", sb.buf); } + if (seen_dashdash) + read_pathspec_from_stdin(revs, &sb, prune); + strbuf_release(&sb); } static void add_grep(struct rev_info *revs, const char *ptn, enum grep_pat_token what) @@ -1229,6 +1267,34 @@ static int for_each_good_bisect_ref(each_ref_fn fn, void *cb_data) return for_each_ref_in("refs/bisect/good", fn, cb_data); } +static void append_prune_data(const char ***prune_data, const char **av) +{ + const char **prune = *prune_data; + int prune_nr; + int prune_alloc; + + if (!prune) { + *prune_data = av; + return; + } + + /* count existing ones */ + for (prune_nr = 0; prune[prune_nr]; prune_nr++) + ; + prune_alloc = prune_nr; /* not really, but we do not know */ + + while (*av) { + ALLOC_GROW(prune, prune_nr+1, prune_alloc); + prune[prune_nr++] = *av; + av++; + } + if (prune) { + ALLOC_GROW(prune, prune_nr+1, prune_alloc); + prune[prune_nr] = NULL; + } + *prune_data = prune; +} + /* * Parse revision information, filling in the "rev_info" structure, * and removing the used arguments from the argument list. @@ -1238,7 +1304,8 @@ static int for_each_good_bisect_ref(each_ref_fn fn, void *cb_data) */ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def) { - int i, flags, left, seen_dashdash; + int i, flags, left, seen_dashdash, read_from_stdin; + const char **prune_data = NULL; /* First, search for "--" */ seen_dashdash = 0; @@ -1249,13 +1316,14 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch argv[i] = NULL; argc = i; if (argv[i + 1]) - revs->prune_data = get_pathspec(revs->prefix, argv + i + 1); + prune_data = argv + i + 1; seen_dashdash = 1; break; } /* Second, deal with arguments and options */ flags = 0; + read_from_stdin = 0; for (left = i = 1; i < argc; i++) { const char *arg = argv[i]; if (*arg == '-') { @@ -1300,6 +1368,16 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch revs->no_walk = 0; continue; } + if (!strcmp(arg, "--stdin")) { + if (revs->disable_stdin) { + argv[left++] = arg; + continue; + } + if (read_from_stdin++) + die("--stdin given twice?"); + read_revisions_from_stdin(revs, &prune_data); + continue; + } opts = handle_revision_opt(revs, argc - i, argv + i, &left, argv); if (opts > 0) { @@ -1325,12 +1403,14 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch for (j = i; j < argc; j++) verify_filename(revs->prefix, argv[j]); - revs->prune_data = get_pathspec(revs->prefix, - argv + i); + append_prune_data(&prune_data, argv + i); break; } } + if (prune_data) + revs->prune_data = get_pathspec(revs->prefix, prune_data); + if (revs->def == NULL) revs->def = def; if (revs->show_merge) diff --git a/revision.h b/revision.h index 921656aaab..d368003159 100644 --- a/revision.h +++ b/revision.h @@ -84,6 +84,8 @@ struct rev_info { use_terminator:1, missing_newline:1, date_mode_explicit:1; + unsigned int disable_stdin:1; + enum date_mode date_mode; unsigned int abbrev; @@ -129,8 +131,6 @@ struct rev_info { #define REV_TREE_DIFFERENT 3 /* Mixed changes */ /* revision.c */ -void read_revisions_from_stdin(struct rev_info *revs); - typedef void (*show_early_output_fn_t)(struct rev_info *, struct commit_list *); extern volatile show_early_output_fn_t show_early_output; diff --git a/t/t6017-rev-list-stdin.sh b/t/t6017-rev-list-stdin.sh new file mode 100755 index 0000000000..f1c32dba42 --- /dev/null +++ b/t/t6017-rev-list-stdin.sh @@ -0,0 +1,61 @@ +#!/bin/sh +# +# Copyright (c) 2009, Junio C Hamano +# + +test_description='log family learns --stdin' + +. ./test-lib.sh + +check () { + for cmd in rev-list "log --stat" + do + for i in "$@" + do + printf "%s\n" $i + done >input && + test_expect_success "check $cmd $*" ' + git $cmd $(cat input) >expect && + git $cmd --stdin actual && + sed -e "s/^/input /" input && + sed -e "s/^/output /" expect && + test_cmp expect actual + ' + done +} + +them='1 2 3 4 5 6 7' + +test_expect_success setup ' + ( + for i in 0 $them + do + for j in $them + do + echo $i.$j >file-$j && + git add file-$j || exit + done && + test_tick && + git commit -m $i || exit + done && + for i in $them + do + git checkout -b side-$i master~$i && + echo updated $i >file-$i && + git add file-$i && + test_tick && + git commit -m side-$i || exit + done + ) +' + +check master +check side-1 ^side-4 +check side-1 ^side-7 -- +check side-1 ^side-7 -- file-1 +check side-1 ^side-7 -- file-2 +check side-3 ^side-4 -- file-3 +check side-3 ^side-2 +check side-3 ^side-2 -- file-1 + +test_done