From a5a6755a1d4707bf2fab7752e5c974ebf63d086a Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Wed, 27 May 2009 11:25:16 +0200 Subject: [PATCH 01/86] git-am foreign patch support: introduce patch_format Set up a framework to allow git-am to support patches which are not in mailbox format. Introduce a patch_format variable that presently can only be set from the command line, defaulting to 'mbox' (the only supported format) if not specified. Signed-off-by: Junio C Hamano --- git-am.sh | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 578780be13..da160de3c3 100755 --- a/git-am.sh +++ b/git-am.sh @@ -18,6 +18,7 @@ whitespace= pass it through git-apply directory= pass it through git-apply C= pass it through git-apply p= pass it through git-apply +patch-format= format the patch(es) are in reject pass it through git-apply resolvemsg= override error message when patch failure occurs r,resolved to be used after a patch failure @@ -133,6 +134,32 @@ It does not apply to blobs recorded in its index." unset GITHEAD_$his_tree } +patch_format= + +check_patch_format () { + # early return if patch_format was set from the command line + if test -n "$patch_format" + then + return 0 + fi + patch_format=mbox +} + +split_patches () { + case "$patch_format" in + mbox) + git mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" || { + rm -fr "$dotest" + exit 1 + } + ;; + *) + echo "Patch format $patch_format is not supported." + exit 1 + ;; + esac +} + prec=4 dotest="$GIT_DIR/rebase-apply" sign= utf8=t keep= skip= interactive= resolved= rebasing= abort= @@ -175,6 +202,8 @@ do git_apply_opt="$git_apply_opt $(sq "$1=$2")"; shift ;; -C|-p) git_apply_opt="$git_apply_opt $(sq "$1$2")"; shift ;; + --patch-format) + shift ; patch_format="$1" ;; --reject) git_apply_opt="$git_apply_opt $1" ;; --committer-date-is-author-date) @@ -274,10 +303,10 @@ else done shift fi - git mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" || { - rm -fr "$dotest" - exit 1 - } + + check_patch_format "$@" + + split_patches "$@" # -s, -u, -k, --whitespace, -3, -C and -p flags are kept # for the resuming session after a patch failure. From 15ced753ac091314941abb28302f7109a9e86b81 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Wed, 27 May 2009 23:20:12 +0200 Subject: [PATCH 02/86] git-am foreign patch support: autodetect some patch formats Default to mbox format if input is from stdin. Otherwise, look at the first few lines of the first patch to try to guess its format. Include checks for mailboxes, stgit patch series, stgit single patches and hg patches. Signed-off-by: Junio C Hamano --- git-am.sh | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index da160de3c3..552b888703 100755 --- a/git-am.sh +++ b/git-am.sh @@ -142,7 +142,45 @@ check_patch_format () { then return 0 fi - patch_format=mbox + + # we default to mbox format if input is from stdin and for + # directories + if test $# = 0 || test "x$1" = "x-" || test -d "$1" + then + patch_format=mbox + return 0 + fi + + # otherwise, check the first few lines of the first patch to try + # to detect its format + { + read l1 + read l2 + read l3 + case "$l1" in + "From "* | "From: "*) + patch_format=mbox + ;; + '# This series applies on GIT commit'*) + patch_format=stgit-series + ;; + "# HG changeset patch") + patch_format=hg + ;; + *) + # if the second line is empty and the third is + # a From, Author or Date entry, this is very + # likely an StGIT patch + case "$l2,$l3" in + ,"From: "* | ,"Author: "* | ,"Date: "*) + patch_format=stgit + ;; + *) + ;; + esac + ;; + esac + } < "$1" } split_patches () { From c574e683b587ee3c302317e4fa9c83cd4605cd82 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Wed, 27 May 2009 11:25:18 +0200 Subject: [PATCH 03/86] git-am foreign patch support: StGIT support Support StGIT patches by implementing a simple perl-based converter mimicking StGIT's own parse_patch. Also support StGIT patch series by 'exploding' the index into a list of files and re-running the mail splitting with patch_format set to stgit. Signed-off-by: Giuseppe Bilotta Signed-off-by: Junio C Hamano --- git-am.sh | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/git-am.sh b/git-am.sh index 552b888703..0ff1f577a3 100755 --- a/git-am.sh +++ b/git-am.sh @@ -191,6 +191,63 @@ split_patches () { exit 1 } ;; + stgit-series) + if test $# -ne 1 + then + echo "Only one StGIT patch series can be applied at once" + exit 1 + fi + series_dir=`dirname "$1"` + series_file="$1" + shift + { + set x + while read filename + do + set "$@" "$series_dir/$filename" + done + # remove the safety x + shift + # remove the arg coming from the first-line comment + shift + } < "$series_file" + # set the patch format appropriately + patch_format=stgit + # now handle the actual StGIT patches + split_patches "$@" + ;; + stgit) + this=0 + for stgit in "$@" + do + this=`expr "$this" + 1` + msgnum=`printf "%0${prec}d" $this` + # Perl version of StGIT parse_patch. The first nonemptyline + # not starting with Author, From or Date is the + # subject, and the body starts with the next nonempty + # line not starting with Author, From or Date + perl -ne 'BEGIN { $subject = 0 } + if ($subject > 1) { print ; } + elsif (/^\s+$/) { next ; } + elsif (/^Author:/) { print s/Author/From/ ; } + elsif (/^(From|Date)/) { print ; } + elsif ($subject) { + $subject = 2 ; + print "\n" ; + print ; + } else { + print "Subject: ", $_ ; + $subject = 1; + } + ' < "$stgit" > "$dotest/$msgnum" || { + echo "Failed to import $patch_format patch $stgit" + exit 1 + } + done + echo "$this" > "$dotest/last" + this= + msgnum= + ;; *) echo "Patch format $patch_format is not supported." exit 1 From ebc9529f0358bdb10192fa27bc75f5d4e452ce90 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Sat, 13 Jun 2009 07:21:06 +0200 Subject: [PATCH 04/86] bisect: use a PRNG with a bias when skipping away from untestable commits Using a PRNG (pseudo random number generator) with a bias should be better than alternating between 3 fixed ratios. In repositories with many untestable commits it should prevent alternating between areas where many commits are untestable. The bias should favor commits that can give more information, so that the bisection process should not loose much efficiency. HPA suggested to use a PRNG and found that the best bias is to raise a ratio between 0 and 1 given by the PRNG to the power 1.5. An integer square root function is implemented to avoid including and linking with -lm. A PRNG function is implemented to get the same number sequence on different machines as suggested by "man 3 rand". Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- bisect.c | 50 +++++++++++++++++++++++++++++-------- t/t6030-bisect-porcelain.sh | 4 +-- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/bisect.c b/bisect.c index 6fdff05722..095b55eba6 100644 --- a/bisect.c +++ b/bisect.c @@ -585,16 +585,49 @@ struct commit_list *filter_skipped(struct commit_list *list, return filtered; } -static struct commit_list *apply_skip_ratio(struct commit_list *list, - int count, - int skip_num, int skip_denom) +#define PRN_MODULO 32768 + +/* + * This is a pseudo random number generator based on "man 3 rand". + * It is not used properly because the seed is the argument and it + * is increased by one between each call, but that should not matter + * for this application. + */ +int get_prn(int count) { + count = count * 1103515245 + 12345; + return ((unsigned)(count/65536) % PRN_MODULO); +} + +/* + * Custom integer square root from + * http://en.wikipedia.org/wiki/Integer_square_root + */ +static int sqrti(int val) +{ + float d, x = val; + + if (val == 0) + return 0; + + do { + float y = (x + (float)val / x) / 2; + d = (y > x) ? y - x : x - y; + x = y; + } while (d >= 0.5); + + return (int)x; +} + +static struct commit_list *skip_away(struct commit_list *list, int count) { - int index, i; struct commit_list *cur, *previous; + int prn, index, i; + + prn = get_prn(count); + index = (count * prn / PRN_MODULO) * sqrti(prn) / sqrti(PRN_MODULO); cur = list; previous = NULL; - index = count * skip_num / skip_denom; for (i = 0; cur; cur = cur->next, i++) { if (i == index) { @@ -614,7 +647,6 @@ static struct commit_list *managed_skipped(struct commit_list *list, struct commit_list **tried) { int count, skipped_first; - int skip_num, skip_denom; *tried = NULL; @@ -626,11 +658,7 @@ static struct commit_list *managed_skipped(struct commit_list *list, if (!skipped_first) return list; - /* Use alternatively 1/5, 2/5 and 3/5 as skip ratio. */ - skip_num = count % 3 + 1; - skip_denom = 5; - - return apply_skip_ratio(list, count, skip_num, skip_denom); + return skip_away(list, count); } static void bisect_rev_setup(struct rev_info *revs, const char *prefix, diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh index 4556cdd8d2..1315bab595 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -563,8 +563,8 @@ test_expect_success 'skipping away from skipped commit' ' hash7=$(git rev-parse --verify HEAD) && test "$hash7" = "$HASH7" && git bisect skip && - hash3=$(git rev-parse --verify HEAD) && - test "$hash3" = "$HASH3" + para3=$(git rev-parse --verify HEAD) && + test "$para3" = "$PARA_HASH3" ' # From 32d86ca53195590f8d7df9f5f58683c9a924d5af Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Sat, 13 Jun 2009 13:11:02 +0200 Subject: [PATCH 05/86] Documentation: remove warning saying that "git bisect skip" may slow bisection This warning was probably useless anyway, but it is even more so now that filtering of skipped commits is done in C and that there is a mechanism to skip away from broken commits. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- Documentation/git-bisect.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt index ffc02c737c..63e7a42cb3 100644 --- a/Documentation/git-bisect.txt +++ b/Documentation/git-bisect.txt @@ -164,9 +164,8 @@ to do it for you by issuing the command: $ git bisect skip # Current version cannot be tested ------------ -But computing the commit to test may be slower afterwards and git may -eventually not be able to tell the first bad commit among a bad commit -and one or more skipped commits. +But git may eventually be unable to tell the first bad commit among +a bad commit and one or more skipped commits. You can even skip a range of commits, instead of just one commit, using the "''..''" notation. For example: From df533f34a31890a43baaf00d03c0a7fa51886bc5 Mon Sep 17 00:00:00 2001 From: Nick Edelen Date: Sat, 13 Jun 2009 17:06:09 -0700 Subject: [PATCH 06/86] diff-tree -r -t: include added/removed directories in the output We used to include only the modified and typechanged directories in the ouptut, but for consistency's sake, we should also include added and removed ones as well. This makes the output more consistent, but it may break existing scripts that expect to see the current output which has long been the established behaviour. Signed-off-by: Nick Edelen Signed-off-by: Junio C Hamano --- t/t4037-diff-r-t-dirs.sh | 53 ++++++++++++++++++++++++++++++++++++++++ tree-diff.c | 6 +++++ 2 files changed, 59 insertions(+) create mode 100755 t/t4037-diff-r-t-dirs.sh diff --git a/t/t4037-diff-r-t-dirs.sh b/t/t4037-diff-r-t-dirs.sh new file mode 100755 index 0000000000..f5ce3b29a2 --- /dev/null +++ b/t/t4037-diff-r-t-dirs.sh @@ -0,0 +1,53 @@ +#!/bin/sh + +test_description='diff -r -t shows directory additions and deletions' + +. ./test-lib.sh + +test_expect_success setup ' + mkdir dc dr dt && + >dc/1 && + >dr/2 && + >dt/3 && + >fc && + >fr && + >ft && + git add . && + test_tick && + git commit -m initial && + + rm -fr dt dr ft fr && + mkdir da ft && + for p in dc/1 da/4 dt ft/5 fc + do + echo hello >$p || exit + done && + git add -u && + git add . && + test_tick && + git commit -m second +' + +cat >expect <<\EOF +A da +A da/4 +M dc +M dc/1 +D dr +D dr/2 +A dt +D dt +D dt/3 +M fc +D fr +D ft +A ft +A ft/5 +EOF + +test_expect_success verify ' + git diff-tree -r -t --name-status HEAD^ HEAD >actual && + test_cmp expect actual +' + +test_done diff --git a/tree-diff.c b/tree-diff.c index 9f67af6c1f..c83a8da392 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -233,6 +233,12 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree if (!tree || type != OBJ_TREE) die("corrupt tree sha %s", sha1_to_hex(sha1)); + if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) { + newbase[baselen + pathlen] = 0; + opt->add_remove(opt, *prefix, mode, sha1, newbase); + newbase[baselen + pathlen] = '/'; + } + init_tree_desc(&inner, tree, size); show_tree(opt, prefix, &inner, newbase, baselen + 1 + pathlen); From 824af25ace464177820fc69c19fc03ae4fc9e4b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 14 Jun 2009 01:58:42 +0200 Subject: [PATCH 07/86] more tests for git rev-parse --parse-opt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König Signed-off-by: Junio C Hamano --- t/t1502-rev-parse-parseopt.sh | 38 +++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh index 997002d4c4..be0959e8a3 100755 --- a/t/t1502-rev-parse-parseopt.sh +++ b/t/t1502-rev-parse-parseopt.sh @@ -20,8 +20,7 @@ Extras EOF -test_expect_success 'test --parseopt help output' ' - git rev-parse --parseopt -- -h 2> output.err < optionspec << EOF some-command [options] ... some-command does foo and bar! @@ -37,7 +36,42 @@ C? option C with an optional argument Extras extra1 line above used to cause a segfault but no longer does EOF + +test_expect_success 'test --parseopt help output' ' + git rev-parse --parseopt -- -h 2> output.err < optionspec test_cmp expect.err output.err ' +cat > expect < output && + test_cmp expect output +' + +test_expect_success 'test --parseopt with mixed options and arguments' ' + git rev-parse --parseopt -- --foo arg --bar=ham < optionspec > output && + test_cmp expect output +' + +cat > expect < output && + test_cmp expect output +' + +cat > expect < output && + test_cmp expect output +' + test_done From 6e0800ef2575751f2e20d11e2cfe305304e5e9b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 14 Jun 2009 01:58:43 +0200 Subject: [PATCH 08/86] parse-opt: make PARSE_OPT_STOP_AT_NON_OPTION available to git rev-parse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König Signed-off-by: Junio C Hamano --- Documentation/git-rev-parse.txt | 5 +++++ builtin-rev-parse.c | 8 ++++++-- t/t1502-rev-parse-parseopt.sh | 5 +++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index 4bbdd056da..82045a2522 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -30,6 +30,11 @@ OPTIONS Only meaningful in `--parseopt` mode. Tells the option parser to echo out the first `--` met instead of skipping it. +--stop-at-non-option:: + Only meaningful in `--parseopt` mode. Lets the option parser stop at + the first non-option argument. This can be used to parse sub-commands + that take options themself. + --sq-quote:: Use 'git-rev-parse' in shell quoting mode (see SQ-QUOTE section below). In contrast to the `--sq` option below, this diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c index 112d622cda..5ea7518b0f 100644 --- a/builtin-rev-parse.c +++ b/builtin-rev-parse.c @@ -301,7 +301,7 @@ static const char *skipspaces(const char *s) static int cmd_parseopt(int argc, const char **argv, const char *prefix) { - static int keep_dashdash = 0; + static int keep_dashdash = 0, stop_at_non_option = 0; static char const * const parseopt_usage[] = { "git rev-parse --parseopt [options] -- [...]", NULL @@ -309,6 +309,9 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix) static struct option parseopt_opts[] = { OPT_BOOLEAN(0, "keep-dashdash", &keep_dashdash, "keep the `--` passed as an arg"), + OPT_BOOLEAN(0, "stop-at-non-option", &stop_at_non_option, + "stop parsing after the " + "first non-option argument"), OPT_END(), }; @@ -394,7 +397,8 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix) ALLOC_GROW(opts, onb + 1, osz); memset(opts + onb, 0, sizeof(opts[onb])); argc = parse_options(argc, argv, prefix, opts, usage, - keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0); + keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0 | + stop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0); strbuf_addf(&parsed, " --"); sq_quote_argv(&parsed, argv, 0); diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh index be0959e8a3..e504058062 100755 --- a/t/t1502-rev-parse-parseopt.sh +++ b/t/t1502-rev-parse-parseopt.sh @@ -65,6 +65,11 @@ test_expect_success 'test --parseopt with --' ' test_cmp expect output ' +test_expect_success 'test --parseopt --stop-at-non-option' ' + git rev-parse --parseopt --stop-at-non-option -- --foo arg --bar=ham < optionspec > output && + test_cmp expect output +' + cat > expect < Date: Wed, 27 May 2009 11:25:19 +0200 Subject: [PATCH 09/86] git-am: refactor 'cleaning up and aborting' Introduce a clean_abort function that echoes an optional error message to standard error, removes the dotest directory and exits with status 1. Use it when patch format detection or patch splitting fails early. Signed-off-by: Giuseppe Bilotta Signed-off-by: Junio C Hamano --- git-am.sh | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/git-am.sh b/git-am.sh index 0ff1f577a3..327807ddcb 100755 --- a/git-am.sh +++ b/git-am.sh @@ -134,6 +134,12 @@ It does not apply to blobs recorded in its index." unset GITHEAD_$his_tree } +clean_abort () { + test $# = 0 || echo >&2 "$@" + rm -fr "$dotest" + exit 1 +} + patch_format= check_patch_format () { @@ -180,22 +186,19 @@ check_patch_format () { esac ;; esac - } < "$1" + } < "$1" || clean_abort } split_patches () { case "$patch_format" in mbox) - git mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" || { - rm -fr "$dotest" - exit 1 - } + git mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" || + clean_abort ;; stgit-series) if test $# -ne 1 then - echo "Only one StGIT patch series can be applied at once" - exit 1 + clean_abort "Only one StGIT patch series can be applied at once" fi series_dir=`dirname "$1"` series_file="$1" @@ -210,7 +213,7 @@ split_patches () { shift # remove the arg coming from the first-line comment shift - } < "$series_file" + } < "$series_file" || clean_abort # set the patch format appropriately patch_format=stgit # now handle the actual StGIT patches @@ -239,18 +242,14 @@ split_patches () { print "Subject: ", $_ ; $subject = 1; } - ' < "$stgit" > "$dotest/$msgnum" || { - echo "Failed to import $patch_format patch $stgit" - exit 1 - } + ' < "$stgit" > "$dotest/$msgnum" || clean_abort done echo "$this" > "$dotest/last" this= msgnum= ;; *) - echo "Patch format $patch_format is not supported." - exit 1 + clean_abort "Patch format $patch_format is not supported." ;; esac } From b3c32ead20bc4d3baa6cffe00dd862f069463869 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Jun 2009 15:32:57 -0700 Subject: [PATCH 10/86] t4150: test applying with a newline in subject Commit 4b7cc26 (git-am: use printf instead of echo on user-supplied strings, 2007-05-25) fixed a bug where subjects with newlines would cause git-am to echo multiple lines when it says "Applying: ". This test ensures that fix stays valid. Signed-off-by: Stephen Boyd Signed-off-by: Junio C Hamano --- t/t4150-am.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/t/t4150-am.sh b/t/t4150-am.sh index d6ebbaebe2..51c369ad14 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -305,4 +305,12 @@ test_expect_success 'am into an unborn branch' ' test "z$result" = "z$(git rev-parse first^{tree})" ' +test_expect_success 'am newline in subject' ' + git checkout first && + test_tick && + sed -e "s/second/second \\\n foo/" patch1 > patchnl && + git am < patchnl > output.out 2>&1 && + grep "^Applying: second \\\n foo$" output.out +' + test_done From 3ddd170323fcf24af8c4a321ed9c73cda532986e Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Jun 2009 15:32:58 -0700 Subject: [PATCH 11/86] am: suppress apply errors when using 3-way git-am with 3-way outputs errors when applying, even though the 3-way will usually be successful. We suppress these errors from git-apply because they are not "true" errors until the 3-way has been attempted. Signed-off-by: Stephen Boyd Signed-off-by: Junio C Hamano --- git-am.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 578780be13..e26c54a3e2 100755 --- a/git-am.sh +++ b/git-am.sh @@ -502,7 +502,14 @@ do case "$resolved" in '') - eval 'git apply '"$git_apply_opt"' --index "$dotest/patch"' + # When we are allowed to fall back to 3-way later, don't give + # false errors during the initial attempt. + squelch= + if test "$threeway" = t + then + squelch='>/dev/null 2>&1 ' + fi + eval "git apply $squelch$git_apply_opt"' --index "$dotest/patch"' apply_status=$? ;; t) From e064c170b4abe21f50658f2ec3b07e4ec7520767 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Jun 2009 15:32:59 -0700 Subject: [PATCH 12/86] git-sh-setup: introduce say() for quiet options Scripts should use say() when they want to output non-error messages. This function helps future script writers easily implement a quiet option by setting GIT_QUIET to enable suppression of non-error messages. Signed-off-by: Stephen Boyd Signed-off-by: Junio C Hamano --- git-sh-setup.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/git-sh-setup.sh b/git-sh-setup.sh index 80acb7de72..c41c2f7439 100755 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -44,6 +44,15 @@ die() { exit 1 } +GIT_QUIET= + +say () { + if test -z "$GIT_QUIET" + then + printf '%s\n' "$*" + fi +} + if test -n "$OPTIONS_SPEC"; then usage() { "$0" -h From 2e6a30ef8fbaedc5f2ee199d36f7256bb0cfdf1e Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Jun 2009 15:33:00 -0700 Subject: [PATCH 13/86] submodule, repack: migrate to git-sh-setup's say() Now that there is say() in git-sh-setup, these scripts don't need to use their own. Migrate them over by setting GIT_QUIET and removing their custom say() functions. Signed-off-by: Stephen Boyd Signed-off-by: Junio C Hamano --- git-repack.sh | 12 +++++------- git-submodule.sh | 24 ++++++------------------ 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/git-repack.sh b/git-repack.sh index 0868734723..1bf239499c 100755 --- a/git-repack.sh +++ b/git-repack.sh @@ -24,7 +24,7 @@ SUBDIRECTORY_OK='Yes' . git-sh-setup no_update_info= all_into_one= remove_redundant= unpack_unreachable= -local= quiet= no_reuse= extra= +local= no_reuse= extra= while test $# != 0 do case "$1" in @@ -33,7 +33,7 @@ do -A) all_into_one=t unpack_unreachable=--unpack-unreachable ;; -d) remove_redundant=t ;; - -q) quiet=-q ;; + -q) GIT_QUIET=t ;; -f) no_reuse=--no-reuse-object ;; -l) local=--local ;; --max-pack-size|--window|--window-memory|--depth) @@ -80,13 +80,11 @@ case ",$all_into_one," in ;; esac -args="$args $local $quiet $no_reuse$extra" +args="$args $local ${GIT_QUIET:+-q} $no_reuse$extra" names=$(git pack-objects --honor-pack-keep --non-empty --all --reflog $args Date: Wed, 17 Jun 2009 15:38:36 +0200 Subject: [PATCH 14/86] fetch: do not create ref from empty name Previously, the refspec ":" would be expanded to ":refs/heads/". Instead, treat an empty just like refspecs without a colon. Signed-off-by: Clemens Buchacher Signed-off-by: Junio C Hamano --- remote.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/remote.c b/remote.c index d66e2f3c93..39583d52b9 100644 --- a/remote.c +++ b/remote.c @@ -1254,7 +1254,7 @@ struct ref *get_remote_ref(const struct ref *remote_refs, const char *name) static struct ref *get_local_ref(const char *name) { - if (!name) + if (!name || name[0] == '\0') return NULL; if (!prefixcmp(name, "refs/")) From 02232adfd8bdc692bbe408ead7332ebfe416e83d Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 16 Jun 2009 15:07:40 -0400 Subject: [PATCH 15/86] Makefile: refactor regex compat support There was no tweakable knob to use the regex compat code; it was embedded in the mingw build. Since other platforms may want to use it, let's factor it out in the usual way for build configuration knobs. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- Makefile | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 41ab8e9e0d..0cb21da6dd 100644 --- a/Makefile +++ b/Makefile @@ -194,6 +194,8 @@ all:: # # Define USE_NED_ALLOCATOR if you want to replace the platforms default # memory allocators with the nedmalloc allocator written by Niall Douglas. +# +# Define NO_REGEX if you have no or inferior regex support in your C library. GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE @$(SHELL_PATH) ./GIT-VERSION-GEN @@ -884,9 +886,10 @@ ifneq (,$(findstring MINGW,$(uname_S))) USE_NED_ALLOCATOR = YesPlease UNRELIABLE_FSTAT = UnfortunatelyYes OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo - COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch + NO_REGEX = YesPlease + COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" - COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o + COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe ifneq (,$(wildcard ../THIS_IS_MSYSGIT)) @@ -1200,6 +1203,10 @@ endif ifdef UNRELIABLE_FSTAT BASIC_CFLAGS += -DUNRELIABLE_FSTAT endif +ifdef NO_REGEX + COMPAT_CFLAGS += -Icompat/regex + COMPAT_OBJS += compat/regex/regex.o +endif ifdef USE_NED_ALLOCATOR COMPAT_CFLAGS += -DUSE_NED_ALLOCATOR -DOVERRIDE_STRDUP -DNDEBUG -DREPLACE_SYSTEM_ALLOCATOR -Icompat/nedmalloc From ee78cac22b3e5e3f93898361b87a38b488c5592e Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 16 Jun 2009 15:08:21 -0400 Subject: [PATCH 16/86] Makefile: use compat regex on Solaris The system regex is either slow or buggy for complex patterns, like the built-in xfuncname pattern for java files. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 0cb21da6dd..3bd0c08f4b 100644 --- a/Makefile +++ b/Makefile @@ -725,6 +725,7 @@ ifeq ($(uname_S),SunOS) NO_MEMMEM = YesPlease NO_MKDTEMP = YesPlease NO_MKSTEMPS = YesPlease + NO_REGEX = YesPlease ifeq ($(uname_R),5.7) NEEDS_RESOLV = YesPlease NO_IPV6 = YesPlease From 30dd916348001e4313708473d91d633d3b14d1b5 Mon Sep 17 00:00:00 2001 From: Mark Lodato Date: Wed, 27 May 2009 23:16:02 -0400 Subject: [PATCH 17/86] http.c: prompt for SSL client certificate password If an SSL client certificate is enabled (via http.sslcert or GIT_SSL_CERT), prompt for the certificate password rather than defaulting to OpenSSL's password prompt. This causes the prompt to only appear once each run. Previously, OpenSSL prompted the user *many* times, causing git to be unusable over HTTPS with client-side certificates. Note that the password is stored in memory in the clear while the program is running. This may be a security problem if git crashes and core dumps. The user is always prompted, even if the certificate is not encrypted. This should be fine; unencrypted certificates are rare and a security risk anyway. Signed-off-by: Mark Lodato Signed-off-by: Junio C Hamano --- http.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/http.c b/http.c index 2e3d6493ef..1c138135d7 100644 --- a/http.c +++ b/http.c @@ -27,6 +27,17 @@ static int curl_ftp_no_epsv; static const char *curl_http_proxy; static char *user_name, *user_pass; +#if LIBCURL_VERSION_NUM >= 0x071700 +/* Use CURLOPT_KEYPASSWD as is */ +#elif LIBCURL_VERSION_NUM >= 0x070903 +#define CURLOPT_KEYPASSWD CURLOPT_SSLKEYPASSWD +#else +#define CURLOPT_KEYPASSWD CURLOPT_SSLCERTPASSWD +#endif + +static char *ssl_cert_password; +static int ssl_cert_password_required; + static struct curl_slist *pragma_header; static struct active_request_slot *active_queue_head; @@ -167,6 +178,22 @@ static void init_curl_http_auth(CURL *result) } } +static int has_cert_password(void) +{ + if (ssl_cert_password != NULL) + return 1; + if (ssl_cert == NULL || ssl_cert_password_required != 1) + return 0; + /* Only prompt the user once. */ + ssl_cert_password_required = -1; + ssl_cert_password = getpass("Certificate Password: "); + if (ssl_cert_password != NULL) { + ssl_cert_password = xstrdup(ssl_cert_password); + return 1; + } else + return 0; +} + static CURL *get_curl_handle(void) { CURL *result = curl_easy_init(); @@ -189,6 +216,8 @@ static CURL *get_curl_handle(void) if (ssl_cert != NULL) curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert); + if (has_cert_password()) + curl_easy_setopt(result, CURLOPT_KEYPASSWD, ssl_cert_password); #if LIBCURL_VERSION_NUM >= 0x070902 if (ssl_key != NULL) curl_easy_setopt(result, CURLOPT_SSLKEY, ssl_key); @@ -329,8 +358,11 @@ void http_init(struct remote *remote) if (getenv("GIT_CURL_FTP_NO_EPSV")) curl_ftp_no_epsv = 1; - if (remote && remote->url && remote->url[0]) + if (remote && remote->url && remote->url[0]) { http_auth_init(remote->url[0]); + if (!prefixcmp(remote->url[0], "https://")) + ssl_cert_password_required = 1; + } #ifndef NO_CURL_EASY_DUPHANDLE curl_default = get_curl_handle(); @@ -370,6 +402,13 @@ void http_cleanup(void) free((void *)curl_http_proxy); curl_http_proxy = NULL; } + + if (ssl_cert_password != NULL) { + memset(ssl_cert_password, 0, strlen(ssl_cert_password)); + free(ssl_cert_password); + ssl_cert_password = NULL; + } + ssl_cert_password_required = 0; } struct active_request_slot *get_active_slot(void) From 754ae192a4390baeb4d00b96e72c69023efb22ee Mon Sep 17 00:00:00 2001 From: Mark Lodato Date: Wed, 27 May 2009 23:16:03 -0400 Subject: [PATCH 18/86] http.c: add http.sslCertPasswordProtected option Add a configuration option, http.sslCertPasswordProtected, and associated environment variable, GIT_SSL_CERT_PASSWORD_PROTECTED, to enable SSL client certificate password prompt from within git. If this option is false and if the environment variable does not exist, git falls back to OpenSSL's prompts (as in earlier versions of git). The environment variable may only be used to enable, not to disable git's password prompt. This behavior mimics GIT_NO_VERIFY; the mere existence of the variable is all that is checked. Signed-off-by: Mark Lodato Signed-off-by: Junio C Hamano --- Documentation/config.txt | 6 ++++++ http.c | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 3a86d1f8f0..2649b303fa 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1043,6 +1043,12 @@ http.sslKey:: over HTTPS. Can be overridden by the 'GIT_SSL_KEY' environment variable. +http.sslCertPasswordProtected:: + Enable git's password prompt for the SSL certificate. Otherwise + OpenSSL will prompt the user, possibly many times, if the + certificate or private key is encrypted. Can be overridden by the + 'GIT_SSL_CERT_PASSWORD_PROTECTED' environment variable. + http.sslCAInfo:: File containing the certificates to verify the peer with when fetching or pushing over HTTPS. Can be overridden by the diff --git a/http.c b/http.c index 1c138135d7..1b140d381d 100644 --- a/http.c +++ b/http.c @@ -140,6 +140,11 @@ static int http_options(const char *var, const char *value, void *cb) #endif if (!strcmp("http.sslcainfo", var)) return git_config_string(&ssl_cainfo, var, value); + if (!strcmp("http.sslcertpasswordprotected", var)) { + if (git_config_bool(var, value)) + ssl_cert_password_required = 1; + return 0; + } #ifdef USE_CURL_MULTI if (!strcmp("http.maxrequests", var)) { max_requests = git_config_int(var, value); @@ -360,7 +365,9 @@ void http_init(struct remote *remote) if (remote && remote->url && remote->url[0]) { http_auth_init(remote->url[0]); - if (!prefixcmp(remote->url[0], "https://")) + if (!ssl_cert_password_required && + getenv("GIT_SSL_CERT_PASSWORD_PROTECTED") && + !prefixcmp(remote->url[0], "https://")) ssl_cert_password_required = 1; } From 5d87dd4fcac808fc0f0b993b470644ba7d2d62a2 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 14 Jun 2009 22:38:51 +0200 Subject: [PATCH 19/86] daemon: send stderr of service programs to the syslog If git-daemon is run with --detach or --inetd, then stderr is explicitly redirected to /dev/null. But notice that the service programs were spawned via execl_git_cmd(), in particular, the stderr channel is inherited from the daemon. This means that errors that the programs wrote to stderr (for example, via die()), went to /dev/null. This patch arranges that the daemon does not merely exec the service program, but forks it and monitors stderr of the child; it writes the errors that it produces to the daemons log via logerror(). A consequence is that the daemon process remains in memory for the full duration of the service program, but this cannot be avoided. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- daemon.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/daemon.c b/daemon.c index b2babcc076..a7834efbab 100644 --- a/daemon.c +++ b/daemon.c @@ -1,6 +1,8 @@ #include "cache.h" #include "pkt-line.h" #include "exec_cmd.h" +#include "run-command.h" +#include "strbuf.h" #include @@ -343,28 +345,66 @@ static int run_service(char *dir, struct daemon_service *service) return service->fn(); } +static void copy_to_log(int fd) +{ + struct strbuf line = STRBUF_INIT; + FILE *fp; + + fp = fdopen(fd, "r"); + if (fp == NULL) { + logerror("fdopen of error channel failed"); + close(fd); + return; + } + + while (strbuf_getline(&line, fp, '\n') != EOF) { + logerror("%s", line.buf); + strbuf_setlen(&line, 0); + } + + strbuf_release(&line); + fclose(fp); +} + +static int run_service_command(const char **argv) +{ + struct child_process cld; + + memset(&cld, 0, sizeof(cld)); + cld.argv = argv; + cld.git_cmd = 1; + cld.err = -1; + if (start_command(&cld)) + return -1; + + close(0); + close(1); + + copy_to_log(cld.err); + + return finish_command(&cld); +} + static int upload_pack(void) { /* Timeout as string */ char timeout_buf[64]; + const char *argv[] = { "upload-pack", "--strict", timeout_buf, ".", NULL }; snprintf(timeout_buf, sizeof timeout_buf, "--timeout=%u", timeout); - - /* git-upload-pack only ever reads stuff, so this is safe */ - execl_git_cmd("upload-pack", "--strict", timeout_buf, ".", NULL); - return -1; + return run_service_command(argv); } static int upload_archive(void) { - execl_git_cmd("upload-archive", ".", NULL); - return -1; + static const char *argv[] = { "upload-archive", ".", NULL }; + return run_service_command(argv); } static int receive_pack(void) { - execl_git_cmd("receive-pack", ".", NULL); - return -1; + static const char *argv[] = { "receive-pack", ".", NULL }; + return run_service_command(argv); } static struct daemon_service daemon_service[] = { From 9462e3f59cd5a545330a9490a27d68b79f1d0ce7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 16 Jun 2009 20:41:16 +0200 Subject: [PATCH 20/86] upload-pack: squelch progress indicator if client cannot see it upload-pack runs pack-objects, which generates progress indicator output on its stderr. If the client requests a sideband, this indicator is sent to the client; but if it did not, then the progress is written to upload-pack's own stderr. If upload-pack is itself run from git-daemon (and if the client did not request a sideband) the progress indicator never reaches the client and it need not be generated in the first place. With this patch the progress indicator is suppressed in this situation. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- upload-pack.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/upload-pack.c b/upload-pack.c index edc7861228..841ebb534a 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -28,7 +28,7 @@ static unsigned long oldest_have; static int multi_ack, nr_our_refs; static int use_thin_pack, use_ofs_delta, use_include_tag; -static int no_progress; +static int no_progress, daemon_mode; static struct object_array have_obj; static struct object_array want_obj; static unsigned int timeout; @@ -521,6 +521,10 @@ static void receive_needs(void) } if (debug_fd) write_in_full(debug_fd, "#E\n", 3); + + if (!use_sideband && daemon_mode) + no_progress = 1; + if (depth == 0 && shallows.nr == 0) return; if (depth > 0) { @@ -630,6 +634,7 @@ int main(int argc, char **argv) } if (!prefixcmp(arg, "--timeout=")) { timeout = atoi(arg+10); + daemon_mode = 1; continue; } if (!strcmp(arg, "--")) { From 0e987a12fc1d481d81ad9c56f4714efb08667213 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Jun 2009 15:33:01 -0700 Subject: [PATCH 21/86] am, rebase: teach quiet option git-am and git-rebase are talkative scripts. Teach them to be quiet when told, allowing them to speak only when they fail or experience errors. The quiet option is maintained when git-am or git-rebase fails to apply a patch. This means subsequent --resolved, --continue, --skip, --abort invocations will be quiet if the original invocation was quiet. Drop a handful of >&2 redirection; the rest of the program sends all the info messages to stdout, not to stderr. Signed-off-by: Stephen Boyd Signed-off-by: Junio C Hamano --- Documentation/git-am.txt | 6 ++++- Documentation/git-rebase.txt | 4 +++ git-am.sh | 26 +++++++++++++------ git-rebase.sh | 48 ++++++++++++++++++++++++++++-------- t/t3400-rebase.sh | 19 +++++++++----- t/t4150-am.sh | 18 ++++++++++++++ 6 files changed, 97 insertions(+), 24 deletions(-) diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt index 6d92cbee64..32e689b2bf 100644 --- a/Documentation/git-am.txt +++ b/Documentation/git-am.txt @@ -13,7 +13,7 @@ SYNOPSIS [--3way] [--interactive] [--committer-date-is-author-date] [--ignore-date] [--whitespace=