From 9991030c0c97285087e5da86cfdbaf143a8a74cb Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Wed, 4 Jun 2008 22:48:42 -0700 Subject: [PATCH 001/654] git-blame: refactor code to emit "porcelain format" output Both the --porcelain and --incremental format shared the same output format but implemented with two identical codepaths. This merges them into one shared function. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-blame.c | 65 +++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/builtin-blame.c b/builtin-blame.c index 48cc0c175d..163d2dc34c 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -1490,6 +1490,34 @@ static void write_filename_info(const char *path) write_name_quoted(path, stdout, '\n'); } +/* + * Porcelain/Incremental format wants to show a lot of details per + * commit. Instead of repeating this every line, emit it only once, + * the first time each commit appears in the output. + */ +static int emit_one_suspect_detail(struct origin *suspect) +{ + struct commit_info ci; + + if (suspect->commit->object.flags & METAINFO_SHOWN) + return 0; + + suspect->commit->object.flags |= METAINFO_SHOWN; + get_commit_info(suspect->commit, &ci, 1); + printf("author %s\n", ci.author); + printf("author-mail %s\n", ci.author_mail); + printf("author-time %lu\n", ci.author_time); + printf("author-tz %s\n", ci.author_tz); + printf("committer %s\n", ci.committer); + printf("committer-mail %s\n", ci.committer_mail); + printf("committer-time %lu\n", ci.committer_time); + printf("committer-tz %s\n", ci.committer_tz); + printf("summary %s\n", ci.summary); + if (suspect->commit->object.flags & UNINTERESTING) + printf("boundary\n"); + return 1; +} + /* * The blame_entry is found to be guilty for the range. Mark it * as such, and show it in incremental output. @@ -1505,22 +1533,7 @@ static void found_guilty_entry(struct blame_entry *ent) printf("%s %d %d %d\n", sha1_to_hex(suspect->commit->object.sha1), ent->s_lno + 1, ent->lno + 1, ent->num_lines); - if (!(suspect->commit->object.flags & METAINFO_SHOWN)) { - struct commit_info ci; - suspect->commit->object.flags |= METAINFO_SHOWN; - get_commit_info(suspect->commit, &ci, 1); - printf("author %s\n", ci.author); - printf("author-mail %s\n", ci.author_mail); - printf("author-time %lu\n", ci.author_time); - printf("author-tz %s\n", ci.author_tz); - printf("committer %s\n", ci.committer); - printf("committer-mail %s\n", ci.committer_mail); - printf("committer-time %lu\n", ci.committer_time); - printf("committer-tz %s\n", ci.committer_tz); - printf("summary %s\n", ci.summary); - if (suspect->commit->object.flags & UNINTERESTING) - printf("boundary\n"); - } + emit_one_suspect_detail(suspect); write_filename_info(suspect->path); maybe_flush_or_die(stdout, "stdout"); } @@ -1627,24 +1640,8 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent) ent->s_lno + 1, ent->lno + 1, ent->num_lines); - if (!(suspect->commit->object.flags & METAINFO_SHOWN)) { - struct commit_info ci; - suspect->commit->object.flags |= METAINFO_SHOWN; - get_commit_info(suspect->commit, &ci, 1); - printf("author %s\n", ci.author); - printf("author-mail %s\n", ci.author_mail); - printf("author-time %lu\n", ci.author_time); - printf("author-tz %s\n", ci.author_tz); - printf("committer %s\n", ci.committer); - printf("committer-mail %s\n", ci.committer_mail); - printf("committer-time %lu\n", ci.committer_time); - printf("committer-tz %s\n", ci.committer_tz); - write_filename_info(suspect->path); - printf("summary %s\n", ci.summary); - if (suspect->commit->object.flags & UNINTERESTING) - printf("boundary\n"); - } - else if (suspect->commit->object.flags & MORE_THAN_ONE_PATH) + if (emit_one_suspect_detail(suspect) || + (suspect->commit->object.flags & MORE_THAN_ONE_PATH)) write_filename_info(suspect->path); cp = nth_line(sb, ent->lno); From 96e117099c0e4f7d508eb071f60b6275038f6f37 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Wed, 4 Jun 2008 22:58:40 -0700 Subject: [PATCH 002/654] blame: show "previous" information in --porcelain/--incremental format When the final blame is laid for a line to a <commit, path> pair, it also gives a "previous" information to --porcelain and --incremental output format. It gives the parent commit of the blamed commit, _and_ a path in that parent commit that corresponds to the blamed path --- in short, it is the origin that would have been blamed (or passed blame through) for the line _if_ the blamed commit did not change that line. This unfortunately makes sanity checking of refcount quite complex, so I ripped it out for now. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-blame.c | 42 ++++++++++++------------------------------ 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/builtin-blame.c b/builtin-blame.c index 163d2dc34c..e386120596 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -73,6 +73,7 @@ static unsigned blame_copy_score; */ struct origin { int refcnt; + struct origin *previous; struct commit *commit; mmfile_t file; unsigned char blob_sha1[20]; @@ -114,6 +115,8 @@ static inline struct origin *origin_incref(struct origin *o) static void origin_decref(struct origin *o) { if (o && --o->refcnt <= 0) { + if (o->previous) + origin_decref(o->previous); free(o->file.ptr); free(o); } @@ -1292,6 +1295,10 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt) struct origin *porigin = sg_origin[i]; if (!porigin) continue; + if (!origin->previous) { + origin_incref(porigin); + origin->previous = porigin; + } if (pass_blame_to_parent(sb, origin, porigin)) goto finish; } @@ -1515,6 +1522,11 @@ static int emit_one_suspect_detail(struct origin *suspect) printf("summary %s\n", ci.summary); if (suspect->commit->object.flags & UNINTERESTING) printf("boundary\n"); + if (suspect->previous) { + struct origin *prev = suspect->previous; + printf("previous %s ", sha1_to_hex(prev->commit->object.sha1)); + write_name_quoted(prev->path, stdout, '\n'); + } return 1; } @@ -1878,36 +1890,6 @@ static void sanity_check_refcnt(struct scoreboard *sb) baa = 1; } } - for (ent = sb->ent; ent; ent = ent->next) { - /* Mark the ones that haven't been checked */ - if (0 < ent->suspect->refcnt) - ent->suspect->refcnt = -ent->suspect->refcnt; - } - for (ent = sb->ent; ent; ent = ent->next) { - /* - * ... then pick each and see if they have the the - * correct refcnt. - */ - int found; - struct blame_entry *e; - struct origin *suspect = ent->suspect; - - if (0 < suspect->refcnt) - continue; - suspect->refcnt = -suspect->refcnt; /* Unmark */ - for (found = 0, e = sb->ent; e; e = e->next) { - if (e->suspect != suspect) - continue; - found++; - } - if (suspect->refcnt != found) { - fprintf(stderr, "%s in %s has refcnt %d, not %d\n", - ent->suspect->path, - sha1_to_hex(ent->suspect->commit->object.sha1), - ent->suspect->refcnt, found); - baa = 2; - } - } if (baa) { int opt = 0160; find_alignment(sb, &opt); From 06569cd5bef7c8e3925bd36870abc083ae7b93f8 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov <angavrilov@gmail.com> Date: Sat, 24 Jan 2009 00:18:13 +0300 Subject: [PATCH 003/654] git-gui: Fix post-commit status with subject in non-locale encoding As pointed out in msysgit bug #181, when a non-locale encoding is used for commits, post-commit status messages display the subject incorrectly. It happens because the file handle is not properly configured before the subject is read back. This patch fixes it by factoring out the code that is used to setup the output handle into a separate function, and calling it from the reading code. Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com> Acked-by: Robin Rosenberg <robin.rosenberg@gmail.com> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- lib/commit.tcl | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/commit.tcl b/lib/commit.tcl index 9cc8410595..17aba914af 100644 --- a/lib/commit.tcl +++ b/lib/commit.tcl @@ -115,6 +115,23 @@ proc create_new_commit {} { rescan ui_ready } +proc setup_commit_encoding {msg_wt {quiet 0}} { + global repo_config + + if {[catch {set enc $repo_config(i18n.commitencoding)}]} { + set enc utf-8 + } + set use_enc [tcl_encoding $enc] + if {$use_enc ne {}} { + fconfigure $msg_wt -encoding $use_enc + } else { + if {!$quiet} { + error_popup [mc "warning: Tcl does not support encoding '%s'." $enc] + } + fconfigure $msg_wt -encoding utf-8 + } +} + proc commit_tree {} { global HEAD commit_type file_states ui_comm repo_config global pch_error @@ -200,16 +217,7 @@ A good commit message has the following format: set msg_p [gitdir GITGUI_EDITMSG] set msg_wt [open $msg_p w] fconfigure $msg_wt -translation lf - if {[catch {set enc $repo_config(i18n.commitencoding)}]} { - set enc utf-8 - } - set use_enc [tcl_encoding $enc] - if {$use_enc ne {}} { - fconfigure $msg_wt -encoding $use_enc - } else { - error_popup [mc "warning: Tcl does not support encoding '%s'." $enc] - fconfigure $msg_wt -encoding utf-8 - } + setup_commit_encoding $msg_wt puts $msg_wt $msg close $msg_wt @@ -362,6 +370,7 @@ A rescan will be automatically started now. append reflogm " ($commit_type)" } set msg_fd [open $msg_p r] + setup_commit_encoding $msg_fd 1 gets $msg_fd subject close $msg_fd append reflogm {: } $subject From 4e1be63c3b05fd379b51b611b7e869ff6977d8ab Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Wed, 4 Feb 2009 00:25:59 +0100 Subject: [PATCH 004/654] Add valgrind support in test scripts This patch adds the ability to use valgrind's memcheck tool to diagnose memory problems in Git while running the test scripts. It requires valgrind 3.4.0 or newer. It works by creating symlinks to a valgrind script, which have the same name as our Git binaries, and then putting that directory in front of the test script's PATH as well as set GIT_EXEC_PATH to that directory. Git scripts are symlinked from that directory directly. That way, Git binaries called by Git scripts are valgrinded, too. Valgrind can be used by specifying "GIT_TEST_OPTS=--valgrind" in the make invocation. Any invocation of git that finds any errors under valgrind will exit with failure code 126. Any valgrind output will go to the usual stderr channel for tests (i.e., /dev/null, unless -v has been specified). If you need to pass options to valgrind -- you might want to run another tool than memcheck, for example -- you can set the environment variable GIT_VALGRIND_OPTIONS. A few default suppressions are included, since libz seems to trigger quite a few false positives. We'll assume that libz works and that we can ignore any errors which are reported there. Note: it is safe to run the valgrind tests in parallel, as the links in t/valgrind/bin/ are created using proper locking. Initial patch and all the hard work by Jeff King. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/README | 8 +++++- t/test-lib.sh | 58 +++++++++++++++++++++++++++++++++++++++-- t/valgrind/.gitignore | 2 ++ t/valgrind/default.supp | 21 +++++++++++++++ t/valgrind/valgrind.sh | 13 +++++++++ 5 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 t/valgrind/.gitignore create mode 100644 t/valgrind/default.supp create mode 100755 t/valgrind/valgrind.sh diff --git a/t/README b/t/README index f208cf1db9..7560db5c02 100644 --- a/t/README +++ b/t/README @@ -39,7 +39,8 @@ this: * passed all 3 test(s) You can pass --verbose (or -v), --debug (or -d), and --immediate -(or -i) command line argument to the test. +(or -i) command line argument to the test, or by setting GIT_TEST_OPTS +appropriately before running "make". --verbose:: This makes the test more verbose. Specifically, the @@ -58,6 +59,11 @@ You can pass --verbose (or -v), --debug (or -d), and --immediate This causes additional long-running tests to be run (where available), for more exhaustive testing. +--valgrind:: + Execute all Git binaries with valgrind and exit with status + 126 on errors (just like regular tests, this will only stop + the test script when running under -i). Valgrind errors + go to stderr, so you might want to pass the -v option, too. Skipping Tests -------------- diff --git a/t/test-lib.sh b/t/test-lib.sh index 6f6244ab7e..da12b0aa43 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -94,6 +94,8 @@ do --no-python) # noop now... shift ;; + --va|--val|--valg|--valgr|--valgri|--valgrin|--valgrind) + valgrind=t; shift ;; *) break ;; esac @@ -492,8 +494,60 @@ test_done () { # Test the binaries we have just built. The tests are kept in # t/ subdirectory and are run in 'trash directory' subdirectory. TEST_DIRECTORY=$(pwd) -PATH=$TEST_DIRECTORY/..:$PATH -GIT_EXEC_PATH=$(pwd)/.. +if test -z "$valgrind" +then + PATH=$TEST_DIRECTORY/..:$PATH + GIT_EXEC_PATH=$TEST_DIRECTORY/.. +else + make_symlink () { + test -h "$2" && + test "$1" = "$(readlink "$2")" || { + # be super paranoid + if mkdir "$2".lock + then + rm -f "$2" && + ln -s "$1" "$2" && + rm -r "$2".lock + else + while test -d "$2".lock + do + say "Waiting for lock on $2." + sleep 1 + done + fi + } + } + + make_valgrind_symlink () { + # handle only executables + test -x "$1" || return + + base=$(basename "$1") + symlink_target=$TEST_DIRECTORY/../$base + # do not override scripts + if test -x "$symlink_target" && + test ! -d "$symlink_target" && + test "#!" != "$(head -c 2 < "$symlink_target")" + then + symlink_target=../valgrind.sh + fi + # create the link, or replace it if it is out of date + make_symlink "$symlink_target" "$GIT_VALGRIND/bin/$base" || exit + } + + # override all git executables in TEST_DIRECTORY/.. + GIT_VALGRIND=$TEST_DIRECTORY/valgrind + mkdir -p "$GIT_VALGRIND"/bin + for file in $TEST_DIRECTORY/../git* $TEST_DIRECTORY/../test-* + do + make_valgrind_symlink $file + done + PATH=$GIT_VALGRIND/bin:$PATH + GIT_EXEC_PATH=$GIT_VALGRIND/bin + export GIT_VALGRIND + + make_symlink ../../../templates "$GIT_VALGRIND"/bin/templates || exit +fi GIT_TEMPLATE_DIR=$(pwd)/../templates/blt unset GIT_CONFIG GIT_CONFIG_NOSYSTEM=1 diff --git a/t/valgrind/.gitignore b/t/valgrind/.gitignore new file mode 100644 index 0000000000..d4ae6676d1 --- /dev/null +++ b/t/valgrind/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/templates diff --git a/t/valgrind/default.supp b/t/valgrind/default.supp new file mode 100644 index 0000000000..2482b3b06a --- /dev/null +++ b/t/valgrind/default.supp @@ -0,0 +1,21 @@ +{ + ignore-zlib-errors-cond + Memcheck:Cond + obj:*libz.so* +} + +{ + ignore-zlib-errors-value4 + Memcheck:Value4 + obj:*libz.so* +} + +{ + writing-data-from-zlib-triggers-errors + Memcheck:Param + write(buf) + obj:/lib/ld-*.so + fun:write_in_full + fun:write_buffer + fun:write_loose_object +} diff --git a/t/valgrind/valgrind.sh b/t/valgrind/valgrind.sh new file mode 100755 index 0000000000..dc9261265b --- /dev/null +++ b/t/valgrind/valgrind.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +base=$(basename "$0") + +exec valgrind -q --error-exitcode=126 \ + --leak-check=no \ + --suppressions="$GIT_VALGRIND/default.supp" \ + --gen-suppressions=all \ + --track-origins=yes \ + --log-fd=4 \ + --input-fd=4 \ + $GIT_VALGRIND_OPTIONS \ + "$GIT_VALGRIND"/../../"$base" "$@" From 6a7e37c99f733821bd3a17432fa6e4591b63866c Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Wed, 4 Feb 2009 00:26:03 +0100 Subject: [PATCH 005/654] valgrind: ignore ldso and more libz errors On some Linux systems, we get a host of Cond and Addr errors from calls to dlopen that are caused by nss modules. We should be able to safely ignore anything happening in ld-*.so as "not our problem." [Johannes: I added some more... unfortunately using valgrind 3.4.0 syntax] Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/valgrind/default.supp | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/t/valgrind/default.supp b/t/valgrind/default.supp index 2482b3b06a..5f341b8598 100644 --- a/t/valgrind/default.supp +++ b/t/valgrind/default.supp @@ -4,6 +4,12 @@ obj:*libz.so* } +{ + ignore-zlib-errors-value8 + Memcheck:Value8 + obj:*libz.so* +} + { ignore-zlib-errors-value4 Memcheck:Value4 @@ -11,11 +17,27 @@ } { - writing-data-from-zlib-triggers-errors + ignore-ldso-cond + Memcheck:Cond + obj:*ld-*.so +} + +{ + ignore-ldso-addr8 + Memcheck:Addr8 + obj:*ld-*.so +} + +{ + ignore-ldso-addr4 + Memcheck:Addr4 + obj:*ld-*.so +} + +{ + writing-data-from-zlib-triggers-even-more-errors Memcheck:Param write(buf) - obj:/lib/ld-*.so - fun:write_in_full - fun:write_buffer + ... fun:write_loose_object } From efd92ffd316d03360e1c8a348091e4f50f749d6f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Wed, 4 Feb 2009 00:26:08 +0100 Subject: [PATCH 006/654] Valgrind support: check for more than just programming errors This patch makes --valgrind try to override _all_ Git binaries in the PATH, and it makes it an error to call *.sh and *.perl scripts directly. While it is not strictly necessary to look through the whole PATH to find git binaries to override, it is in line with running an expensive test (which valgrind is) to make extra sure that only binaries are tested that actually come from the git.git checkout. In the same spirit, we can test that neither our test suite nor our scripts try to run the *.sh or *.perl scripts directly. It's more like a "because we can" than a "this is tightly connected to valgrind", but in the author's opinion "because we can" is "so we should" in this case. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/test-lib.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index da12b0aa43..5a58356c72 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -531,6 +531,10 @@ else then symlink_target=../valgrind.sh fi + case "$base" in + *.sh|*.perl) + symlink_target=../unprocessed-script + esac # create the link, or replace it if it is out of date make_symlink "$symlink_target" "$GIT_VALGRIND/bin/$base" || exit } @@ -542,6 +546,17 @@ else do make_valgrind_symlink $file done + OLDIFS=$IFS + IFS=: + for path in $PATH + do + ls "$path"/git-* 2> /dev/null | + while read file + do + make_valgrind_symlink "$file" + done + done + IFS=$OLDIFS PATH=$GIT_VALGRIND/bin:$PATH GIT_EXEC_PATH=$GIT_VALGRIND/bin export GIT_VALGRIND From 44138559e8b7c89768a2450220b831847059311c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Wed, 4 Feb 2009 00:26:12 +0100 Subject: [PATCH 007/654] test-lib.sh: optionally output to test-results/$TEST.out, too When tests are run in parallel and a few tests fail, it does not help that the output of the terminal is totally confusing, as you rarely know which test which line came from. So introduce the option '--tee' which triggers that the output of the tests will be written to t/test-results/$TEST.out in addition to the terminal, where $TEST is the basename of the script. Unfortunately, there seems to be no way to redirect a given file descriptor to a specified subprocess in POSIX shell, only redirection to a file is supported via 'exec > $FILE'. At least with bash, one might think that 'exec >($COMMAND)' would work as intended, but it does not. The common way to work around the lack of proper tools support is to work with named pipes, alas, one of our most beloved platforms does not really support named pipes. Besides, we would need a pipe for every script, as the whole point of this patch is to allow parallel execution. Therefore, we handle the redirection in the following way: when '--tee' was passed to the test script, the variable GIT_TEST_TEE_STARTED is set (to avoid triggering that code path again) and the script is started _again_, in a subshell, redirected to the command "tee". Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/README | 6 ++++++ t/test-lib.sh | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/t/README b/t/README index 7560db5c02..ed1ebb6a5c 100644 --- a/t/README +++ b/t/README @@ -65,6 +65,12 @@ appropriately before running "make". the test script when running under -i). Valgrind errors go to stderr, so you might want to pass the -v option, too. +--tee:: + In addition to printing the test output to the terminal, + write it to files named 't/test-results/$TEST_NAME.out'. + As the names depend on the tests' file names, it is safe to + run the tests with this option in parallel. + Skipping Tests -------------- diff --git a/t/test-lib.sh b/t/test-lib.sh index 5a58356c72..34f372c92f 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -3,6 +3,22 @@ # Copyright (c) 2005 Junio C Hamano # +# if --tee was passed, write the output not only to the terminal, but +# additionally to the file test-results/$BASENAME.out, too. +case "$GIT_TEST_TEE_STARTED, $* " in +done,*) + # do not redirect again + ;; +*' --tee '*) + mkdir -p test-results + BASE=test-results/$(basename "$0" .sh) + (GIT_TEST_TEE_STARTED=done ${SHELL-sh} "$0" "$@" 2>&1; + echo $? > $BASE.exit) | tee $BASE.out + test "$(cat $BASE.exit)" = 0 + exit + ;; +esac + # Keep the original TERM for say_color ORIGINAL_TERM=$TERM @@ -96,6 +112,8 @@ do shift ;; --va|--val|--valg|--valgr|--valgri|--valgrin|--valgrind) valgrind=t; shift ;; + --tee) + shift ;; # was handled already *) break ;; esac From 7f6fdea1198cd7599c25cf9435df8540e9378a15 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Wed, 4 Feb 2009 00:26:18 +0100 Subject: [PATCH 008/654] t/Makefile: provide a 'valgrind' target It is easy to forget running valgrinded tests without -v, and it is also easy to forget to redirect the output to "tee" (lest the output scroll out of the terminal's buffer). Running "make valgrind" will take care of all that. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/t/Makefile b/t/Makefile index ed49c20b16..e544493d10 100644 --- a/t/Makefile +++ b/t/Makefile @@ -38,4 +38,7 @@ full-svn-test: $(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=1 LC_ALL=C $(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=0 LC_ALL=en_US.UTF-8 -.PHONY: pre-clean $(T) aggregate-results clean +valgrind: + GIT_TEST_OPTS='--valgrind -v --tee' $(MAKE) -k + +.PHONY: pre-clean $(T) aggregate-results clean valgrind From 268fac6919ef673094e50e2d944d09f017f5ad33 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Wed, 4 Feb 2009 00:26:22 +0100 Subject: [PATCH 009/654] Add a script to coalesce the valgrind outputs After running the valgrind tests with GIT_TEST_TREE=t, the test output is in the test-results/$TEST.out files. Call ./valgrind/analyze.sh in $GIT_ROOT/t/ to group the valgrind errors by backtrace. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/valgrind/analyze.sh | 123 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100755 t/valgrind/analyze.sh diff --git a/t/valgrind/analyze.sh b/t/valgrind/analyze.sh new file mode 100755 index 0000000000..d8105d9fab --- /dev/null +++ b/t/valgrind/analyze.sh @@ -0,0 +1,123 @@ +#!/bin/sh + +out_prefix=$(dirname "$0")/../test-results/valgrind.out +output= +count=0 +total_count=0 +missing_message= +new_line=' +' + +# start outputting the current valgrind error in $out_prefix.++$count, +# and the test case which failed in the corresponding .message file +start_output () { + test -z "$output" || return + + # progress + total_count=$(($total_count+1)) + test -t 2 && printf "\rFound %d errors" $total_count >&2 + + count=$(($count+1)) + output=$out_prefix.$count + : > $output + + echo "*** $1 ***" > $output.message +} + +finish_output () { + test ! -z "$output" || return + output= + + # if a test case has more than one valgrind error, we need to + # copy the last .message file to the previous errors + test -z "$missing_message" || { + while test $missing_message -lt $count + do + cp $out_prefix.$count.message \ + $out_prefix.$missing_message.message + missing_message=$(($missing_message+1)) + done + missing_message= + } +} + +# group the valgrind errors by backtrace +output_all () { + last_line= + j=0 + i=1 + while test $i -le $count + do + # output <number> <backtrace-in-one-line> + echo "$i $(tr '\n' ' ' < $out_prefix.$i)" + i=$(($i+1)) + done | + sort -t ' ' -k 2 | # order by <backtrace-in-one-line> + while read number line + do + # find duplicates, do not output backtrace twice + if test "$line" != "$last_line" + then + last_line=$line + j=$(($j+1)) + printf "\nValgrind error $j:\n\n" + cat $out_prefix.$number + printf "\nfound in:\n" + fi + # print the test case where this came from + printf "\n" + cat $out_prefix.$number.message + done +} + +handle_one () { + OLDIFS=$IFS + IFS="$new_line" + while read line + do + case "$line" in + # backtrace, possibly a new one + ==[0-9]*) + + # Does the current valgrind error have a message yet? + case "$output" in + *.message) + test -z "$missing_message" && + missing_message=$count + output= + esac + + start_output $(basename $1) + echo "$line" | + sed 's/==[0-9]*==/==valgrind==/' >> $output + ;; + # end of backtrace + '}') + test -z "$output" || { + echo "$line" >> $output + test $output = ${output%.message} && + output=$output.message + } + ;; + # end of test case + '') + finish_output + ;; + # normal line; if $output is set, print the line + *) + test -z "$output" || echo "$line" >> $output + ;; + esac + done < $1 + IFS=$OLDIFS + + # just to be safe + finish_output +} + +for test_script in "$(dirname "$0")"/../test-results/*.out +do + handle_one $test_script +done + +output_all From 3da936523445eb7a74dfe3ab1fe0ce82fac56174 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Wed, 4 Feb 2009 00:26:26 +0100 Subject: [PATCH 010/654] Tests: let --valgrind imply --verbose and --tee It does not make much sense to run the (expensive) valgrind tests and not look at the output. To prevent output from scrolling out of reach, the parameter --tee is implied, too. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/Makefile | 2 +- t/README | 4 ++++ t/test-lib.sh | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/t/Makefile b/t/Makefile index e544493d10..09623414a7 100644 --- a/t/Makefile +++ b/t/Makefile @@ -39,6 +39,6 @@ full-svn-test: $(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=0 LC_ALL=en_US.UTF-8 valgrind: - GIT_TEST_OPTS='--valgrind -v --tee' $(MAKE) -k + GIT_TEST_OPTS=--valgrind $(MAKE) .PHONY: pre-clean $(T) aggregate-results clean valgrind diff --git a/t/README b/t/README index ed1ebb6a5c..d8f6c7de6d 100644 --- a/t/README +++ b/t/README @@ -65,6 +65,10 @@ appropriately before running "make". the test script when running under -i). Valgrind errors go to stderr, so you might want to pass the -v option, too. + Since it makes no sense to run the tests with --valgrind and + not see any output, this option implies --verbose. For + convenience, it also implies --tee. + --tee:: In addition to printing the test output to the terminal, write it to files named 't/test-results/$TEST_NAME.out'. diff --git a/t/test-lib.sh b/t/test-lib.sh index 34f372c92f..bc87936bab 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -9,7 +9,7 @@ case "$GIT_TEST_TEE_STARTED, $* " in done,*) # do not redirect again ;; -*' --tee '*) +*' --tee '*|*' --va'*) mkdir -p test-results BASE=test-results/$(basename "$0" .sh) (GIT_TEST_TEE_STARTED=done ${SHELL-sh} "$0" "$@" 2>&1; @@ -111,7 +111,7 @@ do # noop now... shift ;; --va|--val|--valg|--valgr|--valgri|--valgrin|--valgrind) - valgrind=t; shift ;; + valgrind=t; verbose=t; shift ;; --tee) shift ;; # was handled already *) From a6d63b749369f3ba9c6d2f382efd27838604b7db Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Wed, 4 Feb 2009 00:26:31 +0100 Subject: [PATCH 011/654] test-lib: avoid assuming that templates/ are in the GIT_EXEC_PATH Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/test-lib.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index bc87936bab..20214468ae 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -454,7 +454,7 @@ test_create_repo () { repo="$1" mkdir -p "$repo" cd "$repo" || error "Cannot setup test environment" - "$GIT_EXEC_PATH/git" init "--template=$GIT_EXEC_PATH/templates/blt/" >&3 2>&4 || + "$GIT_EXEC_PATH/git" init "--template=$owd/../templates/blt/" >&3 2>&4 || error "cannot run git init -- have you built things yet?" mv .git/hooks .git/hooks-disabled cd "$owd" @@ -578,8 +578,6 @@ else PATH=$GIT_VALGRIND/bin:$PATH GIT_EXEC_PATH=$GIT_VALGRIND/bin export GIT_VALGRIND - - make_symlink ../../../templates "$GIT_VALGRIND"/bin/templates || exit fi GIT_TEMPLATE_DIR=$(pwd)/../templates/blt unset GIT_CONFIG From 5caa81d1b4f1b0b9ed73605ab1e4d91ba31a56b4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Thu, 5 Feb 2009 22:03:00 +0100 Subject: [PATCH 012/654] valgrind: do not require valgrind 3.4.0 or newer Valgrind 3.4.0 is pretty new, and even if --track-origins is a nice feature, it is not the end of the world if that is not available. So play nice and use that option only when only an older version of valgrind is available. In the same spirit, refrain from the use of '...' in suppression files, which is also a feature only valgrind 3.4 and newer understand. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/valgrind/default.supp | 4 +++- t/valgrind/valgrind.sh | 11 ++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/t/valgrind/default.supp b/t/valgrind/default.supp index 5f341b8598..9e013fa3b2 100644 --- a/t/valgrind/default.supp +++ b/t/valgrind/default.supp @@ -38,6 +38,8 @@ writing-data-from-zlib-triggers-even-more-errors Memcheck:Param write(buf) - ... + obj:/lib/ld-*.so + fun:write_in_full + fun:write_buffer fun:write_loose_object } diff --git a/t/valgrind/valgrind.sh b/t/valgrind/valgrind.sh index dc9261265b..582b4dca94 100755 --- a/t/valgrind/valgrind.sh +++ b/t/valgrind/valgrind.sh @@ -2,11 +2,20 @@ base=$(basename "$0") +TRACK_ORIGINS= + +VALGRIND_VERSION=$(valgrind --version) +VALGRIND_MAJOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*\([0-9]*\)') +VALGRIND_MINOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*[0-9]*\.\([0-9]*\)') +test 3 -gt "$VALGRIND_MAJOR" || +test 3 -eq "$VALGRIND_MAJOR" -a 4 -gt "$VALGRIND_MINOR" || +TRACK_ORIGINS=--track-origins=yes + exec valgrind -q --error-exitcode=126 \ --leak-check=no \ --suppressions="$GIT_VALGRIND/default.supp" \ --gen-suppressions=all \ - --track-origins=yes \ + $TRACK_ORIGINS \ --log-fd=4 \ --input-fd=4 \ $GIT_VALGRIND_OPTIONS \ From 584fa9ccf4b467e7633c100333cadf92e0c07894 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov <angavrilov@gmail.com> Date: Sat, 7 Feb 2009 19:24:01 +0300 Subject: [PATCH 013/654] git-gui: Avoid an infinite rescan loop in handle_empty_diff. If the index update machinery and git diff happen to disagree on whether a particular file is modified, it may cause git-gui to enter an infinite index rescan loop, where an empty diff starts a rescan, which finds the same set of files modified, and tries to display the diff for the first one, which happens to be the empty one. A current example of a possible disagreement point is the autocrlf filter. This patch breaks the loop by using a global counter to track the auto-rescans. The variable is reset whenever a non-empty diff is displayed. Another suggested approach, which is based on giving the --exit-code argument to git diff, cannot be used, because diff-files seems to trust the timestamps in the index, and returns a non-zero code even if the file is actually unchanged, which essentially defeats the purpose of the auto-rescan logic. Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- lib/diff.tcl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/diff.tcl b/lib/diff.tcl index bbbf15c875..925b3f56c1 100644 --- a/lib/diff.tcl +++ b/lib/diff.tcl @@ -51,11 +51,16 @@ proc force_diff_encoding {enc} { proc handle_empty_diff {} { global current_diff_path file_states file_lists + global diff_empty_count set path $current_diff_path set s $file_states($path) if {[lindex $s 0] ne {_M}} return + # Prevent infinite rescan loops + incr diff_empty_count + if {$diff_empty_count > 1} return + info_popup [mc "No differences detected. %s has no changes. @@ -310,6 +315,7 @@ proc read_diff {fd cont_info} { global ui_diff diff_active global is_3way_diff is_conflict_diff current_diff_header global current_diff_queue + global diff_empty_count $ui_diff conf -state normal while {[gets $fd line] >= 0} { @@ -415,7 +421,10 @@ proc read_diff {fd cont_info} { if {[$ui_diff index end] eq {2.0}} { handle_empty_diff + } else { + set diff_empty_count 0 } + set callback [lindex $cont_info 1] if {$callback ne {}} { eval $callback From 764369c5ea730894c75f32c2f94a651dd517fc5b Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov <angavrilov@gmail.com> Date: Sat, 7 Feb 2009 19:43:57 +0300 Subject: [PATCH 014/654] git-gui: Support more git version notations. Recently the msysgit repository has got a '1.6.1-msysgit1' tag, which, when used to build the git version, is not handled gracefully by the git-gui version code. This patch changes the regular expressions to fix it, and removes the hardcoded 'rc' string. Now git-gui can accept a version tail like '.foo123.GIT.bar.456.7.g89ab' Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- git-gui.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui.sh b/git-gui.sh index e018e076f8..2f1f305019 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -769,9 +769,9 @@ if {![regsub {^git version } $_git_version {} _git_version]} { set _real_git_version $_git_version regsub -- {[\-\.]dirty$} $_git_version {} _git_version regsub {\.[0-9]+\.g[0-9a-f]+$} $_git_version {} _git_version -regsub {\.rc[0-9]+$} $_git_version {} _git_version +regsub {\.[a-zA-Z]+\.?[0-9]+$} $_git_version {} _git_version regsub {\.GIT$} $_git_version {} _git_version -regsub {\.[a-zA-Z]+\.[0-9]+$} $_git_version {} _git_version +regsub {\.[a-zA-Z]+\.?[0-9]+$} $_git_version {} _git_version if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} { catch {wm withdraw .} From 3bec8ff99a7792cae67aaeb5892d832478d7f548 Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Sat, 7 Feb 2009 23:53:00 +0200 Subject: [PATCH 015/654] config: Add new option to open an editor. The idea was originated by discussion about usability of manually editing the config file in 'special needs' systems such as Windows. Now the user can forget a bit about where the config files actually are. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-config.txt | 6 ++++++ builtin-config.c | 13 ++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index 19a8917b83..7d140073b1 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -22,6 +22,7 @@ SYNOPSIS 'git config' [<file-option>] [-z|--null] -l | --list 'git config' [<file-option>] --get-color name [default] 'git config' [<file-option>] --get-colorbool name [stdout-is-tty] +'git config' [<file-option>] -e | --edit DESCRIPTION ----------- @@ -157,6 +158,11 @@ See also <<FILES>>. output. The optional `default` parameter is used instead, if there is no color configured for `name`. +-e:: +--edit:: + Opens an editor to modify the specified config file; either + '--system', '--global', or repository (default). + [[FILES]] FILES ----- diff --git a/builtin-config.c b/builtin-config.c index f71016204b..6937eaf379 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -3,7 +3,7 @@ #include "color.h" static const char git_config_set_usage[] = -"git config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int | --bool-or-int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty]"; +"git config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int | --bool-or-int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty] | --edit | -e ]"; static char *key; static regex_t *key_regexp; @@ -362,6 +362,17 @@ int cmd_config(int argc, const char **argv, const char *prefix) return get_color(argc-2, argv+2); } else if (!strcmp(argv[1], "--get-colorbool")) { return get_colorbool(argc-2, argv+2); + } else if (!strcmp(argv[1], "--edit") || !strcmp(argv[1], "-e")) { + const char *config_filename; + if (argc != 2) + usage(git_config_set_usage); + if (config_exclusive_filename) + config_filename = config_exclusive_filename; + else + config_filename = git_path("config"); + git_config(git_default_config, NULL); + launch_editor(config_filename, NULL, NULL); + return 0; } else break; argc--; From 60b458b7d31ff2497ed90cbe9f65444d84882cec Mon Sep 17 00:00:00 2001 From: Kjetil Barvik <barvik@broadpark.no> Date: Mon, 9 Feb 2009 21:54:04 +0100 Subject: [PATCH 016/654] lstat_cache(): small cleanup and optimisation Simplify the if-else test in longest_match_lstat_cache() such that we only have one simple if test. Instead of testing for 'i == cache.len' or 'i == len', we transform this to a common test for 'i == max_len'. And to further optimise we use 'i >= max_len' instead of 'i == max_len', the reason is that it is now the exact opposite of one part inside the while-loop termination expression 'i < max_len && name[i] == cache.path[i]', and then the compiler can probably reuse a test instruction from it. We also throw away the arguments to reset_lstat_cache(), such that all the safeguard logic inside lstat_cache() is handled at one place. Signed-off-by: Kjetil Barvik <barvik@broadpark.no> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- symlinks.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/symlinks.c b/symlinks.c index f262b7c44b..ae57e5603b 100644 --- a/symlinks.c +++ b/symlinks.c @@ -25,27 +25,30 @@ static inline int longest_match_lstat_cache(int len, const char *name, } i++; } - /* Is the cached path string a substring of 'name'? */ - if (i == cache.len && cache.len < len && name[cache.len] == '/') { + /* + * Is the cached path string a substring of 'name', is 'name' + * a substring of the cached path string, or is 'name' and the + * cached path string the exact same string? + */ + if (i >= max_len && ((len > cache.len && name[cache.len] == '/') || + (len < cache.len && cache.path[len] == '/') || + (len == cache.len))) { match_len_prev = match_len; - match_len = cache.len; - /* Is 'name' a substring of the cached path string? */ - } else if ((i == len && len < cache.len && cache.path[len] == '/') || - (i == len && len == cache.len)) { - match_len_prev = match_len; - match_len = len; + match_len = i; } *previous_slash = match_len_prev; return match_len; } -static inline void reset_lstat_cache(int track_flags, int prefix_len_stat_func) +static inline void reset_lstat_cache(void) { cache.path[0] = '\0'; cache.len = 0; cache.flags = 0; - cache.track_flags = track_flags; - cache.prefix_len_stat_func = prefix_len_stat_func; + /* + * The track_flags and prefix_len_stat_func members is only + * set by the safeguard rule inside lstat_cache() + */ } #define FL_DIR (1 << 0) @@ -77,11 +80,13 @@ static int lstat_cache(int len, const char *name, if (cache.track_flags != track_flags || cache.prefix_len_stat_func != prefix_len_stat_func) { /* - * As a safeguard we clear the cache if the values of - * track_flags and/or prefix_len_stat_func does not - * match with the last supplied values. + * As a safeguard rule we clear the cache if the + * values of track_flags and/or prefix_len_stat_func + * does not match with the last supplied values. */ - reset_lstat_cache(track_flags, prefix_len_stat_func); + reset_lstat_cache(); + cache.track_flags = track_flags; + cache.prefix_len_stat_func = prefix_len_stat_func; match_len = last_slash = 0; } else { /* @@ -153,7 +158,7 @@ static int lstat_cache(int len, const char *name, cache.path[last_slash] = '\0'; cache.len = last_slash; cache.flags = save_flags; - } else if (track_flags & FL_DIR && + } else if ((track_flags & FL_DIR) && last_slash_dir > 0 && last_slash_dir <= PATH_MAX) { /* * We have a separate test for the directory case, @@ -170,7 +175,7 @@ static int lstat_cache(int len, const char *name, cache.len = last_slash_dir; cache.flags = FL_DIR; } else { - reset_lstat_cache(track_flags, prefix_len_stat_func); + reset_lstat_cache(); } return ret_flags; } @@ -190,8 +195,7 @@ void invalidate_lstat_cache(int len, const char *name) cache.len = previous_slash; cache.flags = FL_DIR; } else - reset_lstat_cache(cache.track_flags, - cache.prefix_len_stat_func); + reset_lstat_cache(); } } @@ -200,7 +204,7 @@ void invalidate_lstat_cache(int len, const char *name) */ void clear_lstat_cache(void) { - reset_lstat_cache(0, 0); + reset_lstat_cache(); } #define USE_ONLY_LSTAT 0 From 148bc06b9101042342a89454a003998fc0e1ded3 Mon Sep 17 00:00:00 2001 From: Kjetil Barvik <barvik@broadpark.no> Date: Mon, 9 Feb 2009 21:54:05 +0100 Subject: [PATCH 017/654] lstat_cache(): generalise longest_match_lstat_cache() Rename the function to longst_path_match() and generalise it such that it can also be used by other functions. Signed-off-by: Kjetil Barvik <barvik@broadpark.no> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- symlinks.c | 70 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/symlinks.c b/symlinks.c index ae57e5603b..4596aee9dc 100644 --- a/symlinks.c +++ b/symlinks.c @@ -1,5 +1,37 @@ #include "cache.h" +/* + * Returns the length (on a path component basis) of the longest + * common prefix match of 'name_a' and 'name_b'. + */ +static int longest_path_match(const char *name_a, int len_a, + const char *name_b, int len_b, + int *previous_slash) +{ + int max_len, match_len = 0, match_len_prev = 0, i = 0; + + max_len = len_a < len_b ? len_a : len_b; + while (i < max_len && name_a[i] == name_b[i]) { + if (name_a[i] == '/') { + match_len_prev = match_len; + match_len = i; + } + i++; + } + /* + * Is 'name_b' a substring of 'name_a', the other way around, + * or is 'name_a' and 'name_b' the exact same string? + */ + if (i >= max_len && ((len_a > len_b && name_a[len_b] == '/') || + (len_a < len_b && name_b[len_a] == '/') || + (len_a == len_b))) { + match_len_prev = match_len; + match_len = i; + } + *previous_slash = match_len_prev; + return match_len; +} + static struct cache_def { char path[PATH_MAX + 1]; int len; @@ -8,38 +40,6 @@ static struct cache_def { int prefix_len_stat_func; } cache; -/* - * Returns the length (on a path component basis) of the longest - * common prefix match of 'name' and the cached path string. - */ -static inline int longest_match_lstat_cache(int len, const char *name, - int *previous_slash) -{ - int max_len, match_len = 0, match_len_prev = 0, i = 0; - - max_len = len < cache.len ? len : cache.len; - while (i < max_len && name[i] == cache.path[i]) { - if (name[i] == '/') { - match_len_prev = match_len; - match_len = i; - } - i++; - } - /* - * Is the cached path string a substring of 'name', is 'name' - * a substring of the cached path string, or is 'name' and the - * cached path string the exact same string? - */ - if (i >= max_len && ((len > cache.len && name[cache.len] == '/') || - (len < cache.len && cache.path[len] == '/') || - (len == cache.len))) { - match_len_prev = match_len; - match_len = i; - } - *previous_slash = match_len_prev; - return match_len; -} - static inline void reset_lstat_cache(void) { cache.path[0] = '\0'; @@ -94,7 +94,8 @@ static int lstat_cache(int len, const char *name, * the 2 "excluding" path types. */ match_len = last_slash = - longest_match_lstat_cache(len, name, &previous_slash); + longest_path_match(name, len, cache.path, cache.len, + &previous_slash); match_flags = cache.flags & track_flags & (FL_NOENT|FL_SYMLINK); if (match_flags && match_len == cache.len) return match_flags; @@ -188,7 +189,8 @@ void invalidate_lstat_cache(int len, const char *name) { int match_len, previous_slash; - match_len = longest_match_lstat_cache(len, name, &previous_slash); + match_len = longest_path_match(name, len, cache.path, cache.len, + &previous_slash); if (len == match_len) { if ((cache.track_flags & FL_DIR) && previous_slash > 0) { cache.path[previous_slash] = '\0'; From 571998921d8fd4ee674545406aabb86987921252 Mon Sep 17 00:00:00 2001 From: Kjetil Barvik <barvik@broadpark.no> Date: Mon, 9 Feb 2009 21:54:06 +0100 Subject: [PATCH 018/654] lstat_cache(): swap func(length, string) into func(string, length) Swap function argument pair (length, string) into (string, length) to conform with the commonly used order inside the GIT source code. Also, add a note about this fact into the coding guidelines. Signed-off-by: Kjetil Barvik <barvik@broadpark.no> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/CodingGuidelines | 3 +++ builtin-add.c | 2 +- builtin-apply.c | 2 +- builtin-update-index.c | 2 +- cache.h | 8 ++++---- diff-lib.c | 2 +- dir.c | 2 +- entry.c | 2 +- symlinks.c | 16 ++++++++-------- unpack-trees.c | 4 ++-- 10 files changed, 23 insertions(+), 20 deletions(-) diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines index 0d7fa9cca9..b8bf618a30 100644 --- a/Documentation/CodingGuidelines +++ b/Documentation/CodingGuidelines @@ -129,3 +129,6 @@ For C programs: used in the git core command set (unless your command is clearly separate from it, such as an importer to convert random-scm-X repositories to git). + + - When we pass <string, length> pair to functions, we should try to + pass them in that order. diff --git a/builtin-add.c b/builtin-add.c index ac98c8354d..a23ad96773 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -148,7 +148,7 @@ static const char **validate_pathspec(int argc, const char **argv, const char *p if (pathspec) { const char **p; for (p = pathspec; *p; p++) { - if (has_symlink_leading_path(strlen(*p), *p)) { + if (has_symlink_leading_path(*p, strlen(*p))) { int len = prefix ? strlen(prefix) : 0; die("'%s' is beyond a symbolic link", *p + len); } diff --git a/builtin-apply.c b/builtin-apply.c index f312798af3..106be94105 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2360,7 +2360,7 @@ static int check_to_create_blob(const char *new_name, int ok_if_exists) * In such a case, path "new_name" does not exist as * far as git is concerned. */ - if (has_symlink_leading_path(strlen(new_name), new_name)) + if (has_symlink_leading_path(new_name, strlen(new_name))) return 0; return error("%s: already exists in working directory", new_name); diff --git a/builtin-update-index.c b/builtin-update-index.c index 5604977505..6c55527513 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -195,7 +195,7 @@ static int process_path(const char *path) struct stat st; len = strlen(path); - if (has_symlink_leading_path(len, path)) + if (has_symlink_leading_path(path, len)) return error("'%s' is beyond a symbolic link", path); /* diff --git a/cache.h b/cache.h index 2d889deb26..80eeeb7db8 100644 --- a/cache.h +++ b/cache.h @@ -724,10 +724,10 @@ struct checkout { }; extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath); -extern int has_symlink_leading_path(int len, const char *name); -extern int has_symlink_or_noent_leading_path(int len, const char *name); -extern int has_dirs_only_path(int len, const char *name, int prefix_len); -extern void invalidate_lstat_cache(int len, const char *name); +extern int has_symlink_leading_path(const char *name, int len); +extern int has_symlink_or_noent_leading_path(const char *name, int len); +extern int has_dirs_only_path(const char *name, int len, int prefix_len); +extern void invalidate_lstat_cache(const char *name, int len); extern void clear_lstat_cache(void); extern struct alternate_object_database { diff --git a/diff-lib.c b/diff-lib.c index a41e1ec07c..a3ba20ee29 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -31,7 +31,7 @@ static int check_removed(const struct cache_entry *ce, struct stat *st) return -1; return 1; } - if (has_symlink_leading_path(ce_namelen(ce), ce->name)) + if (has_symlink_leading_path(ce->name, ce_namelen(ce))) return 1; if (S_ISDIR(st->st_mode)) { unsigned char sub[20]; diff --git a/dir.c b/dir.c index cfd1ea587d..8fb5226542 100644 --- a/dir.c +++ b/dir.c @@ -720,7 +720,7 @@ int read_directory(struct dir_struct *dir, const char *path, const char *base, i { struct path_simplify *simplify; - if (has_symlink_leading_path(strlen(path), path)) + if (has_symlink_leading_path(path, strlen(path))) return dir->nr; simplify = create_simplify(pathspec); diff --git a/entry.c b/entry.c index 05aa58d348..bb6bdb90e3 100644 --- a/entry.c +++ b/entry.c @@ -20,7 +20,7 @@ static void create_directories(const char *path, const struct checkout *state) * we test the path components of the prefix with the * stat() function instead of the lstat() function. */ - if (has_dirs_only_path(len, buf, state->base_dir_len)) + if (has_dirs_only_path(buf, len, state->base_dir_len)) continue; /* ok, it is already a directory. */ /* diff --git a/symlinks.c b/symlinks.c index 4596aee9dc..51672868d1 100644 --- a/symlinks.c +++ b/symlinks.c @@ -70,7 +70,7 @@ static inline void reset_lstat_cache(void) * of the prefix, where the cache should use the stat() function * instead of the lstat() function to test each path component. */ -static int lstat_cache(int len, const char *name, +static int lstat_cache(const char *name, int len, int track_flags, int prefix_len_stat_func) { int match_len, last_slash, last_slash_dir, previous_slash; @@ -185,7 +185,7 @@ static int lstat_cache(int len, const char *name, * Invalidate the given 'name' from the cache, if 'name' matches * completely with the cache. */ -void invalidate_lstat_cache(int len, const char *name) +void invalidate_lstat_cache(const char *name, int len) { int match_len, previous_slash; @@ -214,9 +214,9 @@ void clear_lstat_cache(void) /* * Return non-zero if path 'name' has a leading symlink component */ -int has_symlink_leading_path(int len, const char *name) +int has_symlink_leading_path(const char *name, int len) { - return lstat_cache(len, name, + return lstat_cache(name, len, FL_SYMLINK|FL_DIR, USE_ONLY_LSTAT) & FL_SYMLINK; } @@ -225,9 +225,9 @@ int has_symlink_leading_path(int len, const char *name) * Return non-zero if path 'name' has a leading symlink component or * if some leading path component does not exists. */ -int has_symlink_or_noent_leading_path(int len, const char *name) +int has_symlink_or_noent_leading_path(const char *name, int len) { - return lstat_cache(len, name, + return lstat_cache(name, len, FL_SYMLINK|FL_NOENT|FL_DIR, USE_ONLY_LSTAT) & (FL_SYMLINK|FL_NOENT); } @@ -239,9 +239,9 @@ int has_symlink_or_noent_leading_path(int len, const char *name) * 'prefix_len', thus we then allow for symlinks in the prefix part as * long as those points to real existing directories. */ -int has_dirs_only_path(int len, const char *name, int prefix_len) +int has_dirs_only_path(const char *name, int len, int prefix_len) { - return lstat_cache(len, name, + return lstat_cache(name, len, FL_DIR|FL_FULLPATH, prefix_len) & FL_DIR; } diff --git a/unpack-trees.c b/unpack-trees.c index e547282ed5..2293158850 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -61,7 +61,7 @@ static void unlink_entry(struct cache_entry *ce) char *cp, *prev; char *name = ce->name; - if (has_symlink_or_noent_leading_path(ce_namelen(ce), ce->name)) + if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce))) return; if (unlink(name)) return; @@ -583,7 +583,7 @@ static int verify_absent(struct cache_entry *ce, const char *action, if (o->index_only || o->reset || !o->update) return 0; - if (has_symlink_or_noent_leading_path(ce_namelen(ce), ce->name)) + if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce))) return 0; if (!lstat(ce->name, &st)) { From 7847892716a3c9a7b8facc076fc056ac425bcfe6 Mon Sep 17 00:00:00 2001 From: Kjetil Barvik <barvik@broadpark.no> Date: Mon, 9 Feb 2009 21:54:07 +0100 Subject: [PATCH 019/654] unlink_entry(): introduce schedule_dir_for_removal() Currently inside unlink_entry() if we get a successful removal of one file with unlink(), we try to remove the leading directories each and every time. So if one directory containing 200 files is moved to an other location we get 199 failed calls to rmdir() and 1 successful call. To fix this and avoid some unnecessary calls to rmdir(), we schedule each directory for removal and wait much longer before we do the real call to rmdir(). Since the unlink_entry() function is called with alphabetically sorted names, this new function end up being very effective to avoid unnecessary calls to rmdir(). In some cases over 95% of all calls to rmdir() is removed with this patch. Signed-off-by: Kjetil Barvik <barvik@broadpark.no> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- cache.h | 2 ++ symlinks.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ unpack-trees.c | 30 +++++-------------------- 3 files changed, 67 insertions(+), 24 deletions(-) diff --git a/cache.h b/cache.h index 80eeeb7db8..1bf2d4bde6 100644 --- a/cache.h +++ b/cache.h @@ -729,6 +729,8 @@ extern int has_symlink_or_noent_leading_path(const char *name, int len); extern int has_dirs_only_path(const char *name, int len, int prefix_len); extern void invalidate_lstat_cache(const char *name, int len); extern void clear_lstat_cache(void); +extern void schedule_dir_for_removal(const char *name, int len); +extern void remove_scheduled_dirs(void); extern struct alternate_object_database { struct alternate_object_database *next; diff --git a/symlinks.c b/symlinks.c index 51672868d1..1d6b35b858 100644 --- a/symlinks.c +++ b/symlinks.c @@ -245,3 +245,62 @@ int has_dirs_only_path(const char *name, int len, int prefix_len) FL_DIR|FL_FULLPATH, prefix_len) & FL_DIR; } + +static struct removal_def { + char path[PATH_MAX]; + int len; +} removal; + +static void do_remove_scheduled_dirs(int new_len) +{ + while (removal.len > new_len) { + removal.path[removal.len] = '\0'; + if (rmdir(removal.path)) + break; + do { + removal.len--; + } while (removal.len > new_len && + removal.path[removal.len] != '/'); + } + removal.len = new_len; + return; +} + +void schedule_dir_for_removal(const char *name, int len) +{ + int match_len, last_slash, i, previous_slash; + + match_len = last_slash = i = + longest_path_match(name, len, removal.path, removal.len, + &previous_slash); + /* Find last slash inside 'name' */ + while (i < len) { + if (name[i] == '/') + last_slash = i; + i++; + } + + /* + * If we are about to go down the directory tree, we check if + * we must first go upwards the tree, such that we then can + * remove possible empty directories as we go upwards. + */ + if (match_len < last_slash && match_len < removal.len) + do_remove_scheduled_dirs(match_len); + /* + * If we go deeper down the directory tree, we only need to + * save the new path components as we go down. + */ + if (match_len < last_slash) { + memcpy(&removal.path[match_len], &name[match_len], + last_slash - match_len); + removal.len = last_slash; + } + return; +} + +void remove_scheduled_dirs(void) +{ + do_remove_scheduled_dirs(0); + return; +} diff --git a/unpack-trees.c b/unpack-trees.c index 2293158850..e3c3fa12aa 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -52,36 +52,17 @@ static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce, add_index_entry(&o->result, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE|ADD_CACHE_SKIP_DFCHECK); } -/* Unlink the last component and attempt to remove leading - * directories, in case this unlink is the removal of the - * last entry in the directory -- empty directories are removed. +/* + * Unlink the last component and schedule the leading directories for + * removal, such that empty directories get removed. */ static void unlink_entry(struct cache_entry *ce) { - char *cp, *prev; - char *name = ce->name; - if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce))) return; - if (unlink(name)) + if (unlink(ce->name)) return; - prev = NULL; - while (1) { - int status; - cp = strrchr(name, '/'); - if (prev) - *prev = '/'; - if (!cp) - break; - - *cp = 0; - status = rmdir(name); - if (status) { - *cp = '/'; - break; - } - prev = cp; - } + schedule_dir_for_removal(ce->name, ce_namelen(ce)); } static struct checkout state; @@ -117,6 +98,7 @@ static int check_updates(struct unpack_trees_options *o) continue; } } + remove_scheduled_dirs(); for (i = 0; i < index->cache_nr; i++) { struct cache_entry *ce = index->cache[i]; From 81a9aa60a193f1181149b69920930e15c4e34059 Mon Sep 17 00:00:00 2001 From: Kjetil Barvik <barvik@broadpark.no> Date: Mon, 9 Feb 2009 21:54:08 +0100 Subject: [PATCH 020/654] create_directories(): remove some memcpy() and strchr() calls Remove the call to memcpy() and strchr() for each path component tested, and instead add each path component as we go forward inside the while-loop. Impact: small optimisation Signed-off-by: Kjetil Barvik <barvik@broadpark.no> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- entry.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/entry.c b/entry.c index bb6bdb90e3..cc8f0c6077 100644 --- a/entry.c +++ b/entry.c @@ -2,15 +2,19 @@ #include "blob.h" #include "dir.h" -static void create_directories(const char *path, const struct checkout *state) +static void create_directories(const char *path, int path_len, + const struct checkout *state) { - int len = strlen(path); - char *buf = xmalloc(len + 1); - const char *slash = path; + char *buf = xmalloc(path_len + 1); + int len = 0; - while ((slash = strchr(slash+1, '/')) != NULL) { - len = slash - path; - memcpy(buf, path, len); + while (len < path_len) { + do { + buf[len] = path[len]; + len++; + } while (len < path_len && path[len] != '/'); + if (len >= path_len) + break; buf[len] = 0; /* @@ -190,6 +194,7 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t memcpy(path, state->base_dir, len); strcpy(path + len, ce->name); + len += ce_namelen(ce); if (!lstat(path, &st)) { unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID); @@ -218,6 +223,6 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t return error("unable to unlink old '%s' (%s)", path, strerror(errno)); } else if (state->not_new) return 0; - create_directories(path, state); + create_directories(path, len, state); return write_entry(ce, path, state, 0); } From 4857c761e35b07c12ff2ef1140e93b071b8ac4e7 Mon Sep 17 00:00:00 2001 From: Kjetil Barvik <barvik@broadpark.no> Date: Mon, 9 Feb 2009 21:54:50 +0100 Subject: [PATCH 021/654] write_entry(): cleanup of some duplicated code The switch-cases for S_IFREG and S_IFLNK was so similar that it will be better to do some cleanup and use the common parts of it. And the entry.c file should now be clean for 'gcc -Wextra' warnings. Signed-off-by: Kjetil Barvik <barvik@broadpark.no> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- entry.c | 73 +++++++++++++++++++++++---------------------------------- 1 file changed, 29 insertions(+), 44 deletions(-) diff --git a/entry.c b/entry.c index cc8f0c6077..1f53588a11 100644 --- a/entry.c +++ b/entry.c @@ -78,7 +78,7 @@ static int create_file(const char *path, unsigned int mode) return open(path, O_WRONLY | O_CREAT | O_EXCL, mode); } -static void *read_blob_entry(struct cache_entry *ce, const char *path, unsigned long *size) +static void *read_blob_entry(struct cache_entry *ce, unsigned long *size) { enum object_type type; void *new = read_sha1_file(ce->sha1, &type, size); @@ -93,36 +93,51 @@ static void *read_blob_entry(struct cache_entry *ce, const char *path, unsigned static int write_entry(struct cache_entry *ce, char *path, const struct checkout *state, int to_tempfile) { - int fd; - long wrote; - - switch (ce->ce_mode & S_IFMT) { - char *new; - struct strbuf buf; - unsigned long size; + unsigned int ce_mode_s_ifmt = ce->ce_mode & S_IFMT; + int fd, ret; + char *new; + struct strbuf buf = STRBUF_INIT; + unsigned long size; + size_t wrote, newsize = 0; + switch (ce_mode_s_ifmt) { case S_IFREG: - new = read_blob_entry(ce, path, &size); + case S_IFLNK: + new = read_blob_entry(ce, &size); if (!new) return error("git checkout-index: unable to read sha1 file of %s (%s)", path, sha1_to_hex(ce->sha1)); + if (ce_mode_s_ifmt == S_IFLNK && has_symlinks && !to_tempfile) { + ret = symlink(new, path); + free(new); + if (ret) + return error("git checkout-index: unable to create symlink %s (%s)", + path, strerror(errno)); + break; + } + /* * Convert from git internal format to working tree format */ - strbuf_init(&buf, 0); - if (convert_to_working_tree(ce->name, new, size, &buf)) { - size_t newsize = 0; + if (ce_mode_s_ifmt == S_IFREG && + convert_to_working_tree(ce->name, new, size, &buf)) { free(new); new = strbuf_detach(&buf, &newsize); size = newsize; } if (to_tempfile) { - strcpy(path, ".merge_file_XXXXXX"); + if (ce_mode_s_ifmt == S_IFREG) + strcpy(path, ".merge_file_XXXXXX"); + else + strcpy(path, ".merge_link_XXXXXX"); fd = mkstemp(path); - } else + } else if (ce_mode_s_ifmt == S_IFREG) { fd = create_file(path, ce->ce_mode); + } else { + fd = create_file(path, 0666); + } if (fd < 0) { free(new); return error("git checkout-index: unable to create file %s (%s)", @@ -135,36 +150,6 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout if (wrote != size) return error("git checkout-index: unable to write file %s", path); break; - case S_IFLNK: - new = read_blob_entry(ce, path, &size); - if (!new) - return error("git checkout-index: unable to read sha1 file of %s (%s)", - path, sha1_to_hex(ce->sha1)); - if (to_tempfile || !has_symlinks) { - if (to_tempfile) { - strcpy(path, ".merge_link_XXXXXX"); - fd = mkstemp(path); - } else - fd = create_file(path, 0666); - if (fd < 0) { - free(new); - return error("git checkout-index: unable to create " - "file %s (%s)", path, strerror(errno)); - } - wrote = write_in_full(fd, new, size); - close(fd); - free(new); - if (wrote != size) - return error("git checkout-index: unable to write file %s", - path); - } else { - wrote = symlink(new, path); - free(new); - if (wrote) - return error("git checkout-index: unable to create " - "symlink %s (%s)", path, strerror(errno)); - } - break; case S_IFGITLINK: if (to_tempfile) return error("git checkout-index: cannot create temporary subproject %s", path); From e4c7292353dbef39feac1c6a60c5cde9140520a6 Mon Sep 17 00:00:00 2001 From: Kjetil Barvik <barvik@broadpark.no> Date: Mon, 9 Feb 2009 21:54:51 +0100 Subject: [PATCH 022/654] write_entry(): use fstat() instead of lstat() when file is open Currently inside write_entry() we do an lstat(path, &st) call on a file which have just been opened inside the exact same function. It should be better to call fstat(fd, &st) on the file while it is open, and it should be at least as fast as the lstat() method. Signed-off-by: Kjetil Barvik <barvik@broadpark.no> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- entry.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/entry.c b/entry.c index 1f53588a11..5daacc2fe5 100644 --- a/entry.c +++ b/entry.c @@ -94,11 +94,12 @@ static void *read_blob_entry(struct cache_entry *ce, unsigned long *size) static int write_entry(struct cache_entry *ce, char *path, const struct checkout *state, int to_tempfile) { unsigned int ce_mode_s_ifmt = ce->ce_mode & S_IFMT; - int fd, ret; + int fd, ret, fstat_done = 0; char *new; struct strbuf buf = STRBUF_INIT; unsigned long size; size_t wrote, newsize = 0; + struct stat st; switch (ce_mode_s_ifmt) { case S_IFREG: @@ -145,6 +146,11 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout } wrote = write_in_full(fd, new, size); + /* use fstat() only when path == ce->name */ + if (state->refresh_cache && !to_tempfile && !state->base_dir_len) { + fstat(fd, &st); + fstat_done = 1; + } close(fd); free(new); if (wrote != size) @@ -161,8 +167,8 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout } if (state->refresh_cache) { - struct stat st; - lstat(ce->name, &st); + if (!fstat_done) + lstat(ce->name, &st); fill_stat_cache_info(ce, &st); } return 0; From 91fcbcbdcdd845bd43104c5ac0af4c40da15223b Mon Sep 17 00:00:00 2001 From: Kjetil Barvik <barvik@broadpark.no> Date: Mon, 9 Feb 2009 21:54:52 +0100 Subject: [PATCH 023/654] show_patch_diff(): remove a call to fstat() Currently inside show_patch_diff() we have an fstat() call after an ok lstat() call. Since before the call to fstat() we have already tested for the link case with S_ISLNK(), the fstat() can be removed. Signed-off-by: Kjetil Barvik <barvik@broadpark.no> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- combine-diff.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/combine-diff.c b/combine-diff.c index bccc018ab2..4300319cc0 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -713,9 +713,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, result_size = buf.len; result = strbuf_detach(&buf, NULL); elem->mode = canon_mode(st.st_mode); - } - else if (0 <= (fd = open(elem->path, O_RDONLY)) && - !fstat(fd, &st)) { + } else if (0 <= (fd = open(elem->path, O_RDONLY))) { size_t len = xsize_t(st.st_size); ssize_t done; int is_file, i; From 7734f04873cfaddd0b148074a633f1f824fd961f Mon Sep 17 00:00:00 2001 From: Kjetil Barvik <barvik@broadpark.no> Date: Mon, 9 Feb 2009 21:54:53 +0100 Subject: [PATCH 024/654] lstat_cache(): print a warning if doing ping-pong between cache types This is a debug patch which is only to be used while the lstat_cache() is in the test stage, and should be removed/reverted before the final relase. I think it should be useful to catch these warnings, as I it could be an indication of that the cache would not be very effective if it is doing ping-pong by switching between different cache types too many times. Also, if someone is experimenting with the lstat_cache(), this patch will maybe be useful while debugging. If someone is able to trigger the warning, then send a mail to the GIT mailing list, containing the first 15 lines of the warning, and a short description of the GIT commands to trigger the warnings. I hope someone is willing to use this patch for a while, to be able to catch possible ping-pong's. Signed-off-by: Kjetil Barvik <barvik@broadpark.no> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- symlinks.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/symlinks.c b/symlinks.c index 1d6b35b858..cb255a3187 100644 --- a/symlinks.c +++ b/symlinks.c @@ -51,6 +51,11 @@ static inline void reset_lstat_cache(void) */ } +#define SWITCHES_BEFORE_WARNING 10 +static unsigned int cache_switches, number_of_warnings; +static unsigned int current_cache_func, last_cache_func; +static unsigned int total_calls; + #define FL_DIR (1 << 0) #define FL_NOENT (1 << 1) #define FL_SYMLINK (1 << 2) @@ -77,6 +82,7 @@ static int lstat_cache(const char *name, int len, int match_flags, ret_flags, save_flags, max_len, ret; struct stat st; + total_calls++; if (cache.track_flags != track_flags || cache.prefix_len_stat_func != prefix_len_stat_func) { /* @@ -88,6 +94,17 @@ static int lstat_cache(const char *name, int len, cache.track_flags = track_flags; cache.prefix_len_stat_func = prefix_len_stat_func; match_len = last_slash = 0; + cache_switches++; + if (cache_switches > SWITCHES_BEFORE_WARNING) { + if (number_of_warnings < 10 || number_of_warnings % 1000 == 0) + printf("warning from %s:%d cache_switches:%u > %u "\ + "(current:%u last:%u total:%u)\n", + __FILE__, __LINE__, + cache_switches, SWITCHES_BEFORE_WARNING, + current_cache_func, last_cache_func, + total_calls); + number_of_warnings++; + } } else { /* * Check to see if we have a match from the cache for @@ -216,6 +233,8 @@ void clear_lstat_cache(void) */ int has_symlink_leading_path(const char *name, int len) { + last_cache_func = current_cache_func; + current_cache_func = 1; return lstat_cache(name, len, FL_SYMLINK|FL_DIR, USE_ONLY_LSTAT) & FL_SYMLINK; @@ -227,6 +246,8 @@ int has_symlink_leading_path(const char *name, int len) */ int has_symlink_or_noent_leading_path(const char *name, int len) { + last_cache_func = current_cache_func; + current_cache_func = 2; return lstat_cache(name, len, FL_SYMLINK|FL_NOENT|FL_DIR, USE_ONLY_LSTAT) & (FL_SYMLINK|FL_NOENT); @@ -241,6 +262,8 @@ int has_symlink_or_noent_leading_path(const char *name, int len) */ int has_dirs_only_path(const char *name, int len, int prefix_len) { + last_cache_func = current_cache_func; + current_cache_func = 3; return lstat_cache(name, len, FL_DIR|FL_FULLPATH, prefix_len) & FL_DIR; From fa26a401bed5967d6118ac430c5c5f4707c54386 Mon Sep 17 00:00:00 2001 From: Ted Pavlic <ted@tedpavlic.com> Date: Wed, 11 Feb 2009 13:03:23 -0500 Subject: [PATCH 025/654] completion: For consistency, change "git rev-parse" to __gitdir calls Signed-off-by: Ted Pavlic <ted@tedpavlic.com> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index f44f63cfeb..6bbe09ab9a 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -80,7 +80,7 @@ __gitdir () # returns text to add to bash PS1 prompt (includes branch name) __git_ps1 () { - local g="$(git rev-parse --git-dir 2>/dev/null)" + local g="$(__gitdir)" if [ -n "$g" ]; then local r local b @@ -1797,7 +1797,7 @@ _gitk () __git_has_doubledash && return local cur="${COMP_WORDS[COMP_CWORD]}" - local g="$(git rev-parse --git-dir 2>/dev/null)" + local g="$(__gitdir)" local merge="" if [ -f $g/MERGE_HEAD ]; then merge="--merge" From ad244d256865c06804afffef32b753239a06119e Mon Sep 17 00:00:00 2001 From: Ted Pavlic <ted@tedpavlic.com> Date: Wed, 11 Feb 2009 13:03:24 -0500 Subject: [PATCH 026/654] completion: Use consistent if [...] convention, not "test" The local coding convention in bash completion is to use [...] rather than test. Additionally, if [...]; then is preferred over if [...] then and so matching "if [...]\nthen" were changed accordingly. Signed-off-by: Ted Pavlic <ted@tedpavlic.com> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 31 +++++++++----------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 6bbe09ab9a..c61576fcaf 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -84,39 +84,30 @@ __git_ps1 () if [ -n "$g" ]; then local r local b - if [ -d "$g/rebase-apply" ] - then - if test -f "$g/rebase-apply/rebasing" - then + if [ -d "$g/rebase-apply" ]; then + if [ -f "$g/rebase-apply/rebasing" ]; then r="|REBASE" - elif test -f "$g/rebase-apply/applying" - then + elif [ -f "$g/rebase-apply/applying" ]; then r="|AM" else r="|AM/REBASE" fi b="$(git symbolic-ref HEAD 2>/dev/null)" - elif [ -f "$g/rebase-merge/interactive" ] - then + elif [ -f "$g/rebase-merge/interactive" ]; then r="|REBASE-i" b="$(cat "$g/rebase-merge/head-name")" - elif [ -d "$g/rebase-merge" ] - then + elif [ -d "$g/rebase-merge" ]; then r="|REBASE-m" b="$(cat "$g/rebase-merge/head-name")" - elif [ -f "$g/MERGE_HEAD" ] - then + elif [ -f "$g/MERGE_HEAD" ]; then r="|MERGING" b="$(git symbolic-ref HEAD 2>/dev/null)" else - if [ -f "$g/BISECT_LOG" ] - then + if [ -f "$g/BISECT_LOG" ]; then r="|BISECTING" fi - if ! b="$(git symbolic-ref HEAD 2>/dev/null)" - then - if ! b="$(git describe --exact-match HEAD 2>/dev/null)" - then + if ! b="$(git symbolic-ref HEAD 2>/dev/null)"; then + if ! b="$(git describe --exact-match HEAD 2>/dev/null)"; then b="$(cut -c1-7 "$g/HEAD")..." fi fi @@ -125,8 +116,8 @@ __git_ps1 () local w local i - if test -n "${GIT_PS1_SHOWDIRTYSTATE-}"; then - if test "$(git config --bool bash.showDirtyState)" != "false"; then + if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then + if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then git diff --no-ext-diff --ignore-submodules \ --quiet --exit-code || w="*" if git rev-parse --quiet --verify HEAD >/dev/null; then From e5dd864adfeb8b0176b31a132e972d7f7beff32a Mon Sep 17 00:00:00 2001 From: Ted Pavlic <ted@tedpavlic.com> Date: Wed, 11 Feb 2009 13:03:25 -0500 Subject: [PATCH 027/654] completion: Better __git_ps1 support when not in working directory If .git/HEAD is not readable, __git_ps1 does nothing. If --is-in-git-dir, __git_ps1 returns " (GIT_DIR!)" as a cautionary note. The previous behavior would show the branch name (and would optionally attempt to determine the dirtyState of the directory, which was impossible because a "git diff" was used). If --is-in-work-tree, __git_ps1 returns the branch name. Additionally, if showDirtyState is on, the dirty state is displayed. Signed-off-by: Ted Pavlic <ted@tedpavlic.com> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 36 ++++++++++++++++---------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index c61576fcaf..aa8eec24d9 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -108,7 +108,9 @@ __git_ps1 () fi if ! b="$(git symbolic-ref HEAD 2>/dev/null)"; then if ! b="$(git describe --exact-match HEAD 2>/dev/null)"; then - b="$(cut -c1-7 "$g/HEAD")..." + if [ -r "$g/HEAD" ]; then + b="$(cut -c1-7 "$g/HEAD")..." + fi fi fi fi @@ -116,23 +118,29 @@ __git_ps1 () local w local i - if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then - if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then - git diff --no-ext-diff --ignore-submodules \ - --quiet --exit-code || w="*" - if git rev-parse --quiet --verify HEAD >/dev/null; then - git diff-index --cached --quiet \ - --ignore-submodules HEAD -- || i="+" - else - i="#" + if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then + b="GIT_DIR!" + elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then + if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then + if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then + git diff --no-ext-diff --ignore-submodules \ + --quiet --exit-code || w="*" + if git rev-parse --quiet --verify HEAD >/dev/null; then + git diff-index --cached --quiet \ + --ignore-submodules HEAD -- || i="+" + else + i="#" + fi fi fi fi - if [ -n "${1-}" ]; then - printf "$1" "${b##refs/heads/}$w$i$r" - else - printf " (%s)" "${b##refs/heads/}$w$i$r" + if [ -n "$b" ]; then + if [ -n "${1-}" ]; then + printf "$1" "${b##refs/heads/}$w$i$r" + else + printf " (%s)" "${b##refs/heads/}$w$i$r" + fi fi fi } From 5c9cc64a4a608ab0bbd5eb5c8e405bfe050be309 Mon Sep 17 00:00:00 2001 From: Ted Pavlic <ted@tedpavlic.com> Date: Wed, 11 Feb 2009 13:03:26 -0500 Subject: [PATCH 028/654] completion: More fixes to prevent unbound variable errors Several functions make use of "[-n ...]" and "[-z ...]". In many cases, the variables being tested were declared with "local." However, several __variables are not, and so they must be replaced with their ${__-} equivalents. Signed-off-by: Ted Pavlic <ted@tedpavlic.com> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index aa8eec24d9..6e8c5b91ac 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -62,7 +62,7 @@ esac __gitdir () { if [ -z "${1-}" ]; then - if [ -n "$__git_dir" ]; then + if [ -n "${__git_dir-}" ]; then echo "$__git_dir" elif [ -d .git ]; then echo .git @@ -298,7 +298,7 @@ __git_remotes () __git_merge_strategies () { - if [ -n "$__git_merge_strategylist" ]; then + if [ -n "${__git_merge_strategylist-}" ]; then echo "$__git_merge_strategylist" return fi @@ -384,7 +384,7 @@ __git_complete_revlist () __git_all_commands () { - if [ -n "$__git_all_commandlist" ]; then + if [ -n "${__git_all_commandlist-}" ]; then echo "$__git_all_commandlist" return fi @@ -402,7 +402,7 @@ __git_all_commandlist="$(__git_all_commands 2>/dev/null)" __git_porcelain_commands () { - if [ -n "$__git_porcelain_commandlist" ]; then + if [ -n "${__git_porcelain_commandlist-}" ]; then echo "$__git_porcelain_commandlist" return fi From 1d398a03902aab8ec49197d8827c19f9e2203c98 Mon Sep 17 00:00:00 2001 From: Deskin Miller <deskinm@umich.edu> Date: Thu, 12 Feb 2009 00:19:41 -0500 Subject: [PATCH 029/654] add -i: revisit hunk on editor failure Similar to the behaviour for editing a commit message, let terminating the editor with a failure abort the current hunk edit and revisit the option selection for the hunk. Signed-off-by: Deskin Miller <deskinm@umich.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-add--interactive.perl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/git-add--interactive.perl b/git-add--interactive.perl index 5f129a4203..f7b0761732 100755 --- a/git-add--interactive.perl +++ b/git-add--interactive.perl @@ -753,6 +753,10 @@ EOF || $ENV{VISUAL} || $ENV{EDITOR} || "vi"; system('sh', '-c', $editor.' "$@"', $editor, $hunkfile); + if ($? != 0) { + return undef; + } + open $fh, '<', $hunkfile or die "failed to open hunk edit file for reading: " . $!; my @newtext = grep { !/^#/ } <$fh>; From 0db5260bd033cc357186cc13fe23be9635ad69e7 Mon Sep 17 00:00:00 2001 From: Jeremy White <jwhite@codeweavers.com> Date: Thu, 12 Feb 2009 09:51:55 -0600 Subject: [PATCH 030/654] Enable setting attach as the default in .gitconfig for git-format-patch. Signed-off-by: Jeremy White <jwhite@codeweavers.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-format-patch.txt | 11 +++++++++-- builtin-log.c | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index 11a7d77261..e7ae8cf109 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -10,7 +10,8 @@ SYNOPSIS -------- [verse] 'git format-patch' [-k] [-o <dir> | --stdout] [--thread] - [--attach[=<boundary>] | --inline[=<boundary>]] + [--attach[=<boundary>] | --inline[=<boundary>] | + [--no-attach]] [-s | --signoff] [<common diff options>] [-n | --numbered | -N | --no-numbered] [--start-number <n>] [--numbered-files] @@ -117,6 +118,10 @@ include::diff-options.txt[] which is the commit message and the patch itself in the second part, with "Content-Disposition: attachment". +--no-attach:: + Disable the creation of an attachment, overriding the + configuration setting. + --inline[=<boundary>]:: Create multipart/mixed attachment, the first part of which is the commit message and the patch itself in the @@ -174,7 +179,8 @@ CONFIGURATION ------------- You can specify extra mail header lines to be added to each message in the repository configuration, new defaults for the subject prefix -and file suffix, and number patches when outputting more than one. +and file suffix, control attachements, and number patches when outputting +more than one. ------------ [format] @@ -183,6 +189,7 @@ and file suffix, and number patches when outputting more than one. suffix = .txt numbered = auto cc = <email> + attach [ = mime-boundary-string ] ------------ diff --git a/builtin-log.c b/builtin-log.c index 2ae39afccd..8549028817 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -428,6 +428,8 @@ static const char *fmt_patch_suffix = ".patch"; static int numbered = 0; static int auto_number = 1; +static char *default_attach = NULL; + static char **extra_hdr; static int extra_hdr_nr; static int extra_hdr_alloc; @@ -488,6 +490,14 @@ static int git_format_config(const char *var, const char *value, void *cb) auto_number = auto_number && numbered; return 0; } + if (!strcmp(var, "format.attach")) { + if (value && *value) + default_attach = xstrdup(value); + else + default_attach = xstrdup(git_version_string); + return 0; + } + return git_log_config(var, value, cb); } @@ -787,6 +797,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) rev.subject_prefix = fmt_patch_subject_prefix; + if (default_attach) { + rev.mime_boundary = default_attach; + rev.no_inline = 1; + } + /* * Parse the arguments before setup_revisions(), or something * like "git format-patch -o a123 HEAD^.." may fail; a123 is @@ -849,6 +864,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) rev.mime_boundary = argv[i] + 9; rev.no_inline = 1; } + else if (!strcmp(argv[i], "--no-attach")) { + rev.mime_boundary = NULL; + rev.no_inline = 0; + } else if (!strcmp(argv[i], "--inline")) { rev.mime_boundary = git_version_string; rev.no_inline = 0; From 209d336ae3923f2c1783a42b12fca50f3bee0802 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Fri, 13 Feb 2009 04:40:18 -0500 Subject: [PATCH 031/654] builtin-branch: improve output when displaying remote branches When encountering a symref (typically refs/remotes/<remote>/HEAD), display the ref target. When displaying local and remote branches, prefix the remote branch names with "remotes/" to make the remote branches clear from the local branches. If displaying only the remote branches, the prefix is not shown since it would be redundant. Sample output: $ git branch foo -> master * master rather-long-branch-name $ git branch -v foo -> master * master 51cecb2 initial rather-long-branch-name 51cecb2 initial $ git branch -v --no-abbrev foo -> master * master 51cecb2dbb1a1902bb4df79b543c8f951ee59d83 initial rather-long-branch-name 51cecb2dbb1a1902bb4df79b543c8f951ee59d83 initial $ git branch -r frotz/HEAD -> frotz/master frotz/master origin/HEAD -> origin/master origin/UNUSUAL -> refs/heads/master origin/master $ git branch -a foo -> master * master rather-long-branch-name remotes/frotz/HEAD -> frotz/master remotes/frotz/master remotes/origin/HEAD -> origin/master remotes/origin/UNUSUAL -> refs/heads/master remotes/origin/master $ git branch -rv frotz/HEAD -> frotz/master frotz/master e1d8130 added file2 origin/HEAD -> origin/master origin/UNUSUAL -> refs/heads/master origin/master e1d8130 added file2 $ git branch -av foo -> master * master 51cecb2 initial rather-long-branch-name 51cecb2 initial remotes/frotz/HEAD -> frotz/master remotes/frotz/master e1d8130 added file2 remotes/origin/HEAD -> origin/master remotes/origin/UNUSUAL -> refs/heads/master remotes/origin/master e1d8130 added file2 Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-branch.c | 105 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 75 insertions(+), 30 deletions(-) diff --git a/builtin-branch.c b/builtin-branch.c index 56a1971d69..7607f6ab9c 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -181,7 +181,8 @@ static int delete_branches(int argc, const char **argv, int force, int kinds) struct ref_item { char *name; - unsigned int kind; + char *dest; + unsigned int kind, len; struct commit *commit; }; @@ -193,22 +194,47 @@ struct ref_list { int kinds; }; +static char *resolve_symref(const char *src, const char *prefix) +{ + unsigned char sha1[20]; + int flag; + const char *dst, *cp; + + dst = resolve_ref(src, sha1, 0, &flag); + if (!(dst && (flag & REF_ISSYMREF))) + return NULL; + if (prefix && (cp = skip_prefix(dst, prefix))) + dst = cp; + return xstrdup(dst); +} + static int append_ref(const char *refname, const unsigned char *sha1, int flags, void *cb_data) { struct ref_list *ref_list = (struct ref_list*)(cb_data); struct ref_item *newitem; struct commit *commit; - int kind; - int len; + int kind, i; + const char *prefix, *orig_refname = refname; + + static struct { + int kind; + const char *prefix; + int pfxlen; + } ref_kind[] = { + { REF_LOCAL_BRANCH, "refs/heads/", 11 }, + { REF_REMOTE_BRANCH, "refs/remotes/", 13 }, + }; /* Detect kind */ - if (!prefixcmp(refname, "refs/heads/")) { - kind = REF_LOCAL_BRANCH; - refname += 11; - } else if (!prefixcmp(refname, "refs/remotes/")) { - kind = REF_REMOTE_BRANCH; - refname += 13; - } else + for (i = 0; i < ARRAY_SIZE(ref_kind); i++) { + prefix = ref_kind[i].prefix; + if (strncmp(refname, prefix, ref_kind[i].pfxlen)) + continue; + kind = ref_kind[i].kind; + refname += ref_kind[i].pfxlen; + break; + } + if (ARRAY_SIZE(ref_kind) <= i) return 0; commit = lookup_commit_reference_gently(sha1, 1); @@ -239,9 +265,14 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, newitem->name = xstrdup(refname); newitem->kind = kind; newitem->commit = commit; - len = strlen(newitem->name); - if (len > ref_list->maxwidth) - ref_list->maxwidth = len; + newitem->len = strlen(refname); + newitem->dest = resolve_symref(orig_refname, prefix); + /* adjust for "remotes/" */ + if (newitem->kind == REF_REMOTE_BRANCH && + ref_list->kinds != REF_REMOTE_BRANCH) + newitem->len += 8; + if (newitem->len > ref_list->maxwidth) + ref_list->maxwidth = newitem->len; return 0; } @@ -250,8 +281,10 @@ static void free_ref_list(struct ref_list *ref_list) { int i; - for (i = 0; i < ref_list->index; i++) + for (i = 0; i < ref_list->index; i++) { free(ref_list->list[i].name); + free(ref_list->list[i].dest); + } free(ref_list->list); } @@ -292,11 +325,12 @@ static int matches_merge_filter(struct commit *commit) } static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, - int abbrev, int current) + int abbrev, int current, char *prefix) { char c; int color; struct commit *commit = item->commit; + struct strbuf out = STRBUF_INIT, name = STRBUF_INIT; if (!matches_merge_filter(commit)) return; @@ -319,7 +353,18 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, color = COLOR_BRANCH_CURRENT; } - if (verbose) { + strbuf_addf(&name, "%s%s", prefix, item->name); + if (verbose) + strbuf_addf(&out, "%c %s%-*s%s", c, branch_get_color(color), + maxwidth, name.buf, + branch_get_color(COLOR_BRANCH_RESET)); + else + strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color), + name.buf, branch_get_color(COLOR_BRANCH_RESET)); + + if (item->dest) + strbuf_addf(&out, " -> %s", item->dest); + else if (verbose) { struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT; const char *sub = " **** invalid ref ****"; @@ -333,28 +378,25 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, if (item->kind == REF_LOCAL_BRANCH) fill_tracking_info(&stat, item->name); - printf("%c %s%-*s%s %s %s%s\n", c, branch_get_color(color), - maxwidth, item->name, - branch_get_color(COLOR_BRANCH_RESET), - find_unique_abbrev(item->commit->object.sha1, abbrev), - stat.buf, sub); + strbuf_addf(&out, " %s %s%s", + find_unique_abbrev(item->commit->object.sha1, abbrev), + stat.buf, sub); strbuf_release(&stat); strbuf_release(&subject); - } else { - printf("%c %s%s%s\n", c, branch_get_color(color), item->name, - branch_get_color(COLOR_BRANCH_RESET)); } + printf("%s\n", out.buf); + strbuf_release(&name); + strbuf_release(&out); } static int calc_maxwidth(struct ref_list *refs) { - int i, l, w = 0; + int i, w = 0; for (i = 0; i < refs->index; i++) { if (!matches_merge_filter(refs->list[i].commit)) continue; - l = strlen(refs->list[i].name); - if (l > w) - w = l; + if (refs->list[i].len > w) + w = refs->list[i].len; } return w; } @@ -394,7 +436,7 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str item.commit = head_commit; if (strlen(item.name) > ref_list.maxwidth) ref_list.maxwidth = strlen(item.name); - print_ref_item(&item, ref_list.maxwidth, verbose, abbrev, 1); + print_ref_item(&item, ref_list.maxwidth, verbose, abbrev, 1, ""); free(item.name); } @@ -402,8 +444,11 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str int current = !detached && (ref_list.list[i].kind == REF_LOCAL_BRANCH) && !strcmp(ref_list.list[i].name, head); + char *prefix = (kinds != REF_REMOTE_BRANCH && + ref_list.list[i].kind == REF_REMOTE_BRANCH) + ? "remotes/" : ""; print_ref_item(&ref_list.list[i], ref_list.maxwidth, verbose, - abbrev, current); + abbrev, current, prefix); } free_ref_list(&ref_list); From b2f82e05de2512ae4adb63b669f6c1fe6cba3148 Mon Sep 17 00:00:00 2001 From: Sverre Rabbelier <srabbelier@gmail.com> Date: Fri, 13 Feb 2009 23:48:01 +0100 Subject: [PATCH 032/654] Teach rebase to rebase even if upstream is up to date Normally, if the current branch is up to date, the rebase is aborted. However, it may be desirable to allow rebasing even if the current branch is up to date. When using the '--whitespace=fix' option -f is implied. Signed-off-by: Sverre Rabbelier <srabbelier@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-rebase.sh | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/git-rebase.sh b/git-rebase.sh index 6d3eddbada..5d9a393c38 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -3,7 +3,7 @@ # Copyright (c) 2005 Junio C Hamano. # -USAGE='[--interactive | -i] [-v] [--onto <newbase>] [<upstream>|--root] [<branch>]' +USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--onto <newbase>] [<upstream>|--root] [<branch>]' LONG_USAGE='git-rebase replaces <branch> with a new branch of the same name. When the --onto option is provided the new branch starts out with a HEAD equal to <newbase>, otherwise it is equal to <upstream> @@ -48,6 +48,7 @@ prec=4 verbose= git_am_opt= rebase_root= +force_rebase= continue_merge () { test -n "$prev_head" || die "prev_head must be defined" @@ -294,6 +295,11 @@ do ;; --whitespace=*) git_am_opt="$git_am_opt $1" + case "$1" in + --whitespace=fix|--whitespace=strip) + force_rebase=t + ;; + esac ;; -C*) git_am_opt="$git_am_opt $1" @@ -301,6 +307,9 @@ do --root) rebase_root=t ;; + -f|--f|--fo|--for|--forc|force|--force-r|--force-re|--force-reb|--force-reba|--force_rebas|--force-rebase) + force_rebase=t + ;; -*) usage ;; @@ -419,10 +428,15 @@ if test "$upstream" = "$onto" && test "$mb" = "$onto" && # linear history? ! (git rev-list --parents "$onto".."$branch" | grep " .* ") > /dev/null then - # Lazily switch to the target branch if needed... - test -z "$switch_to" || git checkout "$switch_to" - echo >&2 "Current branch $branch_name is up to date." - exit 0 + if test -z "$force_rebase" + then + # Lazily switch to the target branch if needed... + test -z "$switch_to" || git checkout "$switch_to" + echo >&2 "Current branch $branch_name is up to date." + exit 0 + else + echo "Current branch $branch_name is up to date, rebase forced." + fi fi if test -n "$verbose" From dc6ebd4cc5028d59146e02e30f7945ee91974e6e Mon Sep 17 00:00:00 2001 From: Arjen Laarhoven <arjen@yaph.org> Date: Fri, 13 Feb 2009 22:53:40 +0100 Subject: [PATCH 033/654] Clean up use of ANSI color sequences Remove the literal ANSI escape sequences and replace them by readable constants. Signed-off-by: Arjen Laarhoven <arjen@yaph.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-branch.c | 10 +++++----- color.c | 8 +++----- color.h | 10 ++++++++++ diff.c | 16 ++++++++-------- pretty.c | 8 ++++---- wt-status.c | 10 +++++----- 6 files changed, 35 insertions(+), 27 deletions(-) diff --git a/builtin-branch.c b/builtin-branch.c index 56a1971d69..fe139e1f05 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -32,11 +32,11 @@ static unsigned char head_sha1[20]; static int branch_use_color = -1; static char branch_colors[][COLOR_MAXLEN] = { - "\033[m", /* reset */ - "", /* PLAIN (normal) */ - "\033[31m", /* REMOTE (red) */ - "", /* LOCAL (normal) */ - "\033[32m", /* CURRENT (green) */ + GIT_COLOR_RESET, + GIT_COLOR_NORMAL, /* PLAIN */ + GIT_COLOR_RED, /* REMOTE */ + GIT_COLOR_NORMAL, /* LOCAL */ + GIT_COLOR_GREEN, /* CURRENT */ }; enum color_branch { COLOR_BRANCH_RESET = 0, diff --git a/color.c b/color.c index db4dccfb77..62977f4808 100644 --- a/color.c +++ b/color.c @@ -1,8 +1,6 @@ #include "cache.h" #include "color.h" -#define COLOR_RESET "\033[m" - int git_use_color_default = 0; static int parse_color(const char *name, int len) @@ -54,7 +52,7 @@ void color_parse_mem(const char *value, int value_len, const char *var, int bg = -2; if (!strncasecmp(value, "reset", len)) { - strcpy(dst, "\033[m"); + strcpy(dst, GIT_COLOR_RESET); return; } @@ -175,7 +173,7 @@ static int color_vfprintf(FILE *fp, const char *color, const char *fmt, r += fprintf(fp, "%s", color); r += vfprintf(fp, fmt, args); if (*color) - r += fprintf(fp, "%s", COLOR_RESET); + r += fprintf(fp, "%s", GIT_COLOR_RESET); if (trail) r += fprintf(fp, "%s", trail); return r; @@ -217,7 +215,7 @@ int color_fwrite_lines(FILE *fp, const char *color, char *p = memchr(buf, '\n', count); if (p != buf && (fputs(color, fp) < 0 || fwrite(buf, p ? p - buf : count, 1, fp) != 1 || - fputs(COLOR_RESET, fp) < 0)) + fputs(GIT_COLOR_RESET, fp) < 0)) return -1; if (!p) return 0; diff --git a/color.h b/color.h index 5019df82f7..6846be1706 100644 --- a/color.h +++ b/color.h @@ -4,6 +4,16 @@ /* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */ #define COLOR_MAXLEN 24 +#define GIT_COLOR_NORMAL "" +#define GIT_COLOR_RESET "\033[m" +#define GIT_COLOR_BOLD "\033[1m" +#define GIT_COLOR_RED "\033[31m" +#define GIT_COLOR_GREEN "\033[32m" +#define GIT_COLOR_YELLOW "\033[33m" +#define GIT_COLOR_BLUE "\033[34m" +#define GIT_COLOR_CYAN "\033[36m" +#define GIT_COLOR_BG_RED "\033[41m" + /* * This variable stores the value of color.ui */ diff --git a/diff.c b/diff.c index be3859e0a7..a3db16ea66 100644 --- a/diff.c +++ b/diff.c @@ -30,14 +30,14 @@ int diff_auto_refresh_index = 1; static int diff_mnemonic_prefix; static char diff_colors[][COLOR_MAXLEN] = { - "\033[m", /* reset */ - "", /* PLAIN (normal) */ - "\033[1m", /* METAINFO (bold) */ - "\033[36m", /* FRAGINFO (cyan) */ - "\033[31m", /* OLD (red) */ - "\033[32m", /* NEW (green) */ - "\033[33m", /* COMMIT (yellow) */ - "\033[41m", /* WHITESPACE (red background) */ + GIT_COLOR_RESET, + GIT_COLOR_NORMAL, /* PLAIN */ + GIT_COLOR_BOLD, /* METAINFO */ + GIT_COLOR_CYAN, /* FRAGINFO */ + GIT_COLOR_RED, /* OLD */ + GIT_COLOR_GREEN, /* NEW */ + GIT_COLOR_YELLOW, /* COMMIT */ + GIT_COLOR_BG_RED, /* WHITESPACE */ }; static void diff_filespec_load_driver(struct diff_filespec *one); diff --git a/pretty.c b/pretty.c index cc460b5697..66bae42f99 100644 --- a/pretty.c +++ b/pretty.c @@ -567,16 +567,16 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder, return end - placeholder + 1; } if (!prefixcmp(placeholder + 1, "red")) { - strbuf_addstr(sb, "\033[31m"); + strbuf_addstr(sb, GIT_COLOR_RED); return 4; } else if (!prefixcmp(placeholder + 1, "green")) { - strbuf_addstr(sb, "\033[32m"); + strbuf_addstr(sb, GIT_COLOR_GREEN); return 6; } else if (!prefixcmp(placeholder + 1, "blue")) { - strbuf_addstr(sb, "\033[34m"); + strbuf_addstr(sb, GIT_COLOR_BLUE); return 5; } else if (!prefixcmp(placeholder + 1, "reset")) { - strbuf_addstr(sb, "\033[m"); + strbuf_addstr(sb, GIT_COLOR_RESET); return 6; } else return 0; diff --git a/wt-status.c b/wt-status.c index 96ff2f8f56..dd87339ff7 100644 --- a/wt-status.c +++ b/wt-status.c @@ -15,11 +15,11 @@ int wt_status_relative_paths = 1; int wt_status_use_color = -1; int wt_status_submodule_summary; static char wt_status_colors[][COLOR_MAXLEN] = { - "", /* WT_STATUS_HEADER: normal */ - "\033[32m", /* WT_STATUS_UPDATED: green */ - "\033[31m", /* WT_STATUS_CHANGED: red */ - "\033[31m", /* WT_STATUS_UNTRACKED: red */ - "\033[31m", /* WT_STATUS_NOBRANCH: red */ + GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */ + GIT_COLOR_GREEN, /* WT_STATUS_UPDATED */ + GIT_COLOR_RED, /* WT_STATUS_CHANGED */ + GIT_COLOR_RED, /* WT_STATUS_UNTRACKED */ + GIT_COLOR_RED, /* WT_STATUS_NOBRANCH */ }; enum untracked_status_type show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; From 74bb2dfbec15ad47242b9a879b5547b6f4a28318 Mon Sep 17 00:00:00 2001 From: Arjen Laarhoven <arjen@yaph.org> Date: Fri, 13 Feb 2009 22:53:41 +0100 Subject: [PATCH 034/654] builtin-branch.c: Rename branch category color names The branch color constants have the form COLOR_BRANCH_$category. Rename them to BRANCH_COLOR_$category as this conveys their meaning better. Signed-off-by: Arjen Laarhoven <arjen@yaph.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-branch.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/builtin-branch.c b/builtin-branch.c index fe139e1f05..6d241c8eac 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -39,11 +39,11 @@ static char branch_colors[][COLOR_MAXLEN] = { GIT_COLOR_GREEN, /* CURRENT */ }; enum color_branch { - COLOR_BRANCH_RESET = 0, - COLOR_BRANCH_PLAIN = 1, - COLOR_BRANCH_REMOTE = 2, - COLOR_BRANCH_LOCAL = 3, - COLOR_BRANCH_CURRENT = 4, + BRANCH_COLOR_RESET = 0, + BRANCH_COLOR_PLAIN = 1, + BRANCH_COLOR_REMOTE = 2, + BRANCH_COLOR_LOCAL = 3, + BRANCH_COLOR_CURRENT = 4, }; static enum merge_filter { @@ -56,15 +56,15 @@ static unsigned char merge_filter_ref[20]; static int parse_branch_color_slot(const char *var, int ofs) { if (!strcasecmp(var+ofs, "plain")) - return COLOR_BRANCH_PLAIN; + return BRANCH_COLOR_PLAIN; if (!strcasecmp(var+ofs, "reset")) - return COLOR_BRANCH_RESET; + return BRANCH_COLOR_RESET; if (!strcasecmp(var+ofs, "remote")) - return COLOR_BRANCH_REMOTE; + return BRANCH_COLOR_REMOTE; if (!strcasecmp(var+ofs, "local")) - return COLOR_BRANCH_LOCAL; + return BRANCH_COLOR_LOCAL; if (!strcasecmp(var+ofs, "current")) - return COLOR_BRANCH_CURRENT; + return BRANCH_COLOR_CURRENT; die("bad config variable '%s'", var); } @@ -303,20 +303,20 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, switch (item->kind) { case REF_LOCAL_BRANCH: - color = COLOR_BRANCH_LOCAL; + color = BRANCH_COLOR_LOCAL; break; case REF_REMOTE_BRANCH: - color = COLOR_BRANCH_REMOTE; + color = BRANCH_COLOR_REMOTE; break; default: - color = COLOR_BRANCH_PLAIN; + color = BRANCH_COLOR_PLAIN; break; } c = ' '; if (current) { c = '*'; - color = COLOR_BRANCH_CURRENT; + color = BRANCH_COLOR_CURRENT; } if (verbose) { @@ -335,14 +335,14 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, printf("%c %s%-*s%s %s %s%s\n", c, branch_get_color(color), maxwidth, item->name, - branch_get_color(COLOR_BRANCH_RESET), + branch_get_color(BRANCH_COLOR_RESET), find_unique_abbrev(item->commit->object.sha1, abbrev), stat.buf, sub); strbuf_release(&stat); strbuf_release(&subject); } else { printf("%c %s%s%s\n", c, branch_get_color(color), item->name, - branch_get_color(COLOR_BRANCH_RESET)); + branch_get_color(BRANCH_COLOR_RESET)); } } From 900569661bbfe5c0e56cf8b9c014a2f594bb174c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZEDER=20G=C3=A1bor?= <szeder@ira.uka.de> Date: Sat, 14 Feb 2009 23:21:04 +0100 Subject: [PATCH 035/654] rerere: remove duplicated functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both rerere.c and builtin-rerere.c define the static functions rr_path() and has_resolution() the exact same way. To eliminate this code duplication this patch turns the functions in rerere.c non-static, and makes builtin-rerere.c use them. Also, since this puts these two functions into the global namespace, rename them to rerere_path() and has_rerere_resolution(), respectively, and rename their "name" parameter to "hex", because it better reflects what that parameter actually is. Signed-off-by: SZEDER Gábor <szeder@ira.uka.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-rerere.c | 25 +++++++------------------ rerere.c | 22 +++++++++++----------- rerere.h | 2 ++ 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/builtin-rerere.c b/builtin-rerere.c index bd8fc77a7a..020af7377b 100644 --- a/builtin-rerere.c +++ b/builtin-rerere.c @@ -13,28 +13,17 @@ static const char git_rerere_usage[] = static int cutoff_noresolve = 15; static int cutoff_resolve = 60; -static const char *rr_path(const char *name, const char *file) -{ - return git_path("rr-cache/%s/%s", name, file); -} - static time_t rerere_created_at(const char *name) { struct stat st; - return stat(rr_path(name, "preimage"), &st) ? (time_t) 0 : st.st_mtime; -} - -static int has_resolution(const char *name) -{ - struct stat st; - return !stat(rr_path(name, "postimage"), &st); + return stat(rerere_path(name, "preimage"), &st) ? (time_t) 0 : st.st_mtime; } static void unlink_rr_item(const char *name) { - unlink(rr_path(name, "thisimage")); - unlink(rr_path(name, "preimage")); - unlink(rr_path(name, "postimage")); + unlink(rerere_path(name, "thisimage")); + unlink(rerere_path(name, "preimage")); + unlink(rerere_path(name, "postimage")); rmdir(git_path("rr-cache/%s", name)); } @@ -65,7 +54,7 @@ static void garbage_collect(struct string_list *rr) then = rerere_created_at(e->d_name); if (!then) continue; - cutoff = (has_resolution(e->d_name) + cutoff = (has_rerere_resolution(e->d_name) ? cutoff_resolve : cutoff_noresolve); if (then < now - cutoff * 86400) string_list_append(e->d_name, &to_remove); @@ -124,7 +113,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix) if (!strcmp(argv[1], "clear")) { for (i = 0; i < merge_rr.nr; i++) { const char *name = (const char *)merge_rr.items[i].util; - if (!has_resolution(name)) + if (!has_rerere_resolution(name)) unlink_rr_item(name); } unlink(git_path("rr-cache/MERGE_RR")); @@ -137,7 +126,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix) for (i = 0; i < merge_rr.nr; i++) { const char *path = merge_rr.items[i].string; const char *name = (const char *)merge_rr.items[i].util; - diff_two(rr_path(name, "preimage"), path, path, path); + diff_two(rerere_path(name, "preimage"), path, path, path); } else usage(git_rerere_usage); diff --git a/rerere.c b/rerere.c index 3518207c17..713c6e16ac 100644 --- a/rerere.c +++ b/rerere.c @@ -12,15 +12,15 @@ static int rerere_autoupdate; static char *merge_rr_path; -static const char *rr_path(const char *name, const char *file) +const char *rerere_path(const char *hex, const char *file) { - return git_path("rr-cache/%s/%s", name, file); + return git_path("rr-cache/%s/%s", hex, file); } -static int has_resolution(const char *name) +int has_rerere_resolution(const char *hex) { struct stat st; - return !stat(rr_path(name, "postimage"), &st); + return !stat(rerere_path(hex, "postimage"), &st); } static void read_rr(struct string_list *rr) @@ -208,12 +208,12 @@ static int merge(const char *name, const char *path) mmbuffer_t result = {NULL, 0}; xpparam_t xpp = {XDF_NEED_MINIMAL}; - if (handle_file(path, NULL, rr_path(name, "thisimage")) < 0) + if (handle_file(path, NULL, rerere_path(name, "thisimage")) < 0) return 1; - if (read_mmfile(&cur, rr_path(name, "thisimage")) || - read_mmfile(&base, rr_path(name, "preimage")) || - read_mmfile(&other, rr_path(name, "postimage"))) + if (read_mmfile(&cur, rerere_path(name, "thisimage")) || + read_mmfile(&base, rerere_path(name, "preimage")) || + read_mmfile(&other, rerere_path(name, "postimage"))) return 1; ret = xdl_merge(&base, &cur, "", &other, "", &xpp, XDL_MERGE_ZEALOUS, &result); @@ -291,7 +291,7 @@ static int do_plain_rerere(struct string_list *rr, int fd) string_list_insert(path, rr)->util = hex; if (mkdir(git_path("rr-cache/%s", hex), 0755)) continue; - handle_file(path, NULL, rr_path(hex, "preimage")); + handle_file(path, NULL, rerere_path(hex, "preimage")); fprintf(stderr, "Recorded preimage for '%s'\n", path); } } @@ -307,7 +307,7 @@ static int do_plain_rerere(struct string_list *rr, int fd) const char *path = rr->items[i].string; const char *name = (const char *)rr->items[i].util; - if (has_resolution(name)) { + if (has_rerere_resolution(name)) { if (!merge(name, path)) { if (rerere_autoupdate) string_list_insert(path, &update); @@ -326,7 +326,7 @@ static int do_plain_rerere(struct string_list *rr, int fd) continue; fprintf(stderr, "Recorded resolution for '%s'.\n", path); - copy_file(rr_path(name, "postimage"), path, 0666); + copy_file(rerere_path(name, "postimage"), path, 0666); mark_resolved: rr->items[i].util = NULL; } diff --git a/rerere.h b/rerere.h index f9b03862fe..13313f3f2b 100644 --- a/rerere.h +++ b/rerere.h @@ -5,5 +5,7 @@ extern int setup_rerere(struct string_list *); extern int rerere(void); +extern const char *rerere_path(const char *hex, const char *file); +extern int has_rerere_resolution(const char *hex); #endif From c64d84f1452ec56fd1586493a0b0707bf7442c42 Mon Sep 17 00:00:00 2001 From: Jeremy White <jwhite@codeweavers.com> Date: Thu, 12 Feb 2009 08:58:12 -0600 Subject: [PATCH 036/654] imap.preformattedHTML to tell Thunderbird to send non-flowed text Many e-mail based development communities require non-flowed text to carry patches to prevent whitespaces from getting mangled, but there is no easy way to tell Thunderbird MUA not to use format=flowed, unless you configure it to do so unconditionally for all outgoing mails. A workaround for users who use git-imap-send is to wrap the patch in "pre" element in the draft folder as an HTML message, and tell Thunderbird to send "text only". Thunderbird turns such a message into a non-flowed plain text when sending it out, which is what we want for patch e-mails. Signed-off-by: Jeremy White <jwhite@codeweavers.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-imap-send.txt | 7 +++++ imap-send.c | 53 +++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt index 1685f04efe..024084b8b7 100644 --- a/Documentation/git-imap-send.txt +++ b/Documentation/git-imap-send.txt @@ -64,6 +64,13 @@ imap.sslverify:: used by the SSL/TLS connection. Default is `true`. Ignored when imap.tunnel is set. +imap.preformattedHTML:: + A boolean to enable/disable the use of html encoding when sending + a patch. An html encoded patch will be bracketed with <pre> + and have a content type of text/html. Ironically, enabling this + option causes Thunderbird to send the patch as a plain/text, + format=fixed email. Default is `false`. + Examples ~~~~~~~~ diff --git a/imap-send.c b/imap-send.c index f91293c23f..cb518eb613 100644 --- a/imap-send.c +++ b/imap-send.c @@ -135,6 +135,7 @@ struct imap_server_conf { char *pass; int use_ssl; int ssl_verify; + int use_html; }; struct imap_store_conf { @@ -1263,6 +1264,53 @@ static int imap_store_msg(struct store *gctx, struct msg_data *data, int *uid) return DRV_OK; } +static void encode_html_chars(struct strbuf *p) +{ + int i; + for (i = 0; i < p->len; i++) { + if (p->buf[i] == '&') + strbuf_splice(p, i, 1, "&", 5); + if (p->buf[i] == '<') + strbuf_splice(p, i, 1, "<", 4); + if (p->buf[i] == '>') + strbuf_splice(p, i, 1, ">", 4); + if (p->buf[i] == '"') + strbuf_splice(p, i, 1, """, 6); + } +} +static void wrap_in_html(struct msg_data *msg) +{ + struct strbuf buf = STRBUF_INIT; + struct strbuf **lines; + struct strbuf **p; + static char *content_type = "Content-Type: text/html;\n"; + static char *pre_open = "<pre>\n"; + static char *pre_close = "</pre>\n"; + int added_header = 0; + + strbuf_attach(&buf, msg->data, msg->len, msg->len); + lines = strbuf_split(&buf, '\n'); + strbuf_release(&buf); + for (p = lines; *p; p++) { + if (! added_header) { + if ((*p)->len == 1 && *((*p)->buf) == '\n') { + strbuf_addstr(&buf, content_type); + strbuf_addbuf(&buf, *p); + strbuf_addstr(&buf, pre_open); + added_header = 1; + continue; + } + } + else + encode_html_chars(*p); + strbuf_addbuf(&buf, *p); + } + strbuf_addstr(&buf, pre_close); + strbuf_list_free(lines); + msg->len = buf.len; + msg->data = strbuf_detach(&buf, NULL); +} + #define CHUNKSIZE 0x1000 static int read_message(FILE *f, struct msg_data *msg) @@ -1339,6 +1387,7 @@ static struct imap_server_conf server = { NULL, /* pass */ 0, /* use_ssl */ 1, /* ssl_verify */ + 0, /* use_html */ }; static char *imap_folder; @@ -1377,6 +1426,8 @@ static int git_imap_config(const char *key, const char *val, void *cb) server.tunnel = xstrdup(val); else if (!strcmp("sslverify", key)) server.ssl_verify = git_config_bool(key, val); + else if (!strcmp("preformattedHTML", key)) + server.use_html = git_config_bool(key, val); return 0; } @@ -1439,6 +1490,8 @@ int main(int argc, char **argv) fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total); if (!split_msg(&all_msgs, &msg, &ofs)) break; + if (server.use_html) + wrap_in_html(&msg); r = imap_store_msg(ctx, &msg, &uid); if (r != DRV_OK) break; From 45e2b6140147d7a8b2cd68399e4d52d5d8d7b5be Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Wed, 18 Feb 2009 19:14:59 +0100 Subject: [PATCH 037/654] Avoid segfault with 'git branch' when the HEAD is detached A recent addition to the ref_item struct was not taken care of, leading to a segmentation fault when accessing the (uninitialized) "dest" member. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-branch.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builtin-branch.c b/builtin-branch.c index 7607f6ab9c..6106a1abd5 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -432,7 +432,9 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str is_descendant_of(head_commit, with_commit)) { struct ref_item item; item.name = xstrdup("(no branch)"); + item.len = strlen(item.name); item.kind = REF_LOCAL_BRANCH; + item.dest = NULL; item.commit = head_commit; if (strlen(item.name) > ref_list.maxwidth) ref_list.maxwidth = strlen(item.name); From 7c4c97c0ac0cd66861d0c2b8bd7a47ed3c523ea7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <Johannes.Schindelin@gmx.de> Date: Mon, 16 Feb 2009 13:20:25 +0100 Subject: [PATCH 038/654] Turn the flags in struct dir_struct into a single variable By having flags represented as bits in the new member variable 'flags', it will be easier to use parse_options when dir_struct is involved. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-add.c | 2 +- builtin-checkout.c | 2 +- builtin-clean.c | 4 ++-- builtin-ls-files.c | 14 ++++++++------ builtin-merge.c | 2 +- builtin-read-tree.c | 2 +- dir.c | 17 +++++++++-------- dir.h | 12 +++++++----- wt-status.c | 7 +++---- 9 files changed, 33 insertions(+), 29 deletions(-) diff --git a/builtin-add.c b/builtin-add.c index ac98c8354d..c986a3ada1 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -104,7 +104,7 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec, /* Set up the default git porcelain excludes */ memset(dir, 0, sizeof(*dir)); if (!ignored_too) { - dir->collect_ignored = 1; + dir->flags |= DIR_COLLECT_IGNORED; setup_standard_excludes(dir); } diff --git a/builtin-checkout.c b/builtin-checkout.c index 20b34ce6e1..5b4921d48c 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -405,7 +405,7 @@ static int merge_working_tree(struct checkout_opts *opts, topts.verbose_update = !opts->quiet; topts.fn = twoway_merge; topts.dir = xcalloc(1, sizeof(*topts.dir)); - topts.dir->show_ignored = 1; + topts.dir->flags |= DIR_SHOW_IGNORED; topts.dir->exclude_per_dir = ".gitignore"; tree = parse_tree_indirect(old->commit->object.sha1); init_tree_desc(&trees[0], tree->buffer, tree->size); diff --git a/builtin-clean.c b/builtin-clean.c index f78c2fb108..c5ad33d3e6 100644 --- a/builtin-clean.c +++ b/builtin-clean.c @@ -60,7 +60,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix) memset(&dir, 0, sizeof(dir)); if (ignored_only) - dir.show_ignored = 1; + dir.flags |= DIR_SHOW_IGNORED; if (ignored && ignored_only) die("-x and -X cannot be used together"); @@ -69,7 +69,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix) die("clean.requireForce%s set and -n or -f not given; " "refusing to clean", config_set ? "" : " not"); - dir.show_other_directories = 1; + dir.flags |= DIR_SHOW_OTHER_DIRECTORIES; if (!ignored) setup_standard_excludes(&dir); diff --git a/builtin-ls-files.c b/builtin-ls-files.c index 9dec282fba..d36f80b3de 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -174,7 +174,8 @@ static void show_files(struct dir_struct *dir, const char *prefix) for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; int dtype = ce_to_dtype(ce); - if (excluded(dir, ce->name, &dtype) != dir->show_ignored) + if (excluded(dir, ce->name, &dtype) != + !!(dir->flags & DIR_SHOW_IGNORED)) continue; if (show_unmerged && !ce_stage(ce)) continue; @@ -189,7 +190,8 @@ static void show_files(struct dir_struct *dir, const char *prefix) struct stat st; int err; int dtype = ce_to_dtype(ce); - if (excluded(dir, ce->name, &dtype) != dir->show_ignored) + if (excluded(dir, ce->name, &dtype) != + !!(dir->flags & DIR_SHOW_IGNORED)) continue; if (ce->ce_flags & CE_UPDATE) continue; @@ -432,7 +434,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) continue; } if (!strcmp(arg, "-i") || !strcmp(arg, "--ignored")) { - dir.show_ignored = 1; + dir.flags |= DIR_SHOW_IGNORED; require_work_tree = 1; continue; } @@ -446,11 +448,11 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) continue; } if (!strcmp(arg, "--directory")) { - dir.show_other_directories = 1; + dir.flags |= DIR_SHOW_OTHER_DIRECTORIES; continue; } if (!strcmp(arg, "--no-empty-directory")) { - dir.hide_empty_directories = 1; + dir.flags |= DIR_HIDE_EMPTY_DIRECTORIES; continue; } if (!strcmp(arg, "-u") || !strcmp(arg, "--unmerged")) { @@ -542,7 +544,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) ps_matched = xcalloc(1, num); } - if (dir.show_ignored && !exc_given) { + if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given) { fprintf(stderr, "%s: --ignored needs some exclude pattern\n", argv[0]); exit(1); diff --git a/builtin-merge.c b/builtin-merge.c index 6d2160d0a3..4c119359e7 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -636,7 +636,7 @@ static int checkout_fast_forward(unsigned char *head, unsigned char *remote) memset(&opts, 0, sizeof(opts)); memset(&t, 0, sizeof(t)); memset(&dir, 0, sizeof(dir)); - dir.show_ignored = 1; + dir.flags |= DIR_SHOW_IGNORED; dir.exclude_per_dir = ".gitignore"; opts.dir = &dir; diff --git a/builtin-read-tree.c b/builtin-read-tree.c index 38fef34d3f..8e0273864d 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -170,7 +170,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) die("more than one --exclude-per-directory are given."); dir = xcalloc(1, sizeof(*opts.dir)); - dir->show_ignored = 1; + dir->flags |= DIR_SHOW_IGNORED; dir->exclude_per_dir = arg + 24; opts.dir = dir; /* We do not need to nor want to do read-directory diff --git a/dir.c b/dir.c index cfd1ea587d..5011cb4dd4 100644 --- a/dir.c +++ b/dir.c @@ -487,14 +487,14 @@ static enum directory_treatment treat_directory(struct dir_struct *dir, return recurse_into_directory; case index_gitdir: - if (dir->show_other_directories) + if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES) return ignore_directory; return show_directory; case index_nonexistent: - if (dir->show_other_directories) + if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES) break; - if (!dir->no_gitlinks) { + if (!(dir->flags & DIR_NO_GITLINKS)) { unsigned char sha1[20]; if (resolve_gitlink_ref(dirname, "HEAD", sha1) == 0) return show_directory; @@ -503,7 +503,7 @@ static enum directory_treatment treat_directory(struct dir_struct *dir, } /* This is the "show_other_directories" case */ - if (!dir->hide_empty_directories) + if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES)) return show_directory; if (!read_directory_recursive(dir, dirname, dirname, len, 1, simplify)) return ignore_directory; @@ -601,7 +601,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co dtype = DTYPE(de); exclude = excluded(dir, fullname, &dtype); - if (exclude && dir->collect_ignored + if (exclude && (dir->flags & DIR_COLLECT_IGNORED) && in_pathspec(fullname, baselen + len, simplify)) dir_add_ignored(dir, fullname, baselen + len); @@ -609,7 +609,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co * Excluded? If we don't explicitly want to show * ignored files, ignore it */ - if (exclude && !dir->show_ignored) + if (exclude && !(dir->flags & DIR_SHOW_IGNORED)) continue; if (dtype == DT_UNKNOWN) @@ -621,7 +621,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co * even if we don't ignore them, since the * directory may contain files that we do.. */ - if (!exclude && dir->show_ignored) { + if (!exclude && (dir->flags & DIR_SHOW_IGNORED)) { if (dtype != DT_DIR) continue; } @@ -634,7 +634,8 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co len++; switch (treat_directory(dir, fullname, baselen + len, simplify)) { case show_directory: - if (exclude != dir->show_ignored) + if (exclude != !!(dir->flags + & DIR_SHOW_IGNORED)) continue; break; case recurse_into_directory: diff --git a/dir.h b/dir.h index bdc2d47447..541286ad1d 100644 --- a/dir.h +++ b/dir.h @@ -34,11 +34,13 @@ struct exclude_stack { struct dir_struct { int nr, alloc; int ignored_nr, ignored_alloc; - unsigned int show_ignored:1, - show_other_directories:1, - hide_empty_directories:1, - no_gitlinks:1, - collect_ignored:1; + enum { + DIR_SHOW_IGNORED = 1<<0, + DIR_SHOW_OTHER_DIRECTORIES = 1<<1, + DIR_HIDE_EMPTY_DIRECTORIES = 1<<2, + DIR_NO_GITLINKS = 1<<3, + DIR_COLLECT_IGNORED = 1<<4 + } flags; struct dir_entry **entries; struct dir_entry **ignored; diff --git a/wt-status.c b/wt-status.c index 96ff2f8f56..f2eae20d89 100644 --- a/wt-status.c +++ b/wt-status.c @@ -250,10 +250,9 @@ static void wt_status_print_untracked(struct wt_status *s) memset(&dir, 0, sizeof(dir)); - if (!s->untracked) { - dir.show_other_directories = 1; - dir.hide_empty_directories = 1; - } + if (!s->untracked) + dir.flags |= + DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES; setup_standard_excludes(&dir); read_directory(&dir, ".", "", 0, NULL); From ce8e8804068772a24354ee24641ca65ffa417837 Mon Sep 17 00:00:00 2001 From: Miklos Vajna <vmiklos@frugalware.org> Date: Tue, 17 Feb 2009 15:27:11 +0100 Subject: [PATCH 039/654] parse-opt: migrate builtin-ls-files. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-ls-files.c | 255 +++++++++++++++++++++------------------------ 1 file changed, 120 insertions(+), 135 deletions(-) diff --git a/builtin-ls-files.c b/builtin-ls-files.c index d36f80b3de..1742c0f80d 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -10,6 +10,7 @@ #include "dir.h" #include "builtin.h" #include "tree.h" +#include "parse-options.h" static int abbrev; static int show_deleted; @@ -28,6 +29,7 @@ static const char **pathspec; static int error_unmatch; static char *ps_matched; static const char *with_tree; +static int exc_given; static const char *tag_cached = ""; static const char *tag_unmerged = ""; @@ -376,156 +378,139 @@ int report_path_error(const char *ps_matched, const char **pathspec, int prefix_ return errors; } -static const char ls_files_usage[] = - "git ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified])* " - "[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] " - "[ --exclude-per-directory=<filename> ] [--exclude-standard] " - "[--full-name] [--abbrev] [--] [<file>]*"; +static const char * const ls_files_usage[] = { + "git ls-files [options] [<file>]*", + NULL +}; + +static int option_parse_z(const struct option *opt, + const char *arg, int unset) +{ + line_terminator = unset ? '\n' : '\0'; + + return 0; +} + +static int option_parse_exclude(const struct option *opt, + const char *arg, int unset) +{ + struct exclude_list *list = opt->value; + + exc_given = 1; + add_exclude(arg, "", 0, list); + + return 0; +} + +static int option_parse_exclude_from(const struct option *opt, + const char *arg, int unset) +{ + struct dir_struct *dir = opt->value; + + exc_given = 1; + add_excludes_from_file(dir, arg); + + return 0; +} + +static int option_parse_exclude_standard(const struct option *opt, + const char *arg, int unset) +{ + struct dir_struct *dir = opt->value; + + exc_given = 1; + setup_standard_excludes(dir); + + return 0; +} int cmd_ls_files(int argc, const char **argv, const char *prefix) { - int i; - int exc_given = 0, require_work_tree = 0; + int require_work_tree = 0, show_tag = 0; struct dir_struct dir; + struct option builtin_ls_files_options[] = { + { OPTION_CALLBACK, 'z', NULL, NULL, NULL, + "paths are separated with NUL character", + PARSE_OPT_NOARG, option_parse_z }, + OPT_BOOLEAN('t', NULL, &show_tag, + "identify the file status with tags"), + OPT_BOOLEAN('v', NULL, &show_valid_bit, + "use lowercase letters for 'assume unchanged' files"), + OPT_BOOLEAN('c', "cached", &show_cached, + "show cached files in the output (default)"), + OPT_BOOLEAN('d', "deleted", &show_deleted, + "show deleted files in the output"), + OPT_BOOLEAN('m', "modified", &show_modified, + "show modified files in the output"), + OPT_BOOLEAN('o', "others", &show_others, + "show other files in the output"), + OPT_BIT('i', "ignored", &dir.flags, + "show ignored files in the output", + DIR_SHOW_IGNORED), + OPT_BOOLEAN('s', "stage", &show_stage, + "show staged contents' object name in the output"), + OPT_BOOLEAN('k', "killed", &show_killed, + "show files on the filesystem that need to be removed"), + OPT_BIT(0, "directory", &dir.flags, + "show 'other' directories' name only", + DIR_SHOW_OTHER_DIRECTORIES), + OPT_BIT(0, "empty-directory", &dir.flags, + "list empty directories", + DIR_HIDE_EMPTY_DIRECTORIES), + OPT_BOOLEAN('u', "unmerged", &show_unmerged, + "show unmerged files in the output"), + { OPTION_CALLBACK, 'x', "exclude", &dir.exclude_list[EXC_CMDL], "pattern", + "skip files matching pattern", + 0, option_parse_exclude }, + { OPTION_CALLBACK, 'X', "exclude-from", &dir, "file", + "exclude patterns are read from <file>", + 0, option_parse_exclude_from }, + OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, "file", + "read additional per-directory exclude patterns in <file>"), + { OPTION_CALLBACK, 0, "exclude-standard", &dir, NULL, + "add the standard git exclusions", + PARSE_OPT_NOARG, option_parse_exclude_standard }, + { OPTION_SET_INT, 0, "full-name", &prefix_offset, NULL, + "make the output relative to the project top directory", + PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL }, + OPT_BOOLEAN(0, "error-unmatch", &error_unmatch, + "if any <file> is not in the index, treat this as an error"), + OPT_STRING(0, "with-tree", &with_tree, "tree-ish", + "pretend that paths removed since <tree-ish> are still present"), + OPT__ABBREV(&abbrev), + OPT_END() + }; memset(&dir, 0, sizeof(dir)); if (prefix) prefix_offset = strlen(prefix); git_config(git_default_config, NULL); - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; - - if (!strcmp(arg, "--")) { - i++; - break; - } - if (!strcmp(arg, "-z")) { - line_terminator = 0; - continue; - } - if (!strcmp(arg, "-t") || !strcmp(arg, "-v")) { - tag_cached = "H "; - tag_unmerged = "M "; - tag_removed = "R "; - tag_modified = "C "; - tag_other = "? "; - tag_killed = "K "; - if (arg[1] == 'v') - show_valid_bit = 1; - continue; - } - if (!strcmp(arg, "-c") || !strcmp(arg, "--cached")) { - show_cached = 1; - continue; - } - if (!strcmp(arg, "-d") || !strcmp(arg, "--deleted")) { - show_deleted = 1; - continue; - } - if (!strcmp(arg, "-m") || !strcmp(arg, "--modified")) { - show_modified = 1; - require_work_tree = 1; - continue; - } - if (!strcmp(arg, "-o") || !strcmp(arg, "--others")) { - show_others = 1; - require_work_tree = 1; - continue; - } - if (!strcmp(arg, "-i") || !strcmp(arg, "--ignored")) { - dir.flags |= DIR_SHOW_IGNORED; - require_work_tree = 1; - continue; - } - if (!strcmp(arg, "-s") || !strcmp(arg, "--stage")) { - show_stage = 1; - continue; - } - if (!strcmp(arg, "-k") || !strcmp(arg, "--killed")) { - show_killed = 1; - require_work_tree = 1; - continue; - } - if (!strcmp(arg, "--directory")) { - dir.flags |= DIR_SHOW_OTHER_DIRECTORIES; - continue; - } - if (!strcmp(arg, "--no-empty-directory")) { - dir.flags |= DIR_HIDE_EMPTY_DIRECTORIES; - continue; - } - if (!strcmp(arg, "-u") || !strcmp(arg, "--unmerged")) { - /* There's no point in showing unmerged unless - * you also show the stage information. - */ - show_stage = 1; - show_unmerged = 1; - continue; - } - if (!strcmp(arg, "-x") && i+1 < argc) { - exc_given = 1; - add_exclude(argv[++i], "", 0, &dir.exclude_list[EXC_CMDL]); - continue; - } - if (!prefixcmp(arg, "--exclude=")) { - exc_given = 1; - add_exclude(arg+10, "", 0, &dir.exclude_list[EXC_CMDL]); - continue; - } - if (!strcmp(arg, "-X") && i+1 < argc) { - exc_given = 1; - add_excludes_from_file(&dir, argv[++i]); - continue; - } - if (!prefixcmp(arg, "--exclude-from=")) { - exc_given = 1; - add_excludes_from_file(&dir, arg+15); - continue; - } - if (!prefixcmp(arg, "--exclude-per-directory=")) { - exc_given = 1; - dir.exclude_per_dir = arg + 24; - continue; - } - if (!strcmp(arg, "--exclude-standard")) { - exc_given = 1; - setup_standard_excludes(&dir); - continue; - } - if (!strcmp(arg, "--full-name")) { - prefix_offset = 0; - continue; - } - if (!strcmp(arg, "--error-unmatch")) { - error_unmatch = 1; - continue; - } - if (!prefixcmp(arg, "--with-tree=")) { - with_tree = arg + 12; - continue; - } - if (!prefixcmp(arg, "--abbrev=")) { - abbrev = strtoul(arg+9, NULL, 10); - if (abbrev && abbrev < MINIMUM_ABBREV) - abbrev = MINIMUM_ABBREV; - else if (abbrev > 40) - abbrev = 40; - continue; - } - if (!strcmp(arg, "--abbrev")) { - abbrev = DEFAULT_ABBREV; - continue; - } - if (*arg == '-') - usage(ls_files_usage); - break; + argc = parse_options(argc, argv, builtin_ls_files_options, + ls_files_usage, 0); + if (show_tag || show_valid_bit) { + tag_cached = "H "; + tag_unmerged = "M "; + tag_removed = "R "; + tag_modified = "C "; + tag_other = "? "; + tag_killed = "K "; } + if (show_modified || show_others || (dir.flags & DIR_SHOW_IGNORED) || show_killed) + require_work_tree = 1; + if (show_unmerged) + /* + * There's no point in showing unmerged unless + * you also show the stage information. + */ + show_stage = 1; + if (dir.exclude_per_dir) + exc_given = 1; if (require_work_tree && !is_inside_work_tree()) setup_work_tree(); - pathspec = get_pathspec(prefix, argv + i); + pathspec = get_pathspec(prefix, argv); /* be nice with submodule patsh ending in a slash */ read_cache(); From 36419c8ee41cecadf67dfeab2808ff2e5025ca52 Mon Sep 17 00:00:00 2001 From: Kjetil Barvik <barvik@broadpark.no> Date: Wed, 18 Feb 2009 23:18:03 +0100 Subject: [PATCH 040/654] check_updates(): effective removal of cache entries marked CE_REMOVE Below is oprofile output from GIT command 'git chekcout -q my-v2.6.25' (move from tag v2.6.27 to tag v2.6.25 of the Linux kernel): CPU: Core 2, speed 1999.95 MHz (estimated) Counted CPU_CLK_UNHALTED events (Clock cycles when not halted) with a unit mask of 0x00 (Unhalted core cycles) count 20000 Counted INST_RETIRED_ANY_P events (number of instructions retired) with a unit mask of 0x00 (No unit mask) count 20000 CPU_CLK_UNHALT...|INST_RETIRED:2...| samples| %| samples| %| ------------------------------------ 409247 100.000 342878 100.000 git CPU_CLK_UNHALT...|INST_RETIRED:2...| samples| %| samples| %| ------------------------------------ 260476 63.6476 257843 75.1996 libz.so.1.2.3 100876 24.6492 64378 18.7758 kernel-2.6.28.4_2.vmlinux 30850 7.5382 7874 2.2964 libc-2.9.so 14775 3.6103 8390 2.4469 git 2020 0.4936 4325 1.2614 libcrypto.so.0.9.8 191 0.0467 32 0.0093 libpthread-2.9.so 58 0.0142 36 0.0105 ld-2.9.so 1 2.4e-04 0 0 libldap-2.3.so.0.2.31 Detail list of the top 20 function entries (libz counted in one blob): CPU_CLK_UNHALTED INST_RETIRED_ANY_P samples % samples % image name symbol name 260476 63.6862 257843 75.2725 libz.so.1.2.3 /lib/libz.so.1.2.3 16587 4.0555 3636 1.0615 libc-2.9.so memcpy 7710 1.8851 277 0.0809 libc-2.9.so memmove 3679 0.8995 1108 0.3235 kernel-2.6.28.4_2.vmlinux d_validate 3546 0.8670 2607 0.7611 kernel-2.6.28.4_2.vmlinux __getblk 3174 0.7760 1813 0.5293 libc-2.9.so _int_malloc 2396 0.5858 3681 1.0746 kernel-2.6.28.4_2.vmlinux copy_to_user 2270 0.5550 2528 0.7380 kernel-2.6.28.4_2.vmlinux __link_path_walk 2205 0.5391 1797 0.5246 kernel-2.6.28.4_2.vmlinux ext4_mark_iloc_dirty 2103 0.5142 1203 0.3512 kernel-2.6.28.4_2.vmlinux find_first_zero_bit 2077 0.5078 997 0.2911 kernel-2.6.28.4_2.vmlinux do_get_write_access 2070 0.5061 514 0.1501 git cache_name_compare 2043 0.4995 1501 0.4382 kernel-2.6.28.4_2.vmlinux rcu_irq_exit 2022 0.4944 1732 0.5056 kernel-2.6.28.4_2.vmlinux __ext4_get_inode_loc 2020 0.4939 4325 1.2626 libcrypto.so.0.9.8 /usr/lib/libcrypto.so.0.9.8 1965 0.4804 1384 0.4040 git patch_delta 1708 0.4176 984 0.2873 kernel-2.6.28.4_2.vmlinux rcu_sched_grace_period 1682 0.4112 727 0.2122 kernel-2.6.28.4_2.vmlinux sysfs_slab_alias 1659 0.4056 290 0.0847 git find_pack_entry_one 1480 0.3619 1307 0.3816 kernel-2.6.28.4_2.vmlinux ext4_writepage_trans_blocks Notice the memmove line, where the CPU did 7710 / 277 = 27.8 cycles per instruction, and compared to the total cycles spent inside the source code of GIT for this command, all the memmove() calls translates to (7710 * 100) / 14775 = 52.2% of this. Retesting with a GIT program compiled for gcov usage, I found out that the memmove() calls came from remove_index_entry_at() in read-cache.c, where we have: memmove(istate->cache + pos, istate->cache + pos + 1, (istate->cache_nr - pos) * sizeof(struct cache_entry *)); remove_index_entry_at() is called 4902 times from check_updates() in unpack-trees.c, and each time called we move each cache_entry pointers (from the removed one) one step to the left. Since we have 28828 entries in the cache this time, and if we on average move half of them each time, we in total move approximately 4902 * 0.5 * 28828 * 4 = 282 629 712 bytes, or twice this amount if each pointer is 8 bytes (64 bit). OK, is seems that the function check_updates() is called 28 times, so the estimated guess above had been more correct if check_updates() had been called only once, but the point is: we get lots of bytes moved. To fix this, and use an O(N) algorithm instead, where N is the number of cache_entries, we delete/remove all entries in one loop through all entries. From a retest, the new remove_marked_cache_entries() from the patch below, ended up with the following output line from oprofile: 46 0.0105 15 0.0041 git remove_marked_cache_entries If we can trust the numbers from oprofile in this case, we saved approximately ((7710 - 46) * 20000) / (2 * 1000 * 1000 * 1000) = 0.077 seconds CPU time with this fix for this particular test. And notice that now the CPU did only 46 / 15 = 3.1 cycles/instruction. Signed-off-by: Kjetil Barvik <barvik@broadpark.no> Acked-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- cache.h | 1 + read-cache.c | 20 ++++++++++++++++++++ unpack-trees.c | 4 +--- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/cache.h b/cache.h index 1bf2d4bde6..770d8bc950 100644 --- a/cache.h +++ b/cache.h @@ -445,6 +445,7 @@ extern int add_index_entry(struct index_state *, struct cache_entry *ce, int opt extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really); extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name); extern int remove_index_entry_at(struct index_state *, int pos); +extern void remove_marked_cache_entries(struct index_state *istate); extern int remove_file_from_index(struct index_state *, const char *path); #define ADD_CACHE_VERBOSE 1 #define ADD_CACHE_PRETEND 2 diff --git a/read-cache.c b/read-cache.c index 940ec76fdf..59a274b464 100644 --- a/read-cache.c +++ b/read-cache.c @@ -443,6 +443,26 @@ int remove_index_entry_at(struct index_state *istate, int pos) return 1; } +/* + * Remove all cache ententries marked for removal, that is where + * CE_REMOVE is set in ce_flags. This is much more effective than + * calling remove_index_entry_at() for each entry to be removed. + */ +void remove_marked_cache_entries(struct index_state *istate) +{ + struct cache_entry **ce_array = istate->cache; + unsigned int i, j; + + for (i = j = 0; i < istate->cache_nr; i++) { + if (ce_array[i]->ce_flags & CE_REMOVE) + remove_name_hash(ce_array[i]); + else + ce_array[j++] = ce_array[i]; + } + istate->cache_changed = 1; + istate->cache_nr = j; +} + int remove_file_from_index(struct index_state *istate, const char *path) { int pos = index_name_pos(istate, path, strlen(path)); diff --git a/unpack-trees.c b/unpack-trees.c index e3c3fa12aa..273b5da0a2 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -93,11 +93,9 @@ static int check_updates(struct unpack_trees_options *o) display_progress(progress, ++cnt); if (o->update) unlink_entry(ce); - remove_index_entry_at(&o->result, i); - i--; - continue; } } + remove_marked_cache_entries(&o->result); remove_scheduled_dirs(); for (i = 0; i < index->cache_nr; i++) { From 66648ad7fed840adef0343a1e0bf5188d32f5569 Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Wed, 18 Feb 2009 22:35:45 -0500 Subject: [PATCH 041/654] branch: clean up repeated strlen Commit 45e2b61 fixed the initialization of a "len" struct parameter via strlen. We can use that to clean up what is now 3 strlens in a 6-line sequence. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-branch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin-branch.c b/builtin-branch.c index 6106a1abd5..b15d3517f3 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -436,8 +436,8 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str item.kind = REF_LOCAL_BRANCH; item.dest = NULL; item.commit = head_commit; - if (strlen(item.name) > ref_list.maxwidth) - ref_list.maxwidth = strlen(item.name); + if (item.len > ref_list.maxwidth) + ref_list.maxwidth = item.len; print_ref_item(&item, ref_list.maxwidth, verbose, abbrev, 1, ""); free(item.name); } From 0afc304406196e4470fd2a628c3733e966068d98 Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Wed, 18 Feb 2009 22:34:44 -0500 Subject: [PATCH 042/654] add basic branch display tests We were not testing the output of "git branch" anywhere. Not only does this not protect us against regressions in the output, but we are not exercising code paths which may have bugs (such as the one fixed by 45e2b61). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t3203-branch-output.sh | 81 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100755 t/t3203-branch-output.sh diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh new file mode 100755 index 0000000000..809d1c4ed4 --- /dev/null +++ b/t/t3203-branch-output.sh @@ -0,0 +1,81 @@ +#!/bin/sh + +test_description='git branch display tests' +. ./test-lib.sh + +test_expect_success 'make commits' ' + echo content >file && + git add file && + git commit -m one && + echo content >>file && + git commit -a -m two +' + +test_expect_success 'make branches' ' + git branch branch-one + git branch branch-two HEAD^ +' + +test_expect_success 'make remote branches' ' + git update-ref refs/remotes/origin/branch-one branch-one + git update-ref refs/remotes/origin/branch-two branch-two + git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/branch-one +' + +cat >expect <<'EOF' + branch-one + branch-two +* master +EOF +test_expect_success 'git branch shows local branches' ' + git branch >actual && + test_cmp expect actual +' + +cat >expect <<'EOF' + origin/HEAD -> origin/branch-one + origin/branch-one + origin/branch-two +EOF +test_expect_success 'git branch -r shows remote branches' ' + git branch -r >actual && + test_cmp expect actual +' + +cat >expect <<'EOF' + branch-one + branch-two +* master + remotes/origin/HEAD -> origin/branch-one + remotes/origin/branch-one + remotes/origin/branch-two +EOF +test_expect_success 'git branch -a shows local and remote branches' ' + git branch -a >actual && + test_cmp expect actual +' + +cat >expect <<'EOF' +two +one +two +EOF +test_expect_success 'git branch -v shows branch summaries' ' + git branch -v >tmp && + awk "{print \$NF}" <tmp >actual && + test_cmp expect actual +' + +cat >expect <<'EOF' +* (no branch) + branch-one + branch-two + master +EOF +test_expect_success 'git branch shows detached HEAD properly' ' + git checkout HEAD^0 && + git branch >actual && + test_cmp expect actual +' + +test_done From 8cd6192e16d8bf590afa1105c840b72106d72941 Mon Sep 17 00:00:00 2001 From: Kjetil Barvik <barvik@broadpark.no> Date: Thu, 19 Feb 2009 21:08:28 +0100 Subject: [PATCH 043/654] fix compile error when USE_NSEC is defined 'struct cache' does not have a 'usec' member, but a 'unsigned int nsec' member. Simmilar 'struct stat' does not have a 'st_mtim.usec' member, and we should instead use 'st_mtim.tv_nsec'. Signed-off-by: Kjetil Barvik <barvik@broadpark.no> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-fetch-pack.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 67fb80ec48..3b210c7fdf 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -802,14 +802,14 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args, mtime.sec = st.st_mtime; #ifdef USE_NSEC - mtime.usec = st.st_mtim.usec; + mtime.nsec = st.st_mtim.tv_nsec; #endif if (stat(shallow, &st)) { if (mtime.sec) die("shallow file was removed during fetch"); } else if (st.st_mtime != mtime.sec #ifdef USE_NSEC - || st.st_mtim.usec != mtime.usec + || st.st_mtim.tv_nsec != mtime.nsec #endif ) die("shallow file was changed during fetch"); From fba2f38a2c2cda458e490c18e0afbb12cbd37969 Mon Sep 17 00:00:00 2001 From: Kjetil Barvik <barvik@broadpark.no> Date: Thu, 19 Feb 2009 21:08:29 +0100 Subject: [PATCH 044/654] make USE_NSEC work as expected Since the filesystem ext4 is now defined as stable in Linux v2.6.28, and ext4 supports nanonsecond resolution timestamps natively, it is time to make USE_NSEC work as expected. This will make racy git situations less likely to happen. For 'git checkout' this means it will be less likely that we have to open, read the contents of the file into RAM, and check if file is really modified or not. The result sould be a litle less used CPU time, less pagefaults and a litle faster program, at least for 'git checkout'. Since the number of possible racy git situations would increase when disks gets faster, this patch would be more and more helpfull as times go by. For a fast Solid State Disk, this patch should be helpfull. Note that, when file operations starts to take less than 1 nanosecond, one would again start to get more racy git situations. For more info on racy git, see Documentation/technical/racy-git.txt For more info on ext4, see http://kernelnewbies.org/Ext4 Signed-off-by: Kjetil Barvik <barvik@broadpark.no> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- cache.h | 6 ++--- read-cache.c | 70 ++++++++++++++++++++++++++++++++++++++++---------- unpack-trees.c | 8 ++++-- 3 files changed, 65 insertions(+), 19 deletions(-) diff --git a/cache.h b/cache.h index 770d8bc950..2badbfedc4 100644 --- a/cache.h +++ b/cache.h @@ -140,8 +140,8 @@ struct ondisk_cache_entry_extended { }; struct cache_entry { - unsigned int ce_ctime; - unsigned int ce_mtime; + struct cache_time ce_ctime; + struct cache_time ce_mtime; unsigned int ce_dev; unsigned int ce_ino; unsigned int ce_mode; @@ -282,7 +282,7 @@ struct index_state { struct cache_entry **cache; unsigned int cache_nr, cache_alloc, cache_changed; struct cache_tree *cache_tree; - time_t timestamp; + struct cache_time timestamp; void *alloc; unsigned name_hash_initialized : 1, initialized : 1; diff --git a/read-cache.c b/read-cache.c index 59a274b464..bb07371597 100644 --- a/read-cache.c +++ b/read-cache.c @@ -67,8 +67,15 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n */ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st) { - ce->ce_ctime = st->st_ctime; - ce->ce_mtime = st->st_mtime; + ce->ce_ctime.sec = (unsigned int)st->st_ctime; + ce->ce_mtime.sec = (unsigned int)st->st_mtime; +#ifdef USE_NSEC + ce->ce_ctime.nsec = (unsigned int)st->st_ctim.tv_nsec; + ce->ce_mtime.nsec = (unsigned int)st->st_mtim.tv_nsec; +#else + ce->ce_ctime.nsec = 0; + ce->ce_mtime.nsec = 0; +#endif ce->ce_dev = st->st_dev; ce->ce_ino = st->st_ino; ce->ce_uid = st->st_uid; @@ -196,11 +203,18 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) default: die("internal error: ce_mode is %o", ce->ce_mode); } - if (ce->ce_mtime != (unsigned int) st->st_mtime) + if (ce->ce_mtime.sec != (unsigned int)st->st_mtime) changed |= MTIME_CHANGED; - if (trust_ctime && ce->ce_ctime != (unsigned int) st->st_ctime) + if (trust_ctime && ce->ce_ctime.sec != (unsigned int)st->st_ctime) changed |= CTIME_CHANGED; +#ifdef USE_NSEC + if (ce->ce_mtime.nsec != (unsigned int)st->st_mtim.tv_nsec) + changed |= MTIME_CHANGED; + if (trust_ctime && ce->ce_ctime.nsec != (unsigned int)st->st_ctim.tv_nsec) + changed |= CTIME_CHANGED; +#endif + if (ce->ce_uid != (unsigned int) st->st_uid || ce->ce_gid != (unsigned int) st->st_gid) changed |= OWNER_CHANGED; @@ -232,8 +246,16 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) static int is_racy_timestamp(const struct index_state *istate, struct cache_entry *ce) { return (!S_ISGITLINK(ce->ce_mode) && - istate->timestamp && - ((unsigned int)istate->timestamp) <= ce->ce_mtime); + istate->timestamp.sec && +#ifdef USE_NSEC + /* nanosecond timestamped files can also be racy! */ + (istate->timestamp.sec < ce->ce_mtime.sec || + (istate->timestamp.sec == ce->ce_mtime.sec && + istate->timestamp.nsec <= ce->ce_mtime.nsec)) +#else + istate->timestamp.sec <= ce->ce_mtime.sec +#endif + ); } int ie_match_stat(const struct index_state *istate, @@ -1159,8 +1181,15 @@ static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_en size_t len; const char *name; - ce->ce_ctime = ntohl(ondisk->ctime.sec); - ce->ce_mtime = ntohl(ondisk->mtime.sec); + ce->ce_ctime.sec = ntohl(ondisk->ctime.sec); + ce->ce_mtime.sec = ntohl(ondisk->mtime.sec); +#ifdef USE_NSEC + ce->ce_ctime.nsec = ntohl(ondisk->ctime.nsec); + ce->ce_mtime.nsec = ntohl(ondisk->mtime.nsec); +#else + ce->ce_ctime.nsec = 0; + ce->ce_mtime.nsec = 0; +#endif ce->ce_dev = ntohl(ondisk->dev); ce->ce_ino = ntohl(ondisk->ino); ce->ce_mode = ntohl(ondisk->mode); @@ -1226,7 +1255,8 @@ int read_index_from(struct index_state *istate, const char *path) return istate->cache_nr; errno = ENOENT; - istate->timestamp = 0; + istate->timestamp.sec = 0; + istate->timestamp.nsec = 0; fd = open(path, O_RDONLY); if (fd < 0) { if (errno == ENOENT) @@ -1278,7 +1308,13 @@ int read_index_from(struct index_state *istate, const char *path) src_offset += ondisk_ce_size(ce); dst_offset += ce_size(ce); } - istate->timestamp = st.st_mtime; + istate->timestamp.sec = st.st_mtime; +#ifdef USE_NSEC + istate->timestamp.nsec = (unsigned int)st.st_mtim.tv_nsec; +#else + istate->timestamp.nsec = 0; +#endif + while (src_offset <= mmap_size - 20 - 8) { /* After an array of active_nr index entries, * there can be arbitrary number of extended @@ -1308,14 +1344,15 @@ unmap: int is_index_unborn(struct index_state *istate) { - return (!istate->cache_nr && !istate->alloc && !istate->timestamp); + return (!istate->cache_nr && !istate->alloc && !istate->timestamp.sec); } int discard_index(struct index_state *istate) { istate->cache_nr = 0; istate->cache_changed = 0; - istate->timestamp = 0; + istate->timestamp.sec = 0; + istate->timestamp.nsec = 0; istate->name_hash_initialized = 0; free_hash(&istate->name_hash); cache_tree_free(&(istate->cache_tree)); @@ -1461,10 +1498,15 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce) struct ondisk_cache_entry *ondisk = xcalloc(1, size); char *name; - ondisk->ctime.sec = htonl(ce->ce_ctime); + ondisk->ctime.sec = htonl(ce->ce_ctime.sec); + ondisk->mtime.sec = htonl(ce->ce_mtime.sec); +#ifdef USE_NSEC + ondisk->ctime.nsec = htonl(ce->ce_ctime.nsec); + ondisk->mtime.nsec = htonl(ce->ce_mtime.nsec); +#else ondisk->ctime.nsec = 0; - ondisk->mtime.sec = htonl(ce->ce_mtime); ondisk->mtime.nsec = 0; +#endif ondisk->dev = htonl(ce->ce_dev); ondisk->ino = htonl(ce->ce_ino); ondisk->mode = htonl(ce->ce_mode); diff --git a/unpack-trees.c b/unpack-trees.c index 273b5da0a2..11902cd51d 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -360,8 +360,12 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options memset(&o->result, 0, sizeof(o->result)); o->result.initialized = 1; - if (o->src_index) - o->result.timestamp = o->src_index->timestamp; + if (o->src_index) { + o->result.timestamp.sec = o->src_index->timestamp.sec; +#ifdef USE_NSEC + o->result.timestamp.nsec = o->src_index->timestamp.nsec; +#endif + } o->merge_size = len; if (!dfc) From 1dcafcc0e639ecc69b54421bda5f2270ed2601eb Mon Sep 17 00:00:00 2001 From: Kjetil Barvik <barvik@broadpark.no> Date: Thu, 19 Feb 2009 21:08:30 +0100 Subject: [PATCH 045/654] verify_uptodate(): add ce_uptodate(ce) test If we inside verify_uptodate() can already tell from the ce entry that it is already uptodate by testing it with ce_uptodate(ce), there is no need to call lstat(2) and ie_match_stat() afterwards. And, reading from the commit log message from: commit eadb5831342bb2e756fa05c03642c4aa1929d4f5 Author: Junio C Hamano <gitster@pobox.com> Date: Fri Jan 18 23:45:24 2008 -0800 Avoid running lstat(2) on the same cache entry. this also seems to be correct usage of the ce_uptodate() macro introduced by that patch. This will avoid lots of lstat(2) calls in some cases, for example by running the 'git checkout' command. Signed-off-by: Kjetil Barvik <barvik@broadpark.no> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- unpack-trees.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unpack-trees.c b/unpack-trees.c index 11902cd51d..9fe0cd5f9b 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -430,7 +430,7 @@ static int verify_uptodate(struct cache_entry *ce, { struct stat st; - if (o->index_only || o->reset) + if (o->index_only || o->reset || ce_uptodate(ce)) return 0; if (!lstat(ce->name, &st)) { From 484cf6c3f1169786c45ccda54c9961ef66465c03 Mon Sep 17 00:00:00 2001 From: Thomas Rast <trast@student.ethz.ch> Date: Thu, 19 Feb 2009 22:26:30 +0100 Subject: [PATCH 046/654] format-patch: threading test reactivation t4014 tests format-patch --thread since 7d812145, but the tests were ineffective right from the start at least for bash and dash. The loops of the form for ...; do something || break; done introduced by 7d812145 and 5d02294 always exit with status 0, even if 'something' failed, because 'break' returns 0 unless there was no loop to break. We take a rather different approach that uses an admittedly heinous inline Perl script to mangle all interesting information into a format that is invariant between runs. We can then test the full patch sequence in one go (with --stdout), doing away with the loop problem. Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t4014-format-patch.sh | 142 +++++++++++++++++++++++++++++----------- 1 file changed, 103 insertions(+), 39 deletions(-) diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index f045898fe3..345e6deab6 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -138,56 +138,120 @@ test_expect_success 'multiple files' ' ls patches/0001-Side-changes-1.patch patches/0002-Side-changes-2.patch patches/0003-Side-changes-3-with-n-backslash-n-in-it.patch ' -test_expect_success 'thread' ' +check_threading () { + expect="$1" && + shift && + (git format-patch --stdout "$@"; echo $? > status.out) | + # Prints everything between the Message-ID and In-Reply-To, + # and replaces all Message-ID-lookalikes by a sequence number + perl -ne ' + if (/^(message-id|references|in-reply-to)/i) { + $printing = 1; + } elsif (/^\S/) { + $printing = 0; + } + if ($printing) { + $h{$1}=$i++ if (/<([^>]+)>/ and !exists $h{$1}); + for $k (keys %h) {s/$k/$h{$k}/}; + print; + } + print "---\n" if /^From /i; + ' > actual && + test 0 = "$(cat status.out)" && + test_cmp "$expect" actual +} - rm -rf patches/ && +cat >> expect.no-threading <<EOF +--- +--- +--- +EOF + +test_expect_success 'no threading' ' git checkout side && - git format-patch --thread -o patches/ master && - FIRST_MID=$(grep "Message-Id:" patches/0001-* | sed "s/^[^<]*\(<[^>]*>\).*$/\1/") && - for i in patches/0002-* patches/0003-* - do - grep "References: $FIRST_MID" $i && - grep "In-Reply-To: $FIRST_MID" $i || break - done + check_threading expect.no-threading master ' +cat > expect.thread <<EOF +--- +Message-Id: <0> +--- +Message-Id: <1> +In-Reply-To: <0> +References: <0> +--- +Message-Id: <2> +In-Reply-To: <0> +References: <0> +EOF + +test_expect_success 'thread' ' + check_threading expect.thread --thread master +' + +cat > expect.in-reply-to <<EOF +--- +Message-Id: <0> +In-Reply-To: <1> +References: <1> +--- +Message-Id: <2> +In-Reply-To: <1> +References: <1> +--- +Message-Id: <3> +In-Reply-To: <1> +References: <1> +EOF + test_expect_success 'thread in-reply-to' ' - - rm -rf patches/ && - git checkout side && - git format-patch --in-reply-to="<test.message>" --thread -o patches/ master && - FIRST_MID="<test.message>" && - for i in patches/* - do - grep "References: $FIRST_MID" $i && - grep "In-Reply-To: $FIRST_MID" $i || break - done + check_threading expect.in-reply-to --in-reply-to="<test.message>" \ + --thread master ' +cat > expect.cover-letter <<EOF +--- +Message-Id: <0> +--- +Message-Id: <1> +In-Reply-To: <0> +References: <0> +--- +Message-Id: <2> +In-Reply-To: <0> +References: <0> +--- +Message-Id: <3> +In-Reply-To: <0> +References: <0> +EOF + test_expect_success 'thread cover-letter' ' - - rm -rf patches/ && - git checkout side && - git format-patch --cover-letter --thread -o patches/ master && - FIRST_MID=$(grep "Message-Id:" patches/0000-* | sed "s/^[^<]*\(<[^>]*>\).*$/\1/") && - for i in patches/0001-* patches/0002-* patches/0003-* - do - grep "References: $FIRST_MID" $i && - grep "In-Reply-To: $FIRST_MID" $i || break - done + check_threading expect.cover-letter --cover-letter --thread master ' -test_expect_success 'thread cover-letter in-reply-to' ' +cat > expect.cl-irt <<EOF +--- +Message-Id: <0> +In-Reply-To: <1> +References: <1> +--- +Message-Id: <2> +In-Reply-To: <1> +References: <1> +--- +Message-Id: <3> +In-Reply-To: <1> +References: <1> +--- +Message-Id: <4> +In-Reply-To: <1> +References: <1> +EOF - rm -rf patches/ && - git checkout side && - git format-patch --cover-letter --in-reply-to="<test.message>" --thread -o patches/ master && - FIRST_MID="<test.message>" && - for i in patches/* - do - grep "References: $FIRST_MID" $i && - grep "In-Reply-To: $FIRST_MID" $i || break - done +test_expect_success 'thread cover-letter in-reply-to' ' + check_threading expect.cl-irt --cover-letter \ + --in-reply-to="<test.message>" --thread master ' test_expect_success 'excessive subject' ' From 901c369af52ffcc8c08457fb5b330eab217a9cfb Mon Sep 17 00:00:00 2001 From: Thomas Rast <trast@student.ethz.ch> Date: Thu, 19 Feb 2009 12:13:35 +0100 Subject: [PATCH 047/654] Support coverage testing with GCC/gcov With gcc's --coverage option, we can perform automatic coverage data collection for the test suite. Add a new Makefile target 'coverage' that scraps all previous coverage results, recompiles git with the required compiler/linker flags (in addition to any flags you specify manually), then runs the test suite and compiles a report. The compilation must be done with all optimizations disabled, since inlined functions (and for line-by-line coverage, also optimized branches/loops) break coverage tracking. The tests are run serially (with -j1). The coverage code should theoretically allow concurrent access to its data files, but the author saw random test failures. Obviously this could be improved. The report currently consists of a list of functions that were never executed during the tests, which is written to 'coverage-untested-functions'. Once this list becomes reasonably short, we would also want to look at branches that were never taken. Currently only toplevel *.c files are considered. It would be nice to at least include xdiff, but --coverage did not save data to subdirectories on the system used to write this (gcc 4.3.2). Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Makefile b/Makefile index b040a96e50..c32881b00b 100644 --- a/Makefile +++ b/Makefile @@ -1640,3 +1640,27 @@ check-docs:: check-builtins:: ./check-builtins.sh +### Test suite coverage testing +# +.PHONY: coverage coverage-clean coverage-build coverage-report + +coverage: + $(MAKE) coverage-build + $(MAKE) coverage-report + +coverage-clean: + rm -f *.gcda *.gcno + +COVERAGE_CFLAGS = $(CFLAGS) -O0 -ftest-coverage -fprofile-arcs +COVERAGE_LDFLAGS = $(CFLAGS) -O0 -lgcov + +coverage-build: coverage-clean + $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" all + $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \ + -j1 test + +coverage-report: + gcov -b *.c + grep '^function.*called 0 ' *.c.gcov \ + | sed -e 's/\([^:]*\)\.gcov: *function \([^ ]*\) called.*/\1: \2/' \ + | tee coverage-untested-functions From 85569d7498f3933d96a7604512f8832c73127067 Mon Sep 17 00:00:00 2001 From: Thomas Rast <trast@student.ethz.ch> Date: Thu, 19 Feb 2009 12:13:36 +0100 Subject: [PATCH 048/654] Test that diff can read from stdin Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t4002-diff-basic.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/t/t4002-diff-basic.sh b/t/t4002-diff-basic.sh index cc3681f161..18695ce821 100755 --- a/t/t4002-diff-basic.sh +++ b/t/t4002-diff-basic.sh @@ -258,4 +258,12 @@ test_expect_success \ git diff-tree -r -R $tree_A $tree_B >.test-b && cmp -s .test-a .test-b' +test_expect_success \ + 'diff can read from stdin' \ + 'test_must_fail git diff --no-index -- MN - < NN | + grep -v "^index" | sed "s#/-#/NN#" >.test-a && + test_must_fail git diff --no-index -- MN NN | + grep -v "^index" >.test-b && + test_cmp .test-a .test-b' + test_done From f37bfb7a4d965e821591c98e66fe7a4e396377b5 Mon Sep 17 00:00:00 2001 From: Thomas Rast <trast@student.ethz.ch> Date: Thu, 19 Feb 2009 12:13:37 +0100 Subject: [PATCH 049/654] Test diff --dirstat functionality This is only a very rudimentary test, but it was untested before. Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t4013-diff-various.sh | 1 + t/t4013/diff.diff_--dirstat_master~1_master~2 | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 t/t4013/diff.diff_--dirstat_master~1_master~2 diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index aba53202f8..f140b9cd49 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -263,6 +263,7 @@ diff --name-status dir2 dir diff --no-index --name-status dir2 dir diff --no-index --name-status -- dir2 dir diff master master^ side +diff --dirstat master~1 master~2 EOF test_done diff --git a/t/t4013/diff.diff_--dirstat_master~1_master~2 b/t/t4013/diff.diff_--dirstat_master~1_master~2 new file mode 100644 index 0000000000..b672e1ca63 --- /dev/null +++ b/t/t4013/diff.diff_--dirstat_master~1_master~2 @@ -0,0 +1,3 @@ +$ git diff --dirstat master~1 master~2 + 40.0% dir/ +$ From 289e162318bbf4b0f90dd70371046e1b20d4c0be Mon Sep 17 00:00:00 2001 From: Thomas Rast <trast@student.ethz.ch> Date: Thu, 19 Feb 2009 12:13:38 +0100 Subject: [PATCH 050/654] Test log --graph So far there were no tests checking that log --graph actually works. Note that the tests strip trailing whitespace, as the current --graph emits trailing whitespace on lines that do not contain anything but graph lines. Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t4202-log.sh | 148 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 7b976ee36d..93966f78f8 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -134,5 +134,153 @@ test_expect_success 'log --grep -i' ' test_cmp expect actual ' +cat > expect <<EOF +* Second +* sixth +* fifth +* fourth +* third +* second +* initial +EOF + +test_expect_success 'simple log --graph' ' + git log --graph --pretty=tformat:%s >actual && + test_cmp expect actual +' + +test_expect_success 'set up merge history' ' + git checkout -b side HEAD~4 && + test_commit side-1 1 1 && + test_commit side-2 2 2 && + git checkout master && + git merge side +' + +cat > expect <<\EOF +* Merge branch 'side' +|\ +| * side-2 +| * side-1 +* | Second +* | sixth +* | fifth +* | fourth +|/ +* third +* second +* initial +EOF + +test_expect_success 'log --graph with merge' ' + git log --graph --date-order --pretty=tformat:%s | + sed "s/ *$//" >actual && + test_cmp expect actual +' + +cat > expect <<\EOF +* commit master +|\ Merge: A B +| | Author: A U Thor <author@example.com> +| | +| | Merge branch 'side' +| | +| * commit side +| | Author: A U Thor <author@example.com> +| | +| | side-2 +| | +| * commit tags/side-1 +| | Author: A U Thor <author@example.com> +| | +| | side-1 +| | +* | commit master~1 +| | Author: A U Thor <author@example.com> +| | +| | Second +| | +* | commit master~2 +| | Author: A U Thor <author@example.com> +| | +| | sixth +| | +* | commit master~3 +| | Author: A U Thor <author@example.com> +| | +| | fifth +| | +* | commit master~4 +|/ Author: A U Thor <author@example.com> +| +| fourth +| +* commit tags/side-1~1 +| Author: A U Thor <author@example.com> +| +| third +| +* commit tags/side-1~2 +| Author: A U Thor <author@example.com> +| +| second +| +* commit tags/side-1~3 + Author: A U Thor <author@example.com> + + initial +EOF + +test_expect_success 'log --graph with full output' ' + git log --graph --date-order --pretty=short | + git name-rev --name-only --stdin | + sed "s/Merge:.*/Merge: A B/;s/ *$//" >actual && + test_cmp expect actual +' + +test_expect_success 'set up more tangled history' ' + git checkout -b tangle HEAD~6 && + test_commit tangle-a tangle-a a && + git merge master~3 && + git merge side~1 && + git checkout master && + git merge tangle +' + +cat > expect <<\EOF +* Merge branch 'tangle' +|\ +| * Merge branch 'side' (early part) into tangle +| |\ +| * \ Merge branch 'master' (early part) into tangle +| |\ \ +| * | | tangle-a +* | | | Merge branch 'side' +|\ \ \ \ +| * | | | side-2 +| | | |/ +| | |/| +| |/| | +| * | | side-1 +* | | | Second +* | | | sixth +| | |/ +| |/| +|/| | +* | | fifth +* | | fourth +|/ / +* | third +|/ +* second +* initial +EOF + +test_expect_success 'log --graph with merge' ' + git log --graph --date-order --pretty=tformat:%s | + sed "s/ *$//" >actual && + test_cmp expect actual +' + test_done From 02a6552c28eabb524fcd23e8f5bd36e4f5afa63b Mon Sep 17 00:00:00 2001 From: Thomas Rast <trast@student.ethz.ch> Date: Thu, 19 Feb 2009 12:13:39 +0100 Subject: [PATCH 051/654] Test fsck a bit harder git-fsck, of all tools, has very few tests. This adds some more: * a corrupted object; * a branch pointing to a non-commit; * a tag pointing to a nonexistent object; * and a tag pointing to an object of a type other than what the tag itself claims. Only the first two are caught. At least the third probably should, too, but currently slips through. Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t1450-fsck.sh | 67 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index 4597af0eb6..a22632f483 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -28,4 +28,71 @@ test_expect_success 'loose objects borrowed from alternate are not missing' ' ) ' +# Corruption tests follow. Make sure to remove all traces of the +# specific corruption you test afterwards, lest a later test trip over +# it. + +test_expect_success 'object with bad sha1' ' + sha=$(echo blob | git hash-object -w --stdin) && + echo $sha && + old=$(echo $sha | sed "s+^..+&/+") && + new=$(dirname $old)/ffffffffffffffffffffffffffffffffffffff && + sha="$(dirname $new)$(basename $new)" + mv .git/objects/$old .git/objects/$new && + git update-index --add --cacheinfo 100644 $sha foo && + tree=$(git write-tree) && + cmt=$(echo bogus | git commit-tree $tree) && + git update-ref refs/heads/bogus $cmt && + (git fsck 2>out; true) && + grep "$sha.*corrupt" out && + rm -f .git/objects/$new && + git update-ref -d refs/heads/bogus && + git read-tree -u --reset HEAD +' + +test_expect_success 'branch pointing to non-commit' ' + git rev-parse HEAD^{tree} > .git/refs/heads/invalid && + git fsck 2>out && + grep "not a commit" out && + git update-ref -d refs/heads/invalid +' + +cat > invalid-tag <<EOF +object ffffffffffffffffffffffffffffffffffffffff +type commit +tag invalid +tagger T A Gger <tagger@example.com> 1234567890 -0000 + +This is an invalid tag. +EOF + +test_expect_failure 'tag pointing to nonexistent' ' + tag=$(git hash-object -w --stdin < invalid-tag) && + echo $tag > .git/refs/tags/invalid && + git fsck --tags 2>out && + cat out && + grep "could not load tagged object" out && + rm .git/refs/tags/invalid +' + +cat > wrong-tag <<EOF +object $(echo blob | git hash-object -w --stdin) +type commit +tag wrong +tagger T A Gger <tagger@example.com> 1234567890 -0000 + +This is an invalid tag. +EOF + +test_expect_failure 'tag pointing to something else than its type' ' + tag=$(git hash-object -w --stdin < wrong-tag) && + echo $tag > .git/refs/tags/wrong && + git fsck --tags 2>out && + cat out && + grep "some sane error message" out && + rm .git/refs/tags/wrong +' + + + test_done From 28fd76bd0413e386ce5176cfac0fad7317145b91 Mon Sep 17 00:00:00 2001 From: Thomas Rast <trast@student.ethz.ch> Date: Thu, 19 Feb 2009 12:13:40 +0100 Subject: [PATCH 052/654] Test log --decorate Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t4013-diff-various.sh | 1 + t/t4013/diff.log_--decorate_--all | 34 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 t/t4013/diff.log_--decorate_--all diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index f140b9cd49..e5715f35cf 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -203,6 +203,7 @@ log --root -c --patch-with-stat --summary master log --root --cc --patch-with-stat --summary master log -SF master log -SF -p master +log --decorate --all whatchanged master whatchanged -p master diff --git a/t/t4013/diff.log_--decorate_--all b/t/t4013/diff.log_--decorate_--all new file mode 100644 index 0000000000..12da8ac07d --- /dev/null +++ b/t/t4013/diff.log_--decorate_--all @@ -0,0 +1,34 @@ +$ git log --decorate --all +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (refs/heads/master) +Merge: 9a6d494 c7a2ab9 +Author: A U Thor <author@example.com> +Date: Mon Jun 26 00:04:00 2006 +0000 + + Merge branch 'side' + +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (refs/heads/side) +Author: A U Thor <author@example.com> +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side + +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 +Author: A U Thor <author@example.com> +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third + +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 +Author: A U Thor <author@example.com> +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second + + This is the second commit. + +commit 444ac553ac7612cc88969031b02b3767fb8a353a (refs/heads/initial) +Author: A U Thor <author@example.com> +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial +$ From fcbc6efc7c56973e0a308012d2ae1b42c6b11a33 Mon Sep 17 00:00:00 2001 From: Thomas Rast <trast@student.ethz.ch> Date: Thu, 19 Feb 2009 12:13:41 +0100 Subject: [PATCH 053/654] Test rev-list --parents/--children Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t4013-diff-various.sh | 3 +++ t/t4013/diff.rev-list_--children_HEAD | 7 +++++++ t/t4013/diff.rev-list_--parents_HEAD | 7 +++++++ 3 files changed, 17 insertions(+) create mode 100644 t/t4013/diff.rev-list_--children_HEAD create mode 100644 t/t4013/diff.rev-list_--parents_HEAD diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index e5715f35cf..0f359ca28e 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -205,6 +205,9 @@ log -SF master log -SF -p master log --decorate --all +rev-list --parents HEAD +rev-list --children HEAD + whatchanged master whatchanged -p master whatchanged --root master diff --git a/t/t4013/diff.rev-list_--children_HEAD b/t/t4013/diff.rev-list_--children_HEAD new file mode 100644 index 0000000000..e7f17d5aa0 --- /dev/null +++ b/t/t4013/diff.rev-list_--children_HEAD @@ -0,0 +1,7 @@ +$ git rev-list --children HEAD +59d314ad6f356dd08601a4cd5e530381da3e3c64 +c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a 59d314ad6f356dd08601a4cd5e530381da3e3c64 +9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 59d314ad6f356dd08601a4cd5e530381da3e3c64 +1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 +444ac553ac7612cc88969031b02b3767fb8a353a 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +$ diff --git a/t/t4013/diff.rev-list_--parents_HEAD b/t/t4013/diff.rev-list_--parents_HEAD new file mode 100644 index 0000000000..65d2a80208 --- /dev/null +++ b/t/t4013/diff.rev-list_--parents_HEAD @@ -0,0 +1,7 @@ +$ git rev-list --parents HEAD +59d314ad6f356dd08601a4cd5e530381da3e3c64 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a 444ac553ac7612cc88969031b02b3767fb8a353a +9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 +1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 444ac553ac7612cc88969031b02b3767fb8a353a +444ac553ac7612cc88969031b02b3767fb8a353a +$ From b26d8d217d8d960cbd9ed1dbf6b3cccfd1a3a4db Mon Sep 17 00:00:00 2001 From: Thomas Rast <trast@student.ethz.ch> Date: Thu, 19 Feb 2009 12:13:42 +0100 Subject: [PATCH 054/654] Test git-patch-id So far, git-patch-id was untested. Add some simple checks for output format and patch (in)equality. Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t4203-patch-id.sh | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100755 t/t4203-patch-id.sh diff --git a/t/t4203-patch-id.sh b/t/t4203-patch-id.sh new file mode 100755 index 0000000000..04f7bae850 --- /dev/null +++ b/t/t4203-patch-id.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +test_description='git patch-id' + +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit initial foo a && + test_commit first foo b && + git checkout -b same HEAD^ && + test_commit same-msg foo b && + git checkout -b notsame HEAD^ && + test_commit notsame-msg foo c +' + +test_expect_success 'patch-id output is well-formed' ' + git log -p -1 | git patch-id > output && + grep "^[a-f0-9]\{40\} $(git rev-parse HEAD)$" output +' + +get_patch_id () { + git log -p -1 "$1" | git patch-id | + sed "s# .*##" > patch-id_"$1" +} + +test_expect_success 'patch-id detects equality' ' + get_patch_id master && + get_patch_id same && + test_cmp patch-id_master patch-id_same +' + +test_expect_success 'patch-id detects inequality' ' + get_patch_id master && + get_patch_id notsame && + ! test_cmp patch-id_master patch-id_notsame +' + +test_done From b079c50e03a812f5c8197b8f38e0a5fe6dd31321 Mon Sep 17 00:00:00 2001 From: Thomas Rast <trast@student.ethz.ch> Date: Thu, 19 Feb 2009 22:26:31 +0100 Subject: [PATCH 055/654] format-patch: track several references Currently, format-patch can only track a single reference (the In-Reply-To:) for each mail. To ensure proper threading, we should list all known references for every mail. Change the rev_info.ref_message_id field to a string_list, so that we can append references at will, and change the output formatting routines to print all of them in the References: header. The last entry in the list is implicitly assumed to be the In-Reply-To:, which gives output consistent with RFC 2822: The "References:" field will contain the contents of the parent's "References:" field (if any) followed by the contents of the parent's "Message-ID:" field (if any). Note that this is just preparatory work; nothing uses it yet, so all "References:" fields in the output are still only one deep. Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-log.c | 14 ++++++++++---- log-tree.c | 11 ++++++++--- revision.h | 2 +- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/builtin-log.c b/builtin-log.c index 2ae39afccd..59671139b8 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -17,6 +17,7 @@ #include "run-command.h" #include "shortlog.h" #include "remote.h" +#include "string-list.h" /* Set a default date-time format for git log ("log.date" config variable) */ static const char *default_date_mode = NULL; @@ -1011,8 +1012,12 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) numbered = 1; if (numbered) rev.total = total + start_number - 1; - if (in_reply_to) - rev.ref_message_id = clean_message_id(in_reply_to); + if (in_reply_to || thread || cover_letter) + rev.ref_message_ids = xcalloc(1, sizeof(struct string_list)); + if (in_reply_to) { + const char *msgid = clean_message_id(in_reply_to); + string_list_append(msgid, rev.ref_message_ids); + } if (cover_letter) { if (thread) gen_message_id(&rev, "cover"); @@ -1036,10 +1041,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) * otherwise, make everything a reply * to that. */ - if (rev.ref_message_id) + if (rev.ref_message_ids->nr > 0) free(rev.message_id); else - rev.ref_message_id = rev.message_id; + string_list_append(rev.message_id, + rev.ref_message_ids); } gen_message_id(&rev, sha1_to_hex(commit->object.sha1)); } diff --git a/log-tree.c b/log-tree.c index 84a74e544b..a315ebb78f 100644 --- a/log-tree.c +++ b/log-tree.c @@ -6,6 +6,7 @@ #include "log-tree.h" #include "reflog-walk.h" #include "refs.h" +#include "string-list.h" struct decoration name_decoration = { "object names" }; @@ -211,9 +212,13 @@ void log_write_email_headers(struct rev_info *opt, const char *name, printf("Message-Id: <%s>\n", opt->message_id); graph_show_oneline(opt->graph); } - if (opt->ref_message_id) { - printf("In-Reply-To: <%s>\nReferences: <%s>\n", - opt->ref_message_id, opt->ref_message_id); + if (opt->ref_message_ids && opt->ref_message_ids->nr > 0) { + int i, n; + n = opt->ref_message_ids->nr; + printf("In-Reply-To: <%s>\n", opt->ref_message_ids->items[n-1].string); + for (i = 0; i < n; i++) + printf("%s<%s>\n", (i > 0 ? "\t" : "References: "), + opt->ref_message_ids->items[i].string); graph_show_oneline(opt->graph); } if (opt->mime_boundary) { diff --git a/revision.h b/revision.h index 7cf848771b..8c0a41713c 100644 --- a/revision.h +++ b/revision.h @@ -89,7 +89,7 @@ struct rev_info { int nr, total; const char *mime_boundary; char *message_id; - const char *ref_message_id; + struct string_list *ref_message_ids; const char *add_signoff; const char *extra_headers; const char *log_reencode; From 2175c10d5ad2769936f5bf5bcca5ea32715a7307 Mon Sep 17 00:00:00 2001 From: Thomas Rast <trast@student.ethz.ch> Date: Thu, 19 Feb 2009 22:26:32 +0100 Subject: [PATCH 056/654] format-patch: thread as reply to cover letter even with in-reply-to Currently, format-patch --thread --cover-letter --in-reply-to $parent makes all mails, including the cover letter, a reply to $parent. However, we would want the reader to consider the cover letter above all the patches. This changes the semantics so that only the cover letter is a reply to $parent, while all the patches are formatted as replies to the cover letter. Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-log.c | 20 +++++++++++++++----- t/t4014-format-patch.sh | 9 ++++++--- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/builtin-log.c b/builtin-log.c index 59671139b8..1df38e17a2 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -1036,12 +1036,22 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) /* Have we already had a message ID? */ if (rev.message_id) { /* - * If we've got the ID to be a reply - * to, discard the current ID; - * otherwise, make everything a reply - * to that. + * Without --cover-letter and + * --in-reply-to, make every mail a + * reply to the one before. + * + * With --in-reply-to but no + * --cover-letter, make every mail a + * reply to the <reply-to>. + * + * With --cover-letter, make every + * mail but the cover letter a reply + * to the cover letter. The cover + * letter is a reply to the + * --in-reply-to, if specified. */ - if (rev.ref_message_ids->nr > 0) + if (rev.ref_message_ids->nr > 0 + && (!cover_letter || rev.nr > 1)) free(rev.message_id); else string_list_append(rev.message_id, diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 345e6deab6..8b970c39a2 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -237,16 +237,19 @@ In-Reply-To: <1> References: <1> --- Message-Id: <2> -In-Reply-To: <1> +In-Reply-To: <0> References: <1> + <0> --- Message-Id: <3> -In-Reply-To: <1> +In-Reply-To: <0> References: <1> + <0> --- Message-Id: <4> -In-Reply-To: <1> +In-Reply-To: <0> References: <1> + <0> EOF test_expect_success 'thread cover-letter in-reply-to' ' From 30984ed2e92651962c6b8bdacf1f84da75d1da95 Mon Sep 17 00:00:00 2001 From: Thomas Rast <trast@student.ethz.ch> Date: Thu, 19 Feb 2009 22:26:33 +0100 Subject: [PATCH 057/654] format-patch: support deep threading For deep threading mode, i.e., the mode that gives a thread structured like + [PATCH 0/n] Cover letter `-+ [PATCH 1/n] First patch `-+ [PATCH 2/n] Second patch `-+ ... we currently have to use 'git send-email --thread' (the default). On the other hand, format-patch also has a --thread option which gives shallow mode, i.e., + [PATCH 0/n] Cover letter |-+ [PATCH 1/n] First patch |-+ [PATCH 2/n] Second patch ... To reduce the confusion resulting from having two indentically named features in different tools giving different results, let format-patch take an optional argument '--thread=deep' that gives the same output as 'send-mail --thread'. With no argument, or 'shallow', behave as before. Also add a configuration variable format.thread with the same semantics. Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 10 +++ Documentation/git-format-patch.txt | 10 ++- builtin-log.c | 35 ++++++++- t/t4014-format-patch.sh | 120 +++++++++++++++++++++++++++++ 4 files changed, 170 insertions(+), 5 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index f5152c5038..300ab25dcf 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -677,6 +677,16 @@ format.pretty:: See linkgit:git-log[1], linkgit:git-show[1], linkgit:git-whatchanged[1]. +format.thread:: + The default threading style for 'git-format-patch'. Can be + either a boolean value, `shallow` or `deep`. 'Shallow' + threading makes every mail a reply to the head of the series, + where the head is chosen from the cover letter, the + `\--in-reply-to`, and the first patch mail, in this order. + 'Deep' threading makes every mail a reply to the previous one. + A true boolean value is the same as `shallow`, and a false + value disables threading. + gc.aggressiveWindow:: The window size parameter used in the delta compression algorithm used by 'git-gc --aggressive'. This defaults diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index 11a7d77261..4302b1490b 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -122,10 +122,18 @@ include::diff-options.txt[] which is the commit message and the patch itself in the second part, with "Content-Disposition: inline". ---thread:: +--thread[=<style>]:: Add In-Reply-To and References headers to make the second and subsequent mails appear as replies to the first. Also generates the Message-Id header to reference. ++ +The optional <style> argument can be either `shallow` or `deep`. +'Shallow' threading makes every mail a reply to the head of the +series, where the head is chosen from the cover letter, the +`\--in-reply-to`, and the first patch mail, in this order. 'Deep' +threading makes every mail a reply to the previous one. If not +specified, defaults to the 'format.thread' configuration, or `shallow` +if that is not set. --in-reply-to=Message-Id:: Make the first mail (or all the mails with --no-thread) appear as a diff --git a/builtin-log.c b/builtin-log.c index 1df38e17a2..6bf04e8afe 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -460,6 +460,10 @@ static void add_header(const char *value) extra_hdr[extra_hdr_nr++] = xstrndup(value, len); } +#define THREAD_SHALLOW 1 +#define THREAD_DEEP 2 +static int thread = 0; + static int git_format_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "format.headers")) { @@ -489,6 +493,18 @@ static int git_format_config(const char *var, const char *value, void *cb) auto_number = auto_number && numbered; return 0; } + if (!strcmp(var, "format.thread")) { + if (value && !strcasecmp(value, "deep")) { + thread = THREAD_DEEP; + return 0; + } + if (value && !strcasecmp(value, "shallow")) { + thread = THREAD_SHALLOW; + return 0; + } + thread = git_config_bool(var, value) && THREAD_SHALLOW; + return 0; + } return git_log_config(var, value, cb); } @@ -767,7 +783,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) int numbered_files = 0; /* _just_ numbers */ int subject_prefix = 0; int ignore_if_in_upstream = 0; - int thread = 0; int cover_letter = 0; int boundary_count = 0; int no_binary_diff = 0; @@ -860,8 +875,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) } else if (!strcmp(argv[i], "--ignore-if-in-upstream")) ignore_if_in_upstream = 1; - else if (!strcmp(argv[i], "--thread")) - thread = 1; + else if (!strcmp(argv[i], "--thread") + || !strcmp(argv[i], "--thread=shallow")) + thread = THREAD_SHALLOW; + else if (!strcmp(argv[i], "--thread=deep")) + thread = THREAD_DEEP; + else if (!strcmp(argv[i], "--no-thread")) + thread = 0; else if (!prefixcmp(argv[i], "--in-reply-to=")) in_reply_to = argv[i] + 14; else if (!strcmp(argv[i], "--in-reply-to")) { @@ -1036,6 +1056,12 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) /* Have we already had a message ID? */ if (rev.message_id) { /* + * For deep threading: make every mail + * a reply to the previous one, no + * matter what other options are set. + * + * For shallow threading: + * * Without --cover-letter and * --in-reply-to, make every mail a * reply to the one before. @@ -1050,7 +1076,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) * letter is a reply to the * --in-reply-to, if specified. */ - if (rev.ref_message_ids->nr > 0 + if (thread == THREAD_SHALLOW + && rev.ref_message_ids->nr > 0 && (!cover_letter || rev.nr > 1)) free(rev.message_id); else diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 8b970c39a2..ebfc4a6590 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -257,6 +257,126 @@ test_expect_success 'thread cover-letter in-reply-to' ' --in-reply-to="<test.message>" --thread master ' +test_expect_success 'thread explicit shallow' ' + check_threading expect.cl-irt --cover-letter \ + --in-reply-to="<test.message>" --thread=shallow master +' + +cat > expect.deep <<EOF +--- +Message-Id: <0> +--- +Message-Id: <1> +In-Reply-To: <0> +References: <0> +--- +Message-Id: <2> +In-Reply-To: <1> +References: <0> + <1> +EOF + +test_expect_success 'thread deep' ' + check_threading expect.deep --thread=deep master +' + +cat > expect.deep-irt <<EOF +--- +Message-Id: <0> +In-Reply-To: <1> +References: <1> +--- +Message-Id: <2> +In-Reply-To: <0> +References: <1> + <0> +--- +Message-Id: <3> +In-Reply-To: <2> +References: <1> + <0> + <2> +EOF + +test_expect_success 'thread deep in-reply-to' ' + check_threading expect.deep-irt --thread=deep \ + --in-reply-to="<test.message>" master +' + +cat > expect.deep-cl <<EOF +--- +Message-Id: <0> +--- +Message-Id: <1> +In-Reply-To: <0> +References: <0> +--- +Message-Id: <2> +In-Reply-To: <1> +References: <0> + <1> +--- +Message-Id: <3> +In-Reply-To: <2> +References: <0> + <1> + <2> +EOF + +test_expect_success 'thread deep cover-letter' ' + check_threading expect.deep-cl --cover-letter --thread=deep master +' + +cat > expect.deep-cl-irt <<EOF +--- +Message-Id: <0> +In-Reply-To: <1> +References: <1> +--- +Message-Id: <2> +In-Reply-To: <0> +References: <1> + <0> +--- +Message-Id: <3> +In-Reply-To: <2> +References: <1> + <0> + <2> +--- +Message-Id: <4> +In-Reply-To: <3> +References: <1> + <0> + <2> + <3> +EOF + +test_expect_success 'thread deep cover-letter in-reply-to' ' + check_threading expect.deep-cl-irt --cover-letter \ + --in-reply-to="<test.message>" --thread=deep master +' + +test_expect_success 'thread via config' ' + git config format.thread true && + check_threading expect.thread master +' + +test_expect_success 'thread deep via config' ' + git config format.thread deep && + check_threading expect.deep master +' + +test_expect_success 'thread config + override' ' + git config format.thread deep && + check_threading expect.thread --thread master +' + +test_expect_success 'thread config + --no-thread' ' + git config format.thread deep && + check_threading expect.no-threading --no-thread master +' + test_expect_success 'excessive subject' ' rm -rf patches/ && From 4b951b7eb0a4abf7db301bc6dbf8a0cf1b0057d0 Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Sat, 21 Feb 2009 02:48:53 +0200 Subject: [PATCH 058/654] git config: codestyle cleanups Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-config.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/builtin-config.c b/builtin-config.c index 6937eaf379..afc4393b17 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -27,7 +27,7 @@ static int show_all_config(const char *key_, const char *value_, void *cb) return 0; } -static int show_config(const char* key_, const char* value_, void *cb) +static int show_config(const char *key_, const char *value_, void *cb) { char value[256]; const char *vptr = value; @@ -74,7 +74,7 @@ static int show_config(const char* key_, const char* value_, void *cb) return 0; } -static int get_value(const char* key_, const char* regex_) +static int get_value(const char *key_, const char *regex_) { int ret = -1; char *tl; @@ -284,7 +284,7 @@ static int get_colorbool(int argc, const char **argv) int cmd_config(int argc, const char **argv, const char *prefix) { int nongit; - char* value; + char *value; const char *file = setup_git_directory_gently(&nongit); config_exclusive_filename = getenv(CONFIG_ENVIRONMENT); From 414f2e5337b0b78a47f021cb734e9ba4934c0b28 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Sat, 21 Feb 2009 02:48:54 +0200 Subject: [PATCH 059/654] git config: trivial cleanup for editor action Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-config.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/builtin-config.c b/builtin-config.c index afc4393b17..d52a057444 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -363,15 +363,12 @@ int cmd_config(int argc, const char **argv, const char *prefix) } else if (!strcmp(argv[1], "--get-colorbool")) { return get_colorbool(argc-2, argv+2); } else if (!strcmp(argv[1], "--edit") || !strcmp(argv[1], "-e")) { - const char *config_filename; if (argc != 2) usage(git_config_set_usage); - if (config_exclusive_filename) - config_filename = config_exclusive_filename; - else - config_filename = git_path("config"); git_config(git_default_config, NULL); - launch_editor(config_filename, NULL, NULL); + launch_editor(config_exclusive_filename ? + config_exclusive_filename : git_path("config"), + NULL, NULL); return 0; } else break; From aa387407914a574d41df4d64328498d093337ccd Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Sat, 21 Feb 2009 02:48:55 +0200 Subject: [PATCH 060/654] git_config(): not having a per-repo config file is not an error Currently git_config() returns an error if there is no repo config file available (cwd is not a git repo); it will correctly parse the system and global config files, but still return an error. It doesn't affect anything else since almost nobody is checking for the return code (with the exception of 'git remote update'). A reorganization in 'git config' would benefit from being able to properly detect errors in git_config() without the noise generated when cwd is not a git repo. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- config.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/config.c b/config.c index e5d5b4bd06..b4aae71bd3 100644 --- a/config.c +++ b/config.c @@ -637,28 +637,37 @@ int git_config_global(void) int git_config(config_fn_t fn, void *data) { - int ret = 0; + int ret = 0, found = 0; char *repo_config = NULL; const char *home = NULL; /* Setting $GIT_CONFIG makes git read _only_ the given config file. */ if (config_exclusive_filename) return git_config_from_file(fn, config_exclusive_filename, data); - if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) + if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) { ret += git_config_from_file(fn, git_etc_gitconfig(), data); + found += 1; + } home = getenv("HOME"); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); - if (!access(user_config, R_OK)) + if (!access(user_config, R_OK)) { ret += git_config_from_file(fn, user_config, data); + found += 1; + } free(user_config); } repo_config = git_pathdup("config"); - ret += git_config_from_file(fn, repo_config, data); + if (!access(repo_config, R_OK)) { + ret += git_config_from_file(fn, repo_config, data); + found += 1; + } free(repo_config); + if (found == 0) + return -1; return ret; } From b408457f2e167aaf8e7a087b374357f4a74e9680 Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Sat, 21 Feb 2009 02:48:56 +0200 Subject: [PATCH 061/654] git config: trivial rename in preparation for parseopt Essentially this replaces 'file' with 'prefix' in the cases where the variable is used as a prefix, which is consistent with other git commands. When using the --list option general errors where not properly reported, only errors related with the 'file'. Now they are reported, and 'file' is irrelevant. That reduces the rest of 'file' usage to nothing, therefore now only 'prefix' remains. Suggested by Johannes Schindelin. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-config.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/builtin-config.c b/builtin-config.c index d52a057444..5074c6123e 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -178,6 +178,7 @@ static char *normalize_value(const char *key, const char *value) static int get_color_found; static const char *get_color_slot; +static const char *get_colorbool_slot; static char parsed_color[COLOR_MAXLEN]; static int git_get_color_config(const char *var, const char *value, void *cb) @@ -231,7 +232,7 @@ static int get_diff_color_found; static int git_get_colorbool_config(const char *var, const char *value, void *cb) { - if (!strcmp(var, get_color_slot)) { + if (!strcmp(var, get_colorbool_slot)) { get_colorbool_found = git_config_colorbool(var, value, stdout_is_tty); } @@ -263,11 +264,11 @@ static int get_colorbool(int argc, const char **argv) usage(git_config_set_usage); get_colorbool_found = -1; get_diff_color_found = -1; - get_color_slot = argv[0]; + get_colorbool_slot = argv[0]; git_config(git_get_colorbool_config, NULL); if (get_colorbool_found < 0) { - if (!strcmp(get_color_slot, "color.diff")) + if (!strcmp(get_colorbool_slot, "color.diff")) get_colorbool_found = get_diff_color_found; if (get_colorbool_found < 0) get_colorbool_found = git_use_color_default; @@ -281,11 +282,11 @@ static int get_colorbool(int argc, const char **argv) } } -int cmd_config(int argc, const char **argv, const char *prefix) +int cmd_config(int argc, const char **argv, const char *unused_prefix) { int nongit; char *value; - const char *file = setup_git_directory_gently(&nongit); + const char *prefix = setup_git_directory_gently(&nongit); config_exclusive_filename = getenv(CONFIG_ENVIRONMENT); @@ -299,10 +300,13 @@ int cmd_config(int argc, const char **argv, const char *prefix) else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) { if (argc != 2) usage(git_config_set_usage); - if (git_config(show_all_config, NULL) < 0 && - file && errno) - die("unable to read config file %s: %s", file, - strerror(errno)); + if (git_config(show_all_config, NULL) < 0) { + if (config_exclusive_filename) + die("unable to read config file %s: %s", + config_exclusive_filename, strerror(errno)); + else + die("error processing config file(s)"); + } return 0; } else if (!strcmp(argv[1], "--global")) { @@ -319,12 +323,12 @@ int cmd_config(int argc, const char **argv, const char *prefix) else if (!strcmp(argv[1], "--file") || !strcmp(argv[1], "-f")) { if (argc < 3) usage(git_config_set_usage); - if (!is_absolute_path(argv[2]) && file) - file = prefix_filename(file, strlen(file), - argv[2]); + if (!is_absolute_path(argv[2]) && prefix) + config_exclusive_filename = prefix_filename(prefix, + strlen(prefix), + argv[2]); else - file = argv[2]; - config_exclusive_filename = file; + config_exclusive_filename = argv[2]; argc--; argv++; } From 0e854a280a0b064f48ee308ef16283e321a9aa6e Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Sat, 21 Feb 2009 02:48:57 +0200 Subject: [PATCH 062/654] git config: reorganize get_color* In preparation for parseopt. Also remove some unecessary comments since the usage is described in the documentation. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-config.c | 62 ++++++++++++++---------------------------------- 1 file changed, 18 insertions(+), 44 deletions(-) diff --git a/builtin-config.c b/builtin-config.c index 5074c6123e..a2ef5f7c08 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -192,29 +192,8 @@ static int git_get_color_config(const char *var, const char *value, void *cb) return 0; } -static int get_color(int argc, const char **argv) +static void get_color(const char *def_color) { - /* - * grab the color setting for the given slot from the configuration, - * or parse the default value if missing, and return ANSI color - * escape sequence. - * - * e.g. - * git config --get-color color.diff.whitespace "blue reverse" - */ - const char *def_color = NULL; - - switch (argc) { - default: - usage(git_config_set_usage); - case 2: - def_color = argv[1]; - /* fallthru */ - case 1: - get_color_slot = argv[0]; - break; - } - get_color_found = 0; parsed_color[0] = '\0'; git_config(git_get_color_config, NULL); @@ -223,7 +202,6 @@ static int get_color(int argc, const char **argv) color_parse(def_color, "command line", parsed_color); fputs(parsed_color, stdout); - return 0; } static int stdout_is_tty; @@ -247,24 +225,10 @@ static int git_get_colorbool_config(const char *var, const char *value, return 0; } -static int get_colorbool(int argc, const char **argv) +static int get_colorbool(int print) { - /* - * git config --get-colorbool <slot> [<stdout-is-tty>] - * - * returns "true" or "false" depending on how <slot> - * is configured. - */ - - if (argc == 2) - stdout_is_tty = git_config_bool("command line", argv[1]); - else if (argc == 1) - stdout_is_tty = isatty(1); - else - usage(git_config_set_usage); get_colorbool_found = -1; get_diff_color_found = -1; - get_colorbool_slot = argv[0]; git_config(git_get_colorbool_config, NULL); if (get_colorbool_found < 0) { @@ -274,12 +238,11 @@ static int get_colorbool(int argc, const char **argv) get_colorbool_found = git_use_color_default; } - if (argc == 1) { - return get_colorbool_found ? 0 : 1; - } else { + if (print) { printf("%s\n", get_colorbool_found ? "true" : "false"); return 0; - } + } else + return get_colorbool_found ? 0 : 1; } int cmd_config(int argc, const char **argv, const char *unused_prefix) @@ -363,9 +326,20 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } return 0; } else if (!strcmp(argv[1], "--get-color")) { - return get_color(argc-2, argv+2); + if (argc > 4 || argc < 3) + usage(git_config_set_usage); + get_color_slot = argv[2]; + get_color(argv[3]); + return 0; } else if (!strcmp(argv[1], "--get-colorbool")) { - return get_colorbool(argc-2, argv+2); + if (argc == 4) + stdout_is_tty = git_config_bool("command line", argv[3]); + else if (argc == 3) + stdout_is_tty = isatty(1); + else + usage(git_config_set_usage); + get_colorbool_slot = argv[2]; + return get_colorbool(argc != 3); } else if (!strcmp(argv[1], "--edit") || !strcmp(argv[1], "-e")) { if (argc != 2) usage(git_config_set_usage); From d64ec16c2af4ddcf3985d11d5dc28a15db181de5 Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Sat, 21 Feb 2009 02:49:25 +0200 Subject: [PATCH 063/654] git config: reorganize to use parseopt This patch has benefited from comments by Johannes Schindelin and Junio C Hamano. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-config.c | 351 ++++++++++++++++++++++++++--------------------- 1 file changed, 196 insertions(+), 155 deletions(-) diff --git a/builtin-config.c b/builtin-config.c index a2ef5f7c08..08a77cd7df 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -1,9 +1,12 @@ #include "builtin.h" #include "cache.h" #include "color.h" +#include "parse-options.h" -static const char git_config_set_usage[] = -"git config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int | --bool-or-int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty] | --edit | -e ]"; +static const char *const builtin_config_usage[] = { + "git config [options]", + NULL +}; static char *key; static regex_t *key_regexp; @@ -18,6 +21,63 @@ static char key_delim = ' '; static char term = '\n'; static enum { T_RAW, T_INT, T_BOOL, T_BOOL_OR_INT } type = T_RAW; +static int use_global_config, use_system_config; +static const char *given_config_file; +static int actions; +static const char *get_color_slot, *get_colorbool_slot; +static int end_null; + +#define ACTION_GET (1<<0) +#define ACTION_GET_ALL (1<<1) +#define ACTION_GET_REGEXP (1<<2) +#define ACTION_REPLACE_ALL (1<<3) +#define ACTION_ADD (1<<4) +#define ACTION_UNSET (1<<5) +#define ACTION_UNSET_ALL (1<<6) +#define ACTION_RENAME_SECTION (1<<7) +#define ACTION_REMOVE_SECTION (1<<8) +#define ACTION_LIST (1<<9) +#define ACTION_EDIT (1<<10) +#define ACTION_SET (1<<11) +#define ACTION_SET_ALL (1<<12) +#define ACTION_GET_COLOR (1<<13) +#define ACTION_GET_COLORBOOL (1<<14) + +static struct option builtin_config_options[] = { + OPT_GROUP("Config file location"), + OPT_BOOLEAN(0, "global", &use_global_config, "use global config file"), + OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"), + OPT_STRING('f', "file", &given_config_file, "FILE", "use given config file"), + OPT_GROUP("Action"), + OPT_BIT(0, "get", &actions, "get value: name [value-regex]", ACTION_GET), + OPT_BIT(0, "get-all", &actions, "get all values: key [value-regex]", ACTION_GET_ALL), + OPT_BIT(0, "get-regexp", &actions, "get values for regexp: name-regex [value-regex]", ACTION_GET_REGEXP), + OPT_BIT(0, "replace-all", &actions, "replace all matching variables: name [value [value_regex]", ACTION_REPLACE_ALL), + OPT_BIT(0, "add", &actions, "adds a new variable: name value", ACTION_ADD), + OPT_BIT(0, "unset", &actions, "removes a variable: name [value-regex]", ACTION_UNSET), + OPT_BIT(0, "unset-all", &actions, "removes all matches: name [value-regex]", ACTION_UNSET_ALL), + OPT_BIT(0, "rename-section", &actions, "rename section: old-name new-name", ACTION_RENAME_SECTION), + OPT_BIT(0, "remove-section", &actions, "remove a section: name", ACTION_REMOVE_SECTION), + OPT_BIT('l', "list", &actions, "list all", ACTION_LIST), + OPT_BIT('e', "edit", &actions, "opens an editor", ACTION_EDIT), + OPT_STRING(0, "get-color", &get_color_slot, "slot", "find the color configured: [default]"), + OPT_STRING(0, "get-colorbool", &get_colorbool_slot, "slot", "find the color setting: [stdout-is-tty]"), + OPT_GROUP("Type"), + OPT_SET_INT(0, "bool", &type, "value is \"true\" or \"false\"", T_BOOL), + OPT_SET_INT(0, "int", &type, "value is decimal number", T_INT), + OPT_SET_INT(0, "bool-or-int", &type, NULL, T_BOOL_OR_INT), + OPT_GROUP("Other"), + OPT_BOOLEAN('z', "null", &end_null, "terminate values with NUL byte"), + OPT_END(), +}; + +static void check_argc(int argc, int min, int max) { + if (argc >= min && argc <= max) + return; + error("wrong number of arguments"); + usage_with_options(builtin_config_usage, builtin_config_options); +} + static int show_all_config(const char *key_, const char *value_, void *cb) { if (value_) @@ -253,162 +313,143 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) config_exclusive_filename = getenv(CONFIG_ENVIRONMENT); - while (1 < argc) { - if (!strcmp(argv[1], "--int")) - type = T_INT; - else if (!strcmp(argv[1], "--bool")) - type = T_BOOL; - else if (!strcmp(argv[1], "--bool-or-int")) - type = T_BOOL_OR_INT; - else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) { - if (argc != 2) - usage(git_config_set_usage); - if (git_config(show_all_config, NULL) < 0) { - if (config_exclusive_filename) - die("unable to read config file %s: %s", - config_exclusive_filename, strerror(errno)); - else - die("error processing config file(s)"); - } - return 0; + argc = parse_options(argc, argv, builtin_config_options, builtin_config_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + + if (use_global_config) { + char *home = getenv("HOME"); + if (home) { + char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); + config_exclusive_filename = user_config; + } else { + die("$HOME not set"); } - else if (!strcmp(argv[1], "--global")) { - char *home = getenv("HOME"); - if (home) { - char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); - config_exclusive_filename = user_config; - } else { - die("$HOME not set"); - } - } - else if (!strcmp(argv[1], "--system")) - config_exclusive_filename = git_etc_gitconfig(); - else if (!strcmp(argv[1], "--file") || !strcmp(argv[1], "-f")) { - if (argc < 3) - usage(git_config_set_usage); - if (!is_absolute_path(argv[2]) && prefix) - config_exclusive_filename = prefix_filename(prefix, - strlen(prefix), - argv[2]); - else - config_exclusive_filename = argv[2]; - argc--; - argv++; - } - else if (!strcmp(argv[1], "--null") || !strcmp(argv[1], "-z")) { - term = '\0'; - delim = '\n'; - key_delim = '\n'; - } - else if (!strcmp(argv[1], "--rename-section")) { - int ret; - if (argc != 4) - usage(git_config_set_usage); - ret = git_config_rename_section(argv[2], argv[3]); - if (ret < 0) - return ret; - if (ret == 0) { - fprintf(stderr, "No such section!\n"); - return 1; - } - return 0; - } - else if (!strcmp(argv[1], "--remove-section")) { - int ret; - if (argc != 3) - usage(git_config_set_usage); - ret = git_config_rename_section(argv[2], NULL); - if (ret < 0) - return ret; - if (ret == 0) { - fprintf(stderr, "No such section!\n"); - return 1; - } - return 0; - } else if (!strcmp(argv[1], "--get-color")) { - if (argc > 4 || argc < 3) - usage(git_config_set_usage); - get_color_slot = argv[2]; - get_color(argv[3]); - return 0; - } else if (!strcmp(argv[1], "--get-colorbool")) { - if (argc == 4) - stdout_is_tty = git_config_bool("command line", argv[3]); - else if (argc == 3) - stdout_is_tty = isatty(1); - else - usage(git_config_set_usage); - get_colorbool_slot = argv[2]; - return get_colorbool(argc != 3); - } else if (!strcmp(argv[1], "--edit") || !strcmp(argv[1], "-e")) { - if (argc != 2) - usage(git_config_set_usage); - git_config(git_default_config, NULL); - launch_editor(config_exclusive_filename ? - config_exclusive_filename : git_path("config"), - NULL, NULL); - return 0; - } else - break; - argc--; - argv++; + } + else if (use_system_config) + config_exclusive_filename = git_etc_gitconfig(); + else if (given_config_file) { + if (!is_absolute_path(given_config_file) && prefix) + config_exclusive_filename = prefix_filename(prefix, + strlen(prefix), + argv[2]); + else + config_exclusive_filename = given_config_file; } - switch (argc) { - case 2: - return get_value(argv[1], NULL); - case 3: - if (!strcmp(argv[1], "--unset")) - return git_config_set(argv[2], NULL); - else if (!strcmp(argv[1], "--unset-all")) - return git_config_set_multivar(argv[2], NULL, NULL, 1); - else if (!strcmp(argv[1], "--get")) - return get_value(argv[2], NULL); - else if (!strcmp(argv[1], "--get-all")) { - do_all = 1; - return get_value(argv[2], NULL); - } else if (!strcmp(argv[1], "--get-regexp")) { - show_keys = 1; - use_key_regexp = 1; - do_all = 1; - return get_value(argv[2], NULL); - } else { - value = normalize_value(argv[1], argv[2]); - return git_config_set(argv[1], value); - } - case 4: - if (!strcmp(argv[1], "--unset")) - return git_config_set_multivar(argv[2], NULL, argv[3], 0); - else if (!strcmp(argv[1], "--unset-all")) - return git_config_set_multivar(argv[2], NULL, argv[3], 1); - else if (!strcmp(argv[1], "--get")) - return get_value(argv[2], argv[3]); - else if (!strcmp(argv[1], "--get-all")) { - do_all = 1; - return get_value(argv[2], argv[3]); - } else if (!strcmp(argv[1], "--get-regexp")) { - show_keys = 1; - use_key_regexp = 1; - do_all = 1; - return get_value(argv[2], argv[3]); - } else if (!strcmp(argv[1], "--add")) { - value = normalize_value(argv[2], argv[3]); - return git_config_set_multivar(argv[2], value, "^$", 0); - } else if (!strcmp(argv[1], "--replace-all")) { - value = normalize_value(argv[2], argv[3]); - return git_config_set_multivar(argv[2], value, NULL, 1); - } else { - value = normalize_value(argv[1], argv[2]); - return git_config_set_multivar(argv[1], value, argv[3], 0); - } - case 5: - if (!strcmp(argv[1], "--replace-all")) { - value = normalize_value(argv[2], argv[3]); - return git_config_set_multivar(argv[2], value, argv[4], 1); - } - case 1: - default: - usage(git_config_set_usage); + if (end_null) { + term = '\0'; + delim = '\n'; + key_delim = '\n'; } + + if (get_color_slot) + actions |= ACTION_GET_COLOR; + if (get_colorbool_slot) + actions |= ACTION_GET_COLORBOOL; + + if (HAS_MULTI_BITS(actions)) { + error("only one action at a time."); + usage_with_options(builtin_config_usage, builtin_config_options); + } + if (actions == 0) + switch (argc) { + case 1: actions = ACTION_GET; break; + case 2: actions = ACTION_SET; break; + case 3: actions = ACTION_SET_ALL; break; + default: + usage_with_options(builtin_config_usage, builtin_config_options); + } + + if (actions == ACTION_LIST) { + if (git_config(show_all_config, NULL) < 0) { + if (config_exclusive_filename) + die("unable to read config file %s: %s", + config_exclusive_filename, strerror(errno)); + else + die("error processing config file(s)"); + } + } + else if (actions == ACTION_EDIT) { + git_config(git_default_config, NULL); + launch_editor(config_exclusive_filename ? + config_exclusive_filename : git_path("config"), + NULL, NULL); + } + else if (actions == ACTION_SET) { + check_argc(argc, 2, 2); + value = normalize_value(argv[0], argv[1]); + return git_config_set(argv[0], value); + } + else if (actions == ACTION_SET_ALL) { + check_argc(argc, 2, 3); + value = normalize_value(argv[0], argv[1]); + return git_config_set_multivar(argv[0], value, argv[2], 0); + } + else if (actions == ACTION_ADD) { + check_argc(argc, 2, 2); + value = normalize_value(argv[0], argv[1]); + return git_config_set_multivar(argv[0], value, "^$", 0); + } + else if (actions == ACTION_REPLACE_ALL) { + check_argc(argc, 2, 3); + value = normalize_value(argv[0], argv[1]); + return git_config_set_multivar(argv[0], value, argv[2], 1); + } + else if (actions == ACTION_GET) { + check_argc(argc, 1, 2); + return get_value(argv[0], argv[1]); + } + else if (actions == ACTION_GET_ALL) { + do_all = 1; + check_argc(argc, 1, 2); + return get_value(argv[0], argv[1]); + } + else if (actions == ACTION_GET_REGEXP) { + show_keys = 1; + use_key_regexp = 1; + do_all = 1; + check_argc(argc, 1, 2); + return get_value(argv[0], argv[1]); + } + else if (actions == ACTION_UNSET) { + check_argc(argc, 1, 2); + if (argc == 2) + return git_config_set_multivar(argv[0], NULL, argv[1], 0); + else + return git_config_set(argv[0], NULL); + } + else if (actions == ACTION_UNSET_ALL) { + check_argc(argc, 1, 2); + return git_config_set_multivar(argv[0], NULL, argv[1], 1); + } + else if (actions == ACTION_RENAME_SECTION) { + int ret; + check_argc(argc, 2, 2); + ret = git_config_rename_section(argv[0], argv[1]); + if (ret < 0) + return ret; + if (ret == 0) + die("No such section!"); + } + else if (actions == ACTION_REMOVE_SECTION) { + int ret; + check_argc(argc, 1, 1); + ret = git_config_rename_section(argv[0], NULL); + if (ret < 0) + return ret; + if (ret == 0) + die("No such section!"); + } + else if (actions == ACTION_GET_COLOR) { + get_color(argv[0]); + } + else if (actions == ACTION_GET_COLORBOOL) { + if (argc == 1) + stdout_is_tty = git_config_bool("command line", argv[0]); + else if (argc == 0) + stdout_is_tty = isatty(1); + return get_colorbool(argc != 0); + } + return 0; } From 67052c9dcfb3ab46b18e734ea4a9117eb61fea4e Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Sat, 21 Feb 2009 02:49:26 +0200 Subject: [PATCH 064/654] git config: don't allow multiple config file locations Either --global, --system, or --file can be used, but not any combination. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-config.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/builtin-config.c b/builtin-config.c index 08a77cd7df..d037e4745c 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -316,6 +316,11 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) argc = parse_options(argc, argv, builtin_config_options, builtin_config_usage, PARSE_OPT_STOP_AT_NON_OPTION); + if (use_global_config + use_system_config + !!given_config_file > 1) { + error("only one config file at a time."); + usage_with_options(builtin_config_usage, builtin_config_options); + } + if (use_global_config) { char *home = getenv("HOME"); if (home) { From 16c1e939856f6ced97c60beb64936d564d198be3 Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Sat, 21 Feb 2009 02:49:27 +0200 Subject: [PATCH 065/654] git config: don't allow multiple variable types Only --bool, --int, or --bool-or-int can be used, but not any combination of them. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-config.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/builtin-config.c b/builtin-config.c index d037e4745c..6dc205d1f4 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -19,11 +19,10 @@ static int seen; static char delim = '='; static char key_delim = ' '; static char term = '\n'; -static enum { T_RAW, T_INT, T_BOOL, T_BOOL_OR_INT } type = T_RAW; static int use_global_config, use_system_config; static const char *given_config_file; -static int actions; +static int actions, types; static const char *get_color_slot, *get_colorbool_slot; static int end_null; @@ -43,6 +42,10 @@ static int end_null; #define ACTION_GET_COLOR (1<<13) #define ACTION_GET_COLORBOOL (1<<14) +#define TYPE_BOOL (1<<0) +#define TYPE_INT (1<<1) +#define TYPE_BOOL_OR_INT (1<<2) + static struct option builtin_config_options[] = { OPT_GROUP("Config file location"), OPT_BOOLEAN(0, "global", &use_global_config, "use global config file"), @@ -63,9 +66,9 @@ static struct option builtin_config_options[] = { OPT_STRING(0, "get-color", &get_color_slot, "slot", "find the color configured: [default]"), OPT_STRING(0, "get-colorbool", &get_colorbool_slot, "slot", "find the color setting: [stdout-is-tty]"), OPT_GROUP("Type"), - OPT_SET_INT(0, "bool", &type, "value is \"true\" or \"false\"", T_BOOL), - OPT_SET_INT(0, "int", &type, "value is decimal number", T_INT), - OPT_SET_INT(0, "bool-or-int", &type, NULL, T_BOOL_OR_INT), + OPT_BIT(0, "bool", &types, "value is \"true\" or \"false\"", TYPE_BOOL), + OPT_BIT(0, "int", &types, "value is decimal number", TYPE_INT), + OPT_BIT(0, "bool-or-int", &types, NULL, TYPE_BOOL_OR_INT), OPT_GROUP("Other"), OPT_BOOLEAN('z', "null", &end_null, "terminate values with NUL byte"), OPT_END(), @@ -109,11 +112,11 @@ static int show_config(const char *key_, const char *value_, void *cb) } if (seen && !do_all) dup_error = 1; - if (type == T_INT) + if (types == TYPE_INT) sprintf(value, "%d", git_config_int(key_, value_?value_:"")); - else if (type == T_BOOL) + else if (types == TYPE_BOOL) vptr = git_config_bool(key_, value_) ? "true" : "false"; - else if (type == T_BOOL_OR_INT) { + else if (types == TYPE_BOOL_OR_INT) { int is_bool, v; v = git_config_bool_or_int(key_, value_, &is_bool); if (is_bool) @@ -212,18 +215,18 @@ static char *normalize_value(const char *key, const char *value) if (!value) return NULL; - if (type == T_RAW) + if (types == 0) normalized = xstrdup(value); else { normalized = xmalloc(64); - if (type == T_INT) { + if (types == TYPE_INT) { int v = git_config_int(key, value); sprintf(normalized, "%d", v); } - else if (type == T_BOOL) + else if (types == TYPE_BOOL) sprintf(normalized, "%s", git_config_bool(key, value) ? "true" : "false"); - else if (type == T_BOOL_OR_INT) { + else if (types == TYPE_BOOL_OR_INT) { int is_bool, v; v = git_config_bool_or_int(key, value, &is_bool); if (!is_bool) @@ -347,6 +350,11 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) key_delim = '\n'; } + if (HAS_MULTI_BITS(types)) { + error("only one type at a time."); + usage_with_options(builtin_config_usage, builtin_config_options); + } + if (get_color_slot) actions |= ACTION_GET_COLOR; if (get_colorbool_slot) From 225a9caf18911bffe2f32e4960c94e51f135182b Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Sat, 21 Feb 2009 02:49:28 +0200 Subject: [PATCH 066/654] git config: don't allow extra arguments for -e or -l. As suggested by Johannes Schindelin. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builtin-config.c b/builtin-config.c index 6dc205d1f4..a3a334bc63 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -374,6 +374,7 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } if (actions == ACTION_LIST) { + check_argc(argc, 0, 0); if (git_config(show_all_config, NULL) < 0) { if (config_exclusive_filename) die("unable to read config file %s: %s", @@ -383,6 +384,7 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } } else if (actions == ACTION_EDIT) { + check_argc(argc, 0, 0); git_config(git_default_config, NULL); launch_editor(config_exclusive_filename ? config_exclusive_filename : git_path("config"), From c23873589483eb5dc753190309af8c5821169118 Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Sat, 21 Feb 2009 02:49:29 +0200 Subject: [PATCH 067/654] git config: don't allow --get-color* and variable type Doing so would be incoherent since --get-color would pick a color slot and ignore the variable type option (e.g. --bool), and the type would require a variable name. Suggested by Junio C Hamano. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-config.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/builtin-config.c b/builtin-config.c index a3a334bc63..b11a0961bd 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -360,6 +360,11 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) if (get_colorbool_slot) actions |= ACTION_GET_COLORBOOL; + if ((get_color_slot || get_colorbool_slot) && types) { + error("--get-color and variable type are incoherent"); + usage_with_options(builtin_config_usage, builtin_config_options); + } + if (HAS_MULTI_BITS(actions)) { error("only one action at a time."); usage_with_options(builtin_config_usage, builtin_config_options); From f50edca56c40cbfe48734eacd5d79416ba3649eb Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen <git@storm-olsen.com> Date: Sat, 21 Feb 2009 15:48:43 +0100 Subject: [PATCH 068/654] Add bare repository indicator for __git_ps1 Prefixes the branch name with "BARE:" if you're in a bare repository. Signed-off-by: Marius Storm-Olsen <git@storm-olsen.com> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 6e8c5b91ac..a61d852a14 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -135,11 +135,17 @@ __git_ps1 () fi fi + local c + + if [ "true" = "$(git config --bool core.bare 2>/dev/null)" ]; then + c="BARE:" + fi + if [ -n "$b" ]; then if [ -n "${1-}" ]; then - printf "$1" "${b##refs/heads/}$w$i$r" + printf "$1" "$c${b##refs/heads/}$w$i$r" else - printf " (%s)" "${b##refs/heads/}$w$i$r" + printf " (%s)" "$c${b##refs/heads/}$w$i$r" fi fi fi From e1afca4fd3e7cb4000874e991277f10119de4ad2 Mon Sep 17 00:00:00 2001 From: Kjetil Barvik <barvik@broadpark.no> Date: Mon, 23 Feb 2009 19:02:57 +0100 Subject: [PATCH 069/654] write_index(): update index_state->timestamp after flushing to disk Since this timestamp is used to check for racy-clean files, it is important to keep it uptodate. For the 'git checkout' command without the '-q' option, this make a huge difference. Before, each and every file which was updated, was racy-clean after the call to unpack_trees() and write_index() but before the GIT process ended. And because of the call to show_local_changes() in builtin-checkout.c, we ended up reading those files back into memory, doing a SHA1 to check if the files was really different from the index. And, of course, no file was different. With this fix, 'git checkout' without the '-q' option should now be almost as fast as with the '-q' option, but not quite, as we still do some few lstat(2) calls more without the '-q' option. Below is some average numbers for 10 checkout's to v2.6.27 and 10 to v2.6.25 of the Linux kernel, to show the difference: before (git version 1.6.2.rc1.256.g58a87): 7.860 user 2.427 sys 19.465 real 52.8% CPU faults: 0 major 95331 minor after: 6.184 user 2.160 sys 17.619 real 47.4% CPU faults: 0 major 38994 minor Signed-off-by: Kjetil Barvik <barvik@broadpark.no> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- cache.h | 2 +- read-cache.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/cache.h b/cache.h index 2badbfedc4..2f4f0549f9 100644 --- a/cache.h +++ b/cache.h @@ -430,7 +430,7 @@ extern int read_index_preload(struct index_state *, const char **pathspec); extern int read_index_from(struct index_state *, const char *path); extern int is_index_unborn(struct index_state *); extern int read_index_unmerged(struct index_state *); -extern int write_index(const struct index_state *, int newfd); +extern int write_index(struct index_state *, int newfd); extern int discard_index(struct index_state *); extern int unmerged_index(const struct index_state *); extern int verify_path(const char *path); diff --git a/read-cache.c b/read-cache.c index bb07371597..91f1d03c09 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1528,13 +1528,14 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce) return ce_write(c, fd, ondisk, size); } -int write_index(const struct index_state *istate, int newfd) +int write_index(struct index_state *istate, int newfd) { git_SHA_CTX c; struct cache_header hdr; int i, err, removed, extended; struct cache_entry **cache = istate->cache; int entries = istate->cache_nr; + struct stat st; for (i = removed = extended = 0; i < entries; i++) { if (cache[i]->ce_flags & CE_REMOVE) @@ -1578,7 +1579,14 @@ int write_index(const struct index_state *istate, int newfd) if (err) return -1; } - return ce_flush(&c, newfd); + + if (ce_flush(&c, newfd) || fstat(newfd, &st)) + return -1; + istate->timestamp.sec = (unsigned int)st.st_ctime; +#ifdef USE_NSEC + istate->timestamp.nsec = (unsigned int)st.st_ctim.tv_nsec; +#endif + return 0; } /* From ddb6d010231432ba75cf109aa7cd282912c88d2d Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen <git@storm-olsen.com> Date: Sat, 21 Feb 2009 15:48:43 +0100 Subject: [PATCH 070/654] Fixup: Add bare repository indicator for __git_ps1 Signed-off-by: Marius Storm-Olsen <git@storm-olsen.com> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index a61d852a14..dd393cd004 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -117,9 +117,14 @@ __git_ps1 () local w local i + local c if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then - b="GIT_DIR!" + if [ "true" = "$(git config --bool core.bare 2>/dev/null)" ]; then + c="BARE:" + else + b="GIT_DIR!" + fi elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then @@ -135,12 +140,6 @@ __git_ps1 () fi fi - local c - - if [ "true" = "$(git config --bool core.bare 2>/dev/null)" ]; then - c="BARE:" - fi - if [ -n "$b" ]; then if [ -n "${1-}" ]; then printf "$1" "$c${b##refs/heads/}$w$i$r" From 3a4c1a5e212357c3df030b6713c75466694c2e77 Mon Sep 17 00:00:00 2001 From: Nanako Shiraishi <nanako3@lavabit.com> Date: Tue, 24 Feb 2009 18:59:14 +0900 Subject: [PATCH 071/654] Add --format that is a synonym to --pretty Some people prefer to call the pretty-print styles "format", and get annoyed to see "git log --format=short" fail. Introduce it as a synonym to --pretty so that both can be used. Signed-off-by: Nanako Shiraishi <nanako3@lavabit.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/pretty-options.txt | 1 + revision.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt index 5f21efe407..65960192e8 100644 --- a/Documentation/pretty-options.txt +++ b/Documentation/pretty-options.txt @@ -1,4 +1,5 @@ --pretty[='<format>']:: +--format[='<format>']:: Pretty-print the contents of the commit logs in a given format, where '<format>' can be one of 'oneline', 'short', 'medium', diff --git a/revision.c b/revision.c index 286e416b75..556c3195b4 100644 --- a/revision.c +++ b/revision.c @@ -1144,7 +1144,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } else if (!strcmp(arg, "--pretty")) { revs->verbose_header = 1; get_commit_format(arg+8, revs); - } else if (!prefixcmp(arg, "--pretty=")) { + } else if (!prefixcmp(arg, "--pretty=") || !prefixcmp(arg, "--format=")) { revs->verbose_header = 1; get_commit_format(arg+9, revs); } else if (!strcmp(arg, "--graph")) { From 36407548a2825462a91b456755412a65fd611fc0 Mon Sep 17 00:00:00 2001 From: Nanako Shiraishi <nanako3@lavabit.com> Date: Tue, 24 Feb 2009 18:59:15 +0900 Subject: [PATCH 072/654] Give short-hands to --pretty=tformat:%formatstring Allow --pretty="%h %s" (and --format="%h %s") as shorthand for an often used option --pretty=tformat:"%h %s". Signed-off-by: Nanako Shiraishi <nanako3@lavabit.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/pretty-formats.txt | 9 +++++++++ pretty.c | 20 ++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt index 159390c35a..5c6e678aa3 100644 --- a/Documentation/pretty-formats.txt +++ b/Documentation/pretty-formats.txt @@ -152,3 +152,12 @@ $ git log -2 --pretty=tformat:%h 4da45bef \ 4da45be 7134973 --------------------- ++ +In addition, any unrecognized string that has a `%` in it is interpreted +as if it has `tformat:` in front of it. For example, these two are +equivalent: ++ +--------------------- +$ git log -2 --pretty=tformat:%h 4da45bef +$ git log -2 --pretty=%h 4da45bef +--------------------- diff --git a/pretty.c b/pretty.c index 6cd91491d3..d739f6d6c5 100644 --- a/pretty.c +++ b/pretty.c @@ -10,6 +10,15 @@ static char *user_format; +static void save_user_format(struct rev_info *rev, const char *cp, int is_tformat) +{ + free(user_format); + user_format = xstrdup(cp); + if (is_tformat) + rev->use_terminator = 1; + rev->commit_format = CMIT_FMT_USERFORMAT; +} + void get_commit_format(const char *arg, struct rev_info *rev) { int i; @@ -33,12 +42,7 @@ void get_commit_format(const char *arg, struct rev_info *rev) return; } if (!prefixcmp(arg, "format:") || !prefixcmp(arg, "tformat:")) { - const char *cp = strchr(arg, ':') + 1; - free(user_format); - user_format = xstrdup(cp); - if (arg[0] == 't') - rev->use_terminator = 1; - rev->commit_format = CMIT_FMT_USERFORMAT; + save_user_format(rev, strchr(arg, ':') + 1, arg[0] == 't'); return; } for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) { @@ -50,6 +54,10 @@ void get_commit_format(const char *arg, struct rev_info *rev) return; } } + if (strchr(arg, '%')) { + save_user_format(rev, arg, 1); + return; + } die("invalid --pretty format: %s", arg); } From de84accc59baef73f7827d59f0d479521ecad937 Mon Sep 17 00:00:00 2001 From: Nanako Shiraishi <nanako3@lavabit.com> Date: Tue, 24 Feb 2009 18:59:16 +0900 Subject: [PATCH 073/654] Add --oneline that is a synonym to "--pretty=oneline --abbrev-commit" These two are often used together but are too long to type. Signed-off-by: Nanako Shiraishi <nanako3@lavabit.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/pretty-options.txt | 4 ++++ revision.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt index 65960192e8..bff94991b6 100644 --- a/Documentation/pretty-options.txt +++ b/Documentation/pretty-options.txt @@ -18,6 +18,10 @@ configuration (see linkgit:git-config[1]). This should make "--pretty=oneline" a whole lot more readable for people using 80-column terminals. +--oneline:: + This is a shorthand for "--pretty=oneline --abbrev-commit" + used together. + --encoding[=<encoding>]:: The commit objects record the encoding used for the log message in their encoding header; this option can be used to tell the diff --git a/revision.c b/revision.c index 556c3195b4..c4efe5b22e 100644 --- a/revision.c +++ b/revision.c @@ -1147,6 +1147,10 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } else if (!prefixcmp(arg, "--pretty=") || !prefixcmp(arg, "--format=")) { revs->verbose_header = 1; get_commit_format(arg+9, revs); + } else if (!strcmp(arg, "--oneline")) { + revs->verbose_header = 1; + get_commit_format("oneline", revs); + revs->abbrev_commit = 1; } else if (!strcmp(arg, "--graph")) { revs->topo_order = 1; revs->rewrite_parents = 1; From bb93afd5153948e58d6b09c86e7c106a65dbfb65 Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Tue, 24 Feb 2009 23:06:37 +0200 Subject: [PATCH 074/654] Add tests for git log --pretty, --format and --oneline. More specifically; --pretty=format, tformat and new %foo shortcut. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t4202-log.sh | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 7b976ee36d..6d43459dd1 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -37,6 +37,46 @@ test_expect_success setup ' ' +printf "sixth\nfifth\nfourth\nthird\nsecond\ninitial" > expect +test_expect_success 'pretty' ' + + git log --pretty="format:%s" > actual && + test_cmp expect actual +' + +printf "sixth\nfifth\nfourth\nthird\nsecond\ninitial\n" > expect +test_expect_success 'pretty (tformat)' ' + + git log --pretty="tformat:%s" > actual && + test_cmp expect actual +' + +test_expect_success 'pretty (shortcut)' ' + + git log --pretty="%s" > actual && + test_cmp expect actual +' + +test_expect_success 'format' ' + + git log --format="%s" > actual && + test_cmp expect actual +' + +cat > expect << EOF +804a787 sixth +394ef78 fifth +5d31159 fourth +2fbe8c0 third +f7dab8e second +3a2fdcb initial +EOF +test_expect_success 'oneline' ' + + git log --oneline > actual && + test_cmp expect actual +' + test_expect_success 'diff-filter=A' ' actual=$(git log --pretty="format:%s" --diff-filter=A HEAD) && From 75318a3bad4b7a25f617217891bfbcec26a9161a Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Wed, 25 Feb 2009 03:32:08 -0500 Subject: [PATCH 075/654] test scripts: refactor start_httpd helper There are some redirects and some error checking that need to be done by the caller; let's move both into the start_httpd function so that all callers don't have to repeat them (there is only one caller now, but another will follow in this series). This doesn't violate any assumptions that aren't already being made by lib-httpd, which is happy to say "skipping" and call test_done for a number of other cases. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/lib-httpd.sh | 9 +++++++-- t/t5540-http-push.sh | 8 +------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh index 86cdebc727..589aaf8214 100644 --- a/t/lib-httpd.sh +++ b/t/lib-httpd.sh @@ -94,13 +94,18 @@ prepare_httpd() { } start_httpd() { - prepare_httpd + prepare_httpd >&3 2>&4 trap 'stop_httpd; die' EXIT "$LIB_HTTPD_PATH" -d "$HTTPD_ROOT_PATH" \ -f "$TEST_PATH/apache.conf" $HTTPD_PARA \ - -c "Listen 127.0.0.1:$LIB_HTTPD_PORT" -k start + -c "Listen 127.0.0.1:$LIB_HTTPD_PORT" -k start \ + >&3 2>&4 + if ! test $? = 0; then + say "skipping test, web server setup failed" + test_done + fi } stop_httpd() { diff --git a/t/t5540-http-push.sh b/t/t5540-http-push.sh index 11b343274f..57a4411e98 100755 --- a/t/t5540-http-push.sh +++ b/t/t5540-http-push.sh @@ -20,13 +20,7 @@ then fi . "$TEST_DIRECTORY"/lib-httpd.sh - -if ! start_httpd >&3 2>&4 -then - say "skipping test, web server setup failed" - test_done - exit -fi +start_httpd test_expect_success 'setup remote repository' ' cd "$ROOT_PATH" && From 119c8eeede81489b2ce8b26ae7dcb47290e257eb Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Wed, 25 Feb 2009 03:32:09 -0500 Subject: [PATCH 076/654] add basic http clone/fetch tests This was mostly being tested implicitly by the "http push" tests. But making a separate test script means that: - we will run fetch tests even when http pushing support is not built - when there are failures on fetching, they are easier to see and isolate, as they are not in the middle of push tests This script defaults to running the webserver on port 5550, and puts the original t5540 on port 5540, so that the two can be run simultaneously without conflict (but both still respect an externally set LIB_HTTPD_PORT). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 1 + t/t5540-http-push.sh | 1 + t/t5550-http-fetch.sh | 46 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100755 t/t5550-http-fetch.sh diff --git a/Makefile b/Makefile index 0675c43e73..744ab4ff8f 100644 --- a/Makefile +++ b/Makefile @@ -1363,6 +1363,7 @@ GIT-CFLAGS: .FORCE-GIT-CFLAGS GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@ @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@ + @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@ ### Detect Tck/Tk interpreter path changes ifndef NO_TCLTK diff --git a/t/t5540-http-push.sh b/t/t5540-http-push.sh index 57a4411e98..cefab4543a 100755 --- a/t/t5540-http-push.sh +++ b/t/t5540-http-push.sh @@ -11,6 +11,7 @@ This test runs various sanity checks on http-push.' ROOT_PATH="$PWD" LIB_HTTPD_DAV=t +LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5540'} if git http-push > /dev/null 2>&1 || [ $? -eq 128 ] then diff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch.sh new file mode 100755 index 0000000000..b6e6ec9607 --- /dev/null +++ b/t/t5550-http-fetch.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +test_description='test fetching over http' +. ./test-lib.sh + +if test -n "$NO_CURL"; then + say 'skipping test, git built without http support' + test_done +fi + +. "$TEST_DIRECTORY"/lib-httpd.sh +LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5550'} +start_httpd + +test_expect_success 'setup repository' ' + echo content >file && + git add file && + git commit -m one +' + +test_expect_success 'create http-accessible bare repository' ' + mkdir "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + (cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + git --bare init && + echo "exec git update-server-info" >hooks/post-update && + chmod +x hooks/post-update + ) && + git remote add public "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + git push public master:master +' + +test_expect_success 'clone http repository' ' + git clone $HTTPD_URL/repo.git clone && + test_cmp file clone/file +' + +test_expect_success 'fetch changes via http' ' + echo content >>file && + git commit -a -m two && + git push public + (cd clone && git pull) && + test_cmp file clone/file +' + +stop_httpd +test_done From 5483f79998c5a9705d453a713d11fb7591329ed4 Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Wed, 25 Feb 2009 03:32:10 -0500 Subject: [PATCH 077/654] refactor find_ref_by_name() to accept const list Since it doesn't actually touch its argument, this makes sense. However, we still want to return a non-const version (which requires a cast) so that this: struct ref *a, *b; a = find_ref_by_name(b); works. Unfortunately, you can also silently strip the const from a variable: struct ref *a; const struct ref *b; a = find_ref_by_name(b); This is a classic C const problem because there is no way to say "return the type with the same constness that was passed to us"; we provide the same semantics as standard library functions like strchr. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- cache.h | 2 +- refs.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cache.h b/cache.h index 189151de25..609380d935 100644 --- a/cache.h +++ b/cache.h @@ -801,7 +801,7 @@ struct ref { #define REF_HEADS (1u << 1) #define REF_TAGS (1u << 2) -extern struct ref *find_ref_by_name(struct ref *list, const char *name); +extern struct ref *find_ref_by_name(const struct ref *list, const char *name); #define CONNECT_VERBOSE (1u << 0) extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags); diff --git a/refs.c b/refs.c index 6eb5f53846..b2a37e1185 100644 --- a/refs.c +++ b/refs.c @@ -1628,10 +1628,10 @@ int update_ref(const char *action, const char *refname, return 0; } -struct ref *find_ref_by_name(struct ref *list, const char *name) +struct ref *find_ref_by_name(const struct ref *list, const char *name) { for ( ; list; list = list->next) if (!strcmp(list->name, name)) - return list; + return (struct ref *)list; return NULL; } From 454e2025a933593fd751475b59cc014887b4df6d Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Wed, 25 Feb 2009 03:32:11 -0500 Subject: [PATCH 078/654] move duplicated get_local_heads() to remote.c get_local_heads() appears to have been copied from builtin-send-pack.c to http-push.c via cut and paste. This patch moves the function and its helper one_local_ref() to remote.c. The two copies of one_local_ref() were not identical. I used the more recent version from builtin-send-pack.c after confirming with Jeff King that it was an oversight that commit 30affa1e did not update both copies. This is in preparation for being able to call it from builtin-remote.c Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-send-pack.c | 29 ++--------------------------- http-push.c | 23 ++--------------------- remote.c | 26 ++++++++++++++++++++++++++ remote.h | 1 + 4 files changed, 31 insertions(+), 48 deletions(-) diff --git a/builtin-send-pack.c b/builtin-send-pack.c index d65d019692..2fbfc291dc 100644 --- a/builtin-send-pack.c +++ b/builtin-send-pack.c @@ -133,33 +133,8 @@ static int ref_newer(const unsigned char *new_sha1, return found; } -static struct ref *local_refs, **local_tail; static struct ref *remote_refs, **remote_tail; -static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) -{ - struct ref *ref; - int len; - - /* we already know it starts with refs/ to get here */ - if (check_ref_format(refname + 5)) - return 0; - - len = strlen(refname) + 1; - ref = xcalloc(1, sizeof(*ref) + len); - hashcpy(ref->new_sha1, sha1); - memcpy(ref->name, refname, len); - *local_tail = ref; - local_tail = &ref->next; - return 0; -} - -static void get_local_heads(void) -{ - local_tail = &local_refs; - for_each_ref(one_local_ref, NULL); -} - static int receive_status(int in, struct ref *refs) { struct ref *hint; @@ -387,7 +362,7 @@ static int refs_pushed(struct ref *ref) static int do_send_pack(int in, int out, struct remote *remote, const char *dest, int nr_refspec, const char **refspec) { - struct ref *ref; + struct ref *ref, *local_refs; int new_refs; int ask_for_status_report = 0; int allow_deleting_refs = 0; @@ -405,7 +380,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest /* No funny business with the matcher */ remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL, &extra_have); - get_local_heads(); + local_refs = get_local_heads(); /* Does the other end support the reporting? */ if (server_supports("report-status")) diff --git a/http-push.c b/http-push.c index 30d2d34041..cfeed81d07 100644 --- a/http-push.c +++ b/http-push.c @@ -1792,21 +1792,8 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock) return 1; } -static struct ref *local_refs, **local_tail; static struct ref *remote_refs, **remote_tail; -static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) -{ - struct ref *ref; - int len = strlen(refname) + 1; - ref = xcalloc(1, sizeof(*ref) + len); - hashcpy(ref->new_sha1, sha1); - memcpy(ref->name, refname, len); - *local_tail = ref; - local_tail = &ref->next; - return 0; -} - static void one_remote_ref(char *refname) { struct ref *ref; @@ -1839,12 +1826,6 @@ static void one_remote_ref(char *refname) remote_tail = &ref->next; } -static void get_local_heads(void) -{ - local_tail = &local_refs; - for_each_ref(one_local_ref, NULL); -} - static void get_dav_remote_heads(void) { remote_tail = &remote_refs; @@ -2195,7 +2176,7 @@ int main(int argc, char **argv) int rc = 0; int i; int new_refs; - struct ref *ref; + struct ref *ref, *local_refs; char *rewritten_url = NULL; git_extract_argv0_path(argv[0]); @@ -2302,7 +2283,7 @@ int main(int argc, char **argv) fetch_indices(); /* Get a list of all local and remote heads to validate refspecs */ - get_local_heads(); + local_refs = get_local_heads(); fprintf(stderr, "Fetching remote heads...\n"); get_dav_remote_heads(); diff --git a/remote.c b/remote.c index d7079c6dd8..01aae770a9 100644 --- a/remote.c +++ b/remote.c @@ -1376,3 +1376,29 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb) base, num_ours, num_theirs); return 1; } + +static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) +{ + struct ref ***local_tail = cb_data; + struct ref *ref; + int len; + + /* we already know it starts with refs/ to get here */ + if (check_ref_format(refname + 5)) + return 0; + + len = strlen(refname) + 1; + ref = xcalloc(1, sizeof(*ref) + len); + hashcpy(ref->new_sha1, sha1); + memcpy(ref->name, refname, len); + **local_tail = ref; + *local_tail = &ref->next; + return 0; +} + +struct ref *get_local_heads(void) +{ + struct ref *local_refs, **local_tail = &local_refs; + for_each_ref(one_local_ref, &local_tail); + return local_refs; +} diff --git a/remote.h b/remote.h index a46a5be131..56ca8b168f 100644 --- a/remote.h +++ b/remote.h @@ -137,4 +137,5 @@ enum match_refs_flags { int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs); int format_tracking_info(struct branch *branch, struct strbuf *sb); +struct ref *get_local_heads(void); #endif From ec8452d5a797fca865666f761b785b04212426fc Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Wed, 25 Feb 2009 03:32:12 -0500 Subject: [PATCH 079/654] move duplicated ref_newer() to remote.c ref_newer() appears to have been copied from builtin-send-pack.c to http-push.c via cut and paste. This patch moves the function and its helper unmark_and_free() to remote.c. There was a slight difference between the two implementations, one used TMP_MARK for the mark, the other used 1. Per Jeff King, I went with TMP_MARK as more correct. This is in preparation for being able to call it from builtin-remote.c Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-send-pack.c | 50 --------------------------------------------- http-push.c | 49 -------------------------------------------- remote.c | 49 ++++++++++++++++++++++++++++++++++++++++++++ remote.h | 1 + 4 files changed, 50 insertions(+), 99 deletions(-) diff --git a/builtin-send-pack.c b/builtin-send-pack.c index 2fbfc291dc..9072905f10 100644 --- a/builtin-send-pack.c +++ b/builtin-send-pack.c @@ -1,6 +1,5 @@ #include "cache.h" #include "commit.h" -#include "tag.h" #include "refs.h" #include "pkt-line.h" #include "run-command.h" @@ -84,55 +83,6 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext return 0; } -static void unmark_and_free(struct commit_list *list, unsigned int mark) -{ - while (list) { - struct commit_list *temp = list; - temp->item->object.flags &= ~mark; - list = temp->next; - free(temp); - } -} - -static int ref_newer(const unsigned char *new_sha1, - const unsigned char *old_sha1) -{ - struct object *o; - struct commit *old, *new; - struct commit_list *list, *used; - int found = 0; - - /* Both new and old must be commit-ish and new is descendant of - * old. Otherwise we require --force. - */ - o = deref_tag(parse_object(old_sha1), NULL, 0); - if (!o || o->type != OBJ_COMMIT) - return 0; - old = (struct commit *) o; - - o = deref_tag(parse_object(new_sha1), NULL, 0); - if (!o || o->type != OBJ_COMMIT) - return 0; - new = (struct commit *) o; - - if (parse_commit(new) < 0) - return 0; - - used = list = NULL; - commit_list_insert(new, &list); - while (list) { - new = pop_most_recent_commit(&list, 1); - commit_list_insert(new, &used); - if (new == old) { - found = 1; - break; - } - } - unmark_and_free(list, 1); - unmark_and_free(used, 1); - return found; -} - static struct ref *remote_refs, **remote_tail; static int receive_status(int in, struct ref *refs) diff --git a/http-push.c b/http-push.c index cfeed81d07..392533a017 100644 --- a/http-push.c +++ b/http-push.c @@ -1843,55 +1843,6 @@ static int is_zero_sha1(const unsigned char *sha1) return 1; } -static void unmark_and_free(struct commit_list *list, unsigned int mark) -{ - while (list) { - struct commit_list *temp = list; - temp->item->object.flags &= ~mark; - list = temp->next; - free(temp); - } -} - -static int ref_newer(const unsigned char *new_sha1, - const unsigned char *old_sha1) -{ - struct object *o; - struct commit *old, *new; - struct commit_list *list, *used; - int found = 0; - - /* Both new and old must be commit-ish and new is descendant of - * old. Otherwise we require --force. - */ - o = deref_tag(parse_object(old_sha1), NULL, 0); - if (!o || o->type != OBJ_COMMIT) - return 0; - old = (struct commit *) o; - - o = deref_tag(parse_object(new_sha1), NULL, 0); - if (!o || o->type != OBJ_COMMIT) - return 0; - new = (struct commit *) o; - - if (parse_commit(new) < 0) - return 0; - - used = list = NULL; - commit_list_insert(new, &list); - while (list) { - new = pop_most_recent_commit(&list, TMP_MARK); - commit_list_insert(new, &used); - if (new == old) { - found = 1; - break; - } - } - unmark_and_free(list, TMP_MARK); - unmark_and_free(used, TMP_MARK); - return found; -} - static void add_remote_info_ref(struct remote_ls_ctx *ls) { struct strbuf *buf = (struct strbuf *)ls->userData; diff --git a/remote.c b/remote.c index 01aae770a9..c8b7ea4ffa 100644 --- a/remote.c +++ b/remote.c @@ -5,6 +5,7 @@ #include "diff.h" #include "revision.h" #include "dir.h" +#include "tag.h" static struct refspec s_tag_refspec = { 0, @@ -1269,6 +1270,54 @@ int resolve_remote_symref(struct ref *ref, struct ref *list) return 1; } +static void unmark_and_free(struct commit_list *list, unsigned int mark) +{ + while (list) { + struct commit_list *temp = list; + temp->item->object.flags &= ~mark; + list = temp->next; + free(temp); + } +} + +int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1) +{ + struct object *o; + struct commit *old, *new; + struct commit_list *list, *used; + int found = 0; + + /* Both new and old must be commit-ish and new is descendant of + * old. Otherwise we require --force. + */ + o = deref_tag(parse_object(old_sha1), NULL, 0); + if (!o || o->type != OBJ_COMMIT) + return 0; + old = (struct commit *) o; + + o = deref_tag(parse_object(new_sha1), NULL, 0); + if (!o || o->type != OBJ_COMMIT) + return 0; + new = (struct commit *) o; + + if (parse_commit(new) < 0) + return 0; + + used = list = NULL; + commit_list_insert(new, &list); + while (list) { + new = pop_most_recent_commit(&list, TMP_MARK); + commit_list_insert(new, &used); + if (new == old) { + found = 1; + break; + } + } + unmark_and_free(list, TMP_MARK); + unmark_and_free(used, TMP_MARK); + return found; +} + /* * Return true if there is anything to report, otherwise false. */ diff --git a/remote.h b/remote.h index 56ca8b168f..c0666a0758 100644 --- a/remote.h +++ b/remote.h @@ -74,6 +74,7 @@ int check_ref_type(const struct ref *ref, int flags); void free_refs(struct ref *ref); int resolve_remote_symref(struct ref *ref, struct ref *list); +int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1); /* * Removes and frees any duplicate refs in the map. From 8ef517337dc684a333111b46d88c3217202f48c3 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Wed, 25 Feb 2009 03:32:13 -0500 Subject: [PATCH 080/654] move locate_head() to remote.c Move locate_head() to remote.c and rename it to guess_remote_head() to more accurately reflect what it does. This is in preparation for being able to call it from builtin-remote.c Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-clone.c | 41 +++-------------------------------------- remote.c | 37 +++++++++++++++++++++++++++++++++++++ remote.h | 9 +++++++++ 3 files changed, 49 insertions(+), 38 deletions(-) diff --git a/builtin-clone.c b/builtin-clone.c index c338910b1c..d179d1c632 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -20,6 +20,7 @@ #include "dir.h" #include "pack-refs.h" #include "sigchain.h" +#include "remote.h" /* * Overall FIXMEs: @@ -293,43 +294,6 @@ static void remove_junk_on_signal(int signo) raise(signo); } -static const struct ref *locate_head(const struct ref *refs, - const struct ref *mapped_refs, - const struct ref **remote_head_p) -{ - const struct ref *remote_head = NULL; - const struct ref *remote_master = NULL; - const struct ref *r; - for (r = refs; r; r = r->next) - if (!strcmp(r->name, "HEAD")) - remote_head = r; - - for (r = mapped_refs; r; r = r->next) - if (!strcmp(r->name, "refs/heads/master")) - remote_master = r; - - if (remote_head_p) - *remote_head_p = remote_head; - - /* If there's no HEAD value at all, never mind. */ - if (!remote_head) - return NULL; - - /* If refs/heads/master could be right, it is. */ - if (remote_master && !hashcmp(remote_master->old_sha1, - remote_head->old_sha1)) - return remote_master; - - /* Look for another ref that points there */ - for (r = mapped_refs; r; r = r->next) - if (r != remote_head && - !hashcmp(r->old_sha1, remote_head->old_sha1)) - return r; - - /* Nothing is the same */ - return NULL; -} - static struct ref *write_remote_refs(const struct ref *refs, struct refspec *refspec, const char *reflog) { @@ -545,7 +509,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix) mapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf); - head_points_at = locate_head(refs, mapped_refs, &remote_head); + head_points_at = guess_remote_head(refs, mapped_refs, + &remote_head); } else { warning("You appear to have cloned an empty repository."); diff --git a/remote.c b/remote.c index c8b7ea4ffa..49a183eb5a 100644 --- a/remote.c +++ b/remote.c @@ -1451,3 +1451,40 @@ struct ref *get_local_heads(void) for_each_ref(one_local_ref, &local_tail); return local_refs; } + +const struct ref *guess_remote_head(const struct ref *refs, + const struct ref *mapped_refs, + const struct ref **remote_head_p) +{ + const struct ref *remote_head = NULL; + const struct ref *remote_master = NULL; + const struct ref *r; + for (r = refs; r; r = r->next) + if (!strcmp(r->name, "HEAD")) + remote_head = r; + + for (r = mapped_refs; r; r = r->next) + if (!strcmp(r->name, "refs/heads/master")) + remote_master = r; + + if (remote_head_p) + *remote_head_p = remote_head; + + /* If there's no HEAD value at all, never mind. */ + if (!remote_head) + return NULL; + + /* If refs/heads/master could be right, it is. */ + if (remote_master && !hashcmp(remote_master->old_sha1, + remote_head->old_sha1)) + return remote_master; + + /* Look for another ref that points there */ + for (r = mapped_refs; r; r = r->next) + if (r != remote_head && + !hashcmp(r->old_sha1, remote_head->old_sha1)) + return r; + + /* Nothing is the same */ + return NULL; +} diff --git a/remote.h b/remote.h index c0666a0758..9605da9e16 100644 --- a/remote.h +++ b/remote.h @@ -139,4 +139,13 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs); int format_tracking_info(struct branch *branch, struct strbuf *sb); struct ref *get_local_heads(void); +/* + * Look in refs for HEAD. Then look for a matching SHA1 in mapped_refs, + * first checking if refs/heads/master matches. Return NULL if nothing matches + * or if there is no HEAD in refs. remote_head_p is assigned HEAD if not NULL. + */ +const struct ref *guess_remote_head(const struct ref *refs, + const struct ref *mapped_refs, + const struct ref **remote_head_p); + #endif From 6cb4e6cc0f5b2de1998492b0178eeb0f99d4a800 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Wed, 25 Feb 2009 03:32:14 -0500 Subject: [PATCH 081/654] remote: simplify guess_remote_head() This function had complications which made it hard to extend. - It used to do two things: find the HEAD ref, and then find a matching ref, optionally returning the former via assignment to a passed-in pointer. Since finding HEAD is a one-liner, just have a caller do it themselves and pass it as an argument. - It used to manually search through the ref list for refs/heads/master; this can be a one-line call to find_ref_by_name. Originally contributed by Jeff King along with the next commit as a single patch. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-clone.c | 4 ++-- remote.c | 31 ++++++++----------------------- remote.h | 15 +++++++-------- 3 files changed, 17 insertions(+), 33 deletions(-) diff --git a/builtin-clone.c b/builtin-clone.c index d179d1c632..f9ce4fbf19 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -509,8 +509,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix) mapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf); - head_points_at = guess_remote_head(refs, mapped_refs, - &remote_head); + remote_head = find_ref_by_name(refs, "HEAD"); + head_points_at = guess_remote_head(remote_head, mapped_refs); } else { warning("You appear to have cloned an empty repository."); diff --git a/remote.c b/remote.c index 49a183eb5a..aed760ee3a 100644 --- a/remote.c +++ b/remote.c @@ -1452,37 +1452,22 @@ struct ref *get_local_heads(void) return local_refs; } -const struct ref *guess_remote_head(const struct ref *refs, - const struct ref *mapped_refs, - const struct ref **remote_head_p) +const struct ref *guess_remote_head(const struct ref *head, + const struct ref *refs) { - const struct ref *remote_head = NULL; - const struct ref *remote_master = NULL; const struct ref *r; - for (r = refs; r; r = r->next) - if (!strcmp(r->name, "HEAD")) - remote_head = r; - for (r = mapped_refs; r; r = r->next) - if (!strcmp(r->name, "refs/heads/master")) - remote_master = r; - - if (remote_head_p) - *remote_head_p = remote_head; - - /* If there's no HEAD value at all, never mind. */ - if (!remote_head) + if (!head) return NULL; /* If refs/heads/master could be right, it is. */ - if (remote_master && !hashcmp(remote_master->old_sha1, - remote_head->old_sha1)) - return remote_master; + r = find_ref_by_name(refs, "refs/heads/master"); + if (r && !hashcmp(r->old_sha1, head->old_sha1)) + return r; /* Look for another ref that points there */ - for (r = mapped_refs; r; r = r->next) - if (r != remote_head && - !hashcmp(r->old_sha1, remote_head->old_sha1)) + for (r = refs; r; r = r->next) + if (r != head && !hashcmp(r->old_sha1, head->old_sha1)) return r; /* Nothing is the same */ diff --git a/remote.h b/remote.h index 9605da9e16..db49ce0467 100644 --- a/remote.h +++ b/remote.h @@ -139,13 +139,12 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs); int format_tracking_info(struct branch *branch, struct strbuf *sb); struct ref *get_local_heads(void); -/* - * Look in refs for HEAD. Then look for a matching SHA1 in mapped_refs, - * first checking if refs/heads/master matches. Return NULL if nothing matches - * or if there is no HEAD in refs. remote_head_p is assigned HEAD if not NULL. - */ -const struct ref *guess_remote_head(const struct ref *refs, - const struct ref *mapped_refs, - const struct ref **remote_head_p); +/* + * Look for a ref in refs whose SHA1 matches head, first checking if + * refs/heads/master matches. Return NULL if nothing matches or if head + * is NULL. + */ +const struct ref *guess_remote_head(const struct ref *head, + const struct ref *refs); #endif From 72de29c24f50dccc5f045a7756bb0b47e34a7a8e Mon Sep 17 00:00:00 2001 From: Teemu Likonen <tlikonen@iki.fi> Date: Tue, 24 Feb 2009 15:33:29 +0200 Subject: [PATCH 082/654] bash completion: add --format= and --oneline options for "git log" We also add --format= completion for "git show". Signed-off-by: Teemu Likonen <tlikonen@iki.fi> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 0a3092f646..31608cb79f 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1014,6 +1014,11 @@ _git_log () " "" "${cur##--pretty=}" return ;; + --format=*) + __gitcomp "$__git_log_pretty_formats + " "" "${cur##--format=}" + return + ;; --date=*) __gitcomp " relative iso8601 rfc2822 short local default @@ -1029,7 +1034,7 @@ _git_log () --follow --abbrev-commit --abbrev= --relative-date --date= - --pretty= + --pretty= --format= --oneline --cherry-pick --graph --decorate @@ -1541,8 +1546,13 @@ _git_show () " "" "${cur##--pretty=}" return ;; + --format=*) + __gitcomp "$__git_log_pretty_formats + " "" "${cur##--format=}" + return + ;; --*) - __gitcomp "--pretty= + __gitcomp "--pretty= --format= $__git_diff_common_options " return From 7b3db095d53d19e08b27114d8706ff3be6693af7 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Fri, 27 Feb 2009 14:10:04 -0500 Subject: [PATCH 083/654] remote: make copy_ref() perform a deep copy To ensure that copied refs can always be freed w/o causing a double-free, make copy_ref() perform a deep copy. Also have copy_ref() return NULL if asked to copy NULL to simplify things for the caller. Background: currently copy_ref() performs a shallow copy. This is fine for current callers who never free the result and/or only copy refs which contain NULL pointers. But copy_ref() is about to gain a new caller (guess_remote_head()) which copies refs where peer_ref is not NULL and the caller of guess_remote_head() will want to free the result. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- remote.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/remote.c b/remote.c index aed760ee3a..22203ea8e2 100644 --- a/remote.c +++ b/remote.c @@ -779,10 +779,18 @@ struct ref *alloc_ref(const char *name) static struct ref *copy_ref(const struct ref *ref) { - struct ref *ret = xmalloc(sizeof(struct ref) + strlen(ref->name) + 1); - memcpy(ret, ref, sizeof(struct ref) + strlen(ref->name) + 1); - ret->next = NULL; - return ret; + struct ref *cpy; + size_t len; + if (!ref) + return NULL; + len = strlen(ref->name); + cpy = xmalloc(sizeof(struct ref) + len + 1); + memcpy(cpy, ref, sizeof(struct ref) + len + 1); + cpy->next = NULL; + cpy->symref = ref->symref ? xstrdup(ref->symref) : NULL; + cpy->remote_status = ref->remote_status ? xstrdup(ref->remote_status) : NULL; + cpy->peer_ref = copy_ref(ref->peer_ref); + return cpy; } struct ref *copy_ref_list(const struct ref *ref) @@ -801,6 +809,7 @@ static void free_ref(struct ref *ref) { if (!ref) return; + free_ref(ref->peer_ref); free(ref->remote_status); free(ref->symref); free(ref); @@ -811,7 +820,6 @@ void free_refs(struct ref *ref) struct ref *next; while (ref) { next = ref->next; - free(ref->peer_ref); free_ref(ref); ref = next; } From 4229f1fa325870d6b24fe2a4c7d2ed5f14c6f771 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Fri, 27 Feb 2009 14:10:05 -0500 Subject: [PATCH 084/654] remote: let guess_remote_head() optionally return all matches Determining HEAD is ambiguous since it is done by comparing SHA1s. In the case of multiple matches we return refs/heads/master if it matches, else we return the first match we encounter. builtin-remote needs all matches returned to it, so add a flag for it to request such. To be simple and consistent, the return value is now a copy (including peer_ref) of the matching refs. Originally contributed by Jeff King along with the prior commit as a single patch. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-clone.c | 2 +- remote.c | 29 +++++++++++++++++++---------- remote.h | 14 ++++++++------ 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/builtin-clone.c b/builtin-clone.c index f9ce4fbf19..3146ca87f8 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -510,7 +510,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) mapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf); remote_head = find_ref_by_name(refs, "HEAD"); - head_points_at = guess_remote_head(remote_head, mapped_refs); + head_points_at = guess_remote_head(remote_head, mapped_refs, 0); } else { warning("You appear to have cloned an empty repository."); diff --git a/remote.c b/remote.c index 22203ea8e2..304e967e3c 100644 --- a/remote.c +++ b/remote.c @@ -1460,24 +1460,33 @@ struct ref *get_local_heads(void) return local_refs; } -const struct ref *guess_remote_head(const struct ref *head, - const struct ref *refs) +struct ref *guess_remote_head(const struct ref *head, + const struct ref *refs, + int all) { const struct ref *r; + struct ref *list = NULL; + struct ref **tail = &list; if (!head) return NULL; /* If refs/heads/master could be right, it is. */ - r = find_ref_by_name(refs, "refs/heads/master"); - if (r && !hashcmp(r->old_sha1, head->old_sha1)) - return r; + if (!all) { + r = find_ref_by_name(refs, "refs/heads/master"); + if (r && !hashcmp(r->old_sha1, head->old_sha1)) + return copy_ref(r); + } /* Look for another ref that points there */ - for (r = refs; r; r = r->next) - if (r != head && !hashcmp(r->old_sha1, head->old_sha1)) - return r; + for (r = refs; r; r = r->next) { + if (r != head && !hashcmp(r->old_sha1, head->old_sha1)) { + *tail = copy_ref(r); + tail = &((*tail)->next); + if (!all) + break; + } + } - /* Nothing is the same */ - return NULL; + return list; } diff --git a/remote.h b/remote.h index db49ce0467..de3d21b662 100644 --- a/remote.h +++ b/remote.h @@ -139,12 +139,14 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs); int format_tracking_info(struct branch *branch, struct strbuf *sb); struct ref *get_local_heads(void); - /* - * Look for a ref in refs whose SHA1 matches head, first checking if - * refs/heads/master matches. Return NULL if nothing matches or if head - * is NULL. + * Find refs from a list which are likely to be pointed to by the given HEAD + * ref. If 'all' is false, returns the most likely ref; otherwise, returns a + * list of all candidate refs. If no match is found (or 'head' is NULL), + * returns NULL. All returns are newly allocated and should be freed. */ -const struct ref *guess_remote_head(const struct ref *head, - const struct ref *refs); +struct ref *guess_remote_head(const struct ref *head, + const struct ref *refs, + int all); + #endif From cdf690e53b5f5af1ca8679b3f3e47ea198692c18 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Wed, 25 Feb 2009 03:32:16 -0500 Subject: [PATCH 085/654] remote: make match_refs() copy src ref before assigning to peer_ref In some instances, match_refs() sets the peer_ref field of refs in the dst list such that it points to a ref in the src list. This prevents callers from freeing both the src and dst lists, as doing so would cause a double-free since free_refs() frees the peer_ref. As well, the following configuration causes two refs in the dst list to have the same peer_ref, which can also lead to a double-free: push = refs/heads/master:refs/heads/backup push = refs/heads/master:refs/heads/master Existing callers of match_heads() call it only once and then terminate, w/o ever bothering to free the src or dst lists, so this is not currently a problem. This patch modifies match_refs() to first copy any refs it plucks from the src list before assigning them as a peer_ref. This allows builtin-remote, a future caller, to free the src and dst lists. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- remote.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/remote.c b/remote.c index 304e967e3c..b7606acc47 100644 --- a/remote.c +++ b/remote.c @@ -936,6 +936,7 @@ static int match_explicit(struct ref *src, struct ref *dst, struct refspec *rs) { struct ref *matched_src, *matched_dst; + int copy_src; const char *dst_value = rs->dst; char *dst_guess; @@ -946,6 +947,7 @@ static int match_explicit(struct ref *src, struct ref *dst, matched_src = matched_dst = NULL; switch (count_refspec_match(rs->src, src, &matched_src)) { case 1: + copy_src = 1; break; case 0: /* The source could be in the get_sha1() format @@ -955,6 +957,7 @@ static int match_explicit(struct ref *src, struct ref *dst, matched_src = try_explicit_object_name(rs->src); if (!matched_src) return error("src refspec %s does not match any.", rs->src); + copy_src = 0; break; default: return error("src refspec %s matches more than one.", rs->src); @@ -1000,7 +1003,7 @@ static int match_explicit(struct ref *src, struct ref *dst, return error("dst ref %s receives from more than one src.", matched_dst->name); else { - matched_dst->peer_ref = matched_src; + matched_dst->peer_ref = copy_src ? copy_ref(matched_src) : matched_src; matched_dst->force = rs->force; } return 0; @@ -1108,7 +1111,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, dst_peer = make_linked_ref(dst_name, dst_tail); hashcpy(dst_peer->new_sha1, src->new_sha1); } - dst_peer->peer_ref = src; + dst_peer->peer_ref = copy_ref(src); dst_peer->force = pat->force; free_name: free(dst_name); From 5f48cb95aa0d7311623df76249a1c8a1962550f5 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Wed, 25 Feb 2009 03:32:17 -0500 Subject: [PATCH 086/654] remote: make match_refs() not short-circuit match_refs() returns non-zero if there is an error in match_explicit_refs(), without handling any remaining pattern ref specs. Its existing callers exit upon receiving non-zero, so a partial result is of no consequence to them; however a new caller, builtin-remote, is interested in the complete result even if there are errors in match_explicit_refs(). Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- remote.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/remote.c b/remote.c index b7606acc47..2123005d4b 100644 --- a/remote.c +++ b/remote.c @@ -1052,6 +1052,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, struct refspec *rs; int send_all = flags & MATCH_REFS_ALL; int send_mirror = flags & MATCH_REFS_MIRROR; + int errs; static const char *default_refspec[] = { ":", 0 }; if (!nr_refspec) { @@ -1059,8 +1060,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, refspec = default_refspec; } rs = parse_push_refspec(nr_refspec, (const char **) refspec); - if (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec)) - return -1; + errs = match_explicit_refs(src, dst, dst_tail, rs, nr_refspec); /* pick the remainder */ for ( ; src; src = src->next) { @@ -1116,6 +1116,8 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, free_name: free(dst_name); } + if (errs) + return -1; return 0; } From c6f5a7a916b36fc9dd00bb6dce3b68260579abe1 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Wed, 25 Feb 2009 03:32:18 -0500 Subject: [PATCH 087/654] string-list: new for_each_string_list() function Add a convenience function for iterating over a string_list's items via a callback. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- string-list.c | 10 ++++++++++ string-list.h | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/string-list.c b/string-list.c index 15e14cf47a..1ac536e638 100644 --- a/string-list.c +++ b/string-list.c @@ -92,6 +92,16 @@ struct string_list_item *string_list_lookup(const char *string, struct string_li return list->items + i; } +int for_each_string_list(string_list_each_func_t fn, + struct string_list *list, void *cb_data) +{ + int i, ret = 0; + for (i = 0; i < list->nr; i++) + if ((ret = fn(&list->items[i], cb_data))) + break; + return ret; +} + void string_list_clear(struct string_list *list, int free_util) { if (list->items) { diff --git a/string-list.h b/string-list.h index d32ba05202..14bbc477de 100644 --- a/string-list.h +++ b/string-list.h @@ -20,6 +20,11 @@ void string_list_clear(struct string_list *list, int free_util); typedef void (*string_list_clear_func_t)(void *p, const char *str); void string_list_clear_func(struct string_list *list, string_list_clear_func_t clearfunc); +/* Use this function to iterate over each item */ +typedef int (*string_list_each_func_t)(struct string_list_item *, void *); +int for_each_string_list(string_list_each_func_t, + struct string_list *list, void *cb_data); + /* Use these functions only on sorted lists: */ int string_list_has_string(const struct string_list *list, const char *string); int string_list_find_insert_index(const struct string_list *list, const char *string, From 88733235615b24198599b533f9d02578ef739536 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Wed, 25 Feb 2009 03:32:19 -0500 Subject: [PATCH 088/654] builtin-remote: refactor duplicated cleanup code This patch moves identical lines of code into a cleanup function. The function has two callers and is about to gain a third. Also removed a bogus NEEDSWORK comment per Daniel Barkalow: Actually, the comment is wrong; "remote" comes from remote_get(), which returns things from a cache in remote.c; there could be a remote_put() to let the code know that the caller is done with the object, but it wouldn't presently do anything. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-remote.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/builtin-remote.c b/builtin-remote.c index ac69d37c8a..b89a3534de 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -632,6 +632,13 @@ static void show_list(const char *title, struct string_list *list, printf(" %s\n", list->items[i].string); } +static void free_remote_ref_states(struct ref_states *states) +{ + string_list_clear(&states->new, 0); + string_list_clear(&states->stale, 0); + string_list_clear(&states->tracked, 0); +} + static int get_remote_ref_states(const char *name, struct ref_states *states, int query) @@ -738,10 +745,7 @@ static int show(int argc, const char **argv) } } - /* NEEDSWORK: free remote */ - string_list_clear(&states.new, 0); - string_list_clear(&states.stale, 0); - string_list_clear(&states.tracked, 0); + free_remote_ref_states(&states); } return result; @@ -792,10 +796,7 @@ static int prune(int argc, const char **argv) warn_dangling_symref(dangling_msg, refname); } - /* NEEDSWORK: free remote */ - string_list_clear(&states.new, 0); - string_list_clear(&states.stale, 0); - string_list_clear(&states.tracked, 0); + free_remote_ref_states(&states); } return result; From 7b9a5e276cc685788386f1dcbd6a201f9f18da16 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Wed, 25 Feb 2009 03:32:20 -0500 Subject: [PATCH 089/654] builtin-remote: remove unused code in get_ref_states get_ref_states() populates the util pointer of the string_list_item's that it adds to states->new and states->tracked, but nothing ever uses the pointer, so we can get rid of the extra code. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-remote.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/builtin-remote.c b/builtin-remote.c index b89a3534de..3e6dee4ad5 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -250,18 +250,11 @@ static int get_ref_states(const struct ref *ref, struct ref_states *states) states->new.strdup_strings = states->tracked.strdup_strings = 1; for (ref = fetch_map; ref; ref = ref->next) { - struct string_list *target = &states->tracked; unsigned char sha1[20]; - void *util = NULL; - if (!ref->peer_ref || read_ref(ref->peer_ref->name, sha1)) - target = &states->new; - else { - target = &states->tracked; - if (hashcmp(sha1, ref->new_sha1)) - util = &states; - } - string_list_append(abbrev_branch(ref->name), target)->util = util; + string_list_append(abbrev_branch(ref->name), &states->new); + else + string_list_append(abbrev_branch(ref->name), &states->tracked); } free_refs(fetch_map); From e0cc81e63c7bb603545c90e47d4c6398f6347dfb Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Wed, 25 Feb 2009 03:32:21 -0500 Subject: [PATCH 090/654] builtin-remote: rename variables and eliminate redundant function call - The variable name "remote" is used as both a "char *" and as a "struct remote *"; this is confusing, so rename the former to remote_name. - Consistently refer to the refs returned by transport_get_remote_refs() as remote_refs. - There is no need to call "sort_string_list(&branch_list)" as branch_list is populated via string_list_insert(), which maintains its order. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-remote.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/builtin-remote.c b/builtin-remote.c index 3e6dee4ad5..fc02e5f34b 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -143,7 +143,7 @@ static int add(int argc, const char **argv) } struct branch_info { - char *remote; + char *remote_name; struct string_list merge; }; @@ -182,9 +182,9 @@ static int config_read_branches(const char *key, const char *value, void *cb) item->util = xcalloc(sizeof(struct branch_info), 1); info = item->util; if (type == REMOTE) { - if (info->remote) + if (info->remote_name) warning("more than one branch.%s", key); - info->remote = xstrdup(value); + info->remote_name = xstrdup(value); } else { char *space = strchr(value, ' '); value = abbrev_branch(value); @@ -206,7 +206,6 @@ static void read_branches(void) if (branch_list.nr) return; git_config(config_read_branches, NULL); - sort_string_list(&branch_list); } struct ref_states { @@ -238,13 +237,14 @@ static int handle_one_branch(const char *refname, return 0; } -static int get_ref_states(const struct ref *ref, struct ref_states *states) +static int get_ref_states(const struct ref *remote_refs, struct ref_states *states) { struct ref *fetch_map = NULL, **tail = &fetch_map; + struct ref *ref; int i; for (i = 0; i < states->remote->fetch_refspec_nr; i++) - if (get_fetch_map(ref, states->remote->fetch + i, &tail, 1)) + if (get_fetch_map(remote_refs, states->remote->fetch + i, &tail, 1)) die("Could not get fetch map for refspec %s", states->remote->fetch_refspec[i]); @@ -459,7 +459,7 @@ static int mv(int argc, const char **argv) for (i = 0; i < branch_list.nr; i++) { struct string_list_item *item = branch_list.items + i; struct branch_info *info = item->util; - if (info->remote && !strcmp(info->remote, rename.old)) { + if (info->remote_name && !strcmp(info->remote_name, rename.old)) { strbuf_reset(&buf); strbuf_addf(&buf, "branch.%s.remote", item->string); if (git_config_set(buf.buf, rename.new)) { @@ -569,7 +569,7 @@ static int rm(int argc, const char **argv) for (i = 0; i < branch_list.nr; i++) { struct string_list_item *item = branch_list.items + i; struct branch_info *info = item->util; - if (info->remote && !strcmp(info->remote, remote->name)) { + if (info->remote_name && !strcmp(info->remote_name, remote->name)) { const char *keys[] = { "remote", "merge", NULL }, **k; for (k = keys; *k; k++) { strbuf_reset(&buf); @@ -637,7 +637,7 @@ static int get_remote_ref_states(const char *name, int query) { struct transport *transport; - const struct ref *ref; + const struct ref *remote_refs; states->remote = remote_get(name); if (!states->remote) @@ -648,10 +648,10 @@ static int get_remote_ref_states(const char *name, if (query) { transport = transport_get(NULL, states->remote->url_nr > 0 ? states->remote->url[0] : NULL); - ref = transport_get_remote_refs(transport); + remote_refs = transport_get_remote_refs(transport); transport_disconnect(transport); - get_ref_states(ref, states); + get_ref_states(remote_refs, states); } return 0; @@ -701,7 +701,7 @@ static int show(int argc, const char **argv) struct branch_info *info = branch->util; int j; - if (!info->merge.nr || strcmp(*argv, info->remote)) + if (!info->merge.nr || strcmp(*argv, info->remote_name)) continue; printf(" Remote branch%s merged with 'git pull' " "while on branch %s\n ", From cca7c97e37719eaee1d31cdaf1e638d19ecd69e4 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Wed, 25 Feb 2009 03:32:22 -0500 Subject: [PATCH 091/654] builtin-remote: make get_remote_ref_states() always populate states.tracked When not querying the remote, show() was having to populate states.tracked itself. It makes more sense for get_remote_ref_states() to do this consistently. Since show() is the only caller of get_remote_ref_states() with query=0, this change does not affect other callers. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-remote.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/builtin-remote.c b/builtin-remote.c index fc02e5f34b..1b5e8b6811 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -632,6 +632,20 @@ static void free_remote_ref_states(struct ref_states *states) string_list_clear(&states->tracked, 0); } +static int append_ref_to_tracked_list(const char *refname, + const unsigned char *sha1, int flags, void *cb_data) +{ + struct ref_states *states = cb_data; + struct refspec refspec; + + memset(&refspec, 0, sizeof(refspec)); + refspec.dst = (char *)refname; + if (!remote_find_tracking(states->remote, &refspec)) + string_list_append(abbrev_branch(refspec.src), &states->tracked); + + return 0; +} + static int get_remote_ref_states(const char *name, struct ref_states *states, int query) @@ -652,21 +666,8 @@ static int get_remote_ref_states(const char *name, transport_disconnect(transport); get_ref_states(remote_refs, states); - } - - return 0; -} - -static int append_ref_to_tracked_list(const char *refname, - const unsigned char *sha1, int flags, void *cb_data) -{ - struct ref_states *states = cb_data; - struct refspec refspec; - - memset(&refspec, 0, sizeof(refspec)); - refspec.dst = (char *)refname; - if (!remote_find_tracking(states->remote, &refspec)) - string_list_append(abbrev_branch(refspec.src), &states->tracked); + } else + for_each_ref(append_ref_to_tracked_list, states); return 0; } @@ -720,8 +721,6 @@ static int show(int argc, const char **argv) "prune')", &states.stale, ""); } - if (no_query) - for_each_ref(append_ref_to_tracked_list, &states); show_list(" Tracked remote branch%s", &states.tracked, ""); if (states.remote->push_refspec_nr) { From 3bd925636cd11400d1840b39d0d18b640f32bdd2 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Wed, 25 Feb 2009 03:32:23 -0500 Subject: [PATCH 092/654] builtin-remote: fix two inconsistencies in the output of "show <remote>" Remote and stale branches are emitted in alphabetical order, but new and tracked branches are not. So sort the latter to be consistent with the former. This also lets us use more efficient string_list_has_string() instead of unsorted_string_list_has_string(). "show <remote>" prunes symrefs, but "show <remote> -n" does not. Fix the latter to match the former. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-remote.c | 15 ++++++++++----- t/t5505-remote.sh | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/builtin-remote.c b/builtin-remote.c index 1b5e8b6811..963be6df95 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -226,10 +226,8 @@ static int handle_one_branch(const char *refname, const char *name = abbrev_branch(refspec.src); /* symbolic refs pointing nowhere were handled already */ if ((flags & REF_ISSYMREF) || - unsorted_string_list_has_string(&states->tracked, - name) || - unsorted_string_list_has_string(&states->new, - name)) + string_list_has_string(&states->tracked, name) || + string_list_has_string(&states->new, name)) return 0; item = string_list_append(name, &states->stale); item->util = xstrdup(refname); @@ -258,6 +256,8 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat } free_refs(fetch_map); + sort_string_list(&states->new); + sort_string_list(&states->tracked); for_each_ref(handle_one_branch, states); sort_string_list(&states->stale); @@ -638,6 +638,9 @@ static int append_ref_to_tracked_list(const char *refname, struct ref_states *states = cb_data; struct refspec refspec; + if (flags & REF_ISSYMREF) + return 0; + memset(&refspec, 0, sizeof(refspec)); refspec.dst = (char *)refname; if (!remote_find_tracking(states->remote, &refspec)) @@ -666,8 +669,10 @@ static int get_remote_ref_states(const char *name, transport_disconnect(transport); get_ref_states(remote_refs, states); - } else + } else { for_each_ref(append_ref_to_tracked_list, states); + sort_string_list(&states->tracked); + } return 0; } diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index eb637184a0..a13d4b66d6 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -141,8 +141,8 @@ cat > test/expect << EOF New remote branch (next fetch will store in remotes/origin) master Tracked remote branches - side master + side Local branches pushed with 'git push' master:upstream +refs/tags/lastbackup From e61e0cc6b7061d7e791e1c9722b9c4a6d85d629c Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Wed, 25 Feb 2009 03:32:24 -0500 Subject: [PATCH 093/654] builtin-remote: teach show to display remote HEAD This is in preparation for teaching remote how to set refs/remotes/<remote>/HEAD to match what HEAD is set to at <remote>, but is useful in its own right. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-remote.c | 54 ++++++++++++++++++++++++++++++++++++++++++----- t/t5505-remote.sh | 12 +++++++++-- 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/builtin-remote.c b/builtin-remote.c index 963be6df95..4543cf0826 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -18,6 +18,9 @@ static const char * const builtin_remote_usage[] = { NULL }; +#define GET_REF_STATES (1<<0) +#define GET_HEAD_NAMES (1<<1) + static int verbose; static int show_all(void); @@ -210,7 +213,7 @@ static void read_branches(void) struct ref_states { struct remote *remote; - struct string_list new, stale, tracked; + struct string_list new, stale, tracked, heads; }; static int handle_one_branch(const char *refname, @@ -264,6 +267,28 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat return 0; } +static int get_head_names(const struct ref *remote_refs, struct ref_states *states) +{ + struct ref *ref, *matches; + struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map; + struct refspec refspec; + + refspec.force = 0; + refspec.pattern = 1; + refspec.src = refspec.dst = "refs/heads/"; + states->heads.strdup_strings = 1; + get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0); + matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"), + fetch_map, 1); + for(ref = matches; ref; ref = ref->next) + string_list_append(abbrev_branch(ref->name), &states->heads); + + free_refs(fetch_map); + free_refs(matches); + + return 0; +} + struct known_remote { struct known_remote *next; struct remote *remote; @@ -630,6 +655,7 @@ static void free_remote_ref_states(struct ref_states *states) string_list_clear(&states->new, 0); string_list_clear(&states->stale, 0); string_list_clear(&states->tracked, 0); + string_list_clear(&states->heads, 0); } static int append_ref_to_tracked_list(const char *refname, @@ -668,7 +694,10 @@ static int get_remote_ref_states(const char *name, remote_refs = transport_get_remote_refs(transport); transport_disconnect(transport); - get_ref_states(remote_refs, states); + if (query & GET_REF_STATES) + get_ref_states(remote_refs, states); + if (query & GET_HEAD_NAMES) + get_head_names(remote_refs, states); } else { for_each_ref(append_ref_to_tracked_list, states); sort_string_list(&states->tracked); @@ -679,7 +708,7 @@ static int get_remote_ref_states(const char *name, static int show(int argc, const char **argv) { - int no_query = 0, result = 0; + int no_query = 0, result = 0, query_flag = 0; struct option options[] = { OPT_GROUP("show specific options"), OPT_BOOLEAN('n', NULL, &no_query, "do not query remotes"), @@ -692,15 +721,30 @@ static int show(int argc, const char **argv) if (argc < 1) return show_all(); + if (!no_query) + query_flag = (GET_REF_STATES | GET_HEAD_NAMES); + memset(&states, 0, sizeof(states)); for (; argc; argc--, argv++) { int i; - get_remote_ref_states(*argv, &states, !no_query); + get_remote_ref_states(*argv, &states, query_flag); printf("* remote %s\n URL: %s\n", *argv, states.remote->url_nr > 0 ? states.remote->url[0] : "(no URL)"); + if (no_query) + printf(" HEAD branch: (not queried)\n"); + else if (!states.heads.nr) + printf(" HEAD branch: (unknown)\n"); + else if (states.heads.nr == 1) + printf(" HEAD branch: %s\n", states.heads.items[0].string); + else { + printf(" HEAD branch (remote HEAD is ambiguous," + " may be one of the following):\n"); + for (i = 0; i < states.heads.nr; i++) + printf(" %s\n", states.heads.items[i].string); + } for (i = 0; i < branch_list.nr; i++) { struct string_list_item *branch = branch_list.items + i; @@ -772,7 +816,7 @@ static int prune(int argc, const char **argv) for (; argc; argc--, argv++) { int i; - get_remote_ref_states(*argv, &states, 1); + get_remote_ref_states(*argv, &states, GET_REF_STATES); if (states.stale.nr) { printf("Pruning %s\n", *argv); diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index a13d4b66d6..91525c3f9c 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -136,6 +136,7 @@ EOF cat > test/expect << EOF * remote origin URL: $(pwd)/one + HEAD branch: master Remote branch merged with 'git pull' while on branch master master New remote branch (next fetch will store in remotes/origin) @@ -146,6 +147,11 @@ cat > test/expect << EOF Local branches pushed with 'git push' master:upstream +refs/tags/lastbackup +* remote two + URL: ../two + HEAD branch (remote HEAD is ambiguous, may be one of the following): + another + master EOF test_expect_success 'show' ' @@ -154,6 +160,7 @@ test_expect_success 'show' ' refs/heads/master:refs/heads/upstream && git fetch && git branch -d -r origin/master && + git config --add remote.two.url ../two && (cd ../one && echo 1 > file && test_tick && @@ -162,13 +169,14 @@ test_expect_success 'show' ' refs/heads/master:refs/heads/upstream && git config --add remote.origin.push \ +refs/tags/lastbackup && - git remote show origin > output && + git remote show origin two > output && test_cmp expect output) ' cat > test/expect << EOF * remote origin URL: $(pwd)/one + HEAD branch: (not queried) Remote branch merged with 'git pull' while on branch master master Tracked remote branches @@ -343,7 +351,7 @@ test_expect_success '"remote show" does not show symbolic refs' ' git clone one three && (cd three && git remote show origin > output && - ! grep HEAD < output && + ! grep "^ *HEAD$" < output && ! grep -i stale < output) ' From bc14fac825d9728c311aaa9d0aecf4960d4a3103 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Wed, 25 Feb 2009 03:32:25 -0500 Subject: [PATCH 094/654] builtin-remote: add set-head subcommand Provide a porcelain command for setting and deleting $GIT_DIR/remotes/<remote>/HEAD. While we're at it, document what $GIT_DIR/remotes/<remote>/HEAD is all about. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-remote.txt | 28 +++++++++++- builtin-remote.c | 62 ++++++++++++++++++++++++++ contrib/completion/git-completion.bash | 2 +- t/t5505-remote.sh | 40 +++++++++++++++++ 4 files changed, 129 insertions(+), 3 deletions(-) diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt index fad983e297..c9c0e6f932 100644 --- a/Documentation/git-remote.txt +++ b/Documentation/git-remote.txt @@ -13,6 +13,7 @@ SYNOPSIS 'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url> 'git remote rename' <old> <new> 'git remote rm' <name> +'git remote set-head' <name> [-a | -d | <branch>] 'git remote show' [-n] <name> 'git remote prune' [-n | --dry-run] <name> 'git remote update' [group] @@ -53,8 +54,7 @@ is created. You can give more than one `-t <branch>` to track multiple branches without grabbing all branches. + With `-m <master>` option, `$GIT_DIR/remotes/<name>/HEAD` is set -up to point at remote's `<master>` branch instead of whatever -branch the `HEAD` at the remote repository actually points at. +up to point at remote's `<master>` branch. See also the set-head command. + In mirror mode, enabled with `\--mirror`, the refs will not be stored in the 'refs/remotes/' namespace, but in 'refs/heads/'. This option @@ -76,6 +76,30 @@ the configuration file format. Remove the remote named <name>. All remote tracking branches and configuration settings for the remote are removed. +'set-head':: + +Sets or deletes the default branch (`$GIT_DIR/remotes/<name>/HEAD`) for +the named remote. Having a default branch for a remote is not required, +but allows the name of the remote to be specified in lieu of a specific +branch. For example, if the default branch for `origin` is set to +`master`, then `origin` may be specified wherever you would normally +specify `origin/master`. ++ +With `-d`, `$GIT_DIR/remotes/<name>/HEAD` is deleted. ++ +With `-a`, the remote is queried to determine its `HEAD`, then +`$GIT_DIR/remotes/<name>/HEAD` is set to the same branch. e.g., if the remote +`HEAD` is pointed at `next`, "`git remote set-head origin -a`" will set +`$GIT_DIR/refs/remotes/origin/HEAD` to `refs/remotes/origin/next`. This will +only work if `refs/remotes/origin/next` already exists; if not it must be +fetched first. ++ +Use `<branch>` to set `$GIT_DIR/remotes/<name>/HEAD` explicitly. e.g., "git +remote set-head origin master" will set `$GIT_DIR/refs/remotes/origin/HEAD` to +`refs/remotes/origin/master`. This will only work if +`refs/remotes/origin/master` already exists; if not it must be fetched first. ++ + 'show':: Gives some information about the remote <name>. diff --git a/builtin-remote.c b/builtin-remote.c index 4543cf0826..640e4dafbf 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -12,6 +12,7 @@ static const char * const builtin_remote_usage[] = { "git remote add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>", "git remote rename <old> <new>", "git remote rm <name>", + "git remote set-head <name> [-a | -d | <branch>]", "git remote show [-n] <name>", "git remote prune [-n | --dry-run] <name>", "git remote [-v | --verbose] update [group]", @@ -792,6 +793,65 @@ static int show(int argc, const char **argv) return result; } +static int set_head(int argc, const char **argv) +{ + int i, opt_a = 0, opt_d = 0, result = 0; + struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT; + char *head_name = NULL; + + struct option options[] = { + OPT_GROUP("set-head specific options"), + OPT_BOOLEAN('a', "auto", &opt_a, + "set refs/remotes/<name>/HEAD according to remote"), + OPT_BOOLEAN('d', "delete", &opt_d, + "delete refs/remotes/<name>/HEAD"), + OPT_END() + }; + argc = parse_options(argc, argv, options, builtin_remote_usage, 0); + if (argc) + strbuf_addf(&buf, "refs/remotes/%s/HEAD", argv[0]); + + if (!opt_a && !opt_d && argc == 2) { + head_name = xstrdup(argv[1]); + } else if (opt_a && !opt_d && argc == 1) { + struct ref_states states; + memset(&states, 0, sizeof(states)); + get_remote_ref_states(argv[0], &states, GET_HEAD_NAMES); + if (!states.heads.nr) + result |= error("Cannot determine remote HEAD"); + else if (states.heads.nr > 1) { + result |= error("Multiple remote HEAD branches. " + "Please choose one explicitly with:"); + for (i = 0; i < states.heads.nr; i++) + fprintf(stderr, " git remote set-head %s %s\n", + argv[0], states.heads.items[i].string); + } else + head_name = xstrdup(states.heads.items[0].string); + free_remote_ref_states(&states); + } else if (opt_d && !opt_a && argc == 1) { + if (delete_ref(buf.buf, NULL, REF_NODEREF)) + result |= error("Could not delete %s", buf.buf); + } else + usage_with_options(builtin_remote_usage, options); + + if (head_name) { + unsigned char sha1[20]; + strbuf_addf(&buf2, "refs/remotes/%s/%s", argv[0], head_name); + /* make sure it's valid */ + if (!resolve_ref(buf2.buf, sha1, 1, NULL)) + result |= error("Not a valid ref: %s", buf2.buf); + else if (create_symref(buf.buf, buf2.buf, "remote set-head")) + result |= error("Could not setup %s", buf.buf); + if (opt_a) + printf("%s/HEAD set to %s\n", argv[0], head_name); + free(head_name); + } + + strbuf_release(&buf); + strbuf_release(&buf2); + return result; +} + static int prune(int argc, const char **argv) { int dry_run = 0, result = 0; @@ -962,6 +1022,8 @@ int cmd_remote(int argc, const char **argv, const char *prefix) result = mv(argc, argv); else if (!strcmp(argv[0], "rm")) result = rm(argc, argv); + else if (!strcmp(argv[0], "set-head")) + result = set_head(argc, argv); else if (!strcmp(argv[0], "show")) result = show(argc, argv); else if (!strcmp(argv[0], "prune")) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 0a3092f646..15b938b902 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1443,7 +1443,7 @@ _git_config () _git_remote () { - local subcommands="add rename rm show prune update" + local subcommands="add rename rm show prune update set-head" local subcommand="$(__git_find_subcommand "$subcommands")" if [ -z "$subcommand" ]; then __gitcomp "$subcommands" diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 91525c3f9c..de1d0fcf43 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -205,6 +205,46 @@ test_expect_success 'prune' ' test_must_fail git rev-parse refs/remotes/origin/side) ' +test_expect_success 'set-head --delete' ' + (cd test && + git symbolic-ref refs/remotes/origin/HEAD && + git remote set-head --delete origin && + test_must_fail git symbolic-ref refs/remotes/origin/HEAD) +' + +test_expect_success 'set-head --auto' ' + (cd test && + git remote set-head --auto origin && + echo refs/remotes/origin/master >expect && + git symbolic-ref refs/remotes/origin/HEAD >output && + test_cmp expect output + ) +' + +cat >test/expect <<EOF +error: Multiple remote HEAD branches. Please choose one explicitly with: + git remote set-head two another + git remote set-head two master +EOF + +test_expect_success 'set-head --auto fails w/multiple HEADs' ' + (cd test && + test_must_fail git remote set-head --auto two >output 2>&1 && + test_cmp expect output) +' + +cat >test/expect <<EOF +refs/remotes/origin/side2 +EOF + +test_expect_success 'set-head explicit' ' + (cd test && + git remote set-head origin side2 && + git symbolic-ref refs/remotes/origin/HEAD >output && + git remote set-head origin master && + test_cmp expect output) +' + cat > test/expect << EOF Pruning origin URL: $(pwd)/one From fbb074c25352627f650d2ea528ed694e77bece0f Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Fri, 27 Feb 2009 14:10:06 -0500 Subject: [PATCH 095/654] remote: make guess_remote_head() use exact HEAD lookup if it is available Our usual method for determining the ref pointed to by HEAD is to compare HEAD's sha1 to the sha1 of all refs, trying to find a unique match. However, some transports actually get to look at HEAD directly; we should make use of that information when it is available. Currently, only http remotes support this feature. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- remote.c | 8 ++++++++ t/t5550-http-fetch.sh | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/remote.c b/remote.c index 2123005d4b..9b8522db35 100644 --- a/remote.c +++ b/remote.c @@ -1476,6 +1476,14 @@ struct ref *guess_remote_head(const struct ref *head, if (!head) return NULL; + /* + * Some transports support directly peeking at + * where HEAD points; if that is the case, then + * we don't have to guess. + */ + if (head->symref) + return copy_ref(find_ref_by_name(refs, head->symref)); + /* If refs/heads/master could be right, it is. */ if (!all) { r = find_ref_by_name(refs, "refs/heads/master"); diff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch.sh index b6e6ec9607..05b1b62cb6 100755 --- a/t/t5550-http-fetch.sh +++ b/t/t5550-http-fetch.sh @@ -42,5 +42,16 @@ test_expect_success 'fetch changes via http' ' test_cmp file clone/file ' +test_expect_success 'http remote detects correct HEAD' ' + git push public master:other && + (cd clone && + git remote set-head origin -d && + git remote set-head origin -a && + git symbolic-ref refs/remotes/origin/HEAD > output && + echo refs/remotes/origin/master > expect && + test_cmp expect output + ) +' + stop_httpd test_done From 7ecbbf877c9a0716ccccd25609b01023eecd27c0 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Wed, 25 Feb 2009 03:32:27 -0500 Subject: [PATCH 096/654] builtin-remote: new show output style The existing output of "git remote show <remote>" is too verbose for the information it provides. This patch teaches it to provide more information in less space. The output for push refspecs is addressed in the next patch. Before the patch: $ git remote show origin * remote origin URL: git://git.kernel.org/pub/scm/git/git.git HEAD branch: master Remote branch merged with 'git pull' while on branch master master Remote branch merged with 'git pull' while on branch next next Remote branches merged with 'git pull' while on branch octopus foo bar baz frotz New remote branch (next fetch will store in remotes/origin) html Stale tracking branch (use 'git remote prune') bogus Tracked remote branches maint man master next pu todo After this patch: $ git remote show origin * remote origin URL: git://git.kernel.org/pub/scm/git/git.git HEAD branch: master Remote branches: bogus stale (use 'git remote prune' to remove) html new (next fetch will store in remotes/origin) maint tracked man tracked master tracked next tracked pu tracked todo tracked Local branches configured for 'git pull': master rebases onto remote master next rebases onto remote next octopus merges with remote foo and with remote bar and with remote baz and with remote frotz $ git remote show origin -n * remote origin URL: git://git.kernel.org/pub/scm/git/git.git HEAD branch: (not queried) Remote branches: (status not queried) bogus maint man master next pu todo Local branches configured for 'git pull': master rebases onto remote master next rebases onto remote next octopus merges with remote foo and with remote bar and with remote baz and with remote frotz Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-remote.c | 178 +++++++++++++++++++++++++++++++++++----------- t/t5505-remote.sh | 38 +++++----- 2 files changed, 157 insertions(+), 59 deletions(-) diff --git a/builtin-remote.c b/builtin-remote.c index 640e4dafbf..379826eed5 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -149,6 +149,7 @@ static int add(int argc, const char **argv) struct branch_info { char *remote_name; struct string_list merge; + int rebase; }; static struct string_list branch_list; @@ -165,10 +166,11 @@ static const char *abbrev_ref(const char *name, const char *prefix) static int config_read_branches(const char *key, const char *value, void *cb) { if (!prefixcmp(key, "branch.")) { + const char *orig_key = key; char *name; struct string_list_item *item; struct branch_info *info; - enum { REMOTE, MERGE } type; + enum { REMOTE, MERGE, REBASE } type; key += 7; if (!postfixcmp(key, ".remote")) { @@ -177,6 +179,9 @@ static int config_read_branches(const char *key, const char *value, void *cb) } else if (!postfixcmp(key, ".merge")) { name = xstrndup(key, strlen(key) - 6); type = MERGE; + } else if (!postfixcmp(key, ".rebase")) { + name = xstrndup(key, strlen(key) - 7); + type = REBASE; } else return 0; @@ -187,9 +192,9 @@ static int config_read_branches(const char *key, const char *value, void *cb) info = item->util; if (type == REMOTE) { if (info->remote_name) - warning("more than one branch.%s", key); + warning("more than one %s", orig_key); info->remote_name = xstrdup(value); - } else { + } else if (type == MERGE) { char *space = strchr(value, ' '); value = abbrev_branch(value); while (space) { @@ -200,7 +205,8 @@ static int config_read_branches(const char *key, const char *value, void *cb) space = strchr(value, ' '); } string_list_append(xstrdup(value), &info->merge); - } + } else + info->rebase = git_config_bool(orig_key, value); } return 0; } @@ -215,6 +221,7 @@ static void read_branches(void) struct ref_states { struct remote *remote; struct string_list new, stale, tracked, heads; + int queried; }; static int handle_one_branch(const char *refname, @@ -637,20 +644,6 @@ static int rm(int argc, const char **argv) return result; } -static void show_list(const char *title, struct string_list *list, - const char *extra_arg) -{ - int i; - - if (!list->nr) - return; - - printf(title, list->nr > 1 ? "es" : "", extra_arg); - printf("\n"); - for (i = 0; i < list->nr; i++) - printf(" %s\n", list->items[i].string); -} - static void free_remote_ref_states(struct ref_states *states) { string_list_clear(&states->new, 0); @@ -695,6 +688,7 @@ static int get_remote_ref_states(const char *name, remote_refs = transport_get_remote_refs(transport); transport_disconnect(transport); + states->queried = 1; if (query & GET_REF_STATES) get_ref_states(remote_refs, states); if (query & GET_HEAD_NAMES) @@ -707,6 +701,104 @@ static int get_remote_ref_states(const char *name, return 0; } +struct show_info { + struct string_list *list; + struct ref_states *states; + int width; + int any_rebase; +}; + +int add_remote_to_show_info(struct string_list_item *item, void *cb_data) +{ + struct show_info *info = cb_data; + int n = strlen(item->string); + if (n > info->width) + info->width = n; + string_list_insert(item->string, info->list); + return 0; +} + +int show_remote_info_item(struct string_list_item *item, void *cb_data) +{ + struct show_info *info = cb_data; + struct ref_states *states = info->states; + const char *name = item->string; + + if (states->queried) { + const char *fmt = "%s"; + const char *arg = ""; + if (string_list_has_string(&states->new, name)) { + fmt = " new (next fetch will store in remotes/%s)"; + arg = states->remote->name; + } else if (string_list_has_string(&states->tracked, name)) + arg = " tracked"; + else if (string_list_has_string(&states->stale, name)) + arg = " stale (use 'git remote prune' to remove)"; + else + arg = " ???"; + printf(" %-*s", info->width, name); + printf(fmt, arg); + printf("\n"); + } else + printf(" %s\n", name); + + return 0; +} + +int add_local_to_show_info(struct string_list_item *branch_item, void *cb_data) +{ + struct show_info *show_info = cb_data; + struct ref_states *states = show_info->states; + struct branch_info *branch_info = branch_item->util; + struct string_list_item *item; + int n; + + if (!branch_info->merge.nr || !branch_info->remote_name || + strcmp(states->remote->name, branch_info->remote_name)) + return 0; + if ((n = strlen(branch_item->string)) > show_info->width) + show_info->width = n; + if (branch_info->rebase) + show_info->any_rebase = 1; + + item = string_list_insert(branch_item->string, show_info->list); + item->util = branch_info; + + return 0; +} + +int show_local_info_item(struct string_list_item *item, void *cb_data) +{ + struct show_info *show_info = cb_data; + struct branch_info *branch_info = item->util; + struct string_list *merge = &branch_info->merge; + const char *also; + int i; + + if (branch_info->rebase && branch_info->merge.nr > 1) { + error("invalid branch.%s.merge; cannot rebase onto > 1 branch", + item->string); + return 0; + } + + printf(" %-*s ", show_info->width, item->string); + if (branch_info->rebase) { + printf("rebases onto remote %s\n", merge->items[0].string); + return 0; + } else if (show_info->any_rebase) { + printf(" merges with remote %s\n", merge->items[0].string); + also = " and with remote"; + } else { + printf("merges with remote %s\n", merge->items[0].string); + also = " and with remote"; + } + for (i = 1; i < merge->nr; i++) + printf(" %-*s %s %s\n", show_info->width, "", also, + merge->items[i].string); + + return 0; +} + static int show(int argc, const char **argv) { int no_query = 0, result = 0, query_flag = 0; @@ -716,6 +808,8 @@ static int show(int argc, const char **argv) OPT_END() }; struct ref_states states; + struct string_list info_list = { NULL, 0, 0, 0 }; + struct show_info info; argc = parse_options(argc, argv, options, builtin_remote_usage, 0); @@ -726,6 +820,9 @@ static int show(int argc, const char **argv) query_flag = (GET_REF_STATES | GET_HEAD_NAMES); memset(&states, 0, sizeof(states)); + memset(&info, 0, sizeof(info)); + info.states = &states; + info.list = &info_list; for (; argc; argc--, argv++) { int i; @@ -747,32 +844,29 @@ static int show(int argc, const char **argv) printf(" %s\n", states.heads.items[i].string); } - for (i = 0; i < branch_list.nr; i++) { - struct string_list_item *branch = branch_list.items + i; - struct branch_info *info = branch->util; - int j; + /* remote branch info */ + info.width = 0; + for_each_string_list(add_remote_to_show_info, &states.new, &info); + for_each_string_list(add_remote_to_show_info, &states.tracked, &info); + for_each_string_list(add_remote_to_show_info, &states.stale, &info); + if (info.list->nr) + printf(" Remote branch%s:%s\n", + info.list->nr > 1 ? "es" : "", + no_query ? " (status not queried)" : ""); + for_each_string_list(show_remote_info_item, info.list, &info); + string_list_clear(info.list, 0); - if (!info->merge.nr || strcmp(*argv, info->remote_name)) - continue; - printf(" Remote branch%s merged with 'git pull' " - "while on branch %s\n ", - info->merge.nr > 1 ? "es" : "", - branch->string); - for (j = 0; j < info->merge.nr; j++) - printf(" %s", info->merge.items[j].string); - printf("\n"); - } - - if (!no_query) { - show_list(" New remote branch%s (next fetch " - "will store in remotes/%s)", - &states.new, states.remote->name); - show_list(" Stale tracking branch%s (use 'git remote " - "prune')", &states.stale, ""); - } - - show_list(" Tracked remote branch%s", &states.tracked, ""); + /* git pull info */ + info.width = 0; + info.any_rebase = 0; + for_each_string_list(add_local_to_show_info, &branch_list, &info); + if (info.list->nr) + printf(" Local branch%s configured for 'git pull':\n", + info.list->nr > 1 ? "es" : ""); + for_each_string_list(show_local_info_item, info.list, &info); + string_list_clear(info.list, 0); + /* git push info */ if (states.remote->push_refspec_nr) { printf(" Local branch%s pushed with 'git push'\n", states.remote->push_refspec_nr > 1 ? diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index de1d0fcf43..69e241a0a5 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -28,7 +28,7 @@ tokens_match () { } check_remote_track () { - actual=$(git remote show "$1" | sed -e '1,/Tracked/d') && + actual=$(git remote show "$1" | sed -ne 's|^ \(.*\) tracked$|\1|p') shift && tokens_match "$*" "$actual" } @@ -137,13 +137,15 @@ cat > test/expect << EOF * remote origin URL: $(pwd)/one HEAD branch: master - Remote branch merged with 'git pull' while on branch master - master - New remote branch (next fetch will store in remotes/origin) - master - Tracked remote branches - master - side + Remote branches: + master new (next fetch will store in remotes/origin) + side tracked + Local branches configured for 'git pull': + master merges with remote master + octopus merges with remote topic-a + and with remote topic-b + and with remote topic-c + rebase rebases onto remote master Local branches pushed with 'git push' master:upstream +refs/tags/lastbackup @@ -156,20 +158,22 @@ EOF test_expect_success 'show' ' (cd test && - git config --add remote.origin.fetch \ - refs/heads/master:refs/heads/upstream && + git config --add remote.origin.fetch refs/heads/master:refs/heads/upstream && git fetch && + git branch --track octopus origin/master && + git branch --track rebase origin/master && git branch -d -r origin/master && git config --add remote.two.url ../two && + git config branch.rebase.rebase true && + git config branch.octopus.merge "topic-a topic-b topic-c" && (cd ../one && echo 1 > file && test_tick && git commit -m update file) && - git config remote.origin.push \ - refs/heads/master:refs/heads/upstream && - git config --add remote.origin.push \ - +refs/tags/lastbackup && + git config remote.origin.push refs/heads/master:refs/heads/upstream && + git config --add remote.origin.push +refs/tags/lastbackup && git remote show origin two > output && + git branch -d rebase octopus && test_cmp expect output) ' @@ -177,11 +181,11 @@ cat > test/expect << EOF * remote origin URL: $(pwd)/one HEAD branch: (not queried) - Remote branch merged with 'git pull' while on branch master - master - Tracked remote branches + Remote branches: (status not queried) master side + Local branch configured for 'git pull': + master merges with remote master Local branches pushed with 'git push' master:upstream +refs/tags/lastbackup From e5dcbfd9ab7028c464909f26f523b85c1de912a2 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Wed, 25 Feb 2009 03:32:28 -0500 Subject: [PATCH 097/654] builtin-remote: new show output style for push refspecs The existing output of "git remote show <remote>" with respect to push ref specs is basically just to show the raw refspec. This patch teaches the command to interpret the refspecs and show how each branch will be pushed to the destination. The output gives the user an idea of what "git push" should do if it is run w/o any arguments. Example new output: 1a. Typical output with no push refspec (i.e. matching branches only) $ git remote show origin * remote origin [...] Local refs configured for 'git push': master pushes to master (up to date) next pushes to next (local out of date) 1b. Same as above, w/o querying the remote: $ git remote show origin -n * remote origin [...] Local ref configured for 'git push' (status not queried): (matching) pushes to (matching) 2a. With a forcing refspec (+), and a new topic (something like push = refs/heads/*:refs/heads/*): $ git remote show origin * remote origin [...] Local refs configured for 'git push': master pushes to master (fast forwardable) new-topic pushes to new-topic (create) next pushes to next (local out of date) pu forces to pu (up to date) 2b. Same as above, w/o querying the remote $ git remote show origin -n * remote origin [...] Local refs configured for 'git push' (status not queried): master pushes to master new-topic pushes to new-topic next pushes to next pu forces to pu 3. With a remote configured as a mirror: * remote backup [...] Local refs will be mirrored by 'git push' Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-remote.c | 201 ++++++++++++++++++++++++++++++++++++++++++---- t/t5505-remote.sh | 30 +++++-- 2 files changed, 207 insertions(+), 24 deletions(-) diff --git a/builtin-remote.c b/builtin-remote.c index 379826eed5..7e82a52b7d 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -21,6 +21,7 @@ static const char * const builtin_remote_usage[] = { #define GET_REF_STATES (1<<0) #define GET_HEAD_NAMES (1<<1) +#define GET_PUSH_REF_STATES (1<<2) static int verbose; @@ -220,7 +221,7 @@ static void read_branches(void) struct ref_states { struct remote *remote; - struct string_list new, stale, tracked, heads; + struct string_list new, stale, tracked, heads, push; int queried; }; @@ -275,6 +276,112 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat return 0; } +struct push_info { + char *dest; + int forced; + enum { + PUSH_STATUS_CREATE = 0, + PUSH_STATUS_DELETE, + PUSH_STATUS_UPTODATE, + PUSH_STATUS_FASTFORWARD, + PUSH_STATUS_OUTOFDATE, + PUSH_STATUS_NOTQUERIED, + } status; +}; + +static int get_push_ref_states(const struct ref *remote_refs, + struct ref_states *states) +{ + struct remote *remote = states->remote; + struct ref *ref, *local_refs, *push_map, **push_tail; + if (remote->mirror) + return 0; + + local_refs = get_local_heads(); + ref = push_map = copy_ref_list(remote_refs); + while (ref->next) + ref = ref->next; + push_tail = &ref->next; + + match_refs(local_refs, push_map, &push_tail, remote->push_refspec_nr, + remote->push_refspec, MATCH_REFS_NONE); + + states->push.strdup_strings = 1; + for (ref = push_map; ref; ref = ref->next) { + struct string_list_item *item; + struct push_info *info; + + if (!ref->peer_ref) + continue; + hashcpy(ref->new_sha1, ref->peer_ref->new_sha1); + + item = string_list_append(abbrev_branch(ref->peer_ref->name), + &states->push); + item->util = xcalloc(sizeof(struct push_info), 1); + info = item->util; + info->forced = ref->force; + info->dest = xstrdup(abbrev_branch(ref->name)); + + if (is_null_sha1(ref->new_sha1)) { + info->status = PUSH_STATUS_DELETE; + } else if (!hashcmp(ref->old_sha1, ref->new_sha1)) + info->status = PUSH_STATUS_UPTODATE; + else if (is_null_sha1(ref->old_sha1)) + info->status = PUSH_STATUS_CREATE; + else if (has_sha1_file(ref->old_sha1) && + ref_newer(ref->new_sha1, ref->old_sha1)) + info->status = PUSH_STATUS_FASTFORWARD; + else + info->status = PUSH_STATUS_OUTOFDATE; + // ref->peer_ref = NULL; /* local ref which is freed below */ + } + free_refs(local_refs); + free_refs(push_map); + return 0; +} + +static int get_push_ref_states_noquery(struct ref_states *states) +{ + int i; + struct remote *remote = states->remote; + struct string_list_item *item; + struct push_info *info; + + if (remote->mirror) + return 0; + + states->push.strdup_strings = 1; + if (!remote->push_refspec_nr) { + item = string_list_append("(matching)", &states->push); + info = item->util = xcalloc(sizeof(struct push_info), 1); + info->status = PUSH_STATUS_NOTQUERIED; + info->dest = xstrdup(item->string); + } + for (i = 0; i < remote->push_refspec_nr; i++) { + struct refspec *spec = remote->push + i; + char buf[PATH_MAX]; + if (spec->matching) + item = string_list_append("(matching)", &states->push); + else if (spec->pattern) { + snprintf(buf, (sizeof(buf)), "%s*", spec->src); + item = string_list_append(buf, &states->push); + snprintf(buf, (sizeof(buf)), "%s*", spec->dst); + } else if (strlen(spec->src)) + item = string_list_append(spec->src, &states->push); + else + item = string_list_append("(delete)", &states->push); + + info = item->util = xcalloc(sizeof(struct push_info), 1); + info->forced = spec->force; + info->status = PUSH_STATUS_NOTQUERIED; + if (spec->pattern) + info->dest = xstrdup(buf); + else + info->dest = xstrdup(spec->dst ? spec->dst : item->string); + } + return 0; +} + static int get_head_names(const struct ref *remote_refs, struct ref_states *states) { struct ref *ref, *matches; @@ -644,12 +751,20 @@ static int rm(int argc, const char **argv) return result; } +void clear_push_info(void *util, const char *string) +{ + struct push_info *info = util; + free(info->dest); + free(info); +} + static void free_remote_ref_states(struct ref_states *states) { string_list_clear(&states->new, 0); string_list_clear(&states->stale, 0); string_list_clear(&states->tracked, 0); string_list_clear(&states->heads, 0); + string_list_clear_func(&states->push, clear_push_info); } static int append_ref_to_tracked_list(const char *refname, @@ -693,9 +808,12 @@ static int get_remote_ref_states(const char *name, get_ref_states(remote_refs, states); if (query & GET_HEAD_NAMES) get_head_names(remote_refs, states); + if (query & GET_PUSH_REF_STATES) + get_push_ref_states(remote_refs, states); } else { for_each_ref(append_ref_to_tracked_list, states); sort_string_list(&states->tracked); + get_push_ref_states_noquery(states); } return 0; @@ -704,7 +822,7 @@ static int get_remote_ref_states(const char *name, struct show_info { struct string_list *list; struct ref_states *states; - int width; + int width, width2; int any_rebase; }; @@ -799,6 +917,58 @@ int show_local_info_item(struct string_list_item *item, void *cb_data) return 0; } +int add_push_to_show_info(struct string_list_item *push_item, void *cb_data) +{ + struct show_info *show_info = cb_data; + struct push_info *push_info = push_item->util; + struct string_list_item *item; + int n; + if ((n = strlen(push_item->string)) > show_info->width) + show_info->width = n; + if ((n = strlen(push_info->dest)) > show_info->width2) + show_info->width2 = n; + item = string_list_append(push_item->string, show_info->list); + item->util = push_item->util; + return 0; +} + +int show_push_info_item(struct string_list_item *item, void *cb_data) +{ + struct show_info *show_info = cb_data; + struct push_info *push_info = item->util; + char *src = item->string, *status = NULL; + + switch (push_info->status) { + case PUSH_STATUS_CREATE: + status = "create"; + break; + case PUSH_STATUS_DELETE: + status = "delete"; + src = "(none)"; + break; + case PUSH_STATUS_UPTODATE: + status = "up to date"; + break; + case PUSH_STATUS_FASTFORWARD: + status = "fast forwardable"; + break; + case PUSH_STATUS_OUTOFDATE: + status = "local out of date"; + break; + case PUSH_STATUS_NOTQUERIED: + break; + } + if (status) + printf(" %-*s %s to %-*s (%s)\n", show_info->width, src, + push_info->forced ? "forces" : "pushes", + show_info->width2, push_info->dest, status); + else + printf(" %-*s %s to %s\n", show_info->width, src, + push_info->forced ? "forces" : "pushes", + push_info->dest); + return 0; +} + static int show(int argc, const char **argv) { int no_query = 0, result = 0, query_flag = 0; @@ -817,7 +987,7 @@ static int show(int argc, const char **argv) return show_all(); if (!no_query) - query_flag = (GET_REF_STATES | GET_HEAD_NAMES); + query_flag = (GET_REF_STATES | GET_HEAD_NAMES | GET_PUSH_REF_STATES); memset(&states, 0, sizeof(states)); memset(&info, 0, sizeof(info)); @@ -867,19 +1037,18 @@ static int show(int argc, const char **argv) string_list_clear(info.list, 0); /* git push info */ - if (states.remote->push_refspec_nr) { - printf(" Local branch%s pushed with 'git push'\n", - states.remote->push_refspec_nr > 1 ? - "es" : ""); - for (i = 0; i < states.remote->push_refspec_nr; i++) { - struct refspec *spec = states.remote->push + i; - printf(" %s%s%s%s\n", - spec->force ? "+" : "", - abbrev_branch(spec->src), - spec->dst ? ":" : "", - spec->dst ? abbrev_branch(spec->dst) : ""); - } - } + if (states.remote->mirror) + printf(" Local refs will be mirrored by 'git push'\n"); + + info.width = info.width2 = 0; + for_each_string_list(add_push_to_show_info, &states.push, &info); + sort_string_list(info.list); + if (info.list->nr) + printf(" Local ref%s configured for 'git push'%s:\n", + info.list->nr > 1 ? "s" : "", + no_query ? " (status not queried)" : ""); + for_each_string_list(show_push_info_item, info.list, &info); + string_list_clear(info.list, 0); free_remote_ref_states(&states); } diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 69e241a0a5..5ec668d6d8 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -141,25 +141,34 @@ cat > test/expect << EOF master new (next fetch will store in remotes/origin) side tracked Local branches configured for 'git pull': + ahead merges with remote master master merges with remote master octopus merges with remote topic-a and with remote topic-b and with remote topic-c rebase rebases onto remote master - Local branches pushed with 'git push' - master:upstream - +refs/tags/lastbackup + Local refs configured for 'git push': + master pushes to master (local out of date) + master pushes to upstream (create) * remote two URL: ../two HEAD branch (remote HEAD is ambiguous, may be one of the following): another master + Local refs configured for 'git push': + ahead forces to master (fast forwardable) + master pushes to another (up to date) EOF test_expect_success 'show' ' (cd test && git config --add remote.origin.fetch refs/heads/master:refs/heads/upstream && git fetch && + git checkout -b ahead origin/master && + echo 1 >> file && + test_tick && + git commit -m update file && + git checkout master && git branch --track octopus origin/master && git branch --track rebase origin/master && git branch -d -r origin/master && @@ -170,8 +179,11 @@ test_expect_success 'show' ' echo 1 > file && test_tick && git commit -m update file) && - git config remote.origin.push refs/heads/master:refs/heads/upstream && + git config --add remote.origin.push : && + git config --add remote.origin.push refs/heads/master:refs/heads/upstream && git config --add remote.origin.push +refs/tags/lastbackup && + git config --add remote.two.push +refs/heads/ahead:refs/heads/master && + git config --add remote.two.push refs/heads/master:refs/heads/another && git remote show origin two > output && git branch -d rebase octopus && test_cmp expect output) @@ -184,11 +196,13 @@ cat > test/expect << EOF Remote branches: (status not queried) master side - Local branch configured for 'git pull': + Local branches configured for 'git pull': + ahead merges with remote master master merges with remote master - Local branches pushed with 'git push' - master:upstream - +refs/tags/lastbackup + Local refs configured for 'git push' (status not queried): + (matching) pushes to (matching) + refs/heads/master pushes to refs/heads/upstream + refs/tags/lastbackup forces to refs/tags/lastbackup EOF test_expect_success 'show -n' ' From a9c3821ca2fec065260b4314d61337a7529aba5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= <torarnv@gmail.com> Date: Sun, 1 Mar 2009 23:11:38 +0100 Subject: [PATCH 098/654] git-rebase: Add --stat and --no-stat for producing diffstat on rebase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The behavior of --verbose is unchanged, but uses a different state variable internally, so that the meaning of verbose output may be expanded without affecting the diffstat. This is also reflected in the documentation. The configuration option rebase.stat works the same was as merg.stat, but the default is currently false. Signed-off-by: Tor Arne Vestbø <torarnv@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 4 ++++ Documentation/git-rebase.txt | 17 ++++++++++++++++- git-rebase.sh | 25 ++++++++++++++++++------- t/t3406-rebase-message.sh | 23 ++++++++++++++++++++++- 4 files changed, 60 insertions(+), 9 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index f5152c5038..6be2e9935b 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1160,6 +1160,10 @@ pull.octopus:: pull.twohead:: The default merge strategy to use when pulling a single branch. +rebase.stat:: + Whether to show a diffstat of what changed upstream since the last + rebase. False by default. + receive.fsckObjects:: If it is set to true, git-receive-pack will check all received objects. It will abort in the case of a malformed object or a diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index da3c38cd60..57bd333f0b 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -192,6 +192,13 @@ Alternatively, you can undo the 'git-rebase' with git rebase --abort +CONFIGURATION +------------- + +rebase.stat:: + Whether to show a diffstat of what changed upstream since the last + rebase. False by default. + OPTIONS ------- <newbase>:: @@ -232,7 +239,15 @@ OPTIONS -v:: --verbose:: - Display a diffstat of what changed upstream since the last rebase. + Be verbose. Implies --stat. + +--stat:: + Show a diffstat of what changed upstream since the last rebase. The + diffstat is also controlled by the configuration option rebase.stat. + +-n:: +--no-stat:: + Do not show a diffstat as part of the rebase process. --no-verify:: This option bypasses the pre-rebase hook. See also linkgit:githooks[5]. diff --git a/git-rebase.sh b/git-rebase.sh index 368c0ef434..26d75662f9 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -46,6 +46,7 @@ do_merge= dotest="$GIT_DIR"/rebase-merge prec=4 verbose= +diffstat=$(git config --bool rebase.stat) git_am_opt= rebase_root= @@ -289,8 +290,15 @@ do esac do_merge=t ;; + -n|--no-stat) + diffstat= + ;; + --stat) + diffstat=t + ;; -v|--verbose) verbose=t + diffstat=t ;; --whitespace=*) git_am_opt="$git_am_opt $1" @@ -426,18 +434,21 @@ then exit 0 fi -if test -n "$verbose" -then - echo "Changes from $mb to $onto:" - # We want color (if set), but no pager - GIT_PAGER='' git diff --stat --summary "$mb" "$onto" -fi - # Detach HEAD and reset the tree echo "First, rewinding head to replay your work on top of it..." git checkout -q "$onto^0" || die "could not detach HEAD" git update-ref ORIG_HEAD $branch +if test -n "$diffstat" +then + if test -n "$verbose" + then + echo "Changes from $mb to $onto:" + fi + # We want color (if set), but no pager + GIT_PAGER='' git diff --stat --summary "$mb" "$onto" +fi + # If the $onto is a proper descendant of the tip of the branch, then # we just fast forwarded. if test "$mb" = "$branch" diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh index 5391080943..85fc7c4af8 100755 --- a/t/t3406-rebase-message.sh +++ b/t/t3406-rebase-message.sh @@ -22,7 +22,8 @@ test_expect_success setup ' git checkout topic && quick_one A && quick_one B && - quick_one Z + quick_one Z && + git tag start ' @@ -41,4 +42,24 @@ test_expect_success 'rebase -m' ' ' +test_expect_success 'rebase --stat' ' + git reset --hard start + git rebase --stat master >diffstat.txt && + grep "^ fileX | *1 +$" diffstat.txt +' + +test_expect_success 'rebase w/config rebase.stat' ' + git reset --hard start + git config rebase.stat true && + git rebase master >diffstat.txt && + grep "^ fileX | *1 +$" diffstat.txt +' + +test_expect_success 'rebase -n overrides config rebase.stat config' ' + git reset --hard start + git config rebase.stat true && + git rebase -n master >diffstat.txt && + ! grep "^ fileX | *1 +$" diffstat.txt +' + test_done From a334e1254c0c2d55f20b271872fbac9a6a67218b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= <torarnv@gmail.com> Date: Sun, 1 Mar 2009 22:28:28 +0100 Subject: [PATCH 099/654] git-pull: Allow --stat and --no-stat to be used with --rebase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Forwards the --stat, --no-stat, and --summary options on to git-rebase. Signed-off-by: Tor Arne Vestbø <torarnv@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-pull.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/git-pull.sh b/git-pull.sh index 25adddfddf..8a26763206 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -16,7 +16,7 @@ cd_to_toplevel test -z "$(git ls-files -u)" || die "You are in the middle of a conflicted merge." -strategy_args= no_stat= no_commit= squash= no_ff= log_arg= verbosity= +strategy_args= diffstat= no_commit= squash= no_ff= log_arg= verbosity= curr_branch=$(git symbolic-ref -q HEAD) curr_branch_short=$(echo "$curr_branch" | sed "s|refs/heads/||") rebase=$(git config --bool branch.$curr_branch_short.rebase) @@ -28,9 +28,9 @@ do -v|--verbose) verbosity="$verbosity -v" ;; -n|--no-stat|--no-summary) - no_stat=-n ;; + diffstat=--no-stat ;; --stat|--summary) - no_stat=$1 ;; + diffstat=--stat ;; --log|--no-log) log_arg=$1 ;; --no-c|--no-co|--no-com|--no-comm|--no-commi|--no-commit) @@ -188,7 +188,7 @@ fi merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit test true = "$rebase" && - exec git-rebase $strategy_args --onto $merge_head \ + exec git-rebase $diffstat $strategy_args --onto $merge_head \ ${oldremoteref:-$merge_head} -exec git-merge $no_stat $no_commit $squash $no_ff $log_arg $strategy_args \ +exec git-merge $diffstat $no_commit $squash $no_ff $log_arg $strategy_args \ "$merge_name" HEAD $merge_head $verbosity From c1f2aa45b7bdb82c4378443ae23ad9625e782fe2 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Mon, 2 Mar 2009 23:52:18 -0500 Subject: [PATCH 100/654] send-email: add --confirm option and configuration setting send-email violates the principle of least surprise by automatically cc'ing additional recipients without confirming this with the user. This patch teaches send-email a --confirm option. It takes the following values: --confirm=always always confirm before sending --confirm=never never confirm before sending --confirm=cc confirm before sending when send-email has automatically added addresses from the patch to the Cc list --confirm=compose confirm before sending the first message when using --compose. (Needed to maintain backwards compatibility with existing behavior.) --confirm=auto 'cc' + 'compose' If sendemail.confirm is unconfigured, the option defaults to 'compose' if any suppress-Cc related options have been used, otherwise it defaults to 'auto'. Unfortunately, it is impossible to introduce this patch such that it helps new users without potentially annoying some existing users. We attempt to mitigate the latter by: * Allowing the user to set 'git config sendemail.confirm never' * Allowing the user to say 'all' after the first prompt to not be prompted on remaining emails during the same invocation. * Telling the user about the 'sendemail.confirm' setting if it is unconfigured whenever we prompt due to Cc before sending. * Only prompting if no --suppress related options have been passed, as using such an option is likely to indicate an experienced send-email user. There is a slight fib in message informing the user of the sendemail.confirm setting and this is intentional. Setting 'auto' differs from leaving sendemail.confirm unset in two ways: 1) 'auto' obviously squelches the informational message; 2) 'auto' prompts when the Cc list has been expanded even in the presence of a --suppress related option, where leaving sendemail.confirm unset does not. This is intentional to keep the message simple, and to avoid adding another sendemail.confirm value ('auto-except-suppress'?). Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-send-email.txt | 21 ++++++ git-send-email.perl | 84 +++++++++++++++++------- t/t9001-send-email.sh | 108 ++++++++++++++++++++++++++----- 3 files changed, 174 insertions(+), 39 deletions(-) diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index 164d149ea3..0335727012 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -199,6 +199,22 @@ specified, as well as 'body' if --no-signed-off-cc is specified. Administering ~~~~~~~~~~~~~ +--confirm:: + Confirm just before sending: ++ +-- +- 'always' will always confirm before sending +- 'never' will never confirm before sending +- 'cc' will confirm before sending when send-email has automatically + added addresses from the patch to the Cc list +- 'compose' will confirm before sending the first message when using --compose. +- 'auto' is equivalent to 'cc' + 'compose' +-- ++ +Default is the value of 'sendemail.confirm' configuration value; if that +is unspecified, default to 'auto' unless any of the suppress options +have been specified, in which case default to 'compose'. + --dry-run:: Do everything except actually send the emails. @@ -242,6 +258,11 @@ sendemail.multiedit:: summary when '--compose' is used). If false, files will be edited one after the other, spawning a new editor each time. +sendemail.confirm:: + Sets the default for whether to confirm before sending. Must be + one of 'always', 'never', 'cc', 'compose', or 'auto'. See '--confirm' + in the previous section for the meaning of these values. + Author ------ diff --git a/git-send-email.perl b/git-send-email.perl index adf7ecb5c3..57127aa823 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -75,6 +75,8 @@ git send-email [options] <file | directory | rev-list options > --[no-]thread * Use In-Reply-To: field. Default on. Administering: + --confirm <str> * Confirm recipients before sending; + auto, cc, compose, always, or never. --quiet * Output one line of info per email. --dry-run * Don't actually send the emails. --[no-]validate * Perform patch sanity checks. Default on. @@ -181,7 +183,7 @@ sub do_edit { my ($thread, $chain_reply_to, $suppress_from, $signed_off_by_cc, $cc_cmd); my ($smtp_server, $smtp_server_port, $smtp_authuser, $smtp_encryption); my ($identity, $aliasfiletype, @alias_files, @smtp_host_parts); -my ($validate); +my ($validate, $confirm); my (@suppress_cc); my %config_bool_settings = ( @@ -207,6 +209,7 @@ my %config_settings = ( "suppresscc" => \@suppress_cc, "envelopesender" => \$envelope_sender, "multiedit" => \$multiedit, + "confirm" => \$confirm, ); # Handle Uncouth Termination @@ -258,6 +261,7 @@ my $rc = GetOptions("sender|from=s" => \$sender, "suppress-from!" => \$suppress_from, "suppress-cc=s" => \@suppress_cc, "signed-off-cc|signed-off-by-cc!" => \$signed_off_by_cc, + "confirm=s" => \$confirm, "dry-run" => \$dry_run, "envelope-sender=s" => \$envelope_sender, "thread!" => \$thread, @@ -346,6 +350,14 @@ if ($suppress_cc{'body'}) { delete $suppress_cc{'body'}; } +# Set confirm's default value +my $confirm_unconfigured = !defined $confirm; +if ($confirm_unconfigured) { + $confirm = scalar %suppress_cc ? 'compose' : 'auto'; +}; +die "Unknown --confirm setting: '$confirm'\n" + unless $confirm =~ /^(?:auto|cc|compose|always|never)/; + # Debugging, print out the suppressions. if (0) { print "suppressions:\n"; @@ -663,25 +675,13 @@ if (!defined $smtp_server) { $smtp_server ||= 'localhost'; # could be 127.0.0.1, too... *shrug* } -if ($compose) { - while (1) { - $_ = $term->readline("Send this email? (y|n) "); - last if defined $_; - print "\n"; - } - - if (uc substr($_,0,1) ne 'Y') { - cleanup_compose_files(); - exit(0); - } - - if ($compose > 0) { - @files = ($compose_filename . ".final", @files); - } +if ($compose && $compose > 0) { + @files = ($compose_filename . ".final", @files); } # Variables we set as part of the loop over files -our ($message_id, %mail, $subject, $reply_to, $references, $message); +our ($message_id, %mail, $subject, $reply_to, $references, $message, + $needs_confirm, $message_num); sub extract_valid_address { my $address = shift; @@ -837,6 +837,37 @@ X-Mailer: git-send-email $gitversion unshift (@sendmail_parameters, '-f', $raw_from) if(defined $envelope_sender); + if ($needs_confirm && !$dry_run) { + print "\n$header\n"; + if ($needs_confirm eq "inform") { + $confirm_unconfigured = 0; # squelch this message for the rest of this run + print " The Cc list above has been expanded by additional\n"; + print " addresses found in the patch commit message. By default\n"; + print " send-email prompts before sending whenever this occurs.\n"; + print " This behavior is controlled by the sendemail.confirm\n"; + print " configuration setting.\n"; + print "\n"; + print " For additional information, run 'git send-email --help'.\n"; + print " To retain the current behavior, but squelch this message,\n"; + print " run 'git config --global sendemail.confirm auto'.\n\n"; + } + while (1) { + chomp ($_ = $term->readline( + "Send this email? ([y]es|[n]o|[q]uit|[a]ll): " + )); + last if /^(?:yes|y|no|n|quit|q|all|a)/i; + print "\n"; + } + if (/^n/i) { + return; + } elsif (/^q/i) { + cleanup_compose_files(); + exit(0); + } elsif (/^a/i) { + $confirm = 'never'; + } + } + if ($dry_run) { # We don't want to send the email. } elsif ($smtp_server =~ m#^/#) { @@ -935,6 +966,7 @@ X-Mailer: git-send-email $gitversion $reply_to = $initial_reply_to; $references = $initial_reply_to || ''; $subject = $initial_subject; +$message_num = 0; foreach my $t (@files) { open(F,"<",$t) or die "can't open file $t"; @@ -943,11 +975,12 @@ foreach my $t (@files) { my $author_encoding; my $has_content_type; my $body_encoding; - @cc = @initial_cc; + @cc = (); @xh = (); my $input_format = undef; my @header = (); $message = ""; + $message_num++; # First unfold multiline header fields while(<F>) { last if /^\s*$/; @@ -1080,6 +1113,14 @@ foreach my $t (@files) { } } + $needs_confirm = ( + $confirm eq "always" or + ($confirm =~ /^(?:auto|cc)$/ && @cc) or + ($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1)); + $needs_confirm = "inform" if ($needs_confirm && $confirm_unconfigured && @cc); + + @cc = (@initial_cc, @cc); + send_message(); # set up for the next message @@ -1094,13 +1135,10 @@ foreach my $t (@files) { $message_id = undef; } -if ($compose) { - cleanup_compose_files(); -} +cleanup_compose_files(); sub cleanup_compose_files() { - unlink($compose_filename, $compose_filename . ".final"); - + unlink($compose_filename, $compose_filename . ".final") if $compose; } $smtp->quit if $smtp; diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 4df4f965cb..08d5b91c91 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -35,6 +35,47 @@ test_expect_success 'Extract patches' ' patches=`git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1` ' +# Test no confirm early to ensure remaining tests will not hang +test_no_confirm () { + rm -f no_confirm_okay + echo n | \ + GIT_SEND_EMAIL_NOTTY=1 \ + git send-email \ + --from="Example <from@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $@ \ + $patches > stdout && + test_must_fail grep "Send this email" stdout && + > no_confirm_okay +} + +# Exit immediately to prevent hang if a no-confirm test fails +check_no_confirm () { + test -f no_confirm_okay || { + say 'No confirm test failed; skipping remaining tests to prevent hanging' + test_done + } +} + +test_expect_success 'No confirm with --suppress-cc' ' + test_no_confirm --suppress-cc=sob +' +check_no_confirm + +test_expect_success 'No confirm with --confirm=never' ' + test_no_confirm --confirm=never +' +check_no_confirm + +# leave sendemail.confirm set to never after this so that none of the +# remaining tests prompt unintentionally. +test_expect_success 'No confirm with sendemail.confirm=never' ' + git config sendemail.confirm never && + test_no_confirm --compose --subject=foo +' +check_no_confirm + test_expect_success 'Send patches' ' git send-email --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors ' @@ -175,15 +216,13 @@ test_set_editor "$(pwd)/fake-editor" test_expect_success '--compose works' ' clean_fake_sendmail && - echo y | \ - GIT_SEND_EMAIL_NOTTY=1 \ - git send-email \ - --compose --subject foo \ - --from="Example <nobody@example.com>" \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - $patches \ - 2>errors + git send-email \ + --compose --subject foo \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches \ + 2>errors ' test_expect_success 'first message is compose text' ' @@ -375,15 +414,56 @@ test_expect_success '--suppress-cc=cc' ' test_suppression cc ' +test_confirm () { + echo y | \ + GIT_SEND_EMAIL_NOTTY=1 \ + git send-email \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $@ \ + $patches | grep "Send this email" +} + +test_expect_success '--confirm=always' ' + test_confirm --confirm=always --suppress-cc=all +' + +test_expect_success '--confirm=auto' ' + test_confirm --confirm=auto +' + +test_expect_success '--confirm=cc' ' + test_confirm --confirm=cc +' + +test_expect_success '--confirm=compose' ' + test_confirm --confirm=compose --compose +' + +test_expect_success 'confirm by default (due to cc)' ' + CONFIRM=$(git config --get sendemail.confirm) && + git config --unset sendemail.confirm && + test_confirm && + git config sendemail.confirm $CONFIRM +' + +test_expect_success 'confirm by default (due to --compose)' ' + CONFIRM=$(git config --get sendemail.confirm) && + git config --unset sendemail.confirm && + test_confirm --suppress-cc=all --compose + ret="$?" + git config sendemail.confirm ${CONFIRM:-never} + test $ret = "0" +' + test_expect_success '--compose adds MIME for utf8 body' ' clean_fake_sendmail && (echo "#!$SHELL_PATH" && echo "echo utf8 body: àéìöú >>\"\$1\"" ) >fake-editor-utf8 && chmod +x fake-editor-utf8 && - echo y | \ GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ - GIT_SEND_EMAIL_NOTTY=1 \ git send-email \ --compose --subject foo \ --from="Example <nobody@example.com>" \ @@ -405,9 +485,7 @@ test_expect_success '--compose respects user mime type' ' echo " echo utf8 body: àéìöú) >\"\$1\"" ) >fake-editor-utf8-mime && chmod +x fake-editor-utf8-mime && - echo y | \ GIT_EDITOR="\"$(pwd)/fake-editor-utf8-mime\"" \ - GIT_SEND_EMAIL_NOTTY=1 \ git send-email \ --compose --subject foo \ --from="Example <nobody@example.com>" \ @@ -421,9 +499,7 @@ test_expect_success '--compose respects user mime type' ' test_expect_success '--compose adds MIME for utf8 subject' ' clean_fake_sendmail && - echo y | \ GIT_EDITOR="\"$(pwd)/fake-editor\"" \ - GIT_SEND_EMAIL_NOTTY=1 \ git send-email \ --compose --subject utf8-sübjëct \ --from="Example <nobody@example.com>" \ @@ -445,7 +521,7 @@ test_expect_success 'detects ambiguous reference/file conflict' ' test_expect_success 'feed two files' ' rm -fr outdir && git format-patch -2 -o outdir && - GIT_SEND_EMAIL_NOTTY=1 git send-email \ + git send-email \ --dry-run \ --from="Example <nobody@example.com>" \ --to=nobody@example.com \ From dfa7a6c579d75037b9dd5c3654a36d31c60f203c Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Tue, 3 Mar 2009 00:37:51 -0500 Subject: [PATCH 101/654] clone: run post-checkout hook when checking out The mental model for clone is that the branch is "checked out" (and it even says this in Documentation/git-clone.txt: "...creates and checks out an initial branch"). Therefore it is reasonable for users to expect that any post-checkout hook would be run. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-clone.c | 7 ++++++- t/t5403-post-checkout-hook.sh | 12 ++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/builtin-clone.c b/builtin-clone.c index c338910b1c..a6d89bc625 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -20,6 +20,7 @@ #include "dir.h" #include "pack-refs.h" #include "sigchain.h" +#include "run-command.h" /* * Overall FIXMEs: @@ -377,6 +378,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT; struct transport *transport = NULL; char *src_ref_prefix = "refs/heads/"; + int err = 0; struct refspec refspec; @@ -631,6 +633,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (write_cache(fd, active_cache, active_nr) || commit_locked_index(lock_file)) die("unable to write new index file"); + + err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1), + sha1_to_hex(remote_head->old_sha1), "1", NULL); } strbuf_release(&reflog_msg); @@ -638,5 +643,5 @@ int cmd_clone(int argc, const char **argv, const char *prefix) strbuf_release(&key); strbuf_release(&value); junk_pid = 0; - return 0; + return err; } diff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh index 9b2e1a94c5..4fdb418550 100755 --- a/t/t5403-post-checkout-hook.sh +++ b/t/t5403-post-checkout-hook.sh @@ -71,4 +71,16 @@ test_expect_success 'post-checkout receives the right args when not switching br test $old = $new -a $flag = 0 ' +mkdir -p templates/hooks +cat >templates/hooks/post-checkout <<'EOF' +#!/bin/sh +echo $@ > $GIT_DIR/post-checkout.args +EOF +chmod +x templates/hooks/post-checkout + +test_expect_success 'post-checkout hook is triggered by clone' ' + git clone --template=templates . clone3 && + test -f clone3/.git/post-checkout.args +' + test_done From 0e757e30c726d9d8ae82bd9989be3cff5d230288 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <Johannes.Schindelin@gmx.de> Date: Tue, 3 Mar 2009 10:55:31 +0100 Subject: [PATCH 102/654] rebase -i: avoid 'git reset' when possible When picking commits whose parents have not changed, we do not need to rewrite the commit. We do not need to reset the working directory to the parent's state, either. Requested by Sverre Rabbelier. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-rebase--interactive.sh | 26 ++++++++++++++++++++++++++ t/t3404-rebase-interactive.sh | 11 +++++++++++ 2 files changed, 37 insertions(+) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 3dc659dd58..314cd364b8 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -442,6 +442,30 @@ do_rest () { done } +# skip picking commits whose parents are unchanged +skip_unnecessary_picks () { + fd=3 + while read command sha1 rest + do + # fd=3 means we skip the command + case "$fd,$command,$(git rev-parse --verify --quiet $sha1^)" in + 3,pick,"$ONTO"*|3,p,"$ONTO"*) + # pick a commit whose parent is current $ONTO -> skip + ONTO=$sha1 + ;; + 3,#*|3,,*) + # copy comments + ;; + *) + fd=1 + ;; + esac + echo "$command${sha1:+ }$sha1${rest:+ }$rest" >&$fd + done <"$TODO" >"$TODO.new" 3>>"$DONE" && + mv -f "$TODO".new "$TODO" || + die "Could not skip unnecessary pick commands" +} + # check if no other options are set is_standalone () { test $# -eq 2 -a "$2" = '--' && @@ -746,6 +770,8 @@ EOF has_action "$TODO" || die_abort "Nothing to do" + test -d "$REWRITTEN" || skip_unnecessary_picks + git update-ref ORIG_HEAD $HEAD output git checkout $ONTO && do_rest ;; diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 603b003edf..c32ff6682b 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -459,4 +459,15 @@ test_expect_success 'submodule rebase -i' ' FAKE_LINES="1 squash 2 3" git rebase -i A ' +test_expect_success 'avoid unnecessary reset' ' + git checkout master && + test-chmtime =123456789 file3 && + git update-index --refresh && + HEAD=$(git rev-parse HEAD) && + git rebase -i HEAD~4 && + test $HEAD = $(git rev-parse HEAD) && + MTIME=$(test-chmtime -v +0 file3 | sed 's/[^0-9].*$//') && + test 123456789 = $MTIME +' + test_done From a9f2c13685ae9040d52d53cd719a18040f1dd123 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Tue, 3 Mar 2009 22:29:55 -0800 Subject: [PATCH 103/654] Make git-clone respect branch.autosetuprebase When git-clone creates an initial branch it was not checking the branch.autosetuprebase configuration option (which may exist in ~/.gitconfig). Refactor the code used by "git branch" to create a new branch, and use it instead of the insufficiently duplicated code in builtin-clone. Changes are partly, and the test is mostly, based on the previous work by Pat Notz. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- branch.c | 49 ++++++++++++++++++++++++++++++++---------------- branch.h | 7 +++++++ builtin-clone.c | 18 +++--------------- t/t5601-clone.sh | 15 +++++++++++++++ 4 files changed, 58 insertions(+), 31 deletions(-) diff --git a/branch.c b/branch.c index 1f00e44deb..d20fb0490b 100644 --- a/branch.c +++ b/branch.c @@ -32,21 +32,48 @@ static int find_tracked_branch(struct remote *remote, void *priv) return 0; } -static int should_setup_rebase(const struct tracking *tracking) +static int should_setup_rebase(const char *origin) { switch (autorebase) { case AUTOREBASE_NEVER: return 0; case AUTOREBASE_LOCAL: - return tracking->remote == NULL; + return origin == NULL; case AUTOREBASE_REMOTE: - return tracking->remote != NULL; + return origin != NULL; case AUTOREBASE_ALWAYS: return 1; } return 0; } +void install_branch_config(int flag, const char *local, const char *origin, const char *remote) +{ + struct strbuf key = STRBUF_INIT; + int rebasing = should_setup_rebase(origin); + + strbuf_addf(&key, "branch.%s.remote", local); + git_config_set(key.buf, origin ? origin : "."); + + strbuf_reset(&key); + strbuf_addf(&key, "branch.%s.merge", local); + git_config_set(key.buf, remote); + + if (rebasing) { + strbuf_reset(&key); + strbuf_addf(&key, "branch.%s.rebase", local); + git_config_set(key.buf, "true"); + } + + if (flag & BRANCH_CONFIG_VERBOSE) + printf("Branch %s set up to track %s branch %s %s.\n", + local, + origin ? "remote" : "local", + remote, + rebasing ? "by rebasing" : "by merging"); + strbuf_release(&key); +} + /* * This is called when new_ref is branched off of orig_ref, and tries * to infer the settings for branch.<new_ref>.{remote,merge} from the @@ -55,7 +82,6 @@ static int should_setup_rebase(const struct tracking *tracking) static int setup_tracking(const char *new_ref, const char *orig_ref, enum branch_track track) { - char key[1024]; struct tracking tracking; if (strlen(new_ref) > 1024 - 7 - 7 - 1) @@ -80,19 +106,10 @@ static int setup_tracking(const char *new_ref, const char *orig_ref, return error("Not tracking: ambiguous information for ref %s", orig_ref); - sprintf(key, "branch.%s.remote", new_ref); - git_config_set(key, tracking.remote ? tracking.remote : "."); - sprintf(key, "branch.%s.merge", new_ref); - git_config_set(key, tracking.src ? tracking.src : orig_ref); - printf("Branch %s set up to track %s branch %s.\n", new_ref, - tracking.remote ? "remote" : "local", orig_ref); - if (should_setup_rebase(&tracking)) { - sprintf(key, "branch.%s.rebase", new_ref); - git_config_set(key, "true"); - printf("This branch will rebase on pull.\n"); - } - free(tracking.src); + install_branch_config(BRANCH_CONFIG_VERBOSE, new_ref, tracking.remote, + tracking.src ? tracking.src : orig_ref); + free(tracking.src); return 0; } diff --git a/branch.h b/branch.h index 9f0c2a2c1f..eed817a64c 100644 --- a/branch.h +++ b/branch.h @@ -21,4 +21,11 @@ void create_branch(const char *head, const char *name, const char *start_name, */ void remove_branch_state(void); +/* + * Configure local branch "local" to merge remote branch "remote" + * taken from origin "origin". + */ +#define BRANCH_CONFIG_VERBOSE 01 +extern void install_branch_config(int flag, const char *local, const char *origin, const char *remote); + #endif diff --git a/builtin-clone.c b/builtin-clone.c index c338910b1c..a5f000adf4 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -20,6 +20,7 @@ #include "dir.h" #include "pack-refs.h" #include "sigchain.h" +#include "branch.h" /* * Overall FIXMEs: @@ -350,19 +351,6 @@ static struct ref *write_remote_refs(const struct ref *refs, return local_refs; } -static void install_branch_config(const char *local, - const char *origin, - const char *remote) -{ - struct strbuf key = STRBUF_INIT; - strbuf_addf(&key, "branch.%s.remote", local); - git_config_set(key.buf, origin); - strbuf_reset(&key); - strbuf_addf(&key, "branch.%s.merge", local); - git_config_set(key.buf, remote); - strbuf_release(&key); -} - int cmd_clone(int argc, const char **argv, const char *prefix) { int use_local_hardlinks = 1; @@ -553,7 +541,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) remote_head = NULL; option_no_checkout = 1; if (!option_bare) - install_branch_config("master", option_origin, + install_branch_config(0, "master", option_origin, "refs/heads/master"); } @@ -583,7 +571,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) head_points_at->peer_ref->name, reflog_msg.buf); - install_branch_config(head, option_origin, + install_branch_config(0, head, option_origin, head_points_at->name); } } else if (remote_head) { diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 44793f2eee..2335d8bc85 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -159,4 +159,19 @@ test_expect_success 'clone a void' ' test_cmp target-6/.git/config target-7/.git/config ' +test_expect_success 'clone respects global branch.autosetuprebase' ' + ( + HOME=$(pwd) && + export HOME && + test_config="$HOME/.gitconfig" && + unset GIT_CONFIG_NOGLOBAL && + git config -f "$test_config" branch.autosetuprebase remote && + rm -fr dst && + git clone src dst && + cd dst && + actual="z$(git config branch.master.rebase)" && + test ztrue = $actual + ) +' + test_done From 628d5c2b707db207e47c42ca112b182aa171cfaa Mon Sep 17 00:00:00 2001 From: Keith Cascio <keith@cs.ucla.edu> Date: Mon, 16 Feb 2009 19:26:49 -0800 Subject: [PATCH 104/654] Use DIFF_XDL_SET/DIFF_OPT_SET instead of raw bit-masking Signed-off-by: Keith Cascio <keith@cs.ucla.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- diff.c | 17 ++++++++++------- diff.h | 3 +++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/diff.c b/diff.c index 006aa017e2..ff3624e9f6 100644 --- a/diff.c +++ b/diff.c @@ -2567,13 +2567,13 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) /* xdiff options */ else if (!strcmp(arg, "-w") || !strcmp(arg, "--ignore-all-space")) - options->xdl_opts |= XDF_IGNORE_WHITESPACE; + DIFF_XDL_SET(options, IGNORE_WHITESPACE); else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-change")) - options->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE; + DIFF_XDL_SET(options, IGNORE_WHITESPACE_CHANGE); else if (!strcmp(arg, "--ignore-space-at-eol")) - options->xdl_opts |= XDF_IGNORE_WHITESPACE_AT_EOL; + DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL); else if (!strcmp(arg, "--patience")) - options->xdl_opts |= XDF_PATIENCE_DIFF; + DIFF_XDL_SET(options, PATIENCE_DIFF); /* flags options */ else if (!strcmp(arg, "--binary")) { @@ -2594,10 +2594,13 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) DIFF_OPT_SET(options, COLOR_DIFF); else if (!strcmp(arg, "--no-color")) DIFF_OPT_CLR(options, COLOR_DIFF); - else if (!strcmp(arg, "--color-words")) - options->flags |= DIFF_OPT_COLOR_DIFF | DIFF_OPT_COLOR_DIFF_WORDS; + else if (!strcmp(arg, "--color-words")) { + DIFF_OPT_SET(options, COLOR_DIFF); + DIFF_OPT_SET(options, COLOR_DIFF_WORDS); + } else if (!prefixcmp(arg, "--color-words=")) { - options->flags |= DIFF_OPT_COLOR_DIFF | DIFF_OPT_COLOR_DIFF_WORDS; + DIFF_OPT_SET(options, COLOR_DIFF); + DIFF_OPT_SET(options, COLOR_DIFF_WORDS); options->word_regex = arg + 14; } else if (!strcmp(arg, "--exit-code")) diff --git a/diff.h b/diff.h index 6703a4fb4f..6616877ee5 100644 --- a/diff.h +++ b/diff.h @@ -69,6 +69,9 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, #define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag) #define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag) #define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag) +#define DIFF_XDL_TST(opts, flag) ((opts)->xdl_opts & XDF_##flag) +#define DIFF_XDL_SET(opts, flag) ((opts)->xdl_opts |= XDF_##flag) +#define DIFF_XDL_CLR(opts, flag) ((opts)->xdl_opts &= ~XDF_##flag) struct diff_options { const char *filter; From e752f4bba24afe964eb42d6c2b8bf06cc77c9ce4 Mon Sep 17 00:00:00 2001 From: Keith Cascio <keith@cs.ucla.edu> Date: Mon, 16 Feb 2009 18:59:00 -0800 Subject: [PATCH 105/654] Fix neglect of diff_setup()/diff_setup_done() symmetry. Code that calls diff_setup(), including via init_revisions(), should later call diff_setup_done(), possibly via setup_revisions(). Failure to do so could cause errors, especially in the future when we add responsibilities to diff_setup_done(). This instance causes no known errors with the present code. But it resulted in an error with an experimental patch. Signed-off-by: Keith Cascio <keith@cs.ucla.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-checkout.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builtin-checkout.c b/builtin-checkout.c index 20b34ce6e1..c315f63398 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -295,6 +295,8 @@ static void show_local_changes(struct object *head) init_revisions(&rev, NULL); rev.abbrev = 0; rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS; + if (diff_setup_done(&rev.diffopt) < 0) + die("diff_setup_done failed"); add_pending_object(&rev, head, NULL); run_diff_index(&rev, 0); } From 9f199b159580545c39716fd87038f8ff7cd0eace Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sat, 21 Feb 2009 09:26:01 +0100 Subject: [PATCH 106/654] rev-list: estimate number of bisection step left This patch teaches "git rev-list --bisect-vars" to output an estimate of the number of bisection step left _after the current one_ along with the other variables it already outputs. This patch also makes "git-bisect.sh" display this number of steps left _after the current one_, along with the estimate of the number of revisions left to test (after the current one). Here is a table to help analyse what should be the best estimate for the number of bisect steps left. N : linear case --> probabilities --> best ------------------------------------------------------------- 1 : G-B --> 0 --> 0 2 : G-U1-B --> 0 --> 0 3 : G-U1-U2-B --> 0(1/3) 1(2/3) --> 1 4 : G-U1-U2-U3-B --> 1 --> 1 5 : G-U1-U2-U3-U4-B --> 1(3/5) 2(2/5) --> 1 6 : G-U1-U2-U3-U4-U5-B --> 1(2/6) 2(4/6) --> 2 7 : G-U1-U2-U3-U4-U5-U6-B --> 1(1/7) 2(6/7) --> 2 8 : G-U1-U2-U3-U4-U5-U6-U7-B --> 2 --> 2 9 : G-U1-U2-U3-U4-U5-U6-U7-U8-B --> 2(7/9) 3(2/9) --> 2 10: G-U1-U2-U3-U4-U5-U6-U7-U8-U9-B --> 2(6/10)3(4/10)--> 2 In the column "N", there is the number of revisions that could _now_ be the first bad commit we are looking for. The "linear case" column describes the linear history corresponding to the number in column N. G means good, B means bad, and Ux means unknown. Note that the first bad revision we are looking for can be any Ux or B. In the "probabilities" column, there are the different outcomes in number of steps with the odds of each outcome in parenthesis corresponding to the linear case. The "best" column gives the most accurate estimate among the different outcomes in the "probabilities" column. We have the following: best(2^n) == n - 1 and for any x between 0 included and 2^n excluded, the probability for n - 1 steps left looks like: P(2^n + x) == (2^n - x) / (2^n + x) and P(2^n + x) < 0.5 means 2^n < 3x So the algorithm used in this patch calculates 2^n and x, and then choose between returning n - 1 and n. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-rev-list.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- git-bisect.sh | 2 +- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 436afa45f5..40d5fcb6b0 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -574,6 +574,45 @@ static struct commit_list *find_bisection(struct commit_list *list, return best; } +static inline int log2i(int n) +{ + int log2 = 0; + + for (; n > 1; n >>= 1) + log2++; + + return log2; +} + +static inline int exp2i(int n) +{ + return 1 << n; +} + +/* + * Estimate the number of bisect steps left (after the current step) + * + * For any x between 0 included and 2^n excluded, the probability for + * n - 1 steps left looks like: + * + * P(2^n + x) == (2^n - x) / (2^n + x) + * + * and P(2^n + x) < 0.5 means 2^n < 3x + */ +static int estimate_bisect_steps(int all) +{ + int n, x, e; + + if (all < 3) + return 0; + + n = log2i(all); + e = exp2i(n); + x = all - e; + + return (e < 3 * x) ? n : n - 1; +} + int cmd_rev_list(int argc, const char **argv, const char *prefix) { struct commit_list *list; @@ -688,12 +727,14 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) "bisect_nr=%d\n" "bisect_good=%d\n" "bisect_bad=%d\n" - "bisect_all=%d\n", + "bisect_all=%d\n" + "bisect_steps=%d\n", hex, cnt - 1, all - reaches - 1, reaches - 1, - all); + all, + estimate_bisect_steps(all)); return 0; } } diff --git a/git-bisect.sh b/git-bisect.sh index 10ad340920..e313bdea70 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -512,7 +512,7 @@ bisect_next() { # commit is also a "skip" commit (see above). exit_if_skipped_commits "$bisect_rev" - bisect_checkout "$bisect_rev" "$bisect_nr revisions left to test after this" + bisect_checkout "$bisect_rev" "$bisect_nr revisions left to test after this (roughly $bisect_steps steps)" } bisect_visualize() { From 28001d0873cfce1ad6a44f1c2deaf9388d953cc3 Mon Sep 17 00:00:00 2001 From: John Tapsell <johnflux@gmail.com> Date: Thu, 19 Feb 2009 07:36:00 +0000 Subject: [PATCH 107/654] Modify description file to say what this file is A lot of people see this message for the first time on the gitweb interface, where there is no clue as to what 'this file' means. Signed-off-by: John Tapsell <johnflux@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- templates/hooks--update.sample | 6 ++++-- templates/this--description | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/templates/hooks--update.sample b/templates/hooks--update.sample index 93c605594f..a3f68ae3b4 100755 --- a/templates/hooks--update.sample +++ b/templates/hooks--update.sample @@ -43,10 +43,12 @@ allowdeletetag=$(git config --bool hooks.allowdeletetag) # check for no description projectdesc=$(sed -e '1q' "$GIT_DIR/description") -if [ -z "$projectdesc" -o "$projectdesc" = "Unnamed repository; edit this file to name it for gitweb." ]; then +case "$projectdesc" in +"Unnamed repository"* | "") echo "*** Project description file hasn't been set" >&2 exit 1 -fi + ;; +esac # --- Check types # if $newrev is 0000...0000, it's a commit to delete a ref. diff --git a/templates/this--description b/templates/this--description index c6f25e80b8..498b267a8c 100644 --- a/templates/this--description +++ b/templates/this--description @@ -1 +1 @@ -Unnamed repository; edit this file to name it for gitweb. +Unnamed repository; edit this file 'description' to name the repository. From 50dffd4ed577ea50b540bad53950ef2b703b5be8 Mon Sep 17 00:00:00 2001 From: John Tapsell <johnflux@gmail.com> Date: Thu, 19 Feb 2009 07:36:11 +0000 Subject: [PATCH 108/654] Google has renamed the imap folder Also add a comment that the web interface wraps the lines Signed-off-by: John Tapsell <johnflux@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/SubmittingPatches | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 9b559adefc..8d818a2160 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -491,6 +491,12 @@ message, complete the addressing and subject fields, and press send. Gmail ----- +GMail does not appear to have any way to turn off line wrapping in the web +interface, so this will mangle any emails that you send. You can however +use any IMAP email client to connect to the google imap server, and forward +the emails through that. Just make sure to disable line wrapping in that +email client. Alternatively, use "git send-email" instead. + Submitting properly formatted patches via Gmail is simple now that IMAP support is available. First, edit your ~/.gitconfig to specify your account settings: @@ -503,6 +509,9 @@ account settings: port = 993 sslverify = false +You might need to instead use: folder = "[Google Mail]/Drafts" if you get an error +that the "Folder doesn't exist". + Next, ensure that your Gmail settings are correct. In "Settings" the "Use Unicode (UTF-8) encoding for outgoing messages" should be checked. @@ -513,3 +522,4 @@ command to send the patch emails to your Gmail Drafts folder. Go to your Gmail account, open the Drafts folder, find the patch email, fill in the To: and CC: fields and send away! + From 734cd5726cf0f16fcbdc2fc121df23814513c420 Mon Sep 17 00:00:00 2001 From: John Tapsell <johnflux@gmail.com> Date: Thu, 19 Feb 2009 07:36:35 +0000 Subject: [PATCH 109/654] Improve error message for git-filter-branch Tell the user that a backup (original) already exists, and how to solve this problem (with -f option) Signed-off-by: John Tapsell <johnflux@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-filter-branch.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/git-filter-branch.sh b/git-filter-branch.sh index 9a09ba1382..20f6f51750 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -232,7 +232,9 @@ while read sha1 type name do case "$force,$name" in ,$orig_namespace*) - die "Namespace $orig_namespace not empty" + die "Cannot create a new backup. +A previous backup already exists in $orig_namespace +Force overwriting the backup with -f" ;; t,$orig_namespace*) git update-ref -d "$name" $sha1 From aec0c1bbfb2d42659bb710bd79f8228ac59e1b0c Mon Sep 17 00:00:00 2001 From: Carlos Manuel Duclos Vergara <carlos.duclos@nokia.com> Date: Mon, 16 Feb 2009 18:20:25 +0100 Subject: [PATCH 110/654] git-archive: add --output=<file> to send output to a file When archiving a repository there is no way to specify a file as output. This patch adds a new option "--output" that redirects the output to a file instead of stdout. Signed-off-by: Carlos Manuel Duclos Vergara <carlos.duclos@nokia.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-archive.txt | 4 ++++ archive.c | 19 +++++++++++++++++++ t/t5000-tar-tree.sh | 8 ++++++++ 3 files changed, 31 insertions(+) diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt index 5b3eb12c8a..0eeefe0060 100644 --- a/Documentation/git-archive.txt +++ b/Documentation/git-archive.txt @@ -10,6 +10,7 @@ SYNOPSIS -------- [verse] 'git archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>] + [--output=<file>] [--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish> [path...] @@ -47,6 +48,9 @@ OPTIONS --prefix=<prefix>/:: Prepend <prefix>/ to each filename in the archive. +--output=<file>:: + Write the archive to <file> instead of stdout. + <extra>:: This can be any options that the archiver backend understand. See next section. diff --git a/archive.c b/archive.c index e6de0397cc..c6aea8358f 100644 --- a/archive.c +++ b/archive.c @@ -239,6 +239,19 @@ static void parse_treeish_arg(const char **argv, ar_args->time = archive_time; } +static void create_output_file(const char *output_file) +{ + int output_fd = open(output_file, O_CREAT | O_WRONLY | O_TRUNC, 0666); + if (output_fd < 0) + die("could not create archive file: %s ", output_file); + if (output_fd != 1) { + if (dup2(output_fd, 1) < 0) + die("could not redirect output"); + else + close(output_fd); + } +} + #define OPT__COMPR(s, v, h, p) \ { OPTION_SET_INT, (s), NULL, (v), NULL, (h), \ PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, (p) } @@ -253,6 +266,7 @@ static int parse_archive_args(int argc, const char **argv, const char *base = NULL; const char *remote = NULL; const char *exec = NULL; + const char *output = NULL; int compression_level = -1; int verbose = 0; int i; @@ -262,6 +276,8 @@ static int parse_archive_args(int argc, const char **argv, OPT_STRING(0, "format", &format, "fmt", "archive format"), OPT_STRING(0, "prefix", &base, "prefix", "prepend prefix to each pathname in the archive"), + OPT_STRING(0, "output", &output, "file", + "write the archive to this file"), OPT__VERBOSE(&verbose), OPT__COMPR('0', &compression_level, "store only", 0), OPT__COMPR('1', &compression_level, "compress faster", 1), @@ -294,6 +310,9 @@ static int parse_archive_args(int argc, const char **argv, if (!base) base = ""; + if (output) + create_output_file(output); + if (list) { for (i = 0; i < ARRAY_SIZE(archivers); i++) printf("%s\n", archivers[i].name); diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index c942c8be85..b7e362834b 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -86,6 +86,10 @@ test_expect_success \ 'git archive vs. the same in a bare repo' \ 'test_cmp b.tar b3.tar' +test_expect_success 'git archive with --output' \ + 'git archive --output=b4.tar HEAD && + test_cmp b.tar b4.tar' + test_expect_success \ 'validate file modification time' \ 'mkdir extract && @@ -172,6 +176,10 @@ test_expect_success \ 'git archive --format=zip vs. the same in a bare repo' \ 'test_cmp d.zip d1.zip' +test_expect_success 'git archive --format=zip with --output' \ + 'git archive --format=zip --output=d2.zip HEAD && + test_cmp d.zip d2.zip' + $UNZIP -v >/dev/null 2>&1 if [ $? -eq 127 ]; then echo "Skipping ZIP tests, because unzip was not found" From 19de5d6913b9681d2bde533bccc8445c9236a648 Mon Sep 17 00:00:00 2001 From: Kjetil Barvik <barvik@broadpark.no> Date: Wed, 4 Mar 2009 18:47:39 +0100 Subject: [PATCH 111/654] stat_tracking_info(): only count real commits stat_tracking_info() in remote.c is used to collect the statistics to be able to say (for instance) from the output of "git checkout': Your branch and 'foo' have diverged, and have X and Y different commit(s) each, respectively. Currently X and Y also includes the count of merges. This patch excludes the merges from being counted. Signed-off-by: Kjetil Barvik <barvik@broadpark.no> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- remote.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/remote.c b/remote.c index d7079c6dd8..06c414e118 100644 --- a/remote.c +++ b/remote.c @@ -1310,9 +1310,10 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs) if (theirs == ours) return 0; - /* Run "rev-list --left-right ours...theirs" internally... */ + /* Run "rev-list --no-merges --left-right ours...theirs" internally... */ rev_argc = 0; rev_argv[rev_argc++] = NULL; + rev_argv[rev_argc++] = "--no-merges"; rev_argv[rev_argc++] = "--left-right"; rev_argv[rev_argc++] = symmetric; rev_argv[rev_argc++] = "--"; From 05ac6b34e2c2adda5cb85dd0bdacb47fe5db953e Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Wed, 4 Mar 2009 03:32:29 -0500 Subject: [PATCH 112/654] improve missing repository error message Certain remote commands, when asked to do something in a particular directory that was not actually a git repository, would say "unable to chdir or not a git archive". The "chdir" bit is an unnecessary detail, and the term "git archive" is much less common these days than "git repository". So let's switch them all to: fatal: '%s' does not appear to be a git repository Signed-off-by: Jeff King <peff@peff.net> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-receive-pack.c | 2 +- builtin-upload-archive.c | 2 +- daemon.c | 2 +- upload-pack.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/builtin-receive-pack.c b/builtin-receive-pack.c index 849f1fe6f9..a970b39505 100644 --- a/builtin-receive-pack.c +++ b/builtin-receive-pack.c @@ -675,7 +675,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) setup_path(); if (!enter_repo(dir, 0)) - die("'%s': unable to chdir or not a git archive", dir); + die("'%s' does not appear to be a git repository", dir); if (is_repository_shallow()) die("attempt to push into a shallow repository"); diff --git a/builtin-upload-archive.c b/builtin-upload-archive.c index a9b02fa32f..0206b416cb 100644 --- a/builtin-upload-archive.c +++ b/builtin-upload-archive.c @@ -35,7 +35,7 @@ static int run_upload_archive(int argc, const char **argv, const char *prefix) strcpy(buf, argv[1]); /* enter-repo smudges its argument */ if (!enter_repo(buf, 0)) - die("not a git archive"); + die("'%s' does not appear to be a git repository", buf); /* put received options in sent_argv[] */ sent_argc = 1; diff --git a/daemon.c b/daemon.c index d93cf960f9..13401f1baf 100644 --- a/daemon.c +++ b/daemon.c @@ -229,7 +229,7 @@ static char *path_ok(char *directory) } if (!path) { - logerror("'%s': unable to chdir or not a git archive", dir); + logerror("'%s' does not appear to be a git repository", dir); return NULL; } diff --git a/upload-pack.c b/upload-pack.c index 19c24db643..e15ebdc287 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -645,7 +645,7 @@ int main(int argc, char **argv) dir = argv[i]; if (!enter_repo(dir, strict)) - die("'%s': unable to chdir or not a git archive", dir); + die("'%s' does not appear to be a git repository", dir); if (is_repository_shallow()) die("attempt to fetch/clone from a shallow repository"); if (getenv("GIT_DEBUG_SEND_PACK")) From a84bde927c0882db78a37d40168e98add63f2307 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Thu, 5 Mar 2009 14:50:00 -0800 Subject: [PATCH 113/654] Draft release notes: Carry forward the warning for behaviour changes Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/RelNotes-1.6.3.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Documentation/RelNotes-1.6.3.txt b/Documentation/RelNotes-1.6.3.txt index 0f502abea6..2ab2328316 100644 --- a/Documentation/RelNotes-1.6.3.txt +++ b/Documentation/RelNotes-1.6.3.txt @@ -1,6 +1,28 @@ GIT v1.6.3 Release Notes ======================== +With the next major release, "git push" into a branch that is +currently checked out will be refused by default. You can choose +what should happen upon such a push by setting the configuration +variable receive.denyCurrentBranch in the receiving repository. + +To ease the transition plan, the receiving repository of such a +push running this release will issue a big warning when the +configuration variable is missing. Please refer to: + + http://git.or.cz/gitwiki/GitFaq#non-bare + http://thread.gmane.org/gmane.comp.version-control.git/107758/focus=108007 + +for more details on the reason why this change is needed and the +transition plan. + +For a similar reason, "git push $there :$killed" to delete the branch +$killed in a remote repository $there, if $killed branch is the current +branch pointed at by its HEAD, gets a large warning. You can choose what +should happen upon such a push by setting the configuration variable +receive.denyDeleteCurrent in the receiving repository. + + Updates since v1.6.2 -------------------- From fad5c96756fe9524fcb4e6ab7468368c2fb20fa0 Mon Sep 17 00:00:00 2001 From: John Tapsell <johnflux@gmail.com> Date: Thu, 5 Mar 2009 12:36:14 +0000 Subject: [PATCH 114/654] Documentation - More examples for git bisect Including passing parameters to the programs, and running more complicated checks without requiring a seperate shell script. Signed-off-by: John Tapsell <johnflux@gmail.com> Acked-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-bisect.txt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt index 147ea38197..e65c1cae8b 100644 --- a/Documentation/git-bisect.txt +++ b/Documentation/git-bisect.txt @@ -212,7 +212,7 @@ If you have a script that can tell if the current source code is good or bad, you can automatically bisect using: ------------ -$ git bisect run my_script +$ git bisect run my_script arguments ------------ Note that the "run" script (`my_script` in the above example) should @@ -252,6 +252,13 @@ $ git bisect start HEAD v1.2 -- # HEAD is bad, v1.2 is good $ git bisect run make # "make" builds the app ------------ +* Automatically bisect a test failure between origin and HEAD: ++ +------------ +$ git bisect start HEAD origin -- # HEAD is bad, origin is good +$ git bisect run make test # "make test" builds and tests +------------ + * Automatically bisect a broken test suite: + ------------ @@ -291,6 +298,15 @@ It's safer if both "test.sh" and "check_test_case.sh" scripts are outside the repo to prevent interactions between the bisect, make and test processes and the scripts. +* Automatically bisect a broken test suite: ++ +------------ +$ git bisect start HEAD HEAD~10 -- # culprit is among the last 10 +$ git bisect run sh -c "make || exit 125; ~/check_test_case.sh" +------------ ++ +Does the same as the previous example, but on a single line. + Author ------ Written by Linus Torvalds <torvalds@osdl.org> From 1d4e4cd4a108dc105f6c8e739c69b9261d4e92a5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Thu, 5 Mar 2009 17:05:12 +0100 Subject: [PATCH 115/654] MinGW: 64-bit file offsets The type 'off_t' should be used everywhere so that the bit-depth of that type can be adjusted in the standard C library, and you just need to recompile your program to benefit from the extended precision. Only that it was not done that way in the MS runtime library. This patch reroutes off_t to off64_t and provides the other necessary changes so that finally, clones larger than 2 gigabyte work on Windows (provided you are on a file system that allows files larger than 2gb). Initial patch by Sickboy <sb@dev-heaven.net>. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Acked-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- compat/mingw.c | 8 +++++--- compat/mingw.h | 5 ++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 3dbe6a77ff..27bcf3fd6b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -46,7 +46,8 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_uid = 0; buf->st_nlink = 1; buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); - buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ + buf->st_size = fdata.nFileSizeLow | + (((off_t)fdata.nFileSizeHigh)<<32); buf->st_dev = buf->st_rdev = 0; /* not used by Git */ buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); @@ -101,7 +102,7 @@ int mingw_fstat(int fd, struct stat *buf) } /* direct non-file handles to MS's fstat() */ if (GetFileType(fh) != FILE_TYPE_DISK) - return fstat(fd, buf); + return _fstati64(fd, buf); if (GetFileInformationByHandle(fh, &fdata)) { buf->st_ino = 0; @@ -109,7 +110,8 @@ int mingw_fstat(int fd, struct stat *buf) buf->st_uid = 0; buf->st_nlink = 1; buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); - buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ + buf->st_size = fdata.nFileSizeLow | + (((off_t)fdata.nFileSizeHigh)<<32); buf->st_dev = buf->st_rdev = 0; /* not used by Git */ buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); diff --git a/compat/mingw.h b/compat/mingw.h index a255898801..cb9c4d4dd5 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -163,11 +163,14 @@ int mingw_rename(const char*, const char*); /* Use mingw_lstat() instead of lstat()/stat() and * mingw_fstat() instead of fstat() on Windows. */ +#define off_t off64_t +#define stat _stati64 +#define lseek _lseeki64 int mingw_lstat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define stat(x,y) mingw_lstat(x,y) +#define stat64(x,y) mingw_lstat(x,y) int mingw_utime(const char *file_name, const struct utimbuf *times); #define utime mingw_utime From 31653c1abc1ac80206db9efca56ff1969150d8fe Mon Sep 17 00:00:00 2001 From: Eugene Letuchy <eugene@facebook.com> Date: Fri, 20 Feb 2009 14:51:11 -0800 Subject: [PATCH 116/654] Make git blame's date output format configurable, like git log Add the following: - git config value blame.date that expects one of the git log date formats (e.g. relative,local,default,iso,...); - git blame command line option --date expects one of the git log date formats; - documentation in blame-options.txt; - git blame uses the appropriate date.c functions and enums to make sense of the date format and provide appropriate data; git blame continues to line up the output columns by padding the date column up to the max width of the chosen date format. The date format for git blame without both blame.date and --date continues to be ISO for backwards compatibility. git annotate ignores the date format specifiers and continues to uses the ISO format, as before. Signed-off-by: Eugene Letuchy <eugene@facebook.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/blame-options.txt | 8 ++++ builtin-blame.c | 67 +++++++++++++++++++++++++-------- 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt index 7f28432254..e6717af44e 100644 --- a/Documentation/blame-options.txt +++ b/Documentation/blame-options.txt @@ -70,6 +70,14 @@ of lines before or after the line given by <start>. tree copy has the contents of the named file (specify `-` to make the command read from the standard input). +--date <format>:: + The value is one of the following alternatives: + {relative,local,default,iso,rfc,short}. If --date is not + provided, the value of the blame.date config variable is + used. If the blame.date config variable is also not set, the + iso format is used. For more information, See the discussion + of the --date option at linkgit:git-log[1]. + -M|<num>|:: Detect moving lines in the file as well. When a commit moves a block of lines in a file (e.g. the original file diff --git a/builtin-blame.c b/builtin-blame.c index 114a214ed3..0c6ad98d19 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -1,5 +1,5 @@ /* - * Pickaxe + * Blame * * Copyright (c) 2006, Junio C Hamano */ @@ -40,6 +40,10 @@ static int reverse; static int blank_boundary; static int incremental; static int xdl_opts = XDF_NEED_MINIMAL; + +static enum date_mode blame_date_mode = DATE_ISO8601; +static size_t blame_date_width; + static struct string_list mailmap; #ifndef DEBUG @@ -1507,24 +1511,20 @@ static const char *format_time(unsigned long time, const char *tz_str, int show_raw_time) { static char time_buf[128]; - time_t t = time; - int minutes, tz; - struct tm *tm; + const char *time_str; + int time_len; + int tz; if (show_raw_time) { sprintf(time_buf, "%lu %s", time, tz_str); - return time_buf; } - - tz = atoi(tz_str); - minutes = tz < 0 ? -tz : tz; - minutes = (minutes / 100)*60 + (minutes % 100); - minutes = tz < 0 ? -minutes : minutes; - t = time + minutes * 60; - tm = gmtime(&t); - - strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S ", tm); - strcat(time_buf, tz_str); + else { + tz = atoi(tz_str); + time_str = show_date(time, tz, blame_date_mode); + time_len = strlen(time_str); + memcpy(time_buf, time_str, time_len); + memset(time_buf + time_len, ' ', blame_date_width - time_len); + } return time_buf; } @@ -1975,6 +1975,12 @@ static int git_blame_config(const char *var, const char *value, void *cb) blank_boundary = git_config_bool(var, value); return 0; } + if (!strcmp(var, "blame.date")) { + if (!value) + return config_error_nonbool(var); + blame_date_mode = parse_date_format(value); + return 0; + } return git_default_config(var, value, cb); } @@ -2239,6 +2245,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix) git_config(git_blame_config, NULL); init_revisions(&revs, NULL); + revs.date_mode = blame_date_mode; + save_commit_buffer = 0; dashdash_pos = 0; @@ -2263,8 +2271,35 @@ int cmd_blame(int argc, const char **argv, const char *prefix) parse_done: argc = parse_options_end(&ctx); - if (cmd_is_annotate) + if (cmd_is_annotate) { output_option |= OUTPUT_ANNOTATE_COMPAT; + blame_date_mode = DATE_ISO8601; + } else { + blame_date_mode = revs.date_mode; + } + + /* The maximum width used to show the dates */ + switch (blame_date_mode) { + case DATE_RFC2822: + blame_date_width = sizeof("Thu, 19 Oct 2006 16:00:04 -0700"); + break; + case DATE_ISO8601: + blame_date_width = sizeof("2006-10-19 16:00:04 -0700"); + break; + case DATE_RAW: + blame_date_width = sizeof("1161298804 -0700"); + break; + case DATE_SHORT: + blame_date_width = sizeof("2006-10-19"); + break; + case DATE_RELATIVE: + /* "normal" is used as the fallback for "relative" */ + case DATE_LOCAL: + case DATE_NORMAL: + blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700"); + break; + } + blame_date_width -= 1; /* strip the null */ if (DIFF_OPT_TST(&revs.diffopt, FIND_COPIES_HARDER)) opt |= (PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE | From d0baf91db871fdd129057d7844d17457575698ba Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Fri, 6 Mar 2009 01:37:22 -0800 Subject: [PATCH 117/654] Update draft release notes to 1.6.3 --- Documentation/RelNotes-1.6.3.txt | 60 ++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/Documentation/RelNotes-1.6.3.txt b/Documentation/RelNotes-1.6.3.txt index 2ab2328316..ee1fddb76a 100644 --- a/Documentation/RelNotes-1.6.3.txt +++ b/Documentation/RelNotes-1.6.3.txt @@ -32,6 +32,44 @@ Updates since v1.6.2 (usability, bells and whistles) +* "--pretty=<style>" option to the log family of commands can now be + spelled as "--format=<style>". In addition, --format=%formatstring + is a short-hand for --pretty=tformat:%formatstring. + +* "--oneline" is a synonym for "--pretty=oneline --abbrev=commit". + +* If you realize that you botched the patch when you are editing hunks + with the 'edit' action in git-add -i/-p, you can abort the editor to + tell git not to apply it. + +* git-archive learned --output=<file> option. + +* git-bisect shows not just the number of remaining commits whose goodness + is unknown, but also shows the estimated number of remaining rounds. + +* git-branch -r shows HEAD symref that points at a remote branch in + interest of each tracked remote repository. + +* git-config learned -e option to open an editor to edit the config file + directly. + +* git-format-patch can be told to use attachment with a new configuration, + format.attach. + +* git-imap-send learned to work around Thunderbird's inability to easily + disable format=flowed with a new configuration, imap.preformattedHTML. + +* git-rebase can be told to rebase the series even if your branch is a + descendant of the commit you are rebasing onto with --force-rebase + option. + +* git-send-email learned --confirm option to review the Cc: list before + sending the messages out. + +(developers) + +* Test scripts can be run under valgrind. + Fixes since v1.6.2 ------------------ @@ -42,3 +80,25 @@ release, unless otherwise noted. Here are fixes that this release has, but have not been backported to v1.6.2.X series. +* .gitignore learned to handle backslash as a quoting mechanism for + comment introduction character "#" (backport by merging dd482ee if + needed). + +* timestamp output in --date=relative mode used to display timestamps that + are long time ago in the default mode; it now uses "N years M months + ago", and "N years ago" (backport by picking 10edf37 if needed). + +* git-add -i/-p now works with non-ASCII pathnames (backport by picking + 8851f48 if needed). + +* "git hash-object -w" did not read from the configuration file from the + correct .git directory (backport by merging 272459a if needed). + +* git-send-email learned to correctly handle multiple Cc: addresses + (backport by merging afe756c if needed). + +--- +exec >/var/tmp/1 +O=v1.6.2-77-g8cc3fe4 +echo O=$(git describe master) +git shortlog --no-merges $O..master ^maint From ba048224685e661a4cf4736dcffab5fc60cbc70b Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Sat, 7 Mar 2009 12:14:05 -0500 Subject: [PATCH 118/654] config: set help text for --bool-or-int The conversion to parse_opt left this as NULL; on glibc systems, the usage message prints --bool-or-int (null) and on other ones, segfaults. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-config.c b/builtin-config.c index b11a0961bd..1a3baa1f46 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -68,7 +68,7 @@ static struct option builtin_config_options[] = { OPT_GROUP("Type"), OPT_BIT(0, "bool", &types, "value is \"true\" or \"false\"", TYPE_BOOL), OPT_BIT(0, "int", &types, "value is decimal number", TYPE_INT), - OPT_BIT(0, "bool-or-int", &types, NULL, TYPE_BOOL_OR_INT), + OPT_BIT(0, "bool-or-int", &types, "value is --bool or --int", TYPE_BOOL_OR_INT), OPT_GROUP("Other"), OPT_BOOLEAN('z', "null", &end_null, "terminate values with NUL byte"), OPT_END(), From 252d560d215581637fcddd7a0a18f89204ecc8d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Sat, 7 Mar 2009 13:27:15 +0100 Subject: [PATCH 119/654] grep: micro-optimize hit collection for AND nodes In addition to returning if an expression matches a line, match_expr_eval() updates the expression's hit flag if the parameter collect_hits is set. It never sets collect_hits for children of AND nodes, though, so their hit flag will never be updated. Because of that we can return early if the first child didn't match, no matter if collect_hits is set or not. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- grep.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/grep.c b/grep.c index 062b2b6f28..db341b6797 100644 --- a/grep.c +++ b/grep.c @@ -394,13 +394,9 @@ static int match_expr_eval(struct grep_opt *o, h = !match_expr_eval(o, x->u.unary, bol, eol, ctx, 0); break; case GREP_NODE_AND: - if (!collect_hits) - return (match_expr_eval(o, x->u.binary.left, - bol, eol, ctx, 0) && - match_expr_eval(o, x->u.binary.right, - bol, eol, ctx, 0)); - h = match_expr_eval(o, x->u.binary.left, bol, eol, ctx, 0); - h &= match_expr_eval(o, x->u.binary.right, bol, eol, ctx, 0); + if (!match_expr_eval(o, x->u.binary.left, bol, eol, ctx, 0)) + return 0; + h = match_expr_eval(o, x->u.binary.right, bol, eol, ctx, 0); break; case GREP_NODE_OR: if (!collect_hits) From d7eb527d731e2a71eaa4597417d879a15588d9ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Sat, 7 Mar 2009 13:28:40 +0100 Subject: [PATCH 120/654] grep: remove grep_opt argument from match_expr_eval() The only use of the struct grep_opt argument of match_expr_eval() is to pass the option word_regexp to match_one_pattern(). By adding a pattern flag for it we can reduce the number of function arguments of these two functions, as a cleanup and preparation for adding more in the next patch. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- grep.c | 34 +++++++++++++++++----------------- grep.h | 1 + 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/grep.c b/grep.c index db341b6797..f45518233f 100644 --- a/grep.c +++ b/grep.c @@ -39,6 +39,8 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt) { int err; + p->word_regexp = opt->word_regexp; + if (opt->fixed || is_fixed(p->pattern)) p->fixed = 1; if (opt->regflags & REG_ICASE) @@ -306,7 +308,8 @@ static struct { { "committer ", 10 }, }; -static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol, char *eol, enum grep_context ctx) +static int match_one_pattern(struct grep_pat *p, char *bol, char *eol, + enum grep_context ctx) { int hit = 0; int saved_ch = 0; @@ -338,7 +341,7 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol hit = !fixmatch(p->pattern, bol, pmatch); } - if (hit && opt->word_regexp) { + if (hit && p->word_regexp) { if ((pmatch[0].rm_so < 0) || (eol - bol) <= pmatch[0].rm_so || (pmatch[0].rm_eo < 0) || @@ -378,35 +381,32 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol return hit; } -static int match_expr_eval(struct grep_opt *o, - struct grep_expr *x, - char *bol, char *eol, - enum grep_context ctx, - int collect_hits) +static int match_expr_eval(struct grep_expr *x, char *bol, char *eol, + enum grep_context ctx, int collect_hits) { int h = 0; switch (x->node) { case GREP_NODE_ATOM: - h = match_one_pattern(o, x->u.atom, bol, eol, ctx); + h = match_one_pattern(x->u.atom, bol, eol, ctx); break; case GREP_NODE_NOT: - h = !match_expr_eval(o, x->u.unary, bol, eol, ctx, 0); + h = !match_expr_eval(x->u.unary, bol, eol, ctx, 0); break; case GREP_NODE_AND: - if (!match_expr_eval(o, x->u.binary.left, bol, eol, ctx, 0)) + if (!match_expr_eval(x->u.binary.left, bol, eol, ctx, 0)) return 0; - h = match_expr_eval(o, x->u.binary.right, bol, eol, ctx, 0); + h = match_expr_eval(x->u.binary.right, bol, eol, ctx, 0); break; case GREP_NODE_OR: if (!collect_hits) - return (match_expr_eval(o, x->u.binary.left, + return (match_expr_eval(x->u.binary.left, bol, eol, ctx, 0) || - match_expr_eval(o, x->u.binary.right, + match_expr_eval(x->u.binary.right, bol, eol, ctx, 0)); - h = match_expr_eval(o, x->u.binary.left, bol, eol, ctx, 0); + h = match_expr_eval(x->u.binary.left, bol, eol, ctx, 0); x->u.binary.left->hit |= h; - h |= match_expr_eval(o, x->u.binary.right, bol, eol, ctx, 1); + h |= match_expr_eval(x->u.binary.right, bol, eol, ctx, 1); break; default: die("Unexpected node type (internal error) %d", x->node); @@ -420,7 +420,7 @@ static int match_expr(struct grep_opt *opt, char *bol, char *eol, enum grep_context ctx, int collect_hits) { struct grep_expr *x = opt->pattern_expression; - return match_expr_eval(opt, x, bol, eol, ctx, collect_hits); + return match_expr_eval(x, bol, eol, ctx, collect_hits); } static int match_line(struct grep_opt *opt, char *bol, char *eol, @@ -432,7 +432,7 @@ static int match_line(struct grep_opt *opt, char *bol, char *eol, /* we do not call with collect_hits without being extended */ for (p = opt->pattern_list; p; p = p->next) { - if (match_one_pattern(opt, p, bol, eol, ctx)) + if (match_one_pattern(p, bol, eol, ctx)) return 1; } return 0; diff --git a/grep.h b/grep.h index 5102ce335d..d2a8674be2 100644 --- a/grep.h +++ b/grep.h @@ -31,6 +31,7 @@ struct grep_pat { enum grep_header_field field; regex_t regexp; unsigned fixed:1; + unsigned word_regexp:1; }; enum grep_expr_node { From 79212772ce127cc32a67d50eaaa7f1c102ce7d5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Sat, 7 Mar 2009 13:30:27 +0100 Subject: [PATCH 121/654] grep: add pmatch and eflags arguments to match_one_pattern() Push pmatch and eflags to the callers of match_one_pattern(), which allows them to specify regex execution flags and to get the location of a match. Since we only use the first element of the matches array and aren't interested in submatches, no provision is made for callers to provide a larger array. eflags are ignored for fixed patterns, but that's OK, since they only have a meaning in connection with regular expressions containing ^ or $. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- grep.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/grep.c b/grep.c index f45518233f..bdcff7b9e4 100644 --- a/grep.c +++ b/grep.c @@ -309,11 +309,11 @@ static struct { }; static int match_one_pattern(struct grep_pat *p, char *bol, char *eol, - enum grep_context ctx) + enum grep_context ctx, + regmatch_t *pmatch, int eflags) { int hit = 0; int saved_ch = 0; - regmatch_t pmatch[10]; if ((p->token != GREP_PATTERN) && ((p->token == GREP_PATTERN_HEAD) != (ctx == GREP_CONTEXT_HEAD))) @@ -332,14 +332,10 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol, } again: - if (!p->fixed) { - regex_t *exp = &p->regexp; - hit = !regexec(exp, bol, ARRAY_SIZE(pmatch), - pmatch, 0); - } - else { + if (p->fixed) hit = !fixmatch(p->pattern, bol, pmatch); - } + else + hit = !regexec(&p->regexp, bol, 1, pmatch, eflags); if (hit && p->word_regexp) { if ((pmatch[0].rm_so < 0) || @@ -385,10 +381,11 @@ static int match_expr_eval(struct grep_expr *x, char *bol, char *eol, enum grep_context ctx, int collect_hits) { int h = 0; + regmatch_t match; switch (x->node) { case GREP_NODE_ATOM: - h = match_one_pattern(x->u.atom, bol, eol, ctx); + h = match_one_pattern(x->u.atom, bol, eol, ctx, &match, 0); break; case GREP_NODE_NOT: h = !match_expr_eval(x->u.unary, bol, eol, ctx, 0); @@ -427,12 +424,14 @@ static int match_line(struct grep_opt *opt, char *bol, char *eol, enum grep_context ctx, int collect_hits) { struct grep_pat *p; + regmatch_t match; + if (opt->extended) return match_expr(opt, bol, eol, ctx, collect_hits); /* we do not call with collect_hits without being extended */ for (p = opt->pattern_list; p; p = p->next) { - if (match_one_pattern(p, bol, eol, ctx)) + if (match_one_pattern(p, bol, eol, ctx, &match, 0)) return 1; } return 0; From 7e8f59d577e5615ceff06da0d9dde36a63608d53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Sat, 7 Mar 2009 13:32:32 +0100 Subject: [PATCH 122/654] grep: color patterns in output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coloring matches makes them easier to spot in the output. Add two options and two parameters: color.grep (to turn coloring on or off), color.grep.match (to set the color of matches), --color and --no-color (to turn coloring on or off, respectively). The output of external greps is not changed. This patch is based on earlier ones by Nguyễn Thái Ngọc Duy and Thiago Alves. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 9 ++++ Documentation/git-grep.txt | 8 ++++ builtin-grep.c | 32 ++++++++++++++ grep.c | 90 +++++++++++++++++++++++++++++++++----- grep.h | 3 ++ 5 files changed, 130 insertions(+), 12 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index f5152c5038..b75dada9c3 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -548,6 +548,15 @@ color.diff.<slot>:: whitespace errors). The values of these variables may be specified as in color.branch.<slot>. +color.grep:: + When set to `always`, always highlight matches. When `false` (or + `never`), never. When set to `true` or `auto`, use color only + when the output is written to the terminal. Defaults to `false`. + +color.grep.match:: + Use customized color for matches. The value of this variable + may be specified as in color.branch.<slot>. + color.interactive:: When set to `always`, always use colors for interactive prompts and displays (such as those used by "git-add --interactive"). diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 553da6cbb1..fccb82deb4 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -17,6 +17,7 @@ SYNOPSIS [-l | --files-with-matches] [-L | --files-without-match] [-z | --null] [-c | --count] [--all-match] + [--color | --no-color] [-A <post-context>] [-B <pre-context>] [-C <context>] [-f <file>] [-e] <pattern> [--and|--or|--not|(|)|-e <pattern>...] [<tree>...] @@ -105,6 +106,13 @@ OPTIONS Instead of showing every matched line, show the number of lines that match. +--color:: + Show colored matches. + +--no-color:: + Turn off match highlighting, even when the configuration file + gives the default to color output. + -[ABC] <context>:: Show `context` trailing (`A` -- after), or leading (`B` -- before), or both (`C` -- context) lines, and place a diff --git a/builtin-grep.c b/builtin-grep.c index 3f12ba3826..e2c0f01616 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -22,6 +22,24 @@ static int builtin_grep; +static int grep_config(const char *var, const char *value, void *cb) +{ + struct grep_opt *opt = cb; + + if (!strcmp(var, "grep.color") || !strcmp(var, "color.grep")) { + opt->color = git_config_colorbool(var, value, -1); + return 0; + } + if (!strcmp(var, "grep.color.match") || + !strcmp(var, "color.grep.match")) { + if (!value) + return config_error_nonbool(var); + color_parse(value, var, opt->color_match); + return 0; + } + return git_color_default_config(var, value, cb); +} + /* * git grep pathspecs are somewhat different from diff-tree pathspecs; * pathname wildcards are allowed. @@ -536,6 +554,12 @@ int cmd_grep(int argc, const char **argv, const char *prefix) opt.pattern_tail = &opt.pattern_list; opt.regflags = REG_NEWLINE; + strcpy(opt.color_match, GIT_COLOR_RED GIT_COLOR_BOLD); + opt.color = -1; + git_config(grep_config, &opt); + if (opt.color == -1) + opt.color = git_use_color_default; + /* * If there is no -- then the paths must exist in the working * tree. If there is no explicit pattern specified with -e or @@ -732,6 +756,14 @@ int cmd_grep(int argc, const char **argv, const char *prefix) opt.relative = 0; continue; } + if (!strcmp("--color", arg)) { + opt.color = 1; + continue; + } + if (!strcmp("--no-color", arg)) { + opt.color = 0; + continue; + } if (!strcmp("--", arg)) { /* later processing wants to have this at argv[1] */ argv--; diff --git a/grep.c b/grep.c index bdcff7b9e4..cace1c8bcb 100644 --- a/grep.c +++ b/grep.c @@ -253,18 +253,6 @@ static int word_char(char ch) return isalnum(ch) || ch == '_'; } -static void show_line(struct grep_opt *opt, const char *bol, const char *eol, - const char *name, unsigned lno, char sign) -{ - if (opt->null_following_name) - sign = '\0'; - if (opt->pathname) - printf("%s%c", name, sign); - if (opt->linenum) - printf("%d%c", lno, sign); - printf("%.*s\n", (int)(eol-bol), bol); -} - static void show_name(struct grep_opt *opt, const char *name) { printf("%s%c", name, opt->null_following_name ? '\0' : '\n'); @@ -437,6 +425,84 @@ static int match_line(struct grep_opt *opt, char *bol, char *eol, return 0; } +static int match_next_pattern(struct grep_pat *p, char *bol, char *eol, + enum grep_context ctx, + regmatch_t *pmatch, int eflags) +{ + regmatch_t match; + + if (!match_one_pattern(p, bol, eol, ctx, &match, eflags)) + return 0; + if (match.rm_so < 0 || match.rm_eo < 0) + return 0; + if (pmatch->rm_so >= 0 && pmatch->rm_eo >= 0) { + if (match.rm_so > pmatch->rm_so) + return 1; + if (match.rm_so == pmatch->rm_so && match.rm_eo < pmatch->rm_eo) + return 1; + } + pmatch->rm_so = match.rm_so; + pmatch->rm_eo = match.rm_eo; + return 1; +} + +static int next_match(struct grep_opt *opt, char *bol, char *eol, + enum grep_context ctx, regmatch_t *pmatch, int eflags) +{ + struct grep_pat *p; + int hit = 0; + + pmatch->rm_so = pmatch->rm_eo = -1; + if (bol < eol) { + for (p = opt->pattern_list; p; p = p->next) { + switch (p->token) { + case GREP_PATTERN: /* atom */ + case GREP_PATTERN_HEAD: + case GREP_PATTERN_BODY: + hit |= match_next_pattern(p, bol, eol, ctx, + pmatch, eflags); + break; + default: + break; + } + } + } + return hit; +} + +static void show_line(struct grep_opt *opt, char *bol, char *eol, + const char *name, unsigned lno, char sign) +{ + int rest = eol - bol; + + if (opt->null_following_name) + sign = '\0'; + if (opt->pathname) + printf("%s%c", name, sign); + if (opt->linenum) + printf("%d%c", lno, sign); + if (opt->color) { + regmatch_t match; + enum grep_context ctx = GREP_CONTEXT_BODY; + int ch = *eol; + int eflags = 0; + + *eol = '\0'; + while (next_match(opt, bol, eol, ctx, &match, eflags)) { + printf("%.*s%s%.*s%s", + match.rm_so, bol, + opt->color_match, + match.rm_eo - match.rm_so, bol + match.rm_so, + GIT_COLOR_RESET); + bol += match.rm_eo; + rest -= match.rm_eo; + eflags = REG_NOTBOL; + } + *eol = ch; + } + printf("%.*s\n", rest, bol); +} + static int grep_buffer_1(struct grep_opt *opt, const char *name, char *buf, unsigned long size, int collect_hits) { diff --git a/grep.h b/grep.h index d2a8674be2..73b33ab078 100644 --- a/grep.h +++ b/grep.h @@ -1,5 +1,6 @@ #ifndef GREP_H #define GREP_H +#include "color.h" enum grep_pat_token { GREP_PATTERN, @@ -77,6 +78,8 @@ struct grep_opt { unsigned relative:1; unsigned pathname:1; unsigned null_following_name:1; + int color; + char color_match[COLOR_MAXLEN]; int regflags; unsigned pre_context; unsigned post_context; From a94982ef39e1bb9a6f782b5b6ced22e97d6859b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Sat, 7 Mar 2009 13:34:46 +0100 Subject: [PATCH 123/654] grep: add support for coloring with external greps Add the config variable color.grep.external, which can be used to switch on coloring of external greps. To enable auto coloring with GNU grep, one needs to set color.grep.external to --color=always to defeat the pager started by git grep. The value of the config variable will be passed to the external grep only if it would colorize internal grep's output, so automatic terminal detected works. The default is to not pass any option, because the external grep command could be a program without color support. Also set the environment variables GREP_COLOR and GREP_COLORS to pass the configured color for matches to the external grep. This works with GNU grep; other variables could be added as needed. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 12 +++++++++++- builtin-grep.c | 36 ++++++++++++++++++++++++++++++++++++ grep.h | 1 + 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index b75dada9c3..4d42bff718 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -553,9 +553,19 @@ color.grep:: `never`), never. When set to `true` or `auto`, use color only when the output is written to the terminal. Defaults to `false`. +color.grep.external:: + The string value of this variable is passed to an external 'grep' + command as a command line option if match highlighting is turned + on. If set to an empty string, no option is passed at all, + turning off coloring for external 'grep' calls; this is the default. + For GNU grep, set it to `--color=always` to highlight matches even + when a pager is used. + color.grep.match:: Use customized color for matches. The value of this variable - may be specified as in color.branch.<slot>. + may be specified as in color.branch.<slot>. It is passed using + the environment variables 'GREP_COLOR' and 'GREP_COLORS' when + calling an external 'grep'. color.interactive:: When set to `always`, always use colors for interactive prompts diff --git a/builtin-grep.c b/builtin-grep.c index e2c0f01616..9e7e766a49 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -30,6 +30,10 @@ static int grep_config(const char *var, const char *value, void *cb) opt->color = git_config_colorbool(var, value, -1); return 0; } + if (!strcmp(var, "grep.color.external") || + !strcmp(var, "color.grep.external")) { + return git_config_string(&(opt->color_external), var, value); + } if (!strcmp(var, "grep.color.match") || !strcmp(var, "color.grep.match")) { if (!value) @@ -287,6 +291,21 @@ static int flush_grep(struct grep_opt *opt, return status; } +static void grep_add_color(struct strbuf *sb, const char *escape_seq) +{ + size_t orig_len = sb->len; + + while (*escape_seq) { + if (*escape_seq == 'm') + strbuf_addch(sb, ';'); + else if (*escape_seq != '\033' && *escape_seq != '[') + strbuf_addch(sb, *escape_seq); + escape_seq++; + } + if (sb->len > orig_len && sb->buf[sb->len - 1] == ';') + strbuf_setlen(sb, sb->len - 1); +} + static int external_grep(struct grep_opt *opt, const char **paths, int cached) { int i, nr, argc, hit, len, status; @@ -357,6 +376,23 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached) push_arg("-e"); push_arg(p->pattern); } + if (opt->color) { + struct strbuf sb = STRBUF_INIT; + + grep_add_color(&sb, opt->color_match); + setenv("GREP_COLOR", sb.buf, 1); + + strbuf_reset(&sb); + strbuf_addstr(&sb, "mt="); + grep_add_color(&sb, opt->color_match); + strbuf_addstr(&sb, ":sl=:cx=:fn=:ln=:bn=:se="); + setenv("GREP_COLORS", sb.buf, 1); + + strbuf_release(&sb); + + if (opt->color_external && strlen(opt->color_external) > 0) + push_arg(opt->color_external); + } hit = 0; argc = nr; diff --git a/grep.h b/grep.h index 73b33ab078..a67005de62 100644 --- a/grep.h +++ b/grep.h @@ -80,6 +80,7 @@ struct grep_opt { unsigned null_following_name:1; int color; char color_match[COLOR_MAXLEN]; + const char *color_external; int regflags; unsigned pre_context; unsigned post_context; From 689f03964360114bc1139d82b1f6a0d7b897bbf0 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow <barkalow@iabervon.org> Date: Thu, 5 Mar 2009 23:56:16 -0500 Subject: [PATCH 124/654] Make clone parse the default refspec with the normal code Instead of creating a refspec by hand, go through the refspec parsing code, so that changes in the refspec storage will be accounted for. Signed-off-by: Daniel Barkalow <barkalow@iabervon.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-clone.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/builtin-clone.c b/builtin-clone.c index c338910b1c..06b5a7fc39 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -378,7 +378,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix) struct transport *transport = NULL; char *src_ref_prefix = "refs/heads/"; - struct refspec refspec; + struct refspec *refspec; + const char *fetch_pattern; junk_pid = getpid(); @@ -487,8 +488,14 @@ int cmd_clone(int argc, const char **argv, const char *prefix) strbuf_addf(&branch_top, "refs/remotes/%s/", option_origin); } + strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf); + if (option_mirror || !option_bare) { /* Configure the remote */ + strbuf_addf(&key, "remote.%s.fetch", option_origin); + git_config_set_multivar(key.buf, value.buf, "^$", 0); + strbuf_reset(&key); + if (option_mirror) { strbuf_addf(&key, "remote.%s.mirror", option_origin); git_config_set(key.buf, "true"); @@ -497,19 +504,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix) strbuf_addf(&key, "remote.%s.url", option_origin); git_config_set(key.buf, repo); - strbuf_reset(&key); - - strbuf_addf(&key, "remote.%s.fetch", option_origin); - strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf); - git_config_set_multivar(key.buf, value.buf, "^$", 0); strbuf_reset(&key); - strbuf_reset(&value); } - refspec.force = 0; - refspec.pattern = 1; - refspec.src = src_ref_prefix; - refspec.dst = branch_top.buf; + fetch_pattern = value.buf; + refspec = parse_fetch_refspec(1, &fetch_pattern); + + strbuf_reset(&value); if (path && !is_bundle) refs = clone_local(path, git_dir); @@ -543,7 +544,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (refs) { clear_extra_refs(); - mapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf); + mapped_refs = write_remote_refs(refs, refspec, reflog_msg.buf); head_points_at = locate_head(refs, mapped_refs, &remote_head); } From a3c8423901ec4996369b137b46354ddf1cfc0e0e Mon Sep 17 00:00:00 2001 From: Daniel Barkalow <barkalow@iabervon.org> Date: Sat, 7 Mar 2009 01:11:29 -0500 Subject: [PATCH 125/654] Use a single function to match names against patterns This will help when the matching changes. Signed-off-by: Daniel Barkalow <barkalow@iabervon.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- remote.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/remote.c b/remote.c index d7079c6dd8..2816723bb9 100644 --- a/remote.c +++ b/remote.c @@ -719,6 +719,12 @@ int remote_has_url(struct remote *remote, const char *url) return 0; } +static int match_name_with_pattern(const char *key, const char *name) +{ + int ret = !prefixcmp(key, name); + return ret; +} + int remote_find_tracking(struct remote *remote, struct refspec *refspec) { int find_src = refspec->src == NULL; @@ -742,7 +748,7 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec) if (!fetch->dst) continue; if (fetch->pattern) { - if (!prefixcmp(needle, key)) { + if (match_name_with_pattern(key, needle)) { *result = xmalloc(strlen(value) + strlen(needle) - strlen(key) + 1); @@ -1020,7 +1026,7 @@ static const struct refspec *check_pattern_match(const struct refspec *rs, continue; } - if (rs[i].pattern && !prefixcmp(src->name, rs[i].src)) + if (rs[i].pattern && match_name_with_pattern(rs[i].src, src->name)) return rs + i; } if (matching_refs != -1) @@ -1160,7 +1166,7 @@ static struct ref *get_expanded_map(const struct ref *remote_refs, for (ref = remote_refs; ref; ref = ref->next) { if (strchr(ref->name, '^')) continue; /* a dereference item */ - if (!prefixcmp(ref->name, refspec->src)) { + if (match_name_with_pattern(refspec->src, ref->name)) { const char *match; struct ref *cpy = copy_ref(ref); match = ref->name + remote_prefix_len; From e928213fb40c106650dca2632b5e830cfaffb86a Mon Sep 17 00:00:00 2001 From: Daniel Barkalow <barkalow@iabervon.org> Date: Sat, 7 Mar 2009 01:11:34 -0500 Subject: [PATCH 126/654] Use the matching function to generate the match results This puts all of the interpretation of the pattern representation in a single function for easy manipulation. Signed-off-by: Daniel Barkalow <barkalow@iabervon.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- remote.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/remote.c b/remote.c index 2816723bb9..01b8f91c5b 100644 --- a/remote.c +++ b/remote.c @@ -719,9 +719,19 @@ int remote_has_url(struct remote *remote, const char *url) return 0; } -static int match_name_with_pattern(const char *key, const char *name) +static int match_name_with_pattern(const char *key, const char *name, + const char *value, char **result) { - int ret = !prefixcmp(key, name); + size_t klen = strlen(key); + int ret = !strncmp(key, name, klen); + if (ret && value) { + size_t vlen = strlen(value); + *result = xmalloc(vlen + + strlen(name) - + klen + 1); + strcpy(*result, value); + strcpy(*result + vlen, name + klen); + } return ret; } @@ -748,13 +758,7 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec) if (!fetch->dst) continue; if (fetch->pattern) { - if (match_name_with_pattern(key, needle)) { - *result = xmalloc(strlen(value) + - strlen(needle) - - strlen(key) + 1); - strcpy(*result, value); - strcpy(*result + strlen(value), - needle + strlen(key)); + if (match_name_with_pattern(key, needle, value, result)) { refspec->force = fetch->force; return 0; } @@ -1026,7 +1030,8 @@ static const struct refspec *check_pattern_match(const struct refspec *rs, continue; } - if (rs[i].pattern && match_name_with_pattern(rs[i].src, src->name)) + if (rs[i].pattern && match_name_with_pattern(rs[i].src, src->name, + NULL, NULL)) return rs + i; } if (matching_refs != -1) @@ -1080,11 +1085,9 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, } else { const char *dst_side = pat->dst ? pat->dst : pat->src; - dst_name = xmalloc(strlen(dst_side) + - strlen(src->name) - - strlen(pat->src) + 2); - strcpy(dst_name, dst_side); - strcat(dst_name, src->name + strlen(pat->src)); + if (!match_name_with_pattern(pat->src, src->name, + dst_side, &dst_name)) + die("Didn't think it matches any more"); } dst_peer = find_ref_by_name(dst, dst_name); if (dst_peer) { @@ -1160,19 +1163,17 @@ static struct ref *get_expanded_map(const struct ref *remote_refs, struct ref *ret = NULL; struct ref **tail = &ret; - int remote_prefix_len = strlen(refspec->src); - int local_prefix_len = strlen(refspec->dst); + char *expn_name; for (ref = remote_refs; ref; ref = ref->next) { if (strchr(ref->name, '^')) continue; /* a dereference item */ - if (match_name_with_pattern(refspec->src, ref->name)) { - const char *match; + if (match_name_with_pattern(refspec->src, ref->name, + refspec->dst, &expn_name)) { struct ref *cpy = copy_ref(ref); - match = ref->name + remote_prefix_len; - cpy->peer_ref = alloc_ref_with_prefix(refspec->dst, - local_prefix_len, match); + cpy->peer_ref = alloc_ref(expn_name); + free(expn_name); if (refspec->force) cpy->peer_ref->force = 1; *tail = cpy; From 08fbdb30438fd7087c5abe15840a22fe21094515 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow <barkalow@iabervon.org> Date: Sat, 7 Mar 2009 01:11:36 -0500 Subject: [PATCH 127/654] Keep '*' in pattern refspecs In order to do anything more capable with refspecs, the first step is to keep the entire input. Additionally, validate patterns by checking for the ref matching the rules for a pattern as given by check_ref_format(). This requires a slight change to check_ref_format() to make it enforce the requirement that the '*' immediately follow a '/'. Signed-off-by: Daniel Barkalow <barkalow@iabervon.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- refs.c | 4 +--- remote.c | 33 ++++++++++++++++++--------------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/refs.c b/refs.c index 6eb5f53846..a50ba79270 100644 --- a/refs.c +++ b/refs.c @@ -718,9 +718,7 @@ int check_ref_format(const char *ref) while ((ch = *cp++) != 0) { bad_type = bad_ref_char(ch); if (bad_type) { - return (bad_type == 2 && !*cp) - ? CHECK_REF_FORMAT_WILDCARD - : CHECK_REF_FORMAT_ERROR; + return CHECK_REF_FORMAT_ERROR; } if (ch == '/') break; diff --git a/remote.c b/remote.c index 01b8f91c5b..d596a48651 100644 --- a/remote.c +++ b/remote.c @@ -10,8 +10,8 @@ static struct refspec s_tag_refspec = { 0, 1, 0, - "refs/tags/", - "refs/tags/" + "refs/tags/*", + "refs/tags/*" }; const struct refspec *tag_refspec = &s_tag_refspec; @@ -451,16 +451,11 @@ static void read_config(void) */ static int verify_refname(char *name, int is_glob) { - int result, len = -1; + int result; - if (is_glob) { - len = strlen(name); - assert(name[len - 1] == '/'); - name[len - 1] = '\0'; - } result = check_ref_format(name); - if (is_glob) - name[len - 1] = '/'; + if (is_glob && result == CHECK_REF_FORMAT_WILDCARD) + result = CHECK_REF_FORMAT_OK; return result; } @@ -517,7 +512,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp if (rhs) { size_t rlen = strlen(++rhs); is_glob = (2 <= rlen && !strcmp(rhs + rlen - 2, "/*")); - rs[i].dst = xstrndup(rhs, rlen - is_glob); + rs[i].dst = xstrndup(rhs, rlen); } llen = (rhs ? (rhs - lhs - 1) : strlen(lhs)); @@ -525,7 +520,6 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp if ((rhs && !is_glob) || (!rhs && fetch)) goto invalid; is_glob = 1; - llen--; } else if (rhs && is_glob) { goto invalid; } @@ -722,10 +716,19 @@ int remote_has_url(struct remote *remote, const char *url) static int match_name_with_pattern(const char *key, const char *name, const char *value, char **result) { - size_t klen = strlen(key); - int ret = !strncmp(key, name, klen); + const char *kstar = strchr(key, '*'); + size_t klen; + int ret; + if (!kstar) + die("Key '%s' of pattern had no '*'", key); + klen = kstar - key; + ret = !strncmp(key, name, klen); if (ret && value) { - size_t vlen = strlen(value); + const char *vstar = strchr(value, '*'); + size_t vlen; + if (!vstar) + die("Value '%s' of pattern has no '*'", value); + vlen = vstar - value; *result = xmalloc(vlen + strlen(name) - klen + 1); From abd2bde78bd994166900290434a2048e660dabed Mon Sep 17 00:00:00 2001 From: Daniel Barkalow <barkalow@iabervon.org> Date: Sat, 7 Mar 2009 01:11:39 -0500 Subject: [PATCH 128/654] Support '*' in the middle of a refspec In order to keep the requirements strict, each * has to be a full path component, and there may only be one * per side. This requirement is enforced entirely by check_ref_format(); the matching implementation will substitute the whatever matches the * in the lhs for the * in the rhs. Signed-off-by: Daniel Barkalow <barkalow@iabervon.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- refs.c | 11 +++++++---- remote.c | 24 +++++++++++++++++------- t/t5511-refspec.sh | 12 ++++++++++++ 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/refs.c b/refs.c index a50ba79270..fef7c9f26d 100644 --- a/refs.c +++ b/refs.c @@ -694,6 +694,7 @@ static inline int bad_ref_char(int ch) int check_ref_format(const char *ref) { int ch, level, bad_type; + int ret = CHECK_REF_FORMAT_OK; const char *cp = ref; level = 0; @@ -709,9 +710,11 @@ int check_ref_format(const char *ref) return CHECK_REF_FORMAT_ERROR; bad_type = bad_ref_char(ch); if (bad_type) { - return (bad_type == 2 && !*cp) - ? CHECK_REF_FORMAT_WILDCARD - : CHECK_REF_FORMAT_ERROR; + if (bad_type == 2 && (!*cp || *cp == '/') && + ret == CHECK_REF_FORMAT_OK) + ret = CHECK_REF_FORMAT_WILDCARD; + else + return CHECK_REF_FORMAT_ERROR; } /* scan the rest of the path component */ @@ -729,7 +732,7 @@ int check_ref_format(const char *ref) if (!ch) { if (level < 2) return CHECK_REF_FORMAT_ONELEVEL; - return CHECK_REF_FORMAT_OK; + return ret; } } } diff --git a/remote.c b/remote.c index d596a48651..90203e2fe1 100644 --- a/remote.c +++ b/remote.c @@ -511,12 +511,12 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp if (rhs) { size_t rlen = strlen(++rhs); - is_glob = (2 <= rlen && !strcmp(rhs + rlen - 2, "/*")); + is_glob = (1 <= rlen && strchr(rhs, '*')); rs[i].dst = xstrndup(rhs, rlen); } llen = (rhs ? (rhs - lhs - 1) : strlen(lhs)); - if (2 <= llen && !memcmp(lhs + llen - 2, "/*", 2)) { + if (1 <= llen && memchr(lhs, '*', llen)) { if ((rhs && !is_glob) || (!rhs && fetch)) goto invalid; is_glob = 1; @@ -718,22 +718,32 @@ static int match_name_with_pattern(const char *key, const char *name, { const char *kstar = strchr(key, '*'); size_t klen; + size_t ksuffixlen; + size_t namelen; int ret; if (!kstar) die("Key '%s' of pattern had no '*'", key); klen = kstar - key; - ret = !strncmp(key, name, klen); + ksuffixlen = strlen(kstar + 1); + namelen = strlen(name); + ret = !strncmp(name, key, klen) && namelen >= klen + ksuffixlen && + !memcmp(name + namelen - ksuffixlen, kstar + 1, ksuffixlen); if (ret && value) { const char *vstar = strchr(value, '*'); size_t vlen; + size_t vsuffixlen; if (!vstar) die("Value '%s' of pattern has no '*'", value); vlen = vstar - value; - *result = xmalloc(vlen + + vsuffixlen = strlen(vstar + 1); + *result = xmalloc(vlen + vsuffixlen + strlen(name) - - klen + 1); - strcpy(*result, value); - strcpy(*result + vlen, name + klen); + klen - ksuffixlen + 1); + strncpy(*result, value, vlen); + strncpy(*result + vlen, + name + klen, namelen - klen - ksuffixlen); + strcpy(*result + vlen + namelen - klen - ksuffixlen, + vstar + 1); } return ret; } diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh index 22ba380034..c28932216b 100755 --- a/t/t5511-refspec.sh +++ b/t/t5511-refspec.sh @@ -72,4 +72,16 @@ test_refspec fetch ':refs/remotes/frotz/HEAD-to-me' test_refspec push ':refs/remotes/frotz/delete me' invalid test_refspec fetch ':refs/remotes/frotz/HEAD to me' invalid +test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid +test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid + +test_refspec fetch 'refs/heads*/for-linus:refs/remotes/mine/*' invalid +test_refspec push 'refs/heads*/for-linus:refs/remotes/mine/*' invalid + +test_refspec fetch 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid +test_refspec push 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid + +test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*' +test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*' + test_done From d5e31235f2df3d54930c79f46fb7a7e2394899d0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Sat, 7 Mar 2009 15:37:18 +0100 Subject: [PATCH 129/654] Brown paper bag fix for MinGW 64-bit stat When overriding the identifier "stat" so that "struct stat" will be substituted with "struct _stati64" everywhere, I tried to fix the calls to the _function_ stat(), too, but I forgot to change the earlier attempt "stat64" to "_stati64" there. So, the stat() calls were overridden by calls to _stati64() instead. Unfortunately, there is a function _stati64() so that I missed that calls to stat() were not actually overridden by calls to mingw_lstat(), but t4200-rerere.sh showed the error. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Acked-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- compat/mingw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index cb9c4d4dd5..6e24686442 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -170,7 +170,7 @@ int mingw_lstat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define stat64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_lstat(x,y) int mingw_utime(const char *file_name, const struct utimbuf *times); #define utime mingw_utime From 8a3b25da8cdd7f3aa75f18d3245ce83aca90bb1a Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Sat, 7 Mar 2009 20:22:07 -0500 Subject: [PATCH 130/654] t3000: use test_cmp instead of diff These ancient tests predate test_cmp. While we're at it, let's switch to our usual "expected before actual" order of arguments; this makes the diff output "here's what is changed from expected" instead of the reverse. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t3000-ls-files-others.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh index bc0a351392..36eee0f8ae 100755 --- a/t/t3000-ls-files-others.sh +++ b/t/t3000-ls-files-others.sh @@ -42,7 +42,7 @@ test_expect_success \ test_expect_success \ 'git ls-files --others should pick up symlinks.' \ - 'diff output expected1' + 'test_cmp expected1 output' test_expect_success \ 'git ls-files --others --directory to show output.' \ @@ -51,6 +51,6 @@ test_expect_success \ test_expect_success \ 'git ls-files --others --directory should not get confused.' \ - 'diff output expected2' + 'test_cmp expected2 output' test_done From 2fb6d6d6dd1033bfe82d6d327ac270f9cf8943cd Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Sat, 7 Mar 2009 20:27:22 -0500 Subject: [PATCH 131/654] ls-files: fix broken --no-empty-directory Commit ce8e880 converted ls-files to use parseopt; the --no-empty-directory option was converted as an OPT_BIT for "empty-directory" to set the DIR_HIDE_EMPTY_DIRECTORY flag. However, that makes it do the opposite of what it should: --empty-directory would hide, but --no-empty-directory would turn off hiding. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-ls-files.c | 4 ++-- t/t3000-ls-files-others.sh | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/builtin-ls-files.c b/builtin-ls-files.c index 1742c0f80d..437c366c9e 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -454,8 +454,8 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) OPT_BIT(0, "directory", &dir.flags, "show 'other' directories' name only", DIR_SHOW_OTHER_DIRECTORIES), - OPT_BIT(0, "empty-directory", &dir.flags, - "list empty directories", + OPT_BIT(0, "no-empty-directory", &dir.flags, + "don't show empty directories", DIR_HIDE_EMPTY_DIRECTORIES), OPT_BOOLEAN('u', "unmerged", &show_unmerged, "show unmerged files in the output"), diff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh index 36eee0f8ae..379d963cea 100755 --- a/t/t3000-ls-files-others.sh +++ b/t/t3000-ls-files-others.sh @@ -13,12 +13,13 @@ filesystem. path2/file2 - a file in a directory path3-junk - a file to confuse things path3/file3 - a file in a directory + path4 - an empty directory ' . ./test-lib.sh date >path0 ln -s xyzzy path1 -mkdir path2 path3 +mkdir path2 path3 path4 date >path2/file2 date >path2-junk date >path3/file3 @@ -28,6 +29,7 @@ git update-index --add path3-junk path3/file3 cat >expected1 <<EOF expected1 expected2 +expected3 output path0 path1 @@ -35,6 +37,8 @@ path2-junk path2/file2 EOF sed -e 's|path2/file2|path2/|' <expected1 >expected2 +cat <expected2 >expected3 +echo path4/ >>expected2 test_expect_success \ 'git ls-files --others to show output.' \ @@ -53,4 +57,12 @@ test_expect_success \ 'git ls-files --others --directory should not get confused.' \ 'test_cmp expected2 output' +test_expect_success \ + 'git ls-files --others --directory --no-empty-directory to show output.' \ + 'git ls-files --others --directory --no-empty-directory >output' + +test_expect_success \ + '--no-empty-directory hides empty directory' \ + 'test_cmp expected3 output' + test_done From 52d5c3b5b22b6a672ace19f631768a63bb6a2250 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Thu, 5 Mar 2009 23:39:31 -0500 Subject: [PATCH 132/654] bash completion: fix completion issues with fetch, pull, and push Sverre Rabbelier noticed a completion issue with push: $ git push ori<tab> git push origin $ git push -f ori<tab> git push -f origin/ Markus Heidelberg pointed out that the issue extends to fetch and pull. The reason is that the current code naively assumes that if COMP_CWORD=2, it should complete a remote name, otherwise it should complete a refspec. This assumption fails if there are any --options. This patch fixes that issue by instead scanning COMP_CWORDS to see if the remote has been completed yet (we now assume the first non-dashed argument is the remote). The new logic is factored into a function, shared by fetch, pull, and push. The new function also properly handles '.' as the remote. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 109 ++++++++++++++----------- 1 file changed, 60 insertions(+), 49 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index f234c34304..e8c4be2e81 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -387,6 +387,63 @@ __git_complete_revlist () esac } +__git_complete_remote_or_refspec () +{ + local cmd="${COMP_WORDS[1]}" + local cur="${COMP_WORDS[COMP_CWORD]}" + local i c=2 remote="" pfx="" lhs=1 + while [ $c -lt $COMP_CWORD ]; do + i="${COMP_WORDS[c]}" + case "$i" in + -*) ;; + *) remote="$i"; break ;; + esac + c=$((++c)) + done + if [ -z "$remote" ]; then + __gitcomp "$(__git_remotes)" + return + fi + [ "$remote" = "." ] && remote= + case "$cur" in + *:*) + case "$COMP_WORDBREAKS" in + *:*) : great ;; + *) pfx="${cur%%:*}:" ;; + esac + cur="${cur#*:}" + lhs=0 + ;; + +*) + pfx="+" + cur="${cur#+}" + ;; + esac + case "$cmd" in + fetch) + if [ $lhs = 1 ]; then + __gitcomp "$(__git_refs2 "$remote")" "$pfx" "$cur" + else + __gitcomp "$(__git_refs)" "$pfx" "$cur" + fi + ;; + pull) + if [ $lhs = 1 ]; then + __gitcomp "$(__git_refs "$remote")" "$pfx" "$cur" + else + __gitcomp "$(__git_refs)" "$pfx" "$cur" + fi + ;; + push) + if [ $lhs = 1 ]; then + __gitcomp "$(__git_refs)" "$pfx" "$cur" + else + __gitcomp "$(__git_refs "$remote")" "$pfx" "$cur" + fi + ;; + esac +} + __git_all_commands () { if [ -n "${__git_all_commandlist-}" ]; then @@ -832,25 +889,7 @@ _git_diff () _git_fetch () { - local cur="${COMP_WORDS[COMP_CWORD]}" - - if [ "$COMP_CWORD" = 2 ]; then - __gitcomp "$(__git_remotes)" - else - case "$cur" in - *:*) - local pfx="" - case "$COMP_WORDBREAKS" in - *:*) : great ;; - *) pfx="${cur%%:*}:" ;; - esac - __gitcomp "$(__git_refs)" "$pfx" "${cur#*:}" - ;; - *) - __gitcomp "$(__git_refs2 "${COMP_WORDS[2]}")" - ;; - esac - fi + __git_complete_remote_or_refspec } _git_format_patch () @@ -1120,40 +1159,12 @@ _git_name_rev () _git_pull () { - local cur="${COMP_WORDS[COMP_CWORD]}" - - if [ "$COMP_CWORD" = 2 ]; then - __gitcomp "$(__git_remotes)" - else - __gitcomp "$(__git_refs "${COMP_WORDS[2]}")" - fi + __git_complete_remote_or_refspec } _git_push () { - local cur="${COMP_WORDS[COMP_CWORD]}" - - if [ "$COMP_CWORD" = 2 ]; then - __gitcomp "$(__git_remotes)" - else - case "$cur" in - *:*) - local pfx="" - case "$COMP_WORDBREAKS" in - *:*) : great ;; - *) pfx="${cur%%:*}:" ;; - esac - - __gitcomp "$(__git_refs "${COMP_WORDS[2]}")" "$pfx" "${cur#*:}" - ;; - +*) - __gitcomp "$(__git_refs)" + "${cur#+}" - ;; - *) - __gitcomp "$(__git_refs)" - ;; - esac - fi + __git_complete_remote_or_refspec } _git_rebase () From 3c7b480a1cf6e1a1c73b4edde5d8cf0ac0c8111c Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Fri, 6 Mar 2009 11:30:44 -0500 Subject: [PATCH 133/654] bash completion: refactor --strategy completion The code to complete --strategy was duplicated between _git_rebase and _git_merge, and is about to gain a third caller (_git_pull). This patch factors it into its own function. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 38 ++++++++++++++------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index e8c4be2e81..056e43e4ad 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -444,6 +444,23 @@ __git_complete_remote_or_refspec () esac } +__git_complete_strategy () +{ + case "${COMP_WORDS[COMP_CWORD-1]}" in + -s|--strategy) + __gitcomp "$(__git_merge_strategies)" + return 0 + esac + local cur="${COMP_WORDS[COMP_CWORD]}" + case "$cur" in + --strategy=*) + __gitcomp "$(__git_merge_strategies)" "" "${cur##--strategy=}" + return 0 + ;; + esac + return 1 +} + __git_all_commands () { if [ -n "${__git_all_commandlist-}" ]; then @@ -1095,17 +1112,10 @@ _git_log () _git_merge () { + __git_complete_strategy && return + local cur="${COMP_WORDS[COMP_CWORD]}" - case "${COMP_WORDS[COMP_CWORD-1]}" in - -s|--strategy) - __gitcomp "$(__git_merge_strategies)" - return - esac case "$cur" in - --strategy=*) - __gitcomp "$(__git_merge_strategies)" "" "${cur##--strategy=}" - return - ;; --*) __gitcomp " --no-commit --no-stat --log --no-log --squash --strategy @@ -1174,16 +1184,8 @@ _git_rebase () __gitcomp "--continue --skip --abort" return fi - case "${COMP_WORDS[COMP_CWORD-1]}" in - -s|--strategy) - __gitcomp "$(__git_merge_strategies)" - return - esac + __git_complete_strategy && return case "$cur" in - --strategy=*) - __gitcomp "$(__git_merge_strategies)" "" "${cur##--strategy=}" - return - ;; --*) __gitcomp "--onto --merge --strategy --interactive" return From 0a4e14727f53ba2e8263622ba5de917b2f9d1575 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Thu, 5 Mar 2009 23:39:33 -0500 Subject: [PATCH 134/654] bash completion: teach fetch, pull, and push to complete their options fetch, pull, and push didn't know their options. They do now. merge's options are factored into a variable so they can be shared between _git_merge and _git_pull Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 61 +++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 056e43e4ad..271b911f7a 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -391,10 +391,11 @@ __git_complete_remote_or_refspec () { local cmd="${COMP_WORDS[1]}" local cur="${COMP_WORDS[COMP_CWORD]}" - local i c=2 remote="" pfx="" lhs=1 + local i c=2 remote="" pfx="" lhs=1 no_complete_refspec=0 while [ $c -lt $COMP_CWORD ]; do i="${COMP_WORDS[c]}" case "$i" in + --all|--mirror) [ "$cmd" = "push" ] && no_complete_refspec=1 ;; -*) ;; *) remote="$i"; break ;; esac @@ -404,6 +405,10 @@ __git_complete_remote_or_refspec () __gitcomp "$(__git_remotes)" return fi + if [ $no_complete_refspec = 1 ]; then + COMPREPLY=() + return + fi [ "$remote" = "." ] && remote= case "$cur" in *:*) @@ -904,8 +909,20 @@ _git_diff () __git_complete_file } +__git_fetch_options=" + --quiet --verbose --append --upload-pack --force --keep --depth= + --tags --no-tags +" + _git_fetch () { + local cur="${COMP_WORDS[COMP_CWORD]}" + case "$cur" in + --*) + __gitcomp "$__git_fetch_options" + return + ;; + esac __git_complete_remote_or_refspec } @@ -1110,6 +1127,11 @@ _git_log () __git_complete_revlist } +__git_merge_options=" + --no-commit --no-stat --log --no-log --squash --strategy + --commit --stat --no-squash --ff --no-ff +" + _git_merge () { __git_complete_strategy && return @@ -1117,10 +1139,7 @@ _git_merge () local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) - __gitcomp " - --no-commit --no-stat --log --no-log --squash --strategy - --commit --stat --no-squash --ff --no-ff - " + __gitcomp "$__git_merge_options" return esac __gitcomp "$(__git_refs)" @@ -1169,11 +1188,43 @@ _git_name_rev () _git_pull () { + __git_complete_strategy && return + + local cur="${COMP_WORDS[COMP_CWORD]}" + case "$cur" in + --*) + __gitcomp " + --rebase --no-rebase + $__git_merge_options + $__git_fetch_options + " + return + ;; + esac __git_complete_remote_or_refspec } _git_push () { + local cur="${COMP_WORDS[COMP_CWORD]}" + case "${COMP_WORDS[COMP_CWORD-1]}" in + --repo) + __gitcomp "$(__git_remotes)" + return + esac + case "$cur" in + --repo=*) + __gitcomp "$(__git_remotes)" "" "${cur##--repo=}" + return + ;; + --*) + __gitcomp " + --all --mirror --tags --dry-run --force --verbose + --receive-pack= --repo= + " + return + ;; + esac __git_complete_remote_or_refspec } From c06ff4908bf9ad8bf2448439a3574321c9399b17 Mon Sep 17 00:00:00 2001 From: Kjetil Barvik <barvik@broadpark.no> Date: Wed, 4 Mar 2009 18:47:40 +0100 Subject: [PATCH 135/654] Record ns-timestamps if possible, but do not use it without USE_NSEC Traditionally, the lack of USE_NSEC meant "do not record nor use the nanosecond resolution part of the file timestamps". To avoid problems on filesystems that lose the ns part when the metadata is flushed to the disk and then later read back in, disabling USE_NSEC has been a good idea in general. If you are on a filesystem without such an issue, it does not hurt to read and store them in the cached stat data in the index entries even if your git is compiled without USE_NSEC. The index left with such a version of git can be read by git compiled with USE_NSEC and it can make use of the nanosecond part to optimize the check to see if the path on the filesystem hsa been modified since we last looked at. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 8 ++++++++ builtin-fetch-pack.c | 4 +--- git-compat-util.h | 9 +++++++++ read-cache.c | 29 ++++------------------------- unpack-trees.c | 2 -- 5 files changed, 22 insertions(+), 30 deletions(-) diff --git a/Makefile b/Makefile index 27b9569746..65b5b8a63f 100644 --- a/Makefile +++ b/Makefile @@ -126,6 +126,9 @@ all:: # randomly break unless your underlying filesystem supports those sub-second # times (my ext3 doesn't). # +# Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec" +# available. This automatically turns USE_NSEC off. +# # Define USE_STDEV below if you want git to care about the underlying device # change being considered an inode change from the update-index perspective. # @@ -737,6 +740,7 @@ ifeq ($(uname_S),AIX) NO_MEMMEM = YesPlease NO_MKDTEMP = YesPlease NO_STRLCPY = YesPlease + NO_NSEC = YesPlease FREAD_READS_DIRECTORIES = UnfortunatelyYes INTERNAL_QSORT = UnfortunatelyYes NEEDS_LIBICONV=YesPlease @@ -802,6 +806,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) RUNTIME_PREFIX = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease + NO_NSEC = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" @@ -923,6 +928,9 @@ endif ifdef NO_ST_BLOCKS_IN_STRUCT_STAT BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT endif +ifdef NO_NSEC + BASIC_CFLAGS += -DNO_NSEC +endif ifdef NO_C99_FORMAT BASIC_CFLAGS += -DNO_C99_FORMAT endif diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 3b210c7fdf..59b0b0a796 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -801,9 +801,7 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args, int fd; mtime.sec = st.st_mtime; -#ifdef USE_NSEC - mtime.nsec = st.st_mtim.tv_nsec; -#endif + mtime.nsec = ST_MTIME_NSEC(st); if (stat(shallow, &st)) { if (mtime.sec) die("shallow file was removed during fetch"); diff --git a/git-compat-util.h b/git-compat-util.h index 079cbe9440..9b495dcad8 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -384,4 +384,13 @@ void git_qsort(void *base, size_t nmemb, size_t size, # define FORCE_DIR_SET_GID 0 #endif +#ifdef NO_NSEC +#undef USE_NSEC +#define ST_CTIME_NSEC(st) 0 +#define ST_MTIME_NSEC(st) 0 +#else +#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctim.tv_nsec)) +#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtim.tv_nsec)) +#endif + #endif diff --git a/read-cache.c b/read-cache.c index 91f1d03c09..b819abbd00 100644 --- a/read-cache.c +++ b/read-cache.c @@ -69,13 +69,8 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st) { ce->ce_ctime.sec = (unsigned int)st->st_ctime; ce->ce_mtime.sec = (unsigned int)st->st_mtime; -#ifdef USE_NSEC - ce->ce_ctime.nsec = (unsigned int)st->st_ctim.tv_nsec; - ce->ce_mtime.nsec = (unsigned int)st->st_mtim.tv_nsec; -#else - ce->ce_ctime.nsec = 0; - ce->ce_mtime.nsec = 0; -#endif + ce->ce_ctime.nsec = ST_CTIME_NSEC(*st); + ce->ce_mtime.nsec = ST_MTIME_NSEC(*st); ce->ce_dev = st->st_dev; ce->ce_ino = st->st_ino; ce->ce_uid = st->st_uid; @@ -1183,13 +1178,8 @@ static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_en ce->ce_ctime.sec = ntohl(ondisk->ctime.sec); ce->ce_mtime.sec = ntohl(ondisk->mtime.sec); -#ifdef USE_NSEC ce->ce_ctime.nsec = ntohl(ondisk->ctime.nsec); ce->ce_mtime.nsec = ntohl(ondisk->mtime.nsec); -#else - ce->ce_ctime.nsec = 0; - ce->ce_mtime.nsec = 0; -#endif ce->ce_dev = ntohl(ondisk->dev); ce->ce_ino = ntohl(ondisk->ino); ce->ce_mode = ntohl(ondisk->mode); @@ -1309,11 +1299,7 @@ int read_index_from(struct index_state *istate, const char *path) dst_offset += ce_size(ce); } istate->timestamp.sec = st.st_mtime; -#ifdef USE_NSEC - istate->timestamp.nsec = (unsigned int)st.st_mtim.tv_nsec; -#else - istate->timestamp.nsec = 0; -#endif + istate->timestamp.nsec = ST_MTIME_NSEC(st); while (src_offset <= mmap_size - 20 - 8) { /* After an array of active_nr index entries, @@ -1500,13 +1486,8 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce) ondisk->ctime.sec = htonl(ce->ce_ctime.sec); ondisk->mtime.sec = htonl(ce->ce_mtime.sec); -#ifdef USE_NSEC ondisk->ctime.nsec = htonl(ce->ce_ctime.nsec); ondisk->mtime.nsec = htonl(ce->ce_mtime.nsec); -#else - ondisk->ctime.nsec = 0; - ondisk->mtime.nsec = 0; -#endif ondisk->dev = htonl(ce->ce_dev); ondisk->ino = htonl(ce->ce_ino); ondisk->mode = htonl(ce->ce_mode); @@ -1583,9 +1564,7 @@ int write_index(struct index_state *istate, int newfd) if (ce_flush(&c, newfd) || fstat(newfd, &st)) return -1; istate->timestamp.sec = (unsigned int)st.st_ctime; -#ifdef USE_NSEC - istate->timestamp.nsec = (unsigned int)st.st_ctim.tv_nsec; -#endif + istate->timestamp.nsec = ST_CTIME_NSEC(st); return 0; } diff --git a/unpack-trees.c b/unpack-trees.c index 9fe0cd5f9b..da2e3c0915 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -362,9 +362,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options o->result.initialized = 1; if (o->src_index) { o->result.timestamp.sec = o->src_index->timestamp.sec; -#ifdef USE_NSEC o->result.timestamp.nsec = o->src_index->timestamp.nsec; -#endif } o->merge_size = len; From ca31f0b5c2fe379324920094ef1d242dce062737 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <Johannes.Schindelin@gmx.de> Date: Fri, 6 Mar 2009 10:48:53 +0100 Subject: [PATCH 136/654] Add an (optional, since expensive) test for >2gb clones Define GIT_TEST_CLONE_2GB=t if you want the test not to be skipped. The test works by constructing a repository larger than 2gb, and then cloning it. The repository is forced larger than 2gb by setting compression and delta depth to zero, and then adding just enough unique objects of a given size. The objects consist of a running decimal number in ASCII, padded by spaces. Should that break in the future, e.g. when pack v4 becomes default, there is a commented-out call to test-genrandom which can be substituted, but that uses more cycles than the current method. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t5705-clone-2gb.sh | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100755 t/t5705-clone-2gb.sh diff --git a/t/t5705-clone-2gb.sh b/t/t5705-clone-2gb.sh new file mode 100755 index 0000000000..9f52154cac --- /dev/null +++ b/t/t5705-clone-2gb.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +test_description='Test cloning a repository larger than 2 gigabyte' +. ./test-lib.sh + +test -z "$GIT_TEST_CLONE_2GB" && +say "Skipping expensive 2GB clone test; enable it with GIT_TEST_CLONE_2GB=t" && +test_done && +exit + +test_expect_success 'setup' ' + + git config pack.compression 0 && + git config pack.depth 0 && + blobsize=$((20*1024*1024)) && + blobcount=$((2*1024*1024*1024/$blobsize+1)) && + i=1 && + (while test $i -le $blobcount + do + printf "Generating blob $i/$blobcount\r" >&2 && + printf "blob\nmark :$i\ndata $blobsize\n" && + #test-genrandom $i $blobsize && + printf "%-${blobsize}s" $i && + echo "M 100644 :$i $i" >> commit + i=$(($i+1)) || + echo $? > exit-status + done && + echo "commit refs/heads/master" && + echo "author A U Thor <author@email.com> 123456789 +0000" && + echo "committer C O Mitter <committer@email.com> 123456789 +0000" && + echo "data 5" && + echo ">2gb" && + cat commit) | + git fast-import && + test ! -f exit-status + +' + +test_expect_success 'clone' ' + + git clone --bare --no-hardlinks . clone + +' + +test_done From 3b167396b416541f7559f3141392d56b93ea049c Mon Sep 17 00:00:00 2001 From: Pete Wyckoff <pw@padd.com> Date: Fri, 27 Feb 2009 10:53:59 -0800 Subject: [PATCH 137/654] git-p4: remove tabs from usermap file Some users have tabs in their names, oddly enough. This causes problems when loading the usercache from disk, as split separates the fields on the wrong tabs. When fast-import's parse_ident() tries to parse the committer field, it is unhappy about the unbalanced <..> angle brackets. It is easy enough to convert the tabs to single spaces. Signed-off-by: Pete Wyckoff <pw@padd.com> Acked-by: Simon Hausmann <simon@lst.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/fast-import/git-p4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 3832f60225..342529db30 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -1142,7 +1142,7 @@ class P4Sync(Command): s = '' for (key, val) in self.users.items(): - s += "%s\t%s\n" % (key, val) + s += "%s\t%s\n" % (key.expandtabs(1), val.expandtabs(1)) open(self.getUserCacheFilename(), "wb").write(s) self.userMapFromPerforceServer = True From 36adb4abbdf809371b88581c8bf7fe9ea9a5b00a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Sat, 7 Mar 2009 16:51:33 +0100 Subject: [PATCH 138/654] MinGW: fix diff --no-index /dev/null ... When launching "diff --no-index" with a parameter "/dev/null", the MSys bash converts the "/dev/null" to a "nul", which usually makes sense. But Signed-off-by: Junio C Hamano <gitster@pobox.com> --- diff-no-index.c | 4 ++++ t/t4012-diff-binary.sh | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/diff-no-index.c b/diff-no-index.c index 0a14268ba9..598687b50a 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -38,6 +38,10 @@ static int get_mode(const char *path, int *mode) if (!path || !strcmp(path, "/dev/null")) *mode = 0; +#ifdef _WIN32 + else if (!strcasecmp(path, "nul")) + *mode = 0; +#endif else if (!strcmp(path, "-")) *mode = create_ce_mode(0666); else if (lstat(path, &st)) diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh index 3cf5b5c4ea..f64aa48d24 100755 --- a/t/t4012-diff-binary.sh +++ b/t/t4012-diff-binary.sh @@ -87,7 +87,7 @@ nul_to_q() { test_expect_success 'diff --no-index with binary creation' ' echo Q | q_to_nul >binary && - (:# hide error code from diff, which just indicates differences + (: hide error code from diff, which just indicates differences git diff --binary --no-index /dev/null binary >current || true ) && From eb3a9dd3279fe4b05f286665986ebf6d43a6ccc0 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer <benny.kra@googlemail.com> Date: Sat, 7 Mar 2009 21:02:10 +0100 Subject: [PATCH 139/654] Remove unused function scope local variables These variables were unused and can be removed safely: builtin-clone.c::cmd_clone(): use_local_hardlinks, use_separate_remote builtin-fetch-pack.c::find_common(): len builtin-remote.c::mv(): symref diff.c::show_stats():show_stats(): total diffcore-break.c::should_break(): base_size fast-import.c::validate_raw_date(): date, sign fsck.c::fsck_tree(): o_sha1, sha1 xdiff-interface.c::parse_num(): read_some Signed-off-by: Benjamin Kramer <benny.kra@googlemail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-clone.c | 6 ------ builtin-fetch-pack.c | 3 +-- builtin-remote.c | 3 +-- diff.c | 4 +--- diffcore-break.c | 3 +-- fast-import.c | 8 +++----- fsck.c | 6 +----- xdiff-interface.c | 3 +-- 8 files changed, 9 insertions(+), 27 deletions(-) diff --git a/builtin-clone.c b/builtin-clone.c index c338910b1c..92826cd14c 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -365,8 +365,6 @@ static void install_branch_config(const char *local, int cmd_clone(int argc, const char **argv, const char *prefix) { - int use_local_hardlinks = 1; - int use_separate_remote = 1; int is_bundle = 0; struct stat buf; const char *repo_name, *repo, *work_tree, *git_dir; @@ -388,9 +386,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (argc == 0) die("You must specify a repository to clone."); - if (option_no_hardlinks) - use_local_hardlinks = 0; - if (option_mirror) option_bare = 1; @@ -399,7 +394,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix) die("--bare and --origin %s options are incompatible.", option_origin); option_no_checkout = 1; - use_separate_remote = 0; } if (!option_origin) diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 67fb80ec48..c2e5adc884 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -216,9 +216,8 @@ static int find_common(int fd[2], unsigned char *result_sha1, if (args.depth > 0) { char line[1024]; unsigned char sha1[20]; - int len; - while ((len = packet_read_line(fd[0], line, sizeof(line)))) { + while (packet_read_line(fd[0], line, sizeof(line))) { if (!prefixcmp(line, "shallow ")) { if (get_sha1_hex(line + 8, sha1)) die("invalid shallow line: %s", line); diff --git a/builtin-remote.c b/builtin-remote.c index ac69d37c8a..e171096ece 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -484,9 +484,8 @@ static int mv(int argc, const char **argv) struct string_list_item *item = remote_branches.items + i; int flag = 0; unsigned char sha1[20]; - const char *symref; - symref = resolve_ref(item->string, sha1, 1, &flag); + resolve_ref(item->string, sha1, 1, &flag); if (!(flag & REF_ISSYMREF)) continue; if (delete_ref(item->string, NULL, REF_NODEREF)) diff --git a/diff.c b/diff.c index 3feca1b173..e06c93707f 100644 --- a/diff.c +++ b/diff.c @@ -875,7 +875,7 @@ static void fill_print_name(struct diffstat_file *file) static void show_stats(struct diffstat_t* data, struct diff_options *options) { - int i, len, add, del, total, adds = 0, dels = 0; + int i, len, add, del, adds = 0, dels = 0; int max_change = 0, max_len = 0; int total_files = data->nr; int width, name_width; @@ -978,14 +978,12 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) */ add = added; del = deleted; - total = add + del; adds += add; dels += del; if (width <= max_change) { add = scale_linear(add, width, max_change); del = scale_linear(del, width, max_change); - total = add + del; } show_name(options->file, prefix, name, len, reset, set); fprintf(options->file, "%5d%s", added + deleted, diff --git a/diffcore-break.c b/diffcore-break.c index 31cdcfe8bc..d7097bb576 100644 --- a/diffcore-break.c +++ b/diffcore-break.c @@ -45,7 +45,7 @@ static int should_break(struct diff_filespec *src, * The value we return is 1 if we want the pair to be broken, * or 0 if we do not. */ - unsigned long delta_size, base_size, max_size; + unsigned long delta_size, max_size; unsigned long src_copied, literal_added, src_removed; *merge_score_p = 0; /* assume no deletion --- "do not break" @@ -64,7 +64,6 @@ static int should_break(struct diff_filespec *src, if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0)) return 0; /* error but caught downstream */ - base_size = ((src->size < dst->size) ? src->size : dst->size); max_size = ((src->size > dst->size) ? src->size : dst->size); if (max_size < MINIMUM_BREAK_SIZE) return 0; /* we do not break too small filepair */ diff --git a/fast-import.c b/fast-import.c index 3748ddf48d..beeac0d004 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1745,21 +1745,19 @@ static void parse_data(struct strbuf *sb) static int validate_raw_date(const char *src, char *result, int maxlen) { const char *orig_src = src; - char *endp, sign; - unsigned long date; + char *endp; errno = 0; - date = strtoul(src, &endp, 10); + strtoul(src, &endp, 10); if (errno || endp == src || *endp != ' ') return -1; src = endp + 1; if (*src != '-' && *src != '+') return -1; - sign = *src; - date = strtoul(src + 1, &endp, 10); + strtoul(src + 1, &endp, 10); if (errno || endp == src || *endp || (endp - orig_src) >= maxlen) return -1; diff --git a/fsck.c b/fsck.c index 97f76c5815..511b82cba9 100644 --- a/fsck.c +++ b/fsck.c @@ -148,20 +148,17 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func) struct tree_desc desc; unsigned o_mode; const char *o_name; - const unsigned char *o_sha1; init_tree_desc(&desc, item->buffer, item->size); o_mode = 0; o_name = NULL; - o_sha1 = NULL; while (desc.size) { unsigned mode; const char *name; - const unsigned char *sha1; - sha1 = tree_entry_extract(&desc, &name, &mode); + tree_entry_extract(&desc, &name, &mode); if (strchr(name, '/')) has_full_path = 1; @@ -207,7 +204,6 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func) o_mode = mode; o_name = name; - o_sha1 = sha1; } retval = 0; diff --git a/xdiff-interface.c b/xdiff-interface.c index d782f06d99..b9b0db8d86 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -15,11 +15,10 @@ static int parse_num(char **cp_p, int *num_p) { char *cp = *cp_p; int num = 0; - int read_some; while ('0' <= *cp && *cp <= '9') num = num * 10 + *cp++ - '0'; - if (!(read_some = cp - *cp_p)) + if (!(cp - *cp_p)) return -1; *cp_p = cp; *num_p = num; From fd13b21f52b499ff6fa951ce27d4b9c9f0653087 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer <benny.kra@googlemail.com> Date: Sat, 7 Mar 2009 21:02:26 +0100 Subject: [PATCH 140/654] Move local variables to narrower scopes These weren't used outside and can be safely moved Signed-off-by: Benjamin Kramer <benny.kra@googlemail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-fmt-merge-msg.c | 6 ++---- combine-diff.c | 3 +-- log-tree.c | 6 +++--- upload-pack.c | 5 ++--- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c index df18f4070f..a7883690d7 100644 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@ -256,8 +256,7 @@ static void shortlog(const char *name, unsigned char *sha1, int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) { int limit = 20, i = 0, pos = 0; - char line[1024]; - char *p = line, *sep = ""; + char *sep = ""; unsigned char head_sha1[20]; const char *current_branch; @@ -271,9 +270,8 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) { /* get a line */ while (pos < in->len) { int len; - char *newline; + char *newline, *p = in->buf + pos; - p = in->buf + pos; newline = strchr(p, '\n'); len = newline ? newline - p : strlen(p); pos += len + !!newline; diff --git a/combine-diff.c b/combine-diff.c index bccc018ab2..b3b86aebcb 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -526,7 +526,6 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent, return; /* result deleted */ while (1) { - struct sline *sl = &sline[lno]; unsigned long hunk_end; unsigned long rlines; const char *hunk_comment = NULL; @@ -592,7 +591,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent, struct lline *ll; int j; unsigned long p_mask; - sl = &sline[lno++]; + struct sline *sl = &sline[lno++]; ll = (sl->flag & no_pre_delete) ? NULL : sl->lost_head; while (ll) { fputs(c_old, stdout); diff --git a/log-tree.c b/log-tree.c index 84a74e544b..63cff74350 100644 --- a/log-tree.c +++ b/log-tree.c @@ -79,18 +79,18 @@ void show_decorations(struct rev_info *opt, struct commit *commit) */ static int detect_any_signoff(char *letter, int size) { - char ch, *cp; + char *cp; int seen_colon = 0; int seen_at = 0; int seen_name = 0; int seen_head = 0; cp = letter + size; - while (letter <= --cp && (ch = *cp) == '\n') + while (letter <= --cp && *cp == '\n') continue; while (letter <= cp) { - ch = *cp--; + char ch = *cp--; if (ch == '\n') break; diff --git a/upload-pack.c b/upload-pack.c index e15ebdc287..a49d872447 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -397,12 +397,11 @@ static int get_common_commits(void) static char line[1000]; unsigned char sha1[20]; char hex[41], last_hex[41]; - int len; save_commit_buffer = 0; for(;;) { - len = packet_read_line(0, line, sizeof(line)); + int len = packet_read_line(0, line, sizeof(line)); reset_timeout(); if (!len) { @@ -410,7 +409,7 @@ static int get_common_commits(void) packet_write(1, "NAK\n"); continue; } - len = strip(line, len); + strip(line, len); if (!prefixcmp(line, "have ")) { switch (got_sha1(line+5, sha1)) { case -1: /* they have what we do not */ From 113106e06c48cc80432fd1be8af912898e8f240e Mon Sep 17 00:00:00 2001 From: Tay Ray Chuan <rctay89@gmail.com> Date: Sun, 8 Mar 2009 00:47:21 +0800 Subject: [PATCH 141/654] http.c: use strbuf API in quote_ref_url In addition, ''quote_ref_url'' inserts a slash between the base URL and remote ref path only if needed. Previously, this insertion wasn't contingent on the lack of a separating slash. Signed-off-by: Tay Ray Chuan <rctay89@gmail.com> Acked-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- http.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/http.c b/http.c index ee58799ca8..56f18f1b03 100644 --- a/http.c +++ b/http.c @@ -573,31 +573,21 @@ static inline int hex(int v) static char *quote_ref_url(const char *base, const char *ref) { + struct strbuf buf = STRBUF_INIT; const char *cp; - char *dp, *qref; - int len, baselen, ch; + int ch; - baselen = strlen(base); - len = baselen + 2; /* '/' after base and terminating NUL */ - for (cp = ref; (ch = *cp) != 0; cp++, len++) + strbuf_addstr(&buf, base); + if (buf.len && buf.buf[buf.len - 1] != '/' && *ref != '/') + strbuf_addstr(&buf, "/"); + + for (cp = ref; (ch = *cp) != 0; cp++) if (needs_quote(ch)) - len += 2; /* extra two hex plus replacement % */ - qref = xmalloc(len); - memcpy(qref, base, baselen); - dp = qref + baselen; - *(dp++) = '/'; - for (cp = ref; (ch = *cp) != 0; cp++) { - if (needs_quote(ch)) { - *dp++ = '%'; - *dp++ = hex((ch >> 4) & 0xF); - *dp++ = hex(ch & 0xF); - } + strbuf_addf(&buf, "%%%02x", ch); else - *dp++ = ch; - } - *dp = 0; + strbuf_addch(&buf, *cp); - return qref; + return strbuf_detach(&buf, NULL); } int http_fetch_ref(const char *base, struct ref *ref) From 8321c56b6bae25a2d70790f452df894be536b32c Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Sun, 8 Mar 2009 00:10:33 -0800 Subject: [PATCH 142/654] builtin-remote.c: no "commented out" code, please And especially do not use // comment. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-remote.c | 1 - 1 file changed, 1 deletion(-) diff --git a/builtin-remote.c b/builtin-remote.c index 7e82a52b7d..7b31e554e9 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -333,7 +333,6 @@ static int get_push_ref_states(const struct ref *remote_refs, info->status = PUSH_STATUS_FASTFORWARD; else info->status = PUSH_STATUS_OUTOFDATE; - // ref->peer_ref = NULL; /* local ref which is freed below */ } free_refs(local_refs); free_refs(push_map); From b5ce3a54302cb6e29a02cd8fe4ea55eacea0a86e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Sun, 8 Mar 2009 19:12:47 +0100 Subject: [PATCH 143/654] parseopt: add PARSE_OPT_KEEP_UNKNOWN Add a parseopt flag, PARSE_OPT_KEEP_UNKNOWN, that can be used to keep unknown options in argv, similar to the existing KEEP flags. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- parse-options.c | 12 +++++++++--- parse-options.h | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/parse-options.c b/parse-options.c index 4c5d09dd25..39808ae458 100644 --- a/parse-options.c +++ b/parse-options.c @@ -274,7 +274,7 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, case -1: return parse_options_usage(usagestr, options); case -2: - return PARSE_OPT_UNKNOWN; + goto unknown; } if (ctx->opt) check_typos(arg + 1, options); @@ -292,7 +292,7 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, */ ctx->argv[0] = xstrdup(ctx->opt - 1); *(char *)ctx->argv[0] = '-'; - return PARSE_OPT_UNKNOWN; + goto unknown; } } continue; @@ -314,8 +314,14 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, case -1: return parse_options_usage(usagestr, options); case -2: - return PARSE_OPT_UNKNOWN; + goto unknown; } + continue; +unknown: + if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN)) + return PARSE_OPT_UNKNOWN; + ctx->out[ctx->cpidx++] = ctx->argv[0]; + ctx->opt = NULL; } return PARSE_OPT_DONE; } diff --git a/parse-options.h b/parse-options.h index 912290549b..b7d08b13d1 100644 --- a/parse-options.h +++ b/parse-options.h @@ -21,6 +21,7 @@ enum parse_opt_flags { PARSE_OPT_KEEP_DASHDASH = 1, PARSE_OPT_STOP_AT_NON_OPTION = 2, PARSE_OPT_KEEP_ARGV0 = 4, + PARSE_OPT_KEEP_UNKNOWN = 8, }; enum parse_opt_option_flags { From b92891f9783ae197bb84b90d8404ad08c3875fa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Sun, 8 Mar 2009 19:15:08 +0100 Subject: [PATCH 144/654] parseopt: add PARSE_OPT_NO_INTERNAL_HELP Add a parseopt flag, PARSE_OPT_NO_INTERNAL_HELP, that turns off internal handling of -h, --help and --help-all. This allows the implementation of custom help option handlers or incremental parsers. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- parse-options.c | 10 ++++++---- parse-options.h | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/parse-options.c b/parse-options.c index 39808ae458..8b21dea72e 100644 --- a/parse-options.c +++ b/parse-options.c @@ -253,6 +253,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, const struct option *options, const char * const usagestr[]) { + int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP); + /* we must reset ->opt, unknown short option leave it dangling */ ctx->opt = NULL; @@ -268,7 +270,7 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, if (arg[1] != '-') { ctx->opt = arg + 1; - if (*ctx->opt == 'h') + if (internal_help && *ctx->opt == 'h') return parse_options_usage(usagestr, options); switch (parse_short_opt(ctx, options)) { case -1: @@ -279,7 +281,7 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, if (ctx->opt) check_typos(arg + 1, options); while (ctx->opt) { - if (*ctx->opt == 'h') + if (internal_help && *ctx->opt == 'h') return parse_options_usage(usagestr, options); switch (parse_short_opt(ctx, options)) { case -1: @@ -306,9 +308,9 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, break; } - if (!strcmp(arg + 2, "help-all")) + if (internal_help && !strcmp(arg + 2, "help-all")) return usage_with_options_internal(usagestr, options, 1); - if (!strcmp(arg + 2, "help")) + if (internal_help && !strcmp(arg + 2, "help")) return parse_options_usage(usagestr, options); switch (parse_long_opt(ctx, arg + 2, options)) { case -1: diff --git a/parse-options.h b/parse-options.h index b7d08b13d1..f8ef1db128 100644 --- a/parse-options.h +++ b/parse-options.h @@ -22,6 +22,7 @@ enum parse_opt_flags { PARSE_OPT_STOP_AT_NON_OPTION = 2, PARSE_OPT_KEEP_ARGV0 = 4, PARSE_OPT_KEEP_UNKNOWN = 8, + PARSE_OPT_NO_INTERNAL_HELP = 16, }; enum parse_opt_option_flags { From 49b6180252000e37ec47ccb4156240ed625949ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Sun, 8 Mar 2009 19:16:58 +0100 Subject: [PATCH 145/654] parseopt: make usage optional Allow usagestr to be NULL and don't display any help screen in this case. This is useful to implement incremental parsers. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- parse-options.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/parse-options.c b/parse-options.c index 8b21dea72e..51e804b3be 100644 --- a/parse-options.c +++ b/parse-options.c @@ -364,6 +364,9 @@ int parse_options(int argc, const char **argv, const struct option *options, int usage_with_options_internal(const char * const *usagestr, const struct option *opts, int full) { + if (!usagestr) + return PARSE_OPT_HELP; + fprintf(stderr, "usage: %s\n", *usagestr++); while (*usagestr && **usagestr) fprintf(stderr, " or: %s\n", *usagestr++); From 52e7787609d18af76a8c1befb0a06123fb7ce89e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Sun, 8 Mar 2009 19:21:53 +0100 Subject: [PATCH 146/654] archive: use parseopt for local-only options Replace the hand-rolled parsers that find and remove --remote and --exec by a parseopt parser that also handles --output. All three options only have a meaning if no remote server is used or on the local side. They must be rejected by upload-archive and should not be sent to the server by archive. We can't use a single parser for both remote and local side because the remote end possibly understands a different set of options than the local side. A local parser would then wrongly accuse options valid on the other side as being incorrect. This patch implements a very forgiving parser that understands only the three options mentioned above. All others are passed to the normal, complete parser in archive.c (running either locally in archive, or remotely in upload-archive). This normal parser definition contains dummy entries for the three options, in order for them to appear in the help screen. The parseopt parser allows multiple occurrences of --remote and --exec unlike the previous one; the one specified last wins. This looseness is acceptable, I think. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- archive.c | 18 +------- builtin-archive.c | 103 +++++++++++++++++----------------------------- 2 files changed, 40 insertions(+), 81 deletions(-) diff --git a/archive.c b/archive.c index c6aea8358f..96b62d4309 100644 --- a/archive.c +++ b/archive.c @@ -239,19 +239,6 @@ static void parse_treeish_arg(const char **argv, ar_args->time = archive_time; } -static void create_output_file(const char *output_file) -{ - int output_fd = open(output_file, O_CREAT | O_WRONLY | O_TRUNC, 0666); - if (output_fd < 0) - die("could not create archive file: %s ", output_file); - if (output_fd != 1) { - if (dup2(output_fd, 1) < 0) - die("could not redirect output"); - else - close(output_fd); - } -} - #define OPT__COMPR(s, v, h, p) \ { OPTION_SET_INT, (s), NULL, (v), NULL, (h), \ PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, (p) } @@ -306,13 +293,12 @@ static int parse_archive_args(int argc, const char **argv, die("Unexpected option --remote"); if (exec) die("Option --exec can only be used together with --remote"); + if (output) + die("Unexpected option --output"); if (!base) base = ""; - if (output) - create_output_file(output); - if (list) { for (i = 0; i < ARRAY_SIZE(archivers); i++) printf("%s\n", archivers[i].name); diff --git a/builtin-archive.c b/builtin-archive.c index 5ceec433fd..60adef9363 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -5,44 +5,35 @@ #include "cache.h" #include "builtin.h" #include "archive.h" +#include "parse-options.h" #include "pkt-line.h" #include "sideband.h" -static int run_remote_archiver(const char *remote, int argc, - const char **argv) +static void create_output_file(const char *output_file) +{ + int output_fd = open(output_file, O_CREAT | O_WRONLY | O_TRUNC, 0666); + if (output_fd < 0) + die("could not create archive file: %s ", output_file); + if (output_fd != 1) { + if (dup2(output_fd, 1) < 0) + die("could not redirect output"); + else + close(output_fd); + } +} + +static int run_remote_archiver(int argc, const char **argv, + const char *remote, const char *exec) { char *url, buf[LARGE_PACKET_MAX]; int fd[2], i, len, rv; struct child_process *conn; - const char *exec = "git-upload-archive"; - int exec_at = 0, exec_value_at = 0; - - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; - if (!prefixcmp(arg, "--exec=")) { - if (exec_at) - die("multiple --exec specified"); - exec = arg + 7; - exec_at = i; - } else if (!strcmp(arg, "--exec")) { - if (exec_at) - die("multiple --exec specified"); - if (i + 1 >= argc) - die("option --exec requires a value"); - exec = argv[i + 1]; - exec_at = i; - exec_value_at = ++i; - } - } url = xstrdup(remote); conn = git_connect(fd, url, exec, 0); - for (i = 1; i < argc; i++) { - if (i == exec_at || i == exec_value_at) - continue; + for (i = 1; i < argc; i++) packet_write(fd[1], "argument %s\n", argv[i]); - } packet_flush(fd[1]); len = packet_read_line(fd[0], buf, sizeof(buf)); @@ -69,51 +60,33 @@ static int run_remote_archiver(const char *remote, int argc, return !!rv; } -static const char *extract_remote_arg(int *ac, const char **av) -{ - int ix, iy, cnt = *ac; - int no_more_options = 0; - const char *remote = NULL; - - for (ix = iy = 1; ix < cnt; ix++) { - const char *arg = av[ix]; - if (!strcmp(arg, "--")) - no_more_options = 1; - if (!no_more_options) { - if (!prefixcmp(arg, "--remote=")) { - if (remote) - die("Multiple --remote specified"); - remote = arg + 9; - continue; - } else if (!strcmp(arg, "--remote")) { - if (remote) - die("Multiple --remote specified"); - if (++ix >= cnt) - die("option --remote requires a value"); - remote = av[ix]; - continue; - } - if (arg[0] != '-') - no_more_options = 1; - } - if (ix != iy) - av[iy] = arg; - iy++; - } - if (remote) { - av[--cnt] = NULL; - *ac = cnt; - } - return remote; -} +#define PARSE_OPT_KEEP_ALL ( PARSE_OPT_KEEP_DASHDASH | \ + PARSE_OPT_KEEP_ARGV0 | \ + PARSE_OPT_KEEP_UNKNOWN | \ + PARSE_OPT_NO_INTERNAL_HELP ) int cmd_archive(int argc, const char **argv, const char *prefix) { + const char *exec = "git-upload-archive"; + const char *output = NULL; const char *remote = NULL; + struct option local_opts[] = { + OPT_STRING(0, "output", &output, "file", + "write the archive to this file"), + OPT_STRING(0, "remote", &remote, "repo", + "retrieve the archive from remote repository <repo>"), + OPT_STRING(0, "exec", &exec, "cmd", + "path to the remote git-upload-archive command"), + OPT_END() + }; + + argc = parse_options(argc, argv, local_opts, NULL, PARSE_OPT_KEEP_ALL); + + if (output) + create_output_file(output); - remote = extract_remote_arg(&argc, argv); if (remote) - return run_remote_archiver(remote, argc, argv); + return run_remote_archiver(argc, argv, remote, exec); setvbuf(stderr, NULL, _IOLBF, BUFSIZ); From 110c46a909fe27f5b8aff412a78cb821300fb985 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Sun, 8 Mar 2009 13:51:33 -0700 Subject: [PATCH 147/654] Not all systems use st_[cm]tim field for ns resolution file timestamp Some codepaths do not still use the ST_[CM]TIME_NSEC() pair of macros introduced by the previous commit but assumes all systems use st_mtim and st_ctim fields in "struct stat" to record nanosecond resolution part of the file timestamps. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-fetch-pack.c | 2 +- read-cache.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 59b0b0a796..1d7e02326f 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -807,7 +807,7 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args, die("shallow file was removed during fetch"); } else if (st.st_mtime != mtime.sec #ifdef USE_NSEC - || st.st_mtim.tv_nsec != mtime.nsec + || ST_CTIME_NSEC(st) != mtime.nsec #endif ) die("shallow file was changed during fetch"); diff --git a/read-cache.c b/read-cache.c index b819abbd00..7f74c8d161 100644 --- a/read-cache.c +++ b/read-cache.c @@ -204,9 +204,9 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) changed |= CTIME_CHANGED; #ifdef USE_NSEC - if (ce->ce_mtime.nsec != (unsigned int)st->st_mtim.tv_nsec) + if (ce->ce_mtime.nsec != ST_MTIME_NSEC(*st)) changed |= MTIME_CHANGED; - if (trust_ctime && ce->ce_ctime.nsec != (unsigned int)st->st_ctim.tv_nsec) + if (trust_ctime && ce->ce_ctime.nsec != ST_CTIME_NSEC(*st)) changed |= CTIME_CHANGED; #endif From c567383b1e3205c895b371d42a39fbdf131032ba Mon Sep 17 00:00:00 2001 From: Brian Gernhardt <benji@silverinsanity.com> Date: Sun, 8 Mar 2009 16:04:28 -0400 Subject: [PATCH 148/654] Create USE_ST_TIMESPEC and turn it on for Darwin Not all OSes use st_ctim and st_mtim in their struct stat. In particular, it appears that OS X uses st_*timespec instead. So add a Makefile variable and #define called USE_ST_TIMESPEC to switch the USE_NSEC defines to use st_*timespec. This also turns it on by default for OS X (Darwin) machines. Likely this is a sane default for other BSD kernels as well, but I don't have any to test that assumption on. Signed-off-by: Brian Gernhardt <benji@silverinsanity.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 7 +++++++ git-compat-util.h | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/Makefile b/Makefile index 65b5b8a63f..7b310859e9 100644 --- a/Makefile +++ b/Makefile @@ -126,6 +126,9 @@ all:: # randomly break unless your underlying filesystem supports those sub-second # times (my ext3 doesn't). # +# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of +# "st_ctim" +# # Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec" # available. This automatically turns USE_NSEC off. # @@ -663,6 +666,7 @@ ifeq ($(uname_S),Darwin) endif NO_MEMMEM = YesPlease THREADED_DELTA_SEARCH = YesPlease + USE_ST_TIMESPEC = YesPlease endif ifeq ($(uname_S),SunOS) NEEDS_SOCKET = YesPlease @@ -928,6 +932,9 @@ endif ifdef NO_ST_BLOCKS_IN_STRUCT_STAT BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT endif +ifdef USE_ST_TIMESPEC + BASIC_CFLAGS += -DUSE_ST_TIMESPEC +endif ifdef NO_NSEC BASIC_CFLAGS += -DNO_NSEC endif diff --git a/git-compat-util.h b/git-compat-util.h index 9b495dcad8..c915752a24 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -389,8 +389,13 @@ void git_qsort(void *base, size_t nmemb, size_t size, #define ST_CTIME_NSEC(st) 0 #define ST_MTIME_NSEC(st) 0 #else +#ifdef USE_ST_TIMESPEC +#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctimespec.tv_nsec)) +#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtimespec.tv_nsec)) +#else #define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctim.tv_nsec)) #define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtim.tv_nsec)) #endif +#endif #endif From d7371a2d4d308d961d22c12ae9bc3d28cf35f029 Mon Sep 17 00:00:00 2001 From: Brian Gernhardt <benji@silverinsanity.com> Date: Sun, 8 Mar 2009 17:22:51 -0400 Subject: [PATCH 149/654] Makefile: Set compiler switch for USE_NSEC The comments indicated that setting a Makefile variable USE_NSEC would enable the code for sub-second [cm]times. However, the Makefile variable was never turned into a compiler switch so the code was never enabled. This patch allows USE_NSEC to be noticed by the compiler. Signed-off-by: Brian Gernhardt <benji@silverinsanity.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 7b310859e9..e8cdbfb3d0 100644 --- a/Makefile +++ b/Makefile @@ -932,6 +932,9 @@ endif ifdef NO_ST_BLOCKS_IN_STRUCT_STAT BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT endif +ifdef USE_NSEC + BASIC_CFLAGS += -DUSE_NSEC +endif ifdef USE_ST_TIMESPEC BASIC_CFLAGS += -DUSE_ST_TIMESPEC endif From 747a322bcc4df5f9a371890ffe728741456704c7 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Sun, 8 Mar 2009 18:22:44 -0700 Subject: [PATCH 150/654] grep: cast printf %.*s "precision" argument explicitly to int On some systems, regoff_t that is the type of rm_so/rm_eo members are wider than int; %.*s precision specifier expects an int, so use an explicit cast. A breakage reported on Darwin by Brian Gernhardt should be fixed with this patch. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- grep.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grep.c b/grep.c index cace1c8bcb..be99b34168 100644 --- a/grep.c +++ b/grep.c @@ -490,9 +490,9 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol, *eol = '\0'; while (next_match(opt, bol, eol, ctx, &match, eflags)) { printf("%.*s%s%.*s%s", - match.rm_so, bol, + (int)match.rm_so, bol, opt->color_match, - match.rm_eo - match.rm_so, bol + match.rm_so, + (int)(match.rm_eo - match.rm_so), bol + match.rm_so, GIT_COLOR_RESET); bol += match.rm_eo; rest -= match.rm_eo; From 9162b8640b4e9e199fb92eb6b8a3787f268531d5 Mon Sep 17 00:00:00 2001 From: Michael Lai <myllai@gmail.com> Date: Mon, 9 Mar 2009 11:45:47 -0700 Subject: [PATCH 151/654] git-svn: support intermediate paths when matching tags/branches For repositories laid out like the following: [svn-remote "svn"] url = http://foo.com/svn/repos/bar fetch = myproject/trunk:refs/remotes/trunk branches = bar/myproject/branches/*:refs/remotes/* tags = bar/myproject/tags/*:refs/remotes/tags/* The "bar" component above is considered the intermediate path and was not handled correctly. Signed-off-by: Michael Lai <myllai@gmail.com> Acked-by: Eric Wong <normalperson@yhbt.net> --- git-svn.perl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/git-svn.perl b/git-svn.perl index 959eb52f3f..8be6be00c6 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -2351,7 +2351,10 @@ sub match_paths { if (my $path = $paths->{"/$self->{path}"}) { return ($path->{action} eq 'D') ? 0 : 1; } - $self->{path_regex} ||= qr/^\/\Q$self->{path}\E\//; + my $repos_root = $self->ra->{repos_root}; + my $extended_path = $self->{url} . '/' . $self->{path}; + $extended_path =~ s#^\Q$repos_root\E(/|$)##; + $self->{path_regex} ||= qr/^\/\Q$extended_path\E\//; if (grep /$self->{path_regex}/, keys %$paths) { return 1; } From 9ad7e6ea24739c298d0a9660121de6df0502915a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Mon, 9 Mar 2009 21:26:56 +0100 Subject: [PATCH 152/654] parseopt: document KEEP_ARGV0, KEEP_UNKNOWN, NO_INTERNAL_HELP Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/technical/api-parse-options.txt | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt index 539863b1f9..20b44ff9f3 100644 --- a/Documentation/technical/api-parse-options.txt +++ b/Documentation/technical/api-parse-options.txt @@ -66,6 +66,12 @@ Steps to parse options non-option arguments in `argv[]`. `argc` is updated appropriately because of the assignment. + +You can also pass NULL instead of a usage array as fourth parameter of +parse_options(), to avoid displaying a help screen with usage info and +option list. This should only be done if necessary, e.g. to implement +a limited parser for only a subset of the options that needs to be run +before the full parser, which in turn shows the full help message. ++ Flags are the bitwise-or of: `PARSE_OPT_KEEP_DASHDASH`:: @@ -77,6 +83,27 @@ Flags are the bitwise-or of: Using this flag, processing is stopped at the first non-option argument. +`PARSE_OPT_KEEP_ARGV0`:: + Keep the first argument, which contains the program name. It's + removed from argv[] by default. + +`PARSE_OPT_KEEP_UNKNOWN`:: + Keep unknown arguments instead of erroring out. This doesn't + work for all combinations of arguments as users might expect + it to do. E.g. if the first argument in `--unknown --known` + takes a value (which we can't know), the second one is + mistakenly interpreted as a known option. Similarly, if + `PARSE_OPT_STOP_AT_NON_OPTION` is set, the second argument in + `--unknown value` will be mistakenly interpreted as a + non-option, not as a value belonging to the unknown option, + stopping the parser early. + +`PARSE_OPT_NO_INTERNAL_HELP`:: + By default, parse_options() handles `-h`, `--help` and + `--help-all` internally, by showing a help screen. This option + turns it off and allows one to add custom handlers for these + options, or to just leave them unknown. + Data Structure -------------- From 0d260f9a09a2febeb86fdada7224d271a76d2e3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Mon, 9 Mar 2009 21:57:38 +0100 Subject: [PATCH 153/654] parseopt: prevent KEEP_UNKNOWN and STOP_AT_NON_OPTION from being used together As suggested by Junio, disallow the flags PARSE_OPT_KEEP_UNKNOWN and PARSE_OPT_STOP_AT_NON_OPTION to be turned on at the same time, as a value of an unknown option could be mistakenly classified as a non-option, stopping the parser early. E.g.: git cmd --known --unknown value arg0 arg1 The parser should have stopped at "arg0", but it already stops at "value". This patch makes parse_options() die if the two flags are used in combination. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/technical/api-parse-options.txt | 3 ++- parse-options.c | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt index 20b44ff9f3..e66ca9f70c 100644 --- a/Documentation/technical/api-parse-options.txt +++ b/Documentation/technical/api-parse-options.txt @@ -96,7 +96,8 @@ Flags are the bitwise-or of: `PARSE_OPT_STOP_AT_NON_OPTION` is set, the second argument in `--unknown value` will be mistakenly interpreted as a non-option, not as a value belonging to the unknown option, - stopping the parser early. + the parser early. That's why parse_options() errors out if + both options are set. `PARSE_OPT_NO_INTERNAL_HELP`:: By default, parse_options() handles `-h`, `--help` and diff --git a/parse-options.c b/parse-options.c index 51e804b3be..cf71bcffd2 100644 --- a/parse-options.c +++ b/parse-options.c @@ -244,6 +244,9 @@ void parse_options_start(struct parse_opt_ctx_t *ctx, ctx->out = argv; ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0); ctx->flags = flags; + if ((flags & PARSE_OPT_KEEP_UNKNOWN) && + (flags & PARSE_OPT_STOP_AT_NON_OPTION)) + die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together"); } static int usage_with_options_internal(const char * const *, From a9c37a72c4fbc8537de294d66b05bdfd7f9a4016 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow <barkalow@iabervon.org> Date: Sun, 8 Mar 2009 21:06:05 -0400 Subject: [PATCH 154/654] Use a common function to get the pretty name of refs The result should be consistent between fetch and push, so we ought to use the same code in both cases, even though it's short. Signed-off-by: Daniel Barkalow <barkalow@iabervon.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-fetch.c | 6 +----- builtin-send-pack.c | 10 ---------- refs.c | 10 ++++++++++ refs.h | 2 ++ 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/builtin-fetch.c b/builtin-fetch.c index 1e4a3d9c51..f3bdeda059 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -197,11 +197,7 @@ static int update_local_ref(struct ref *ref, struct commit *current = NULL, *updated; enum object_type type; struct branch *current_branch = branch_get(NULL); - const char *pretty_ref = ref->name + ( - !prefixcmp(ref->name, "refs/heads/") ? 11 : - !prefixcmp(ref->name, "refs/tags/") ? 10 : - !prefixcmp(ref->name, "refs/remotes/") ? 13 : - 0); + const char *pretty_ref = prettify_ref(ref); *display = 0; type = sha1_object_info(ref->new_sha1, NULL); diff --git a/builtin-send-pack.c b/builtin-send-pack.c index 9072905f10..43b89ece36 100644 --- a/builtin-send-pack.c +++ b/builtin-send-pack.c @@ -172,16 +172,6 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref) } } -static const char *prettify_ref(const struct ref *ref) -{ - const char *name = ref->name; - return name + ( - !prefixcmp(name, "refs/heads/") ? 11 : - !prefixcmp(name, "refs/tags/") ? 10 : - !prefixcmp(name, "refs/remotes/") ? 13 : - 0); -} - #define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3) static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg) diff --git a/refs.c b/refs.c index b2a37e1185..8f968b51a1 100644 --- a/refs.c +++ b/refs.c @@ -736,6 +736,16 @@ int check_ref_format(const char *ref) } } +const char *prettify_ref(const struct ref *ref) +{ + const char *name = ref->name; + return name + ( + !prefixcmp(name, "refs/heads/") ? 11 : + !prefixcmp(name, "refs/tags/") ? 10 : + !prefixcmp(name, "refs/remotes/") ? 13 : + 0); +} + const char *ref_rev_parse_rules[] = { "%.*s", "refs/%.*s", diff --git a/refs.h b/refs.h index 29bdcecd4e..68c2d16d53 100644 --- a/refs.h +++ b/refs.h @@ -79,6 +79,8 @@ extern int for_each_reflog(each_ref_fn, void *); #define CHECK_REF_FORMAT_WILDCARD (-3) extern int check_ref_format(const char *target); +extern const char *prettify_ref(const struct ref *ref); + /** rename ref, return 0 on success **/ extern int rename_ref(const char *oldref, const char *newref, const char *logmsg); From 64fcef2daa03f6093b480142c6ab2a4173b0b43e Mon Sep 17 00:00:00 2001 From: Daniel Barkalow <barkalow@iabervon.org> Date: Sun, 8 Mar 2009 21:06:07 -0400 Subject: [PATCH 155/654] Move push matching and reporting logic into transport.c For native-protocol pushes (and other protocols as they are converted to the new method), this moves the refspec match, tracking update, and report message out of send-pack() and into transport_push(), where it can be shared completely with other protocols. This also makes fetch and push more similar in terms of what code is in what file. Signed-off-by: Daniel Barkalow <barkalow@iabervon.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-send-pack.c | 143 +++++++++++----------- send-pack.h | 6 +- transport.c | 283 +++++++++++++++++++++++++++++++++++++++++--- transport.h | 3 +- 4 files changed, 343 insertions(+), 92 deletions(-) diff --git a/builtin-send-pack.c b/builtin-send-pack.c index 43b89ece36..91c36512a8 100644 --- a/builtin-send-pack.c +++ b/builtin-send-pack.c @@ -11,7 +11,6 @@ static const char send_pack_usage[] = " --all and explicit <ref> specification are mutually exclusive."; static struct send_pack_args args = { - /* .receivepack = */ "git-receive-pack", }; static int feed_object(const unsigned char *sha1, int fd, int negative) @@ -31,7 +30,7 @@ static int feed_object(const unsigned char *sha1, int fd, int negative) /* * Make a pack stream and spit it out into file descriptor fd */ -static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra) +static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra, struct send_pack_args *args) { /* * The child becomes pack-objects --revs; we feed @@ -49,7 +48,7 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext struct child_process po; int i; - if (args.use_thin_pack) + if (args->use_thin_pack) argv[4] = "--thin"; memset(&po, 0, sizeof(po)); po.argv = argv; @@ -83,8 +82,6 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext return 0; } -static struct ref *remote_refs, **remote_tail; - static int receive_status(int in, struct ref *refs) { struct ref *hint; @@ -300,27 +297,19 @@ static int refs_pushed(struct ref *ref) return 0; } -static int do_send_pack(int in, int out, struct remote *remote, const char *dest, int nr_refspec, const char **refspec) +int send_pack(struct send_pack_args *args, + int fd[], struct child_process *conn, + struct ref *remote_refs, + struct extra_have_objects *extra_have) { - struct ref *ref, *local_refs; + int in = fd[0]; + int out = fd[1]; + struct ref *ref; int new_refs; int ask_for_status_report = 0; int allow_deleting_refs = 0; int expect_status_report = 0; - int flags = MATCH_REFS_NONE; int ret; - struct extra_have_objects extra_have; - - memset(&extra_have, 0, sizeof(extra_have)); - if (args.send_all) - flags |= MATCH_REFS_ALL; - if (args.send_mirror) - flags |= MATCH_REFS_MIRROR; - - /* No funny business with the matcher */ - remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL, - &extra_have); - local_refs = get_local_heads(); /* Does the other end support the reporting? */ if (server_supports("report-status")) @@ -328,19 +317,9 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest if (server_supports("delete-refs")) allow_deleting_refs = 1; - /* match them up */ - if (!remote_tail) - remote_tail = &remote_refs; - if (match_refs(local_refs, remote_refs, &remote_tail, - nr_refspec, refspec, flags)) { - close(out); - return -1; - } - if (!remote_refs) { fprintf(stderr, "No refs in common and none specified; doing nothing.\n" "Perhaps you should specify a branch such as 'master'.\n"); - close(out); return 0; } @@ -352,7 +331,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest if (ref->peer_ref) hashcpy(ref->new_sha1, ref->peer_ref->new_sha1); - else if (!args.send_mirror) + else if (!args->send_mirror) continue; ref->deletion = is_null_sha1(ref->new_sha1); @@ -391,7 +370,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest (!has_sha1_file(ref->old_sha1) || !ref_newer(ref->new_sha1, ref->old_sha1)); - if (ref->nonfastforward && !ref->force && !args.force_update) { + if (ref->nonfastforward && !ref->force && !args->force_update) { ref->status = REF_STATUS_REJECT_NONFASTFORWARD; continue; } @@ -399,7 +378,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest if (!ref->deletion) new_refs++; - if (!args.dry_run) { + if (!args->dry_run) { char *old_hex = sha1_to_hex(ref->old_sha1); char *new_hex = sha1_to_hex(ref->new_sha1); @@ -420,27 +399,19 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest } packet_flush(out); - if (new_refs && !args.dry_run) { - if (pack_objects(out, remote_refs, &extra_have) < 0) + if (new_refs && !args->dry_run) { + if (pack_objects(out, remote_refs, extra_have, args) < 0) { + for (ref = remote_refs; ref; ref = ref->next) + ref->status = REF_STATUS_NONE; return -1; + } } - else - close(out); if (expect_status_report) ret = receive_status(in, remote_refs); else ret = 0; - print_push_status(dest, remote_refs); - - if (!args.dry_run && remote) { - for (ref = remote_refs; ref; ref = ref->next) - update_tracking_ref(remote, ref); - } - - if (!refs_pushed(remote_refs)) - fprintf(stderr, "Everything up-to-date\n"); if (ret < 0) return ret; for (ref = remote_refs; ref; ref = ref->next) { @@ -489,11 +460,19 @@ static void verify_remote_names(int nr_heads, const char **heads) int cmd_send_pack(int argc, const char **argv, const char *prefix) { - int i, nr_heads = 0; - const char **heads = NULL; + int i, nr_refspecs = 0; + const char **refspecs = NULL; const char *remote_name = NULL; struct remote *remote = NULL; const char *dest = NULL; + int fd[2]; + struct child_process *conn; + struct extra_have_objects extra_have; + struct ref *remote_refs, **remote_tail, *local_refs; + int ret; + int send_all = 0; + const char *receivepack = "git-receive-pack"; + int flags; argv++; for (i = 1; i < argc; i++, argv++) { @@ -501,11 +480,11 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) if (*arg == '-') { if (!prefixcmp(arg, "--receive-pack=")) { - args.receivepack = arg + 15; + receivepack = arg + 15; continue; } if (!prefixcmp(arg, "--exec=")) { - args.receivepack = arg + 7; + receivepack = arg + 7; continue; } if (!prefixcmp(arg, "--remote=")) { @@ -513,7 +492,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) continue; } if (!strcmp(arg, "--all")) { - args.send_all = 1; + send_all = 1; continue; } if (!strcmp(arg, "--dry-run")) { @@ -542,8 +521,8 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) dest = arg; continue; } - heads = (const char **) argv; - nr_heads = argc - i; + refspecs = (const char **) argv; + nr_refspecs = argc - i; break; } if (!dest) @@ -552,8 +531,8 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) * --all and --mirror are incompatible; neither makes sense * with any refspecs. */ - if ((heads && (args.send_all || args.send_mirror)) || - (args.send_all && args.send_mirror)) + if ((refspecs && (send_all || args.send_mirror)) || + (send_all && args.send_mirror)) usage(send_pack_usage); if (remote_name) { @@ -564,24 +543,50 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) } } - return send_pack(&args, dest, remote, nr_heads, heads); -} + conn = git_connect(fd, dest, receivepack, args.verbose ? CONNECT_VERBOSE : 0); -int send_pack(struct send_pack_args *my_args, - const char *dest, struct remote *remote, - int nr_heads, const char **heads) -{ - int fd[2], ret; - struct child_process *conn; + memset(&extra_have, 0, sizeof(extra_have)); - memcpy(&args, my_args, sizeof(args)); + get_remote_heads(fd[0], &remote_refs, 0, NULL, REF_NORMAL, + &extra_have); - verify_remote_names(nr_heads, heads); + verify_remote_names(nr_refspecs, refspecs); - conn = git_connect(fd, dest, args.receivepack, args.verbose ? CONNECT_VERBOSE : 0); - ret = do_send_pack(fd[0], fd[1], remote, dest, nr_heads, heads); + local_refs = get_local_heads(); + + flags = MATCH_REFS_NONE; + + if (send_all) + flags |= MATCH_REFS_ALL; + if (args.send_mirror) + flags |= MATCH_REFS_MIRROR; + + /* match them up */ + remote_tail = &remote_refs; + while (*remote_tail) + remote_tail = &((*remote_tail)->next); + if (match_refs(local_refs, remote_refs, &remote_tail, + nr_refspecs, refspecs, flags)) { + return -1; + } + + ret = send_pack(&args, fd, conn, remote_refs, &extra_have); + + close(fd[1]); close(fd[0]); - /* do_send_pack always closes fd[1] */ + ret |= finish_connect(conn); - return !!ret; + + print_push_status(dest, remote_refs); + + if (!args.dry_run && remote) { + struct ref *ref; + for (ref = remote_refs; ref; ref = ref->next) + update_tracking_ref(remote, ref); + } + + if (!ret && !refs_pushed(remote_refs)) + fprintf(stderr, "Everything up-to-date\n"); + + return ret; } diff --git a/send-pack.h b/send-pack.h index 8ff1dc3539..83d76c7e35 100644 --- a/send-pack.h +++ b/send-pack.h @@ -2,9 +2,7 @@ #define SEND_PACK_H struct send_pack_args { - const char *receivepack; unsigned verbose:1, - send_all:1, send_mirror:1, force_update:1, use_thin_pack:1, @@ -12,7 +10,7 @@ struct send_pack_args { }; int send_pack(struct send_pack_args *args, - const char *dest, struct remote *remote, - int nr_heads, const char **heads); + int fd[], struct child_process *conn, + struct ref *remote_refs, struct extra_have_objects *extra_have); #endif diff --git a/transport.c b/transport.c index 9ad4a16c31..73bb9b50be 100644 --- a/transport.c +++ b/transport.c @@ -138,7 +138,7 @@ static void insert_packed_refs(const char *packed_refs, struct ref **list) } } -static struct ref *get_refs_via_rsync(struct transport *transport) +static struct ref *get_refs_via_rsync(struct transport *transport, int for_push) { struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT; struct ref dummy, *tail = &dummy; @@ -146,6 +146,9 @@ static struct ref *get_refs_via_rsync(struct transport *transport) const char *args[5]; int temp_dir_len; + if (for_push) + return NULL; + /* copy the refs to the temporary directory */ strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX")); @@ -422,7 +425,7 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons return !!err; } -static struct ref *get_refs_via_curl(struct transport *transport) +static struct ref *get_refs_via_curl(struct transport *transport, int for_push) { struct strbuf buffer = STRBUF_INIT; char *data, *start, *mid; @@ -439,6 +442,9 @@ static struct ref *get_refs_via_curl(struct transport *transport) struct walker *walker; + if (for_push) + return NULL; + if (!transport->data) transport->data = get_http_walker(transport->url, transport->remote); @@ -525,12 +531,15 @@ struct bundle_transport_data { struct bundle_header header; }; -static struct ref *get_refs_from_bundle(struct transport *transport) +static struct ref *get_refs_from_bundle(struct transport *transport, int for_push) { struct bundle_transport_data *data = transport->data; struct ref *result = NULL; int i; + if (for_push) + return NULL; + if (data->fd > 0) close(data->fd); data->fd = read_bundle_header(transport->url, &data->header); @@ -571,6 +580,7 @@ struct git_transport_data { int fd[2]; const char *uploadpack; const char *receivepack; + struct extra_have_objects extra_have; }; static int set_git_option(struct transport *connection, @@ -602,20 +612,23 @@ static int set_git_option(struct transport *connection, return 1; } -static int connect_setup(struct transport *transport) +static int connect_setup(struct transport *transport, int for_push, int verbose) { struct git_transport_data *data = transport->data; - data->conn = git_connect(data->fd, transport->url, data->uploadpack, 0); + data->conn = git_connect(data->fd, transport->url, + for_push ? data->receivepack : data->uploadpack, + verbose ? CONNECT_VERBOSE : 0); return 0; } -static struct ref *get_refs_via_connect(struct transport *transport) +static struct ref *get_refs_via_connect(struct transport *transport, int for_push) { struct git_transport_data *data = transport->data; struct ref *refs; - connect_setup(transport); - get_remote_heads(data->fd[0], &refs, 0, NULL, 0, NULL); + connect_setup(transport, for_push, 0); + get_remote_heads(data->fd[0], &refs, 0, NULL, + for_push ? REF_NORMAL : 0, &data->extra_have); return refs; } @@ -647,7 +660,7 @@ static int fetch_refs_via_pack(struct transport *transport, origh[i] = heads[i] = xstrdup(to_fetch[i]->name); if (!data->conn) { - connect_setup(transport); + connect_setup(transport, 0, 0); get_remote_heads(data->fd[0], &refs_tmp, 0, NULL, 0, NULL); } @@ -670,20 +683,216 @@ static int fetch_refs_via_pack(struct transport *transport, return (refs ? 0 : -1); } -static int git_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) +static int refs_pushed(struct ref *ref) +{ + for (; ref; ref = ref->next) { + switch(ref->status) { + case REF_STATUS_NONE: + case REF_STATUS_UPTODATE: + break; + default: + return 1; + } + } + return 0; +} + +static void update_tracking_ref(struct remote *remote, struct ref *ref, int verbose) +{ + struct refspec rs; + + if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE) + return; + + rs.src = ref->name; + rs.dst = NULL; + + if (!remote_find_tracking(remote, &rs)) { + if (verbose) + fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst); + if (ref->deletion) { + delete_ref(rs.dst, NULL, 0); + } else + update_ref("update by push", rs.dst, + ref->new_sha1, NULL, 0, 0); + free(rs.dst); + } +} + +#define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3) + +static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg) +{ + fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary); + if (from) + fprintf(stderr, "%s -> %s", prettify_ref(from), prettify_ref(to)); + else + fputs(prettify_ref(to), stderr); + if (msg) { + fputs(" (", stderr); + fputs(msg, stderr); + fputc(')', stderr); + } + fputc('\n', stderr); +} + +static const char *status_abbrev(unsigned char sha1[20]) +{ + return find_unique_abbrev(sha1, DEFAULT_ABBREV); +} + +static void print_ok_ref_status(struct ref *ref) +{ + if (ref->deletion) + print_ref_status('-', "[deleted]", ref, NULL, NULL); + else if (is_null_sha1(ref->old_sha1)) + print_ref_status('*', + (!prefixcmp(ref->name, "refs/tags/") ? "[new tag]" : + "[new branch]"), + ref, ref->peer_ref, NULL); + else { + char quickref[84]; + char type; + const char *msg; + + strcpy(quickref, status_abbrev(ref->old_sha1)); + if (ref->nonfastforward) { + strcat(quickref, "..."); + type = '+'; + msg = "forced update"; + } else { + strcat(quickref, ".."); + type = ' '; + msg = NULL; + } + strcat(quickref, status_abbrev(ref->new_sha1)); + + print_ref_status(type, quickref, ref, ref->peer_ref, msg); + } +} + +static int print_one_push_status(struct ref *ref, const char *dest, int count) +{ + if (!count) + fprintf(stderr, "To %s\n", dest); + + switch(ref->status) { + case REF_STATUS_NONE: + print_ref_status('X', "[no match]", ref, NULL, NULL); + break; + case REF_STATUS_REJECT_NODELETE: + print_ref_status('!', "[rejected]", ref, NULL, + "remote does not support deleting refs"); + break; + case REF_STATUS_UPTODATE: + print_ref_status('=', "[up to date]", ref, + ref->peer_ref, NULL); + break; + case REF_STATUS_REJECT_NONFASTFORWARD: + print_ref_status('!', "[rejected]", ref, ref->peer_ref, + "non-fast forward"); + break; + case REF_STATUS_REMOTE_REJECT: + print_ref_status('!', "[remote rejected]", ref, + ref->deletion ? NULL : ref->peer_ref, + ref->remote_status); + break; + case REF_STATUS_EXPECTING_REPORT: + print_ref_status('!', "[remote failure]", ref, + ref->deletion ? NULL : ref->peer_ref, + "remote failed to report status"); + break; + case REF_STATUS_OK: + print_ok_ref_status(ref); + break; + } + + return 1; +} + +static void print_push_status(const char *dest, struct ref *refs, int verbose) +{ + struct ref *ref; + int n = 0; + + if (verbose) { + for (ref = refs; ref; ref = ref->next) + if (ref->status == REF_STATUS_UPTODATE) + n += print_one_push_status(ref, dest, n); + } + + for (ref = refs; ref; ref = ref->next) + if (ref->status == REF_STATUS_OK) + n += print_one_push_status(ref, dest, n); + + for (ref = refs; ref; ref = ref->next) { + if (ref->status != REF_STATUS_NONE && + ref->status != REF_STATUS_UPTODATE && + ref->status != REF_STATUS_OK) + n += print_one_push_status(ref, dest, n); + } +} + +static void verify_remote_names(int nr_heads, const char **heads) +{ + int i; + + for (i = 0; i < nr_heads; i++) { + const char *local = heads[i]; + const char *remote = strrchr(heads[i], ':'); + + if (*local == '+') + local++; + + /* A matching refspec is okay. */ + if (remote == local && remote[1] == '\0') + continue; + + remote = remote ? (remote + 1) : local; + switch (check_ref_format(remote)) { + case 0: /* ok */ + case CHECK_REF_FORMAT_ONELEVEL: + /* ok but a single level -- that is fine for + * a match pattern. + */ + case CHECK_REF_FORMAT_WILDCARD: + /* ok but ends with a pattern-match character */ + continue; + } + die("remote part of refspec is not a valid name in %s", + heads[i]); + } +} + +static int git_transport_push(struct transport *transport, struct ref *remote_refs, int flags) { struct git_transport_data *data = transport->data; struct send_pack_args args; + int ret; + + if (!data->conn) { + struct ref *tmp_refs; + connect_setup(transport, 1, 0); + + get_remote_heads(data->fd[0], &tmp_refs, 0, NULL, REF_NORMAL, + NULL); + } - args.receivepack = data->receivepack; - args.send_all = !!(flags & TRANSPORT_PUSH_ALL); args.send_mirror = !!(flags & TRANSPORT_PUSH_MIRROR); args.force_update = !!(flags & TRANSPORT_PUSH_FORCE); args.use_thin_pack = data->thin; args.verbose = !!(flags & TRANSPORT_PUSH_VERBOSE); args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN); - return send_pack(&args, transport->url, transport->remote, refspec_nr, refspec); + ret = send_pack(&args, data->fd, data->conn, remote_refs, + &data->extra_have); + + close(data->fd[1]); + close(data->fd[0]); + ret |= finish_connect(data->conn); + data->conn = NULL; + + return ret; } static int disconnect_git(struct transport *transport) @@ -753,7 +962,7 @@ struct transport *transport_get(struct remote *remote, const char *url) ret->set_option = set_git_option; ret->get_refs_list = get_refs_via_connect; ret->fetch = fetch_refs_via_pack; - ret->push = git_transport_push; + ret->push_refs = git_transport_push; ret->disconnect = disconnect_git; data->thin = 1; @@ -780,15 +989,53 @@ int transport_set_option(struct transport *transport, int transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) { - if (!transport->push) - return 1; - return transport->push(transport, refspec_nr, refspec, flags); + verify_remote_names(refspec_nr, refspec); + + if (transport->push) + return transport->push(transport, refspec_nr, refspec, flags); + if (transport->push_refs) { + struct ref *remote_refs = + transport->get_refs_list(transport, 1); + struct ref **remote_tail; + struct ref *local_refs = get_local_heads(); + int match_flags = MATCH_REFS_NONE; + int verbose = flags & TRANSPORT_PUSH_VERBOSE; + int ret; + + if (flags & TRANSPORT_PUSH_ALL) + match_flags |= MATCH_REFS_ALL; + if (flags & TRANSPORT_PUSH_MIRROR) + match_flags |= MATCH_REFS_MIRROR; + + remote_tail = &remote_refs; + while (*remote_tail) + remote_tail = &((*remote_tail)->next); + if (match_refs(local_refs, remote_refs, &remote_tail, + refspec_nr, refspec, match_flags)) { + return -1; + } + + ret = transport->push_refs(transport, remote_refs, flags); + + print_push_status(transport->url, remote_refs, verbose); + + if (!(flags & TRANSPORT_PUSH_DRY_RUN)) { + struct ref *ref; + for (ref = remote_refs; ref; ref = ref->next) + update_tracking_ref(transport->remote, ref, verbose); + } + + if (!ret && !refs_pushed(remote_refs)) + fprintf(stderr, "Everything up-to-date\n"); + return ret; + } + return 1; } const struct ref *transport_get_remote_refs(struct transport *transport) { if (!transport->remote_refs) - transport->remote_refs = transport->get_refs_list(transport); + transport->remote_refs = transport->get_refs_list(transport, 0); return transport->remote_refs; } diff --git a/transport.h b/transport.h index 6bbc1a8264..b1c2252766 100644 --- a/transport.h +++ b/transport.h @@ -18,8 +18,9 @@ struct transport { int (*set_option)(struct transport *connection, const char *name, const char *value); - struct ref *(*get_refs_list)(struct transport *transport); + struct ref *(*get_refs_list)(struct transport *transport, int for_push); int (*fetch)(struct transport *transport, int refs_nr, const struct ref **refs); + int (*push_refs)(struct transport *transport, struct ref *refs, int flags); int (*push)(struct transport *connection, int refspec_nr, const char **refspec, int flags); int (*disconnect)(struct transport *connection); From 880fa117f197a2c1f41fb16b09cd1e8d6050d6fc Mon Sep 17 00:00:00 2001 From: Phil Lawrence <prlawrence@gmail.com> Date: Mon, 9 Mar 2009 17:09:49 -0500 Subject: [PATCH 156/654] Append ampersand to "Target" of lnk files created by do_cygwin_shortcut The git-gui menu item "Repository | Create Desktop Icon" creates a shortcut (.lnk file) on the Windows desktop. The purpose of the created shortcut is to make it easy for a user to launch git-gui for a particular repo in the future. A Windows user would expect to see git gui launch when they click the shortcut; they would not expect (nor want) to see a cmd window open and remain open in the background. msysGit avoids opening a command window altogether when it's Git GUI shortcut is used. Ideally, git on cygwin would also have shortcuts that simply open the GUI, but as a first step, this change allows the shell window to politely disappear after starting git gui as a background process. Signed-off-by: Phil Lawrence <prlawrence@gmail.com> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- lib/shortcut.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/shortcut.tcl b/lib/shortcut.tcl index 38c3151b05..2f20eb39c0 100644 --- a/lib/shortcut.tcl +++ b/lib/shortcut.tcl @@ -54,7 +54,7 @@ proc do_cygwin_shortcut {} { $argv0] win32_create_lnk $fn [list \ $sh -c \ - "CHERE_INVOKING=1 source /etc/profile;[sq $me]" \ + "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \ ] \ [file dirname [file normalize [gitdir]]] } err]} { From 4251ccbd80eff92270503a48d35385516c3d106d Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Mon, 9 Mar 2009 18:47:29 -0700 Subject: [PATCH 157/654] http.c: style cleanups Signed-off-by: Junio C Hamano <gitster@pobox.com> --- http.c | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/http.c b/http.c index 56f18f1b03..d1ead6643d 100644 --- a/http.c +++ b/http.c @@ -1,7 +1,7 @@ #include "http.h" int data_received; -int active_requests = 0; +int active_requests; #ifdef USE_CURL_MULTI static int max_requests = -1; @@ -13,22 +13,22 @@ static CURL *curl_default; char curl_errorstr[CURL_ERROR_SIZE]; static int curl_ssl_verify = -1; -static const char *ssl_cert = NULL; +static const char *ssl_cert; #if LIBCURL_VERSION_NUM >= 0x070902 -static const char *ssl_key = NULL; +static const char *ssl_key; #endif #if LIBCURL_VERSION_NUM >= 0x070908 -static const char *ssl_capath = NULL; +static const char *ssl_capath; #endif -static const char *ssl_cainfo = NULL; +static const char *ssl_cainfo; static long curl_low_speed_limit = -1; static long curl_low_speed_time = -1; -static int curl_ftp_no_epsv = 0; -static const char *curl_http_proxy = NULL; +static int curl_ftp_no_epsv; +static const char *curl_http_proxy; static struct curl_slist *pragma_header; -static struct active_request_slot *active_queue_head = NULL; +static struct active_request_slot *active_queue_head; size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, void *buffer_) { @@ -94,9 +94,8 @@ static void process_curl_messages(void) static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { - if (curl_ssl_verify == -1) { + if (curl_ssl_verify == -1) curl_ssl_verify = git_config_bool(var, value); - } return 0; } @@ -158,9 +157,9 @@ static int http_options(const char *var, const char *value, void *cb) return git_default_config(var, value, cb); } -static CURL* get_curl_handle(void) +static CURL *get_curl_handle(void) { - CURL* result = curl_easy_init(); + CURL *result = curl_easy_init(); if (!curl_ssl_verify) { curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 0); @@ -322,15 +321,14 @@ struct active_request_slot *get_active_slot(void) /* Wait for a slot to open up if the queue is full */ while (active_requests >= max_requests) { curl_multi_perform(curlm, &num_transfers); - if (num_transfers < active_requests) { + if (num_transfers < active_requests) process_curl_messages(); - } } #endif - while (slot != NULL && slot->in_use) { + while (slot != NULL && slot->in_use) slot = slot->next; - } + if (slot == NULL) { newslot = xmalloc(sizeof(*newslot)); newslot->curl = NULL; @@ -341,9 +339,8 @@ struct active_request_slot *get_active_slot(void) if (slot == NULL) { active_queue_head = newslot; } else { - while (slot->next != NULL) { + while (slot->next != NULL) slot = slot->next; - } slot->next = newslot; } slot = newslot; @@ -404,7 +401,7 @@ struct fill_chain { struct fill_chain *next; }; -static struct fill_chain *fill_cfg = NULL; +static struct fill_chain *fill_cfg; void add_fill_function(void *data, int (*fill)(void *)) { @@ -535,9 +532,8 @@ static void finish_active_slot(struct active_request_slot *slot) } /* Run callback if appropriate */ - if (slot->callback_func != NULL) { + if (slot->callback_func != NULL) slot->callback_func(slot->callback_data); - } } void finish_all_active_slots(void) @@ -567,8 +563,10 @@ static inline int needs_quote(int ch) static inline int hex(int v) { - if (v < 10) return '0' + v; - else return 'A' + v - 10; + if (v < 10) + return '0' + v; + else + return 'A' + v - 10; } static char *quote_ref_url(const char *base, const char *ref) From 15112c9599f99487211855db7a7a347f20ad9ed5 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund <kusmabite@gmail.com> Date: Wed, 11 Mar 2009 02:38:12 +0000 Subject: [PATCH 158/654] connect.c: remove a few globals by using git_config callback data Since ef90d6d (Provide git_config with a callback-data parameter, 2008-05-14), git_config() takes a callback data pointer that can be used to pass extra parameters to the parsing function. The codepath to parse configuration variables related to git proxy predates this facility and used a pair of file scope static variables instead. This patch removes the need for these global variables by passing the name of the host we are trying to access as the callback data. Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- connect.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/connect.c b/connect.c index 2f23ab3b87..0a35cc1b25 100644 --- a/connect.c +++ b/connect.c @@ -373,8 +373,6 @@ static void git_tcp_connect(int fd[2], char *host, int flags) static char *git_proxy_command; -static const char *rhost_name; -static int rhost_len; static int git_proxy_command_options(const char *var, const char *value, void *cb) @@ -383,6 +381,8 @@ static int git_proxy_command_options(const char *var, const char *value, const char *for_pos; int matchlen = -1; int hostlen; + const char *rhost_name = cb; + int rhost_len = strlen(rhost_name); if (git_proxy_command) return 0; @@ -426,11 +426,8 @@ static int git_proxy_command_options(const char *var, const char *value, static int git_use_proxy(const char *host) { - rhost_name = host; - rhost_len = strlen(host); git_proxy_command = getenv("GIT_PROXY_COMMAND"); - git_config(git_proxy_command_options, NULL); - rhost_name = NULL; + git_config(git_proxy_command_options, (void*)host); return (git_proxy_command && *git_proxy_command); } From 72f600832f75db626fd9290a21d02d49c92ca9ca Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Tue, 10 Mar 2009 01:20:42 -0700 Subject: [PATCH 159/654] Improve "git branch --tracking" output An earlier patch always spelled the full name of the ref that we track (e.g. "refs/heads/frotz" instead of just "frotz" when we mean the branch whose name is "frotz"). Worse yet, because we now use the true name of the ref at the original repository when talk about a tracking branch that copies from a remote, such a full name alone still does not give enough information. This reorganizes the verbose codepath to: - differentiate "refs/heads/something" and everything else; we say that the branch tracks "branch <something>" if it begins with "refs/heads/", and otherwise the branch tracks "ref refs/<someother>/<something>"; - report the name of the remote when we talk about a tracking branch, by saying "branch frotz from origin"; - not say "by merging" at the end; it is the default and is not worth reporting. Signed-off-by: Junio C Hamano <junio@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- branch.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/branch.c b/branch.c index d20fb0490b..5f889fee6b 100644 --- a/branch.c +++ b/branch.c @@ -65,12 +65,23 @@ void install_branch_config(int flag, const char *local, const char *origin, cons git_config_set(key.buf, "true"); } - if (flag & BRANCH_CONFIG_VERBOSE) - printf("Branch %s set up to track %s branch %s %s.\n", - local, - origin ? "remote" : "local", - remote, - rebasing ? "by rebasing" : "by merging"); + if (flag & BRANCH_CONFIG_VERBOSE) { + strbuf_reset(&key); + + strbuf_addstr(&key, origin ? "remote" : "local"); + + /* Are we tracking a proper "branch"? */ + if (!prefixcmp(remote, "refs/heads/")) { + strbuf_addf(&key, " branch %s", remote + 11); + if (origin) + strbuf_addf(&key, " from %s", origin); + } + else + strbuf_addf(&key, " ref %s", remote); + printf("Branch %s set up to track %s%s.\n", + local, key.buf, + rebasing ? " by rebasing" : ""); + } strbuf_release(&key); } From 7059cd99fc671f9594b61cee7d10d69704f3ebe2 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Mon, 9 Mar 2009 19:00:30 -0700 Subject: [PATCH 160/654] http_init(): Fix config file parsing We honor the command line options, environment variables, variables in repository configuration file, variables in user's global configuration file, variables in the system configuration file, and then finally use built-in default. To implement this semantics, the code should: - start from built-in default values; - call git_config() with the configuration parser callback, which implements "later definition overrides earlier ones" logic (git_config() reads the system's, user's and then repository's configuration file in this order); - override the result from the above with environment variables if set; - override the result from the above with command line options. The initialization code http_init() for http transfer got this wrong, and implemented a "first one wins, ignoring the later ones" in http_options(), to compensate this mistake, read environment variables before calling git_config(). This is all wrong. As a second class citizen, the http codepath hasn't been audited as closely as other parts of the system, but we should try to bring sanity to it, before inviting contributors to improve on it. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- http.c | 69 +++++++++++++++++++++++----------------------------------- 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/http.c b/http.c index d1ead6643d..4c4614c92f 100644 --- a/http.c +++ b/http.c @@ -94,52 +94,33 @@ static void process_curl_messages(void) static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { - if (curl_ssl_verify == -1) - curl_ssl_verify = git_config_bool(var, value); - return 0; - } - - if (!strcmp("http.sslcert", var)) { - if (ssl_cert == NULL) - return git_config_string(&ssl_cert, var, value); + curl_ssl_verify = git_config_bool(var, value); return 0; } + if (!strcmp("http.sslcert", var)) + return git_config_string(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070902 - if (!strcmp("http.sslkey", var)) { - if (ssl_key == NULL) - return git_config_string(&ssl_key, var, value); - return 0; - } + if (!strcmp("http.sslkey", var)) + return git_config_string(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 - if (!strcmp("http.sslcapath", var)) { - if (ssl_capath == NULL) - return git_config_string(&ssl_capath, var, value); - return 0; - } + if (!strcmp("http.sslcapath", var)) + return git_config_string(&ssl_capath, var, value); #endif - if (!strcmp("http.sslcainfo", var)) { - if (ssl_cainfo == NULL) - return git_config_string(&ssl_cainfo, var, value); - return 0; - } - + if (!strcmp("http.sslcainfo", var)) + return git_config_string(&ssl_cainfo, var, value); #ifdef USE_CURL_MULTI if (!strcmp("http.maxrequests", var)) { - if (max_requests == -1) - max_requests = git_config_int(var, value); + max_requests = git_config_int(var, value); return 0; } #endif - if (!strcmp("http.lowspeedlimit", var)) { - if (curl_low_speed_limit == -1) - curl_low_speed_limit = (long)git_config_int(var, value); + curl_low_speed_limit = (long)git_config_int(var, value); return 0; } if (!strcmp("http.lowspeedtime", var)) { - if (curl_low_speed_time == -1) - curl_low_speed_time = (long)git_config_int(var, value); + curl_low_speed_time = (long)git_config_int(var, value); return 0; } @@ -147,11 +128,8 @@ static int http_options(const char *var, const char *value, void *cb) curl_ftp_no_epsv = git_config_bool(var, value); return 0; } - if (!strcmp("http.proxy", var)) { - if (curl_http_proxy == NULL) - return git_config_string(&curl_http_proxy, var, value); - return 0; - } + if (!strcmp("http.proxy", var)) + return git_config_string(&curl_http_proxy, var, value); /* Fall back on the default ones */ return git_default_config(var, value, cb); @@ -212,11 +190,20 @@ static CURL *get_curl_handle(void) return result; } +static void set_from_env(const char **var, const char *envname) +{ + const char *val = getenv(envname); + if (val) + *var = val; +} + void http_init(struct remote *remote) { char *low_speed_limit; char *low_speed_time; + git_config(http_options, NULL); + curl_global_init(CURL_GLOBAL_ALL); if (remote && remote->http_proxy) @@ -241,14 +228,14 @@ void http_init(struct remote *remote) if (getenv("GIT_SSL_NO_VERIFY")) curl_ssl_verify = 0; - ssl_cert = getenv("GIT_SSL_CERT"); + set_from_env(&ssl_cert, "GIT_SSL_CERT"); #if LIBCURL_VERSION_NUM >= 0x070902 - ssl_key = getenv("GIT_SSL_KEY"); + set_from_env(&ssl_key, "GIT_SSL_KEY"); #endif #if LIBCURL_VERSION_NUM >= 0x070908 - ssl_capath = getenv("GIT_SSL_CAPATH"); + set_from_env(&ssl_capath, "GIT_SSL_CAPATH"); #endif - ssl_cainfo = getenv("GIT_SSL_CAINFO"); + set_from_env(&ssl_cainfo, "GIT_SSL_CAINFO"); low_speed_limit = getenv("GIT_HTTP_LOW_SPEED_LIMIT"); if (low_speed_limit != NULL) @@ -257,8 +244,6 @@ void http_init(struct remote *remote) if (low_speed_time != NULL) curl_low_speed_time = strtol(low_speed_time, NULL, 10); - git_config(http_options, NULL); - if (curl_ssl_verify == -1) curl_ssl_verify = 1; From c33976cbc6d1895fca5c1683fba678e786ee3e58 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Mon, 9 Mar 2009 23:34:25 -0700 Subject: [PATCH 161/654] http authentication via prompts Curl is designed not to ask for password when only username is given in the URL, but has a way for application to feed a (username, password) pair to it. With this patch, you do not have to keep your password in plaintext in your $HOME/.netrc file when talking with a password protected URL with http://<username>@<host>/path/to/repository.git/ syntax. The code handles only the http-walker side, not the push side. At least, not yet. But interested parties can add support for it. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- http.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/http.c b/http.c index 4c4614c92f..b8f947e405 100644 --- a/http.c +++ b/http.c @@ -25,6 +25,7 @@ static long curl_low_speed_limit = -1; static long curl_low_speed_time = -1; static int curl_ftp_no_epsv; static const char *curl_http_proxy; +static char *user_name, *user_pass; static struct curl_slist *pragma_header; @@ -135,6 +136,20 @@ static int http_options(const char *var, const char *value, void *cb) return git_default_config(var, value, cb); } +static void init_curl_http_auth(CURL *result) +{ + if (!user_name) + curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); + else { + struct strbuf up = STRBUF_INIT; + if (!user_pass) + user_pass = xstrdup(getpass("Password: ")); + strbuf_addf(&up, "%s:%s", user_name, user_pass); + curl_easy_setopt(result, CURLOPT_USERPWD, + strbuf_detach(&up, NULL)); + } +} + static CURL *get_curl_handle(void) { CURL *result = curl_easy_init(); @@ -153,6 +168,8 @@ static CURL *get_curl_handle(void) curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); #endif + init_curl_http_auth(result); + if (ssl_cert != NULL) curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert); #if LIBCURL_VERSION_NUM >= 0x070902 @@ -190,6 +207,46 @@ static CURL *get_curl_handle(void) return result; } +static void http_auth_init(const char *url) +{ + char *at, *colon, *cp, *slash; + int len; + + cp = strstr(url, "://"); + if (!cp) + return; + + /* + * Ok, the URL looks like "proto://something". Which one? + * "proto://<user>:<pass>@<host>/...", + * "proto://<user>@<host>/...", or just + * "proto://<host>/..."? + */ + cp += 3; + at = strchr(cp, '@'); + colon = strchr(cp, ':'); + slash = strchrnul(cp, '/'); + if (!at || slash <= at) + return; /* No credentials */ + if (!colon || at <= colon) { + /* Only username */ + len = at - cp; + user_name = xmalloc(len + 1); + memcpy(user_name, cp, len); + user_name[len] = '\0'; + user_pass = NULL; + } else { + len = colon - cp; + user_name = xmalloc(len + 1); + memcpy(user_name, cp, len); + user_name[len] = '\0'; + len = at - (colon + 1); + user_pass = xmalloc(len + 1); + memcpy(user_pass, colon + 1, len); + user_pass[len] = '\0'; + } +} + static void set_from_env(const char **var, const char *envname) { const char *val = getenv(envname); @@ -255,6 +312,9 @@ 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]) + http_auth_init(remote->url[0]); + #ifndef NO_CURL_EASY_DUPHANDLE curl_default = get_curl_handle(); #endif From c7cb12b86ca9d0b92fa80045dfa0dd2b64bf71b7 Mon Sep 17 00:00:00 2001 From: Michael J Gruber <git@drmicha.warpmail.net> Date: Tue, 10 Mar 2009 16:06:30 +0100 Subject: [PATCH 162/654] Typo and language fixes for git-checkout.txt Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-checkout.txt | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 3bccffae62..125d8f3c32 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -8,7 +8,7 @@ git-checkout - Checkout a branch or paths to the working tree SYNOPSIS -------- [verse] -'git checkout' [-q] [-f] [--track | --no-track] [-b <new_branch> [-l]] [-m] [<branch>] +'git checkout' [-q] [-f] [-t | --track | --no-track] [-b <new_branch> [-l]] [-m] [<branch>] 'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>... DESCRIPTION @@ -21,15 +21,15 @@ specified, <new_branch>. Using -b will cause <new_branch> to be created; in this case you can use the --track or --no-track options, which will be passed to `git branch`. -As a convenience, --track will default to create a branch whose +As a convenience, --track will default to creating a branch whose name is constructed from the specified branch name by stripping the first namespace level. When <paths> are given, this command does *not* switch branches. It updates the named paths in the working tree from the index file, or from a named <tree-ish> (most often a commit). In -this case, the `-b` options is meaningless and giving -either of them results in an error. <tree-ish> argument can be +this case, the `-b` and `--track` options are meaningless and giving +either of them results in an error. The <tree-ish> argument can be used to specify a specific tree-ish (i.e. commit, tag or tree) to update the index for the given paths before updating the working tree. @@ -75,14 +75,13 @@ entries; instead, unmerged entries are ignored. <repository> <refspec>" explicitly. This behavior is the default when the start point is a remote branch. Set the branch.autosetupmerge configuration variable to `false` if you want - 'git-checkout' and 'git-branch' to always behave as if '--no-track' were + 'git checkout' and 'git branch' to always behave as if '--no-track' were given. Set it to `always` if you want this behavior when the - start-point is either a local or remote branch. + start point is either a local or remote branch. + -If no '-b' option was given, the name of the new branch will be -derived from the remote branch, by attempting to guess the name -of the branch on remote system. If "remotes/" or "refs/remotes/" -are prefixed, it is stripped away, and then the part up to the +If no '-b' option is given, the name of the new branch will be +derived from the remote branch. If "remotes/" or "refs/remotes/" +is prefixed it is stripped away, and then the part up to the next slash (which would be the nickname of the remote) is removed. This would tell us to use "hack" as the local branch when branching off of "origin/hack" (or "remotes/origin/hack", or even @@ -152,12 +151,12 @@ $ git checkout v2.6.18 ------------ Earlier versions of git did not allow this and asked you to -create a temporary branch using `-b` option, but starting from +create a temporary branch using the `-b` option, but starting from version 1.5.0, the above command 'detaches' your HEAD from the -current branch and directly point at the commit named by the tag -(`v2.6.18` in the above example). +current branch and directly points at the commit named by the tag +(`v2.6.18` in the example above). -You can use usual git commands while in this state. You can use +You can use all git commands while in this state. You can use `git reset --hard $othercommit` to further move around, for example. You can make changes and create a new commit on top of a detached HEAD. You can even create a merge by using `git @@ -191,7 +190,7 @@ $ git checkout hello.c <3> ------------ + <1> switch branch -<2> take out a file out of other commit +<2> take a file out of another commit <3> restore hello.c from HEAD of current branch + If you have an unfortunate branch that is named `hello.c`, this @@ -202,7 +201,7 @@ You should instead write: $ git checkout -- hello.c ------------ -. After working in a wrong branch, switching to the correct +. After working in the wrong branch, switching to the correct branch would be done using: + ------------ @@ -210,7 +209,7 @@ $ git checkout mytopic ------------ + However, your "wrong" branch and correct "mytopic" branch may -differ in files that you have locally modified, in which case, +differ in files that you have modified locally, in which case the above checkout would fail like this: + ------------ From 4d5d3984749bfb7e2137fb4bce6ac1ace9286aca Mon Sep 17 00:00:00 2001 From: Daniel Barkalow <barkalow@iabervon.org> Date: Tue, 10 Mar 2009 23:23:45 -0400 Subject: [PATCH 163/654] Include log_config module in apache.conf The log_config module is needed for at least some versions of apache to support the LogFormat directive. Signed-off-by: Daniel Barkalow <barkalow@iabervon.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/lib-httpd/apache.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf index af6e5e1d6a..a0d4077ee3 100644 --- a/t/lib-httpd/apache.conf +++ b/t/lib-httpd/apache.conf @@ -4,6 +4,7 @@ DocumentRoot www LogFormat "%h %l %u %t \"%r\" %>s %b" common CustomLog access.log common ErrorLog error.log +LoadModule log_config_module modules/mod_log_config.so <IfDefine Darwin> LoadModule log_config_module modules/mod_log_config.so From e47eec8fc6efb5ad0574b4862fd8e8e82b6a62fa Mon Sep 17 00:00:00 2001 From: Ramsay Jones <ramsay@ramsay1.demon.co.uk> Date: Mon, 9 Mar 2009 18:31:55 +0000 Subject: [PATCH 164/654] git-instaweb: fix lighttpd configuration on cygwin Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk> Tested-by: Pascal Obry <pascal@obry.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-instaweb.sh | 69 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/git-instaweb.sh b/git-instaweb.sh index 0843372b57..5f4419b69b 100755 --- a/git-instaweb.sh +++ b/git-instaweb.sh @@ -49,7 +49,7 @@ resolve_full_httpd () { esac httpd_only="$(echo $httpd | cut -f1 -d' ')" - if case "$httpd_only" in /*) : ;; *) which $httpd_only >/dev/null;; esac + if case "$httpd_only" in /*) : ;; *) which $httpd_only >/dev/null 2>&1;; esac then full_httpd=$httpd else @@ -179,11 +179,74 @@ lighttpd_conf () { cat > "$conf" <<EOF server.document-root = "$fqgitdir/gitweb" server.port = $port -server.modules = ( "mod_cgi" ) +server.modules = ( "mod_setenv", "mod_cgi" ) server.indexfiles = ( "gitweb.cgi" ) server.pid-file = "$fqgitdir/pid" +server.errorlog = "$fqgitdir/gitweb/error.log" + +# to enable, add "mod_access", "mod_accesslog" to server.modules +# variable above and uncomment this +#accesslog.filename = "$fqgitdir/gitweb/access.log" + +setenv.add-environment = ( "PATH" => "/usr/local/bin:/usr/bin:/bin" ) + cgi.assign = ( ".cgi" => "" ) -mimetype.assign = ( ".css" => "text/css" ) + +# mimetype mapping +mimetype.assign = ( + ".pdf" => "application/pdf", + ".sig" => "application/pgp-signature", + ".spl" => "application/futuresplash", + ".class" => "application/octet-stream", + ".ps" => "application/postscript", + ".torrent" => "application/x-bittorrent", + ".dvi" => "application/x-dvi", + ".gz" => "application/x-gzip", + ".pac" => "application/x-ns-proxy-autoconfig", + ".swf" => "application/x-shockwave-flash", + ".tar.gz" => "application/x-tgz", + ".tgz" => "application/x-tgz", + ".tar" => "application/x-tar", + ".zip" => "application/zip", + ".mp3" => "audio/mpeg", + ".m3u" => "audio/x-mpegurl", + ".wma" => "audio/x-ms-wma", + ".wax" => "audio/x-ms-wax", + ".ogg" => "application/ogg", + ".wav" => "audio/x-wav", + ".gif" => "image/gif", + ".jpg" => "image/jpeg", + ".jpeg" => "image/jpeg", + ".png" => "image/png", + ".xbm" => "image/x-xbitmap", + ".xpm" => "image/x-xpixmap", + ".xwd" => "image/x-xwindowdump", + ".css" => "text/css", + ".html" => "text/html", + ".htm" => "text/html", + ".js" => "text/javascript", + ".asc" => "text/plain", + ".c" => "text/plain", + ".cpp" => "text/plain", + ".log" => "text/plain", + ".conf" => "text/plain", + ".text" => "text/plain", + ".txt" => "text/plain", + ".dtd" => "text/xml", + ".xml" => "text/xml", + ".mpeg" => "video/mpeg", + ".mpg" => "video/mpeg", + ".mov" => "video/quicktime", + ".qt" => "video/quicktime", + ".avi" => "video/x-msvideo", + ".asf" => "video/x-ms-asf", + ".asx" => "video/x-ms-asf", + ".wmv" => "video/x-ms-wmv", + ".bz2" => "application/x-bzip", + ".tbz" => "application/x-bzip-compressed-tar", + ".tar.bz2" => "application/x-bzip-compressed-tar", + "" => "text/plain" + ) EOF test x"$local" = xtrue && echo 'server.bind = "127.0.0.1"' >> "$conf" } From 34df8abaf358c83cc1447d0a81bda7848685a1c9 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Tue, 10 Mar 2009 22:54:17 +0100 Subject: [PATCH 165/654] recv_sideband: Bands #2 and #3 always go to stderr This removes the last parameter of recv_sideband, by which the callers told which channel bands #2 and #3 should be written to. Sayeth Shawn Pearce: The definition of the streams in the current sideband protocol are rather well defined for the one protocol that uses it, fetch-pack/receive-pack: stream #1: pack data stream #2: stderr messages, progress, meant for tty stream #3: abort message, remote is dead, goodbye! Since both callers of the function passed 2 for the parameter, we hereby remove it and send bands #2 and #3 to stderr explicitly using fprintf. This has the nice side-effect that these two streams pass through our ANSI emulation layer on Windows. Signed-off-by: Johannes Sixt <j6t@kdbg.org> Acked-by: Nicolas Pitre <nico@cam.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-archive.c | 2 +- builtin-fetch-pack.c | 2 +- sideband.c | 19 ++++++++----------- sideband.h | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/builtin-archive.c b/builtin-archive.c index 60adef9363..ab50cebba0 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -52,7 +52,7 @@ static int run_remote_archiver(int argc, const char **argv, die("git archive: expected a flush"); /* Now, start reading from fd[0] and spit it out to stdout */ - rv = recv_sideband("archive", fd[0], 1, 2); + rv = recv_sideband("archive", fd[0], 1); close(fd[0]); close(fd[1]); rv |= finish_connect(conn); diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index c2e5adc884..2b360994bf 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -482,7 +482,7 @@ static int sideband_demux(int fd, void *data) { int *xd = data; - return recv_sideband("fetch-pack", xd[0], fd, 2); + return recv_sideband("fetch-pack", xd[0], fd); } static int get_pack(int xd[2], char **pack_lockfile) diff --git a/sideband.c b/sideband.c index cca3360546..899b1ff366 100644 --- a/sideband.c +++ b/sideband.c @@ -19,7 +19,7 @@ #define FIX_SIZE 10 /* large enough for any of the above */ -int recv_sideband(const char *me, int in_stream, int out, int err) +int recv_sideband(const char *me, int in_stream, int out) { unsigned pf = strlen(PREFIX); unsigned sf; @@ -41,8 +41,7 @@ int recv_sideband(const char *me, int in_stream, int out, int err) if (len == 0) break; if (len < 1) { - len = sprintf(buf, "%s: protocol error: no band designator\n", me); - safe_write(err, buf, len); + fprintf(stderr, "%s: protocol error: no band designator\n", me); return SIDEBAND_PROTOCOL_ERROR; } band = buf[pf] & 0xff; @@ -50,8 +49,8 @@ int recv_sideband(const char *me, int in_stream, int out, int err) switch (band) { case 3: buf[pf] = ' '; - buf[pf+1+len] = '\n'; - safe_write(err, buf, pf+1+len+1); + buf[pf+1+len] = '\0'; + fprintf(stderr, "%s\n", buf); return SIDEBAND_REMOTE_ERROR; case 2: buf[pf] = ' '; @@ -95,12 +94,12 @@ int recv_sideband(const char *me, int in_stream, int out, int err) memcpy(save, b + brk, sf); b[brk + sf - 1] = b[brk - 1]; memcpy(b + brk - 1, suffix, sf); - safe_write(err, b, brk + sf); + fprintf(stderr, "%.*s", brk + sf, b); memcpy(b + brk, save, sf); len -= brk; } else { int l = brk ? brk : len; - safe_write(err, b, l); + fprintf(stderr, "%.*s", l, b); len -= l; } @@ -112,10 +111,8 @@ int recv_sideband(const char *me, int in_stream, int out, int err) safe_write(out, buf + pf+1, len); continue; default: - len = sprintf(buf, - "%s: protocol error: bad band #%d\n", - me, band); - safe_write(err, buf, len); + fprintf(stderr, "%s: protocol error: bad band #%d\n", + me, band); return SIDEBAND_PROTOCOL_ERROR; } } diff --git a/sideband.h b/sideband.h index a84b6917c7..d72db35d1e 100644 --- a/sideband.h +++ b/sideband.h @@ -7,7 +7,7 @@ #define DEFAULT_PACKET_MAX 1000 #define LARGE_PACKET_MAX 65520 -int recv_sideband(const char *me, int in_stream, int out, int err); +int recv_sideband(const char *me, int in_stream, int out); ssize_t send_sideband(int fd, int band, const char *data, ssize_t sz, int packet_max); #endif From 1897713fbd96229f3581b8e8a5653da917882195 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Tue, 10 Mar 2009 22:58:09 +0100 Subject: [PATCH 166/654] winansi: support ESC [ K (erase in line) Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- compat/winansi.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index e2d96dfe6f..44dc293ad3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -18,8 +18,6 @@ This file is git-specific. Therefore, this file does not attempt to implement any codes that are not used by git. - - TODO: K */ static HANDLE console; @@ -79,6 +77,20 @@ static void set_console_attr(void) SetConsoleTextAttribute(console, attributes); } +static void erase_in_line(void) +{ + CONSOLE_SCREEN_BUFFER_INFO sbi; + + if (!console) + return; + + GetConsoleScreenBufferInfo(console, &sbi); + FillConsoleOutputCharacterA(console, ' ', + sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition, + NULL); +} + + static const char *set_attr(const char *str) { const char *func; @@ -218,7 +230,7 @@ static const char *set_attr(const char *str) set_console_attr(); break; case 'K': - /* TODO */ + erase_in_line(); break; default: /* Unsupported code */ From 7d59ceed9d1e4f8f0dc52cebf55219d6d395c9da Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <Johannes.Schindelin@gmx.de> Date: Wed, 11 Mar 2009 12:47:06 +0100 Subject: [PATCH 167/654] test: do not LoadModule log_config_module unconditionally LoadModule directive for log_config_module will not work if the module is built-in. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/lib-httpd/apache.conf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf index a0d4077ee3..f460e40416 100644 --- a/t/lib-httpd/apache.conf +++ b/t/lib-httpd/apache.conf @@ -4,7 +4,9 @@ DocumentRoot www LogFormat "%h %l %u %t \"%r\" %>s %b" common CustomLog access.log common ErrorLog error.log -LoadModule log_config_module modules/mod_log_config.so +<IfModule !mod_log_config.c> + LoadModule log_config_module modules/mod_log_config.so +</IfModule> <IfDefine Darwin> LoadModule log_config_module modules/mod_log_config.so From f4e52f0babdb3ec655a168801e613688a7942839 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Wed, 11 Mar 2009 21:47:02 -0700 Subject: [PATCH 168/654] Update release notes to 1.6.3 Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/RelNotes-1.6.3.txt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Documentation/RelNotes-1.6.3.txt b/Documentation/RelNotes-1.6.3.txt index 7f36b6c5c1..f519739ab0 100644 --- a/Documentation/RelNotes-1.6.3.txt +++ b/Documentation/RelNotes-1.6.3.txt @@ -47,15 +47,21 @@ Updates since v1.6.2 * git-bisect shows not just the number of remaining commits whose goodness is unknown, but also shows the estimated number of remaining rounds. +* You can give --date=<format> option to git-blame. + * git-branch -r shows HEAD symref that points at a remote branch in interest of each tracked remote repository. * git-config learned -e option to open an editor to edit the config file directly. +* git-clone runs post-checkout hook when run without --no-checkout. + * git-format-patch can be told to use attachment with a new configuration, format.attach. +* git-format-patch can be told to produce deep or shallow message threads. + * git-imap-send learned to work around Thunderbird's inability to easily disable format=flowed with a new configuration, imap.preformattedHTML. @@ -63,6 +69,8 @@ Updates since v1.6.2 descendant of the commit you are rebasing onto with --force-rebase option. +* git-rebase can be told to report diffstat with the --stat option. + * git-send-email learned --confirm option to review the Cc: list before sending the messages out. @@ -70,6 +78,8 @@ Updates since v1.6.2 * Test scripts can be run under valgrind. +* Makefile learned 'coverage' option to run the test suites with + coverage tracking enabled. Fixes since v1.6.2 ------------------ @@ -80,8 +90,15 @@ release, unless otherwise noted. Here are fixes that this release has, but have not been backported to v1.6.2.X series. +* 'git-submodule add' did not tolerate extra slashes and ./ in the + path it accepted from the command line; it now is more lenient + (if needed, backport by merging db75ada). + +* git-gc spent excessive amount of time to decide if an object appears + in a locally existing pack (if needed, backport by merging 69e020a). + --- exec >/var/tmp/1 -O=v1.6.2-77-g8cc3fe4 +O=v1.6.2-149-g6462146 echo O=$(git describe master) git shortlog --no-merges $O..master ^maint From 2464456a6ac9216d59d9e2cf0d86fee072f63cf8 Mon Sep 17 00:00:00 2001 From: David Aguilar <davvid@gmail.com> Date: Mon, 9 Mar 2009 02:12:36 -0700 Subject: [PATCH 169/654] contrib/difftool: use a separate config namespace for difftool commands Some users have different mergetool and difftool settings, so teach difftool to read config vars from the difftool.* namespace. This allows having distinct configurations for the diff and merge scenarios. We don't want to force existing users to set new values for no reason so difftool falls back to existing mergetool config variables when the difftool equivalents are not defined. Signed-off-by: David Aguilar <davvid@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/difftool/git-difftool | 6 ++--- contrib/difftool/git-difftool-helper | 19 ++++++++++++---- contrib/difftool/git-difftool.txt | 34 ++++++++++++++-------------- 3 files changed, 34 insertions(+), 25 deletions(-) diff --git a/contrib/difftool/git-difftool b/contrib/difftool/git-difftool index 0cda3d2eea..0deda3a0e4 100755 --- a/contrib/difftool/git-difftool +++ b/contrib/difftool/git-difftool @@ -4,7 +4,7 @@ # This is a wrapper around the GIT_EXTERNAL_DIFF-compatible # git-difftool-helper script. This script exports # GIT_EXTERNAL_DIFF and GIT_PAGER for use by git, and -# GIT_DIFFTOOL_NO_PROMPT and GIT_MERGE_TOOL for use by git-difftool-helper. +# GIT_DIFFTOOL_NO_PROMPT and GIT_DIFF_TOOL for use by git-difftool-helper. # Any arguments that are unknown to this script are forwarded to 'git diff'. use strict; @@ -49,12 +49,12 @@ sub generate_command } if ($arg eq '-t' or $arg eq '--tool') { usage() if $#ARGV <= $idx; - $ENV{GIT_MERGE_TOOL} = $ARGV[$idx + 1]; + $ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1]; $skip_next = 1; next; } if ($arg =~ /^--tool=/) { - $ENV{GIT_MERGE_TOOL} = substr($arg, 7); + $ENV{GIT_DIFF_TOOL} = substr($arg, 7); next; } if ($arg eq '--no-prompt') { diff --git a/contrib/difftool/git-difftool-helper b/contrib/difftool/git-difftool-helper index db3af6a833..9c0a13452a 100755 --- a/contrib/difftool/git-difftool-helper +++ b/contrib/difftool/git-difftool-helper @@ -128,8 +128,10 @@ launch_merge_tool () { cleanup_temp_files } -# Verifies that mergetool.<tool>.cmd exists +# Verifies that (difftool|mergetool).<tool>.cmd exists valid_custom_tool() { + merge_tool_cmd="$(git config difftool.$1.cmd)" + test -z "$merge_tool_cmd" && merge_tool_cmd="$(git config mergetool.$1.cmd)" test -n "$merge_tool_cmd" } @@ -150,8 +152,11 @@ valid_tool() { } # Sets up the merge_tool_path variable. -# This handles the mergetool.<tool>.path configuration. +# This handles the difftool.<tool>.path configuration. +# This also falls back to mergetool defaults. init_merge_tool_path() { + merge_tool_path=$(git config difftool."$1".path) + test -z "$merge_tool_path" && merge_tool_path=$(git config mergetool."$1".path) if test -z "$merge_tool_path"; then case "$1" in @@ -165,15 +170,19 @@ init_merge_tool_path() { fi } -# Allow the GIT_MERGE_TOOL variable to provide a default value +# Allow GIT_DIFF_TOOL and GIT_MERGE_TOOL to provide default values test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL" +test -n "$GIT_DIFF_TOOL" && merge_tool="$GIT_DIFF_TOOL" -# If not merge tool was specified then use the merge.tool +# If merge tool was not specified then use the diff.tool # configuration variable. If that's invalid then reset merge_tool. +# Fallback to merge.tool. if test -z "$merge_tool"; then + merge_tool=$(git config diff.tool) + test -z "$merge_tool" && merge_tool=$(git config merge.tool) if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then - echo >&2 "git config option merge.tool set to unknown tool: $merge_tool" + echo >&2 "git config option diff.tool set to unknown tool: $merge_tool" echo >&2 "Resetting to default..." unset merge_tool fi diff --git a/contrib/difftool/git-difftool.txt b/contrib/difftool/git-difftool.txt index 6e2610cda6..2b7bc03ec3 100644 --- a/contrib/difftool/git-difftool.txt +++ b/contrib/difftool/git-difftool.txt @@ -32,23 +32,23 @@ OPTIONS vimdiff, gvimdiff, ecmerge, and opendiff + If a merge resolution program is not specified, 'git-difftool' -will use the configuration variable `merge.tool`. If the -configuration variable `merge.tool` is not set, 'git difftool' +will use the configuration variable `diff.tool`. If the +configuration variable `diff.tool` is not set, 'git-difftool' will pick a suitable default. + You can explicitly provide a full path to the tool by setting the -configuration variable `mergetool.<tool>.path`. For example, you +configuration variable `difftool.<tool>.path`. For example, you can configure the absolute path to kdiff3 by setting -`mergetool.kdiff3.path`. Otherwise, 'git-difftool' assumes the +`difftool.kdiff3.path`. Otherwise, 'git-difftool' assumes the tool is available in PATH. + Instead of running one of the known merge tool programs, 'git-difftool' can be customized to run an alternative program by specifying the command line to invoke in a configuration -variable `mergetool.<tool>.cmd`. +variable `difftool.<tool>.cmd`. + When 'git-difftool' is invoked with this tool (either through the -`-t` or `--tool` option or the `merge.tool` configuration variable) +`-t` or `--tool` option or the `diff.tool` configuration variable) the configured command line will be invoked with the following variables available: `$LOCAL` is set to the name of the temporary file containing the contents of the diff pre-image and `$REMOTE` @@ -61,8 +61,18 @@ with custom merge tool commands and has the same value as `$LOCAL`. CONFIG VARIABLES ---------------- -merge.tool:: +'git-difftool' falls back to 'git-mergetool' config variables when the +difftool equivalents have not been defined. + +diff.tool:: The default merge tool to use. + +difftool.<tool>.path:: + Override the path for the given tool. This is useful in case + your tool is not in the PATH. + +difftool.<tool>.cmd:: + Specify the command to invoke the specified merge tool. + See the `--tool=<tool>` option above for more details. @@ -70,16 +80,6 @@ merge.keepBackup:: The original, unedited file content can be saved to a file with a `.orig` extension. Defaults to `true` (i.e. keep the backup files). -mergetool.<tool>.path:: - Override the path for the given tool. This is useful in case - your tool is not in the PATH. - -mergetool.<tool>.cmd:: - Specify the command to invoke the specified merge tool. -+ -See the `--tool=<tool>` option above for more details. - - SEE ALSO -------- linkgit:git-diff[1]:: From 3bc427e01342a5a6ae2052d27373f8759c680398 Mon Sep 17 00:00:00 2001 From: Thomas Rast <trast@student.ethz.ch> Date: Thu, 12 Mar 2009 00:00:56 +0100 Subject: [PATCH 170/654] Documentation: filter-branch: show --ignore-unmatch in main index-filter example Rearrange the example usage of git filter-branch --index-filter 'git rm --cached ...' so that --ignore-unmatch is in the main example block. People keep stumbling over the (lack of this) option to the point where it is a FAQ, so we would want to expose the most common usage where it stands out. Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-filter-branch.txt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt index 7ffe03f427..237f85e767 100644 --- a/Documentation/git-filter-branch.txt +++ b/Documentation/git-filter-branch.txt @@ -91,7 +91,9 @@ OPTIONS --index-filter <command>:: This is the filter for rewriting the index. It is similar to the tree filter but does not check out the tree, which makes it much - faster. For hairy cases, see linkgit:git-update-index[1]. + faster. Frequently used with `git rm \--cached + \--ignore-unmatch ...`, see EXAMPLES below. For hairy + cases, see linkgit:git-update-index[1]. --parent-filter <command>:: This is the filter for rewriting the commit's parent list. @@ -204,19 +206,18 @@ However, if the file is absent from the tree of some commit, a simple `rm filename` will fail for that tree and commit. Thus you may instead want to use `rm -f filename` as the script. -A significantly faster version: +Using `\--index-filter` with 'git-rm' yields a significantly faster +version. Like with using `rm filename`, `git rm --cached filename` +will fail if the file is absent from the tree of a commit. If you +want to "completely forget" a file, it does not matter when it entered +history, so we also add `\--ignore-unmatch`: -------------------------------------------------------------------------- -git filter-branch --index-filter 'git rm --cached filename' HEAD +git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD -------------------------------------------------------------------------- Now, you will get the rewritten history saved in HEAD. -As with using `rm filename`, `git rm --cached filename` will fail -if the file is absent from the tree of a commit. If it is not important -whether the file is already absent from the tree, you can use -`git rm --cached --ignore-unmatch filename` instead. - To rewrite the repository to look as if `foodir/` had been its project root, and discard all other history: From 750d9305009a0f3fd14c0b5c5e62ae1eb2b18fda Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Thu, 12 Mar 2009 22:34:43 -0700 Subject: [PATCH 171/654] http.c: CURLOPT_NETRC_OPTIONAL is not available in ancient versions of cURL Besides, we have already called easy_setopt with the option before coming to this function if it was available, so there is no need to repeat it here. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- http.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/http.c b/http.c index b8f947e405..2fc55d671e 100644 --- a/http.c +++ b/http.c @@ -138,9 +138,7 @@ static int http_options(const char *var, const char *value, void *cb) static void init_curl_http_auth(CURL *result) { - if (!user_name) - curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); - else { + if (user_name) { struct strbuf up = STRBUF_INIT; if (!user_pass) user_pass = xstrdup(getpass("Password: ")); From e068f4f53b22c64f2058c316d858a892a5e24a6e Mon Sep 17 00:00:00 2001 From: Ben Walton <bwalton@artsci.utoronto.ca> Date: Thu, 12 Mar 2009 15:20:06 -0400 Subject: [PATCH 172/654] configure: ensure settings from user are also usable in the script Allow things set by the user (--with-lib, --with-iconv, etc) to set variables for use by other parts of the script. Display values as they're set. Signed-off-by: Ben Walton <bwalton@artsci.utoronto.ca> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- configure.ac | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/configure.ac b/configure.ac index 082a03d3cf..0b314d7359 100644 --- a/configure.ac +++ b/configure.ac @@ -42,6 +42,8 @@ else \ if test "$withval" = "yes"; then \ AC_MSG_WARN([You should provide path for --with-$1=PATH]); \ else \ + m4_toupper($1)_PATH=$withval; \ + AC_MSG_NOTICE([Setting m4_toupper($1)_PATH to $withval]); \ GIT_CONF_APPEND_LINE(${PROGRAM}_PATH=$withval); \ fi; \ fi; \ @@ -61,6 +63,8 @@ elif test "$withval" = "yes"; then \ m4_toupper(NO_$1)=; \ else \ m4_toupper(NO_$1)=; \ + m4_toupper($1)DIR=$withval; \ + AC_MSG_NOTICE([Setting m4_toupper($1)DIR to $withval]); \ GIT_CONF_APPEND_LINE(${PACKAGE}DIR=$withval); \ fi \ ])# GIT_PARSE_WITH @@ -86,9 +90,16 @@ AC_ARG_WITH([lib], [if test "$withval" = "no" || test "$withval" = "yes"; then \ AC_MSG_WARN([You should provide name for --with-lib=ARG]); \ else \ + lib=$withval; \ + AC_MSG_NOTICE([Setting lib to '$lib']); \ GIT_CONF_APPEND_LINE(lib=$withval); \ fi; \ ],[]) + +if test -z "$lib"; then + AC_MSG_NOTICE([Setting lib to 'lib' (the default)]) + lib=lib +fi # # Define SHELL_PATH to provide path to shell. GIT_ARG_SET_PATH(shell) From 08df6a3086f4bcd5b224d442f103a7f63a605967 Mon Sep 17 00:00:00 2001 From: Ben Walton <bwalton@artsci.utoronto.ca> Date: Thu, 12 Mar 2009 15:20:07 -0400 Subject: [PATCH 173/654] configure: reorganize flow of argument checks Move the argument tests from the 'site overrides' so that they are ahead of any library tests. This allows for library tests to take user specified paths into account. The intent here is to avoid things like NO_DEFLATE_BOUND being set due to finding old zlib when the user has specified an alternate location for zlib. (Ignore the fact that properly set *FLAGS can avoid solve this issue.) Signed-off-by: Ben Walton <bwalton@artsci.utoronto.ca> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- configure.ac | 174 +++++++++++++++++++++++++-------------------------- 1 file changed, 87 insertions(+), 87 deletions(-) diff --git a/configure.ac b/configure.ac index 0b314d7359..0bff4808c0 100644 --- a/configure.ac +++ b/configure.ac @@ -100,6 +100,93 @@ if test -z "$lib"; then AC_MSG_NOTICE([Setting lib to 'lib' (the default)]) lib=lib fi + +## Site configuration (override autodetection) +## --with-PACKAGE[=ARG] and --without-PACKAGE +AC_MSG_NOTICE([CHECKS for site configuration]) +# +# Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability +# tests. These tests take up a significant amount of the total test time +# but are not needed unless you plan to talk to SVN repos. +# +# Define MOZILLA_SHA1 environment variable when running make to make use of +# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast +# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default +# choice) has very fast version optimized for i586. +# +# Define PPC_SHA1 environment variable when running make to make use of +# a bundled SHA1 routine optimized for PowerPC. +# +# Define ARM_SHA1 environment variable when running make to make use of +# a bundled SHA1 routine optimized for ARM. +# +# Define NO_OPENSSL environment variable if you do not have OpenSSL. +# This also implies MOZILLA_SHA1. +# +# Define OPENSSLDIR=/foo/bar if your openssl header and library files are in +# /foo/bar/include and /foo/bar/lib directories. +AC_ARG_WITH(openssl, +AS_HELP_STRING([--with-openssl],[use OpenSSL library (default is YES)]) +AS_HELP_STRING([], [ARG can be prefix for openssl library and headers]),\ +GIT_PARSE_WITH(openssl)) +# +# Define NO_CURL if you do not have curl installed. git-http-pull and +# git-http-push are not built, and you cannot use http:// and https:// +# transports. +# +# Define CURLDIR=/foo/bar if your curl header and library files are in +# /foo/bar/include and /foo/bar/lib directories. +AC_ARG_WITH(curl, +AS_HELP_STRING([--with-curl],[support http(s):// transports (default is YES)]) +AS_HELP_STRING([], [ARG can be also prefix for curl library and headers]), +GIT_PARSE_WITH(curl)) +# +# Define NO_EXPAT if you do not have expat installed. git-http-push is +# not built, and you cannot push using http:// and https:// transports. +# +# Define EXPATDIR=/foo/bar if your expat header and library files are in +# /foo/bar/include and /foo/bar/lib directories. +AC_ARG_WITH(expat, +AS_HELP_STRING([--with-expat], +[support git-push using http:// and https:// transports via WebDAV (default is YES)]) +AS_HELP_STRING([], [ARG can be also prefix for expat library and headers]), +GIT_PARSE_WITH(expat)) +# +# Define NO_FINK if you are building on Darwin/Mac OS X, have Fink +# installed in /sw, but don't want GIT to link against any libraries +# installed there. If defined you may specify your own (or Fink's) +# include directories and library directories by defining CFLAGS +# and LDFLAGS appropriately. +# +# Define NO_DARWIN_PORTS if you are building on Darwin/Mac OS X, +# have DarwinPorts installed in /opt/local, but don't want GIT to +# link against any libraries installed there. If defined you may +# specify your own (or DarwinPort's) include directories and +# library directories by defining CFLAGS and LDFLAGS appropriately. +# +# Define NO_MMAP if you want to avoid mmap. +# +# Define NO_ICONV if your libc does not properly support iconv. +AC_ARG_WITH(iconv, +AS_HELP_STRING([--without-iconv], +[if your architecture doesn't properly support iconv]) +AS_HELP_STRING([--with-iconv=PATH], +[PATH is prefix for libiconv library and headers]) +AS_HELP_STRING([], +[used only if you need linking with libiconv]), +GIT_PARSE_WITH(iconv)) + +## --enable-FEATURE[=ARG] and --disable-FEATURE +# +# Define USE_NSEC below if you want git to care about sub-second file mtimes +# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and +# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely +# randomly break unless your underlying filesystem supports those sub-second +# times (my ext3 doesn't). +# +# Define USE_STDEV below if you want git to care about the underlying device +# change being considered an inode change from the update-index perspective. + # # Define SHELL_PATH to provide path to shell. GIT_ARG_SET_PATH(shell) @@ -526,93 +613,6 @@ AC_SUBST(PTHREAD_LIBS) AC_SUBST(NO_PTHREADS) AC_SUBST(THREADED_DELTA_SEARCH) -## Site configuration (override autodetection) -## --with-PACKAGE[=ARG] and --without-PACKAGE -AC_MSG_NOTICE([CHECKS for site configuration]) -# -# Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability -# tests. These tests take up a significant amount of the total test time -# but are not needed unless you plan to talk to SVN repos. -# -# Define MOZILLA_SHA1 environment variable when running make to make use of -# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast -# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default -# choice) has very fast version optimized for i586. -# -# Define PPC_SHA1 environment variable when running make to make use of -# a bundled SHA1 routine optimized for PowerPC. -# -# Define ARM_SHA1 environment variable when running make to make use of -# a bundled SHA1 routine optimized for ARM. -# -# Define NO_OPENSSL environment variable if you do not have OpenSSL. -# This also implies MOZILLA_SHA1. -# -# Define OPENSSLDIR=/foo/bar if your openssl header and library files are in -# /foo/bar/include and /foo/bar/lib directories. -AC_ARG_WITH(openssl, -AS_HELP_STRING([--with-openssl],[use OpenSSL library (default is YES)]) -AS_HELP_STRING([], [ARG can be prefix for openssl library and headers]),\ -GIT_PARSE_WITH(openssl)) -# -# Define NO_CURL if you do not have curl installed. git-http-pull and -# git-http-push are not built, and you cannot use http:// and https:// -# transports. -# -# Define CURLDIR=/foo/bar if your curl header and library files are in -# /foo/bar/include and /foo/bar/lib directories. -AC_ARG_WITH(curl, -AS_HELP_STRING([--with-curl],[support http(s):// transports (default is YES)]) -AS_HELP_STRING([], [ARG can be also prefix for curl library and headers]), -GIT_PARSE_WITH(curl)) -# -# Define NO_EXPAT if you do not have expat installed. git-http-push is -# not built, and you cannot push using http:// and https:// transports. -# -# Define EXPATDIR=/foo/bar if your expat header and library files are in -# /foo/bar/include and /foo/bar/lib directories. -AC_ARG_WITH(expat, -AS_HELP_STRING([--with-expat], -[support git-push using http:// and https:// transports via WebDAV (default is YES)]) -AS_HELP_STRING([], [ARG can be also prefix for expat library and headers]), -GIT_PARSE_WITH(expat)) -# -# Define NO_FINK if you are building on Darwin/Mac OS X, have Fink -# installed in /sw, but don't want GIT to link against any libraries -# installed there. If defined you may specify your own (or Fink's) -# include directories and library directories by defining CFLAGS -# and LDFLAGS appropriately. -# -# Define NO_DARWIN_PORTS if you are building on Darwin/Mac OS X, -# have DarwinPorts installed in /opt/local, but don't want GIT to -# link against any libraries installed there. If defined you may -# specify your own (or DarwinPort's) include directories and -# library directories by defining CFLAGS and LDFLAGS appropriately. -# -# Define NO_MMAP if you want to avoid mmap. -# -# Define NO_ICONV if your libc does not properly support iconv. -AC_ARG_WITH(iconv, -AS_HELP_STRING([--without-iconv], -[if your architecture doesn't properly support iconv]) -AS_HELP_STRING([--with-iconv=PATH], -[PATH is prefix for libiconv library and headers]) -AS_HELP_STRING([], -[used only if you need linking with libiconv]), -GIT_PARSE_WITH(iconv)) - -## --enable-FEATURE[=ARG] and --disable-FEATURE -# -# Define USE_NSEC below if you want git to care about sub-second file mtimes -# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and -# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely -# randomly break unless your underlying filesystem supports those sub-second -# times (my ext3 doesn't). -# -# Define USE_STDEV below if you want git to care about the underlying device -# change being considered an inode change from the update-index perspective. - - ## Output files AC_CONFIG_FILES(["${config_file}":"${config_in}":"${config_append}"]) AC_OUTPUT From 918c8120172514704809cbdf889794d8b1345d0a Mon Sep 17 00:00:00 2001 From: Ben Walton <bwalton@artsci.utoronto.ca> Date: Thu, 12 Mar 2009 15:20:08 -0400 Subject: [PATCH 174/654] configure: add macros to stash FLAG variables Allow for quick stash/unstash of CPPFLAGS and LDFLAGS. Library tests can now be easily bracketted with these macros to allow for values set in user/site arguments. Signed-off-by: Ben Walton <bwalton@artsci.utoronto.ca> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- configure.ac | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/configure.ac b/configure.ac index 0bff4808c0..469c9a98d2 100644 --- a/configure.ac +++ b/configure.ac @@ -80,6 +80,32 @@ AC_DEFUN([GIT_CHECK_FUNC],[AC_CHECK_FUNC([$1],[ AC_SEARCH_LIBS([$1],, [$2],[$3]) ],[$3])]) + +dnl +dnl GIT_STASH_FLAGS(BASEPATH_VAR) +dnl ----------------------------- +dnl Allow for easy stashing of LDFLAGS and CPPFLAGS before running +dnl tests that may want to take user settings into account. +AC_DEFUN([GIT_STASH_FLAGS],[ +if test -n "$1"; then + old_CPPFLAGS="$CPPFLAGS" + old_LDFLAGS="$LDFLAGS" + CPPFLAGS="-I$1/include $CPPFLAGS" + LDFLAGS="-L$1/$lib $LDFLAGS" +fi +]) + +dnl +dnl GIT_UNSTASH_FLAGS(BASEPATH_VAR) +dnl ----------------------------- +dnl Restore the stashed *FLAGS values. +AC_DEFUN([GIT_UNSTASH_FLAGS],[ +if test -n "$1"; then + CPPFLAGS="$old_CPPFLAGS" + LDFLAGS="$old_LDFLAGS" +fi +]) + ## Site configuration related to programs (before tests) ## --with-PACKAGE[=ARG] and --without-PACKAGE # From 310386f07b5ef3dc337db1be37345fbd8d7a3af8 Mon Sep 17 00:00:00 2001 From: Ben Walton <bwalton@artsci.utoronto.ca> Date: Thu, 12 Mar 2009 15:20:09 -0400 Subject: [PATCH 175/654] configure: wrap some library tests with GIT_STASH_FLAGS Libraries that can have user specificed base paths are wrapped with GIT_STASH_FLAGS/GIT_UNSTASH_FLAGS to ensure that the proper versions on the system are tested. This ensures, for example, that the zlib tests for deflateUnbound are done with the version of zlib requested by the user. This is most useful in the absence of good settings for CPPFLAGS and/or LDFLAGS. Signed-off-by: Ben Walton <bwalton@artsci.utoronto.ca> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- configure.ac | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 469c9a98d2..fe9d7eb463 100644 --- a/configure.ac +++ b/configure.ac @@ -315,33 +315,57 @@ AC_MSG_NOTICE([CHECKS for libraries]) # # Define NO_OPENSSL environment variable if you do not have OpenSSL. # Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin). + +GIT_STASH_FLAGS($OPENSSLDIR) + AC_CHECK_LIB([crypto], [SHA1_Init], [NEEDS_SSL_WITH_CRYPTO=], [AC_CHECK_LIB([ssl], [SHA1_Init], [NEEDS_SSL_WITH_CRYPTO=YesPlease NEEDS_SSL_WITH_CRYPTO=], [NO_OPENSSL=YesPlease])]) + +GIT_UNSTASH_FLAGS($OPENSSLDIR) + AC_SUBST(NEEDS_SSL_WITH_CRYPTO) AC_SUBST(NO_OPENSSL) + # # Define NO_CURL if you do not have libcurl installed. git-http-pull and # git-http-push are not built, and you cannot use http:// and https:// # transports. + +GIT_STASH_FLAGS($CURLDIR) + AC_CHECK_LIB([curl], [curl_global_init], [NO_CURL=], [NO_CURL=YesPlease]) + +GIT_UNSTASH_FLAGS($CURLDIR) + AC_SUBST(NO_CURL) + # # Define NO_EXPAT if you do not have expat installed. git-http-push is # not built, and you cannot push using http:// and https:// transports. + +GIT_STASH_FLAGS($EXPATDIR) + AC_CHECK_LIB([expat], [XML_ParserCreate], [NO_EXPAT=], [NO_EXPAT=YesPlease]) + +GIT_UNSTASH_FLAGS($EXPATDIR) + AC_SUBST(NO_EXPAT) + # # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin and # some Solaris installations). # Define NO_ICONV if neither libc nor libiconv support iconv. + +GIT_STASH_FLAGS($ICONVDIR) + AC_DEFUN([ICONVTEST_SRC], [ #include <iconv.h> @@ -365,11 +389,17 @@ AC_LINK_IFELSE(ICONVTEST_SRC, [AC_MSG_RESULT([no]) NO_ICONV=YesPlease]) LIBS="$old_LIBS"]) + +GIT_UNSTASH_FLAGS($ICONVDIR) + AC_SUBST(NEEDS_LIBICONV) AC_SUBST(NO_ICONV) -test -n "$NEEDS_LIBICONV" && LIBS="$LIBS -liconv" + # # Define NO_DEFLATE_BOUND if deflateBound is missing from zlib. + +GIT_STASH_FLAGS($ZLIB_PATH) + AC_DEFUN([ZLIBTEST_SRC], [ #include <zlib.h> @@ -387,7 +417,11 @@ AC_LINK_IFELSE(ZLIBTEST_SRC, [AC_MSG_RESULT([no]) NO_DEFLATE_BOUND=yes]) LIBS="$old_LIBS" + +GIT_UNSTASH_FLAGS($ZLIB_PATH) + AC_SUBST(NO_DEFLATE_BOUND) + # # Define NEEDS_SOCKET if linking with libc is not enough (SunOS, # Patrick Mauritz). From 29adc8baf997e143d8aeac9a0aeb257539d32e6d Mon Sep 17 00:00:00 2001 From: Ben Walton <bwalton@artsci.utoronto.ca> Date: Thu, 12 Mar 2009 15:20:10 -0400 Subject: [PATCH 176/654] configure: asciidoc version test cleanup Redirect stderr to /dev/null instead of stdout. This discards warnings generated by python 2.6 related to the reorganization of functions within modules. The warnings were causing the version detection to break. Signed-off-by: Ben Walton <bwalton@artsci.utoronto.ca> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index fe9d7eb463..f4b8e49dc3 100644 --- a/configure.ac +++ b/configure.ac @@ -291,7 +291,7 @@ fi AC_CHECK_PROGS(ASCIIDOC, [asciidoc]) if test -n "$ASCIIDOC"; then AC_MSG_CHECKING([for asciidoc version]) - asciidoc_version=`$ASCIIDOC --version 2>&1` + asciidoc_version=`$ASCIIDOC --version 2>/dev/null` case "${asciidoc_version}" in asciidoc' '8*) ASCIIDOC8=YesPlease From a8304f7a70832a8e333fcf547589bc9d3bc0ca3c Mon Sep 17 00:00:00 2001 From: Ben Walton <bwalton@artsci.utoronto.ca> Date: Thu, 12 Mar 2009 15:20:11 -0400 Subject: [PATCH 177/654] configure: make iconv tests aware of user arguments --with-iconv is now taken into account when doing the tests for iconv. If the user requests alternate handling for libiconv, the -liconv test is run before the -lc test. Signed-off-by: Ben Walton <bwalton@artsci.utoronto.ca> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- configure.ac | 48 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/configure.ac b/configure.ac index f4b8e49dc3..6fe4bfe738 100644 --- a/configure.ac +++ b/configure.ac @@ -375,20 +375,35 @@ int main(void) return 0; } ]) -AC_MSG_CHECKING([for iconv in -lc]) -AC_LINK_IFELSE(ICONVTEST_SRC, + +if test -n "$ICONVDIR"; then + lib_order="-liconv -lc" +else + lib_order="-lc -liconv" +fi + +NO_ICONV=YesPlease + +for l in $lib_order; do + if test "$l" = "-liconv"; then + NEEDS_LIBICONV=YesPlease + else + NEEDS_LIBICONV= + fi + + old_LIBS="$LIBS" + LIBS="$LIBS $l" + AC_MSG_CHECKING([for iconv in $l]) + AC_LINK_IFELSE(ICONVTEST_SRC, [AC_MSG_RESULT([yes]) - NEEDS_LIBICONV=], - [AC_MSG_RESULT([no]) - old_LIBS="$LIBS" - LIBS="$LIBS -liconv" - AC_MSG_CHECKING([for iconv in -liconv]) - AC_LINK_IFELSE(ICONVTEST_SRC, - [AC_MSG_RESULT([yes]) - NEEDS_LIBICONV=YesPlease], - [AC_MSG_RESULT([no]) - NO_ICONV=YesPlease]) - LIBS="$old_LIBS"]) + NO_ICONV= + break], + [AC_MSG_RESULT([no])]) + LIBS="$old_LIBS" +done + +#in case of break +LIBS="$old_LIBS" GIT_UNSTASH_FLAGS($ICONVDIR) @@ -455,13 +470,18 @@ int main(void) return 0; } ]]) + +GIT_STASH_FLAGS($ICONVDIR) + AC_MSG_CHECKING([for old iconv()]) AC_COMPILE_IFELSE(OLDICONVTEST_SRC, [AC_MSG_RESULT([no])], [AC_MSG_RESULT([yes]) OLD_ICONV=UnfortunatelyYes]) -AC_SUBST(OLD_ICONV) +GIT_UNSTASH_FLAGS($ICONVDIR) + +AC_SUBST(OLD_ICONV) ## Checks for typedefs, structures, and compiler characteristics. AC_MSG_NOTICE([CHECKS for typedefs, structures, and compiler characteristics]) From 1973b0d790155b5d8a32a6f7401116fad2205721 Mon Sep 17 00:00:00 2001 From: Ben Walton <bwalton@artsci.utoronto.ca> Date: Thu, 12 Mar 2009 15:20:12 -0400 Subject: [PATCH 178/654] configure: rework pthread handling to allow for user defined flags The tests for POSIX threads can now be controlled by the user with the --enable-pthreads=FLAGS option. If this is set (to some value other than yes or no), the value is passed to the compiler. Thread support is based solely on the outcome of this test. The user may specify not to use threading at all or to use the default tests (first -pthread then -lpthread) by not specifying FLAGS when passing --enable-pthreads. Signed-off-by: Ben Walton <bwalton@artsci.utoronto.ca> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- configure.ac | 89 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 74 insertions(+), 15 deletions(-) diff --git a/configure.ac b/configure.ac index 6fe4bfe738..4e728bca35 100644 --- a/configure.ac +++ b/configure.ac @@ -127,6 +127,27 @@ if test -z "$lib"; then lib=lib fi +AC_ARG_ENABLE([pthreads], + [AS_HELP_STRING([--enable-pthreads=FLAGS], + [FLAGS is the value to pass to the compiler to enable POSIX Threads.] + [The default if FLAGS is not specified is to try first -pthread] + [and then -lpthread.] + [--without-pthreads will disable threading.])], +[ +if test "x$enableval" = "xyes"; then + AC_MSG_NOTICE([Will try -pthread then -lpthread to enable POSIX Threads]) +elif test "x$enableval" != "xno"; then + PTHREAD_CFLAGS=$enableval + AC_MSG_NOTICE([Setting '$PTHREAD_CFLAGS' as the FLAGS to enable POSIX Threads]) +else + AC_MSG_NOTICE([POSIX Threads will be disabled.]) + NO_PTHREADS=YesPlease + USER_NOPTHREAD=1 +fi], +[ + AC_MSG_NOTICE([Will try -pthread then -lpthread to enable POSIX Threads.]) +]) + ## Site configuration (override autodetection) ## --with-PACKAGE[=ARG] and --without-PACKAGE AC_MSG_NOTICE([CHECKS for site configuration]) @@ -672,23 +693,61 @@ AC_SUBST(NO_MKDTEMP) # # Define PTHREAD_LIBS to the linker flag used for Pthread support and define # THREADED_DELTA_SEARCH if Pthreads are available. -AC_LANG_CONFTEST([AC_LANG_PROGRAM( - [[#include <pthread.h>]], - [[pthread_mutex_t test_mutex;]] -)]) -${CC} -pthread conftest.c -o conftest.o > /dev/null 2>&1 -if test $? -eq 0;then - PTHREAD_LIBS="-pthread" - THREADED_DELTA_SEARCH=YesPlease +AC_DEFUN([PTHREADTEST_SRC], [ +#include <pthread.h> + +int main(void) +{ + pthread_mutex_t test_mutex; + return (0); +} +]) + +dnl AC_LANG_CONFTEST([AC_LANG_PROGRAM( +dnl [[#include <pthread.h>]], +dnl [[pthread_mutex_t test_mutex;]] +dnl )]) + +NO_PTHREADS=UnfortunatelyYes +THREADED_DELTA_SEARCH= +PTHREAD_LIBS= + +if test -n "$USER_NOPTHREAD"; then + AC_MSG_NOTICE([Skipping POSIX Threads at user request.]) +# handle these separately since PTHREAD_CFLAGS could be '-lpthreads +# -D_REENTRANT' or some such. +elif test -z "$PTHREAD_CFLAGS"; then + for opt in -pthread -lpthread; do + old_CFLAGS="$CFLAGS" + CFLAGS="$opt $CFLAGS" + AC_MSG_CHECKING([Checking for POSIX Threads with '$opt']) + AC_LINK_IFELSE(PTHREADTEST_SRC, + [AC_MSG_RESULT([yes]) + NO_PTHREADS= + PTHREAD_LIBS="$opt" + THREADED_DELTA_SEARCH=YesPlease + break + ], + [AC_MSG_RESULT([no])]) + CFLAGS="$old_CFLAGS" + done else - ${CC} -lpthread conftest.c -o conftest.o > /dev/null 2>&1 - if test $? -eq 0;then - PTHREAD_LIBS="-lpthread" - THREADED_DELTA_SEARCH=YesPlease - else - NO_PTHREADS=UnfortunatelyYes - fi + old_CFLAGS="$CFLAGS" + CFLAGS="$PTHREAD_CFLAGS $CFLAGS" + AC_MSG_CHECKING([Checking for POSIX Threads with '$PTHREAD_CFLAGS']) + AC_LINK_IFELSE(PTHREADTEST_SRC, + [AC_MSG_RESULT([yes]) + NO_PTHREADS= + PTHREAD_LIBS="$PTHREAD_CFLAGS" + THREADED_DELTA_SEARCH=YesPlease + ], + [AC_MSG_RESULT([no])]) + + CFLAGS="$old_CFLAGS" fi + +CFLAGS="$old_CFLAGS" + AC_SUBST(PTHREAD_LIBS) AC_SUBST(NO_PTHREADS) AC_SUBST(THREADED_DELTA_SEARCH) From 06f33c1735bf76e02f3e2601cde5161e969872a7 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Fri, 13 Mar 2009 21:24:08 -0700 Subject: [PATCH 179/654] Read attributes from the index that is being checked out Traditionally we used .gitattributes file from the work tree if exists, and otherwise read from the index as a fallback. When switching to a branch that has an updated .gitattributes file, and entries in it give different attributes to other paths being checked out, we should instead read from the .gitattributes in the index. This breaks a use case of fixing incorrect entries in the .gitattributes in the work tree (without adding it to the index) and checking other paths out, though. $ edit .gitattributes ;# mark foo.dat as binary $ rm foo.dat $ git checkout foo.dat Signed-off-by: Junio C Hamano <gitster@pobox.com> --- attr.c | 73 +++++++++++++++++++++++++++++++++++++------------- attr.h | 6 +++++ unpack-trees.c | 3 +++ 3 files changed, 64 insertions(+), 18 deletions(-) diff --git a/attr.c b/attr.c index 17f6a4dca5..43259e5b01 100644 --- a/attr.c +++ b/attr.c @@ -1,3 +1,4 @@ +#define NO_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" #include "attr.h" @@ -318,6 +319,9 @@ static struct attr_stack *read_attr_from_array(const char **list) return res; } +static enum git_attr_direction direction; +static struct index_state *use_index; + static struct attr_stack *read_attr_from_file(const char *path, int macro_ok) { FILE *fp = fopen(path, "r"); @@ -340,9 +344,10 @@ static void *read_index_data(const char *path) unsigned long sz; enum object_type type; void *data; + struct index_state *istate = use_index ? use_index : &the_index; len = strlen(path); - pos = cache_name_pos(path, len); + pos = index_name_pos(istate, path, len); if (pos < 0) { /* * We might be in the middle of a merge, in which @@ -350,15 +355,15 @@ static void *read_index_data(const char *path) */ int i; for (i = -pos - 1; - (pos < 0 && i < active_nr && - !strcmp(active_cache[i]->name, path)); + (pos < 0 && i < istate->cache_nr && + !strcmp(istate->cache[i]->name, path)); i++) - if (ce_stage(active_cache[i]) == 2) + if (ce_stage(istate->cache[i]) == 2) pos = i; } if (pos < 0) return NULL; - data = read_sha1_file(active_cache[pos]->sha1, &type, &sz); + data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz); if (!data || type != OBJ_BLOB) { free(data); return NULL; @@ -366,27 +371,17 @@ static void *read_index_data(const char *path) return data; } -static struct attr_stack *read_attr(const char *path, int macro_ok) +static struct attr_stack *read_attr_from_index(const char *path, int macro_ok) { struct attr_stack *res; char *buf, *sp; int lineno = 0; - res = read_attr_from_file(path, macro_ok); - if (res) - return res; - - res = xcalloc(1, sizeof(*res)); - - /* - * There is no checked out .gitattributes file there, but - * we might have it in the index. We allow operation in a - * sparsely checked out work tree, so read from it. - */ buf = read_index_data(path); if (!buf) - return res; + return NULL; + res = xcalloc(1, sizeof(*res)); for (sp = buf; *sp; ) { char *ep; int more; @@ -401,6 +396,30 @@ static struct attr_stack *read_attr(const char *path, int macro_ok) return res; } +static struct attr_stack *read_attr(const char *path, int macro_ok) +{ + struct attr_stack *res; + + if (direction == GIT_ATTR_CHECKOUT) { + res = read_attr_from_index(path, macro_ok); + if (!res) + res = read_attr_from_file(path, macro_ok); + } + else { + res = read_attr_from_file(path, macro_ok); + if (!res) + /* + * There is no checked out .gitattributes file there, but + * we might have it in the index. We allow operation in a + * sparsely checked out work tree, so read from it. + */ + res = read_attr_from_index(path, macro_ok); + } + if (!res) + res = xcalloc(1, sizeof(*res)); + return res; +} + #if DEBUG_ATTR static void debug_info(const char *what, struct attr_stack *elem) { @@ -428,6 +447,15 @@ static void debug_set(const char *what, const char *match, struct git_attr *attr #define debug_set(a,b,c,d) do { ; } while (0) #endif +static void drop_attr_stack(void) +{ + while (attr_stack) { + struct attr_stack *elem = attr_stack; + attr_stack = elem->prev; + free_attr_elem(elem); + } +} + static void bootstrap_attr_stack(void) { if (!attr_stack) { @@ -642,3 +670,12 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check) return 0; } + +void git_attr_set_direction(enum git_attr_direction new, struct index_state *istate) +{ + enum git_attr_direction old = direction; + direction = new; + if (new != old) + drop_attr_stack(); + use_index = istate; +} diff --git a/attr.h b/attr.h index f1c2038b09..3a2f4ec1a0 100644 --- a/attr.h +++ b/attr.h @@ -31,4 +31,10 @@ struct git_attr_check { int git_checkattr(const char *path, int, struct git_attr_check *); +enum git_attr_direction { + GIT_ATTR_CHECKIN, + GIT_ATTR_CHECKOUT +}; +void git_attr_set_direction(enum git_attr_direction, struct index_state *); + #endif /* ATTR_H */ diff --git a/unpack-trees.c b/unpack-trees.c index e547282ed5..661218c5ae 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -7,6 +7,7 @@ #include "unpack-trees.h" #include "progress.h" #include "refs.h" +#include "attr.h" /* * Error messages expected by scripts out of plumbing commands such as @@ -105,6 +106,7 @@ static int check_updates(struct unpack_trees_options *o) cnt = 0; } + git_attr_set_direction(GIT_ATTR_CHECKOUT, &o->result); for (i = 0; i < index->cache_nr; i++) { struct cache_entry *ce = index->cache[i]; @@ -130,6 +132,7 @@ static int check_updates(struct unpack_trees_options *o) } } stop_progress(&progress); + git_attr_set_direction(GIT_ATTR_CHECKIN, NULL); return errs != 0; } From 7f733de04e69c8ba40158d1da46c4aa121f714b6 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Fri, 13 Mar 2009 13:23:26 +0100 Subject: [PATCH 180/654] test-suite: Make test script numbers unique In order to selectively skip tests, the environment variable GIT_SKIP_TESTS can be set like this: $ GIT_SKIP_TESTS='t1301 t4150.18' make test That is, its value can contain only the test script numbers, but not the full script name. Therefore, it is important that the test scripts are uniquely numbered. This makes it so. Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/{t3409-rebase-hook.sh => t3413-rebase-hook.sh} | 0 t/{t4017-quiet.sh => t4035-diff-quiet.sh} | 0 ...mat-patch-signer-mime.sh => t4036-format-patch-signer-mime.sh} | 0 t/{t4203-patch-id.sh => t4204-patch-id.sh} | 0 t/{t5521-pull-symlink.sh => t5522-pull-symlink.sh} | 0 ...6023-merge-rename-nocruft.sh => t6034-merge-rename-nocruft.sh} | 0 t/{t7502-status.sh => t7508-status.sh} | 0 t/{t9108-git-svn-multi-glob.sh => t9109-git-svn-multi-glob.sh} | 0 ...-clobber-series.sh => t9137-git-svn-dcommit-clobber-series.sh} | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename t/{t3409-rebase-hook.sh => t3413-rebase-hook.sh} (100%) rename t/{t4017-quiet.sh => t4035-diff-quiet.sh} (100%) rename t/{t4021-format-patch-signer-mime.sh => t4036-format-patch-signer-mime.sh} (100%) rename t/{t4203-patch-id.sh => t4204-patch-id.sh} (100%) rename t/{t5521-pull-symlink.sh => t5522-pull-symlink.sh} (100%) rename t/{t6023-merge-rename-nocruft.sh => t6034-merge-rename-nocruft.sh} (100%) rename t/{t7502-status.sh => t7508-status.sh} (100%) rename t/{t9108-git-svn-multi-glob.sh => t9109-git-svn-multi-glob.sh} (100%) rename t/{t9106-git-svn-dcommit-clobber-series.sh => t9137-git-svn-dcommit-clobber-series.sh} (100%) diff --git a/t/t3409-rebase-hook.sh b/t/t3413-rebase-hook.sh similarity index 100% rename from t/t3409-rebase-hook.sh rename to t/t3413-rebase-hook.sh diff --git a/t/t4017-quiet.sh b/t/t4035-diff-quiet.sh similarity index 100% rename from t/t4017-quiet.sh rename to t/t4035-diff-quiet.sh diff --git a/t/t4021-format-patch-signer-mime.sh b/t/t4036-format-patch-signer-mime.sh similarity index 100% rename from t/t4021-format-patch-signer-mime.sh rename to t/t4036-format-patch-signer-mime.sh diff --git a/t/t4203-patch-id.sh b/t/t4204-patch-id.sh similarity index 100% rename from t/t4203-patch-id.sh rename to t/t4204-patch-id.sh diff --git a/t/t5521-pull-symlink.sh b/t/t5522-pull-symlink.sh similarity index 100% rename from t/t5521-pull-symlink.sh rename to t/t5522-pull-symlink.sh diff --git a/t/t6023-merge-rename-nocruft.sh b/t/t6034-merge-rename-nocruft.sh similarity index 100% rename from t/t6023-merge-rename-nocruft.sh rename to t/t6034-merge-rename-nocruft.sh diff --git a/t/t7502-status.sh b/t/t7508-status.sh similarity index 100% rename from t/t7502-status.sh rename to t/t7508-status.sh diff --git a/t/t9108-git-svn-multi-glob.sh b/t/t9109-git-svn-multi-glob.sh similarity index 100% rename from t/t9108-git-svn-multi-glob.sh rename to t/t9109-git-svn-multi-glob.sh diff --git a/t/t9106-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh similarity index 100% rename from t/t9106-git-svn-dcommit-clobber-series.sh rename to t/t9137-git-svn-dcommit-clobber-series.sh From 8e76bf3fc915ff9c530842123263e7147df207bb Mon Sep 17 00:00:00 2001 From: Benjamin Kramer <benny.kra@googlemail.com> Date: Fri, 13 Mar 2009 13:51:33 +0100 Subject: [PATCH 181/654] Remove unused assignments These variables were always overwritten or the assigned value was unused: builtin-diff-tree.c::cmd_diff_tree(): nr_sha1 builtin-for-each-ref.c::opt_parse_sort(): sort_tail builtin-mailinfo.c::decode_header_bq(): in builtin-shortlog.c::insert_one_record(): len connect.c::git_connect(): path imap-send.c::v_issue_imap_cmd(): n pretty.c::pp_user_info(): filler remote::parse_refspec_internal(): llen Signed-off-by: Benjamin Kramer <benny.kra@googlemail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-diff-tree.c | 1 - builtin-for-each-ref.c | 1 - builtin-mailinfo.c | 1 - builtin-shortlog.c | 1 - connect.c | 2 +- imap-send.c | 2 +- pretty.c | 4 +--- remote.c | 2 +- 8 files changed, 4 insertions(+), 10 deletions(-) diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c index 8ecefd4f0f..79cedb72c4 100644 --- a/builtin-diff-tree.c +++ b/builtin-diff-tree.c @@ -102,7 +102,6 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix) init_revisions(opt, prefix); git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ - nr_sha1 = 0; opt->abbrev = 0; opt->diff = 1; argc = setup_revisions(argc, argv, opt, NULL); diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index e46b7adc97..5cbb4b081d 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -943,7 +943,6 @@ static int opt_parse_sort(const struct option *opt, const char *arg, int unset) return -1; *sort_tail = s = xcalloc(1, sizeof(*s)); - sort_tail = &s->next; if (*arg == '-') { s->reverse = 1; diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c index 2789ccdf7d..1eeeb4de6d 100644 --- a/builtin-mailinfo.c +++ b/builtin-mailinfo.c @@ -537,7 +537,6 @@ static int decode_header_bq(struct strbuf *it) */ strbuf_add(&outbuf, in, ep - in); } - in = ep; } /* E.g. * ep : "=?iso-2022-jp?B?GyR...?= foo" diff --git a/builtin-shortlog.c b/builtin-shortlog.c index badd912038..b28091b445 100644 --- a/builtin-shortlog.c +++ b/builtin-shortlog.c @@ -101,7 +101,6 @@ static void insert_one_record(struct shortlog *log, } while (*oneline && isspace(*oneline) && *oneline != '\n') oneline++; - len = eol - oneline; format_subject(&subject, oneline, " "); buffer = strbuf_detach(&subject, NULL); diff --git a/connect.c b/connect.c index 0a35cc1b25..7636bf976e 100644 --- a/connect.c +++ b/connect.c @@ -504,7 +504,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig, const char *prog, int flags) { char *url = xstrdup(url_orig); - char *host, *path = url; + char *host, *path; char *end; int c; struct child_process *conn; diff --git a/imap-send.c b/imap-send.c index cb518eb613..8154cb2116 100644 --- a/imap-send.c +++ b/imap-send.c @@ -579,7 +579,7 @@ static struct imap_cmd *v_issue_imap_cmd(struct imap_store *ctx, n = socket_write(&imap->buf.sock, cmd->cb.data, cmd->cb.dlen); free(cmd->cb.data); if (n != cmd->cb.dlen || - (n = socket_write(&imap->buf.sock, "\r\n", 2)) != 2) { + socket_write(&imap->buf.sock, "\r\n", 2) != 2) { free(cmd->cmd); free(cmd); return NULL; diff --git a/pretty.c b/pretty.c index c018408099..efa70245f1 100644 --- a/pretty.c +++ b/pretty.c @@ -135,7 +135,6 @@ void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb, int namelen; unsigned long time; int tz; - const char *filler = " "; if (fmt == CMIT_FMT_ONELINE) return; @@ -154,7 +153,6 @@ void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb, while (line < name_tail && isspace(name_tail[-1])) name_tail--; display_name_length = name_tail - line; - filler = ""; strbuf_addstr(sb, "From: "); add_rfc2047(sb, line, display_name_length, encoding); strbuf_add(sb, name_tail, namelen - display_name_length); @@ -162,7 +160,7 @@ void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb, } else { strbuf_addf(sb, "%s: %.*s%.*s\n", what, (fmt == CMIT_FMT_FULLER) ? 4 : 0, - filler, namelen, line); + " ", namelen, line); } switch (fmt) { case CMIT_FMT_MEDIUM: diff --git a/remote.c b/remote.c index d7079c6dd8..7efaa023b9 100644 --- a/remote.c +++ b/remote.c @@ -495,7 +495,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp int is_glob; const char *lhs, *rhs; - llen = is_glob = 0; + is_glob = 0; lhs = refspec[i]; if (*lhs == '+') { From bba2a7b22fdde7a214516e93d957a950571a2026 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Fri, 13 Mar 2009 17:26:36 +0100 Subject: [PATCH 182/654] test-lib: write test results to test-results/<basename>-<pid> The earlier code meant to attempt to strip everything except the test number, but only stripped the part starting with the last dash. However, there is no reason why we should not use the whole basename. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/test-lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index 7a847ecbde..1e01a912ab 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -464,7 +464,7 @@ test_done () { trap - EXIT test_results_dir="$TEST_DIRECTORY/test-results" mkdir -p "$test_results_dir" - test_results_path="$test_results_dir/${0%-*}-$$" + test_results_path="$test_results_dir/${0%.sh}-$$" echo "total $test_count" >> $test_results_path echo "success $test_success" >> $test_results_path From 5bcf109cdf7f7b676600883be8dc7dbf26ddb055 Mon Sep 17 00:00:00 2001 From: Kjetil Barvik <barvik@broadpark.no> Date: Sun, 15 Mar 2009 12:38:55 +0100 Subject: [PATCH 183/654] checkout bugfix: use stat.mtime instead of stat.ctime in two places Commit e1afca4fd "write_index(): update index_state->timestamp after flushing to disk" on 2009-02-23 used stat.ctime to record the timestamp of the index-file. This is wrong, so fix this and use the correct stat.mtime timestamp instead. Commit 110c46a909 "Not all systems use st_[cm]tim field for ns resolution file timestamp" on 2009-03-08, has a similar bug for the builtin-fetch-pack.c file. Signed-off-by: Kjetil Barvik <barvik@broadpark.no> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-fetch-pack.c | 2 +- read-cache.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 1d7e02326f..8b33861681 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -807,7 +807,7 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args, die("shallow file was removed during fetch"); } else if (st.st_mtime != mtime.sec #ifdef USE_NSEC - || ST_CTIME_NSEC(st) != mtime.nsec + || ST_MTIME_NSEC(st) != mtime.nsec #endif ) die("shallow file was changed during fetch"); diff --git a/read-cache.c b/read-cache.c index 7f74c8d161..3f587110cb 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1563,8 +1563,8 @@ int write_index(struct index_state *istate, int newfd) if (ce_flush(&c, newfd) || fstat(newfd, &st)) return -1; - istate->timestamp.sec = (unsigned int)st.st_ctime; - istate->timestamp.nsec = ST_CTIME_NSEC(st); + istate->timestamp.sec = (unsigned int)st.st_mtime; + istate->timestamp.nsec = ST_MTIME_NSEC(st); return 0; } From 8e24cbaeafc7eed709e251fda1673ffea84edfb1 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer <benny.kra@googlemail.com> Date: Sun, 15 Mar 2009 22:01:20 +0100 Subject: [PATCH 184/654] Fix various dead stores found by the clang static analyzer http-push.c::finish_request(): request is initialized by the for loop index-pack.c::free_base_data(): b is initialized by the for loop merge-recursive.c::process_renames(): move compare to narrower scope, and remove unused assignments to it remove unused variable renames2 xdiff/xdiffi.c::xdl_recs_cmp(): remove unused variable ec xdiff/xemit.c::xdl_emit_diff(): xche is always overwritten Signed-off-by: Benjamin Kramer <benny.kra@googlemail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- http-push.c | 2 +- index-pack.c | 2 +- merge-recursive.c | 11 +++-------- xdiff/xdiffi.c | 5 ++--- xdiff/xemit.c | 2 +- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/http-push.c b/http-push.c index 30d2d34041..671569594e 100644 --- a/http-push.c +++ b/http-push.c @@ -816,7 +816,7 @@ static void finish_request(struct transfer_request *request) #ifdef USE_CURL_MULTI static int fill_active_slot(void *unused) { - struct transfer_request *request = request_queue_head; + struct transfer_request *request; if (aborted) return 0; diff --git a/index-pack.c b/index-pack.c index 7fee872533..75468228d3 100644 --- a/index-pack.c +++ b/index-pack.c @@ -232,7 +232,7 @@ static void free_base_data(struct base_data *c) static void prune_base_data(struct base_data *retain) { - struct base_data *b = base_cache; + struct base_data *b; for (b = base_cache; base_cache_used > delta_base_cache_limit && b; b = b->child) { diff --git a/merge-recursive.c b/merge-recursive.c index ee853b990d..3e1bc3e07f 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -801,22 +801,19 @@ static int process_renames(struct merge_options *o, } for (i = 0, j = 0; i < a_renames->nr || j < b_renames->nr;) { - int compare; char *src; - struct string_list *renames1, *renames2, *renames2Dst; + struct string_list *renames1, *renames2Dst; struct rename *ren1 = NULL, *ren2 = NULL; const char *branch1, *branch2; const char *ren1_src, *ren1_dst; if (i >= a_renames->nr) { - compare = 1; ren2 = b_renames->items[j++].util; } else if (j >= b_renames->nr) { - compare = -1; ren1 = a_renames->items[i++].util; } else { - compare = strcmp(a_renames->items[i].string, - b_renames->items[j].string); + int compare = strcmp(a_renames->items[i].string, + b_renames->items[j].string); if (compare <= 0) ren1 = a_renames->items[i++].util; if (compare >= 0) @@ -826,14 +823,12 @@ static int process_renames(struct merge_options *o, /* TODO: refactor, so that 1/2 are not needed */ if (ren1) { renames1 = a_renames; - renames2 = b_renames; renames2Dst = &b_by_dst; branch1 = o->branch1; branch2 = o->branch2; } else { struct rename *tmp; renames1 = b_renames; - renames2 = a_renames; renames2Dst = &a_by_dst; branch1 = o->branch2; branch2 = o->branch1; diff --git a/xdiff/xdiffi.c b/xdiff/xdiffi.c index 3e97462bdd..02184d9cde 100644 --- a/xdiff/xdiffi.c +++ b/xdiff/xdiffi.c @@ -293,15 +293,14 @@ int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1, for (; off1 < lim1; off1++) rchg1[rindex1[off1]] = 1; } else { - long ec; xdpsplit_t spl; spl.i1 = spl.i2 = 0; /* * Divide ... */ - if ((ec = xdl_split(ha1, off1, lim1, ha2, off2, lim2, kvdf, kvdb, - need_min, &spl, xenv)) < 0) { + if (xdl_split(ha1, off1, lim1, ha2, off2, lim2, kvdf, kvdb, + need_min, &spl, xenv) < 0) { return -1; } diff --git a/xdiff/xemit.c b/xdiff/xemit.c index 05bfa41f10..c4bedf0d1c 100644 --- a/xdiff/xemit.c +++ b/xdiff/xemit.c @@ -132,7 +132,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, if (xecfg->flags & XDL_EMIT_COMMON) return xdl_emit_common(xe, xscr, ecb, xecfg); - for (xch = xche = xscr; xch; xch = xche->next) { + for (xch = xscr; xch; xch = xche->next) { xche = xdl_get_hunk(xch, xecfg); s1 = XDL_MAX(xch->i1 - xecfg->ctxlen, 0); From 7ee3760e2c8f181f22d4b80afc03309e4f764385 Mon Sep 17 00:00:00 2001 From: Michael J Gruber <git@drmicha.warpmail.net> Date: Mon, 16 Mar 2009 18:03:11 +0100 Subject: [PATCH 185/654] test-lib.sh: Test for presence of git-init in the right path. It just happens so that when GIT_EXEC_PATH points to a compiled checkout of git.git it contains "git". Since this is not true in general make test-lib check for "git-init" which is always in GIT_EXEC_PATH. Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/test-lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index 1e01a912ab..dace24c541 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -454,7 +454,7 @@ test_create_repo () { repo="$1" mkdir -p "$repo" cd "$repo" || error "Cannot setup test environment" - "$GIT_EXEC_PATH/git" init "--template=$owd/../templates/blt/" >&3 2>&4 || + "$GIT_EXEC_PATH/git-init" "--template=$owd/../templates/blt/" >&3 2>&4 || error "cannot run git init -- have you built things yet?" mv .git/hooks .git/hooks-disabled cd "$owd" From 6720721e152aee230387546efac865319f025597 Mon Sep 17 00:00:00 2001 From: Michael J Gruber <git@drmicha.warpmail.net> Date: Mon, 16 Mar 2009 18:03:12 +0100 Subject: [PATCH 186/654] test-lib.sh: Allow running the test suite against installed git Introduce variables GIT_TEST_INSTALLED and GIT_TEST_EXEC_PATH such that the test suite can be run against a git which is installed at GIT_TEST_INSTALLED with subcommands at GIT_TEST_EXEC_PATH. GIT_TEST_INSTALLED defaults to the git.git checkout, GIT_TEST_EXEC_PATH defaults to the output of '$GIT_TEST_INSTALLED/git --exec-path'. Run the suite e.g. as GIT_TEST_INSTALLED=/some/path make test but note that this requires and uses parts of a compiled git in the git.git checkout: test helpers, templates and perl libraries are taken from there. Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/test-lib.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index dace24c541..a70b633dd9 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -514,8 +514,16 @@ test_done () { TEST_DIRECTORY=$(pwd) if test -z "$valgrind" then - PATH=$TEST_DIRECTORY/..:$PATH - GIT_EXEC_PATH=$TEST_DIRECTORY/.. + if test -z "$GIT_TEST_INSTALLED" + then + PATH=$TEST_DIRECTORY/..:$PATH + GIT_EXEC_PATH=$TEST_DIRECTORY/.. + else + GIT_EXEC_PATH=$($GIT_TEST_INSTALLED/git --exec-path) || + error "Cannot run git from $GIT_TEST_INSTALLED." + PATH=$GIT_TEST_INSTALLED:$TEST_DIRECTORY/..:$PATH + GIT_EXEC_PATH=${GIT_TEST_EXEC_PATH:-$GIT_EXEC_PATH} + fi else make_symlink () { test -h "$2" && From 379f84b8d19b5412aff5b9d6bd7bb1ada37b9353 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg <markus.heidelberg@web.de> Date: Sat, 14 Mar 2009 00:42:37 +0100 Subject: [PATCH 187/654] git-gui: don't hide the Browse button when resizing the repo chooser Rather shrink the input field for "Create New Repository" and "Open Existing Repository" as it's already done for "Clone Existing Repository". Signed-off-by: Markus Heidelberg <markus.heidelberg@web.de> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- lib/choose_repository.tcl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/choose_repository.tcl b/lib/choose_repository.tcl index f9ff62a3b2..09277e9fa1 100644 --- a/lib/choose_repository.tcl +++ b/lib/choose_repository.tcl @@ -398,6 +398,8 @@ method _do_new {} { grid $w_body.where.l $w_body.where.t $w_body.where.b -sticky ew pack $w_body.where -fill x + grid columnconfigure $w_body.where 1 -weight 1 + trace add variable @local_path write [cb _write_local_path] bind $w_body.h <Destroy> [list trace remove variable @local_path write [cb _write_local_path]] update @@ -998,6 +1000,8 @@ method _do_open {} { grid $w_body.where.l $w_body.where.t $w_body.where.b -sticky ew pack $w_body.where -fill x + grid columnconfigure $w_body.where 1 -weight 1 + trace add variable @local_path write [cb _write_local_path] bind $w_body.h <Destroy> [list trace remove variable @local_path write [cb _write_local_path]] update From b3debd2b0c091990c420f78e074c0c160498e51d Mon Sep 17 00:00:00 2001 From: Petr Kodl <petrkodl@gmail.com> Date: Sat, 24 Jan 2009 15:04:39 +0100 Subject: [PATCH 188/654] MinGW: a helper function that translates Win32 API error codes This function translates many possible Win32 error codes to suitable errno numbers. We will use it in our wrapper functions that need to call into Win32. Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- compat/mingw.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 27bcf3fd6b..f66ad56aae 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -4,6 +4,119 @@ unsigned int _CRT_fmode = _O_BINARY; +static int err_win_to_posix(DWORD winerr) +{ + int error = ENOSYS; + switch(winerr) { + case ERROR_ACCESS_DENIED: error = EACCES; break; + case ERROR_ACCOUNT_DISABLED: error = EACCES; break; + case ERROR_ACCOUNT_RESTRICTION: error = EACCES; break; + case ERROR_ALREADY_ASSIGNED: error = EBUSY; break; + case ERROR_ALREADY_EXISTS: error = EEXIST; break; + case ERROR_ARITHMETIC_OVERFLOW: error = ERANGE; break; + case ERROR_BAD_COMMAND: error = EIO; break; + case ERROR_BAD_DEVICE: error = ENODEV; break; + case ERROR_BAD_DRIVER_LEVEL: error = ENXIO; break; + case ERROR_BAD_EXE_FORMAT: error = ENOEXEC; break; + case ERROR_BAD_FORMAT: error = ENOEXEC; break; + case ERROR_BAD_LENGTH: error = EINVAL; break; + case ERROR_BAD_PATHNAME: error = ENOENT; break; + case ERROR_BAD_PIPE: error = EPIPE; break; + case ERROR_BAD_UNIT: error = ENODEV; break; + case ERROR_BAD_USERNAME: error = EINVAL; break; + case ERROR_BROKEN_PIPE: error = EPIPE; break; + case ERROR_BUFFER_OVERFLOW: error = ENAMETOOLONG; break; + case ERROR_BUSY: error = EBUSY; break; + case ERROR_BUSY_DRIVE: error = EBUSY; break; + case ERROR_CALL_NOT_IMPLEMENTED: error = ENOSYS; break; + case ERROR_CANNOT_MAKE: error = EACCES; break; + case ERROR_CANTOPEN: error = EIO; break; + case ERROR_CANTREAD: error = EIO; break; + case ERROR_CANTWRITE: error = EIO; break; + case ERROR_CRC: error = EIO; break; + case ERROR_CURRENT_DIRECTORY: error = EACCES; break; + case ERROR_DEVICE_IN_USE: error = EBUSY; break; + case ERROR_DEV_NOT_EXIST: error = ENODEV; break; + case ERROR_DIRECTORY: error = EINVAL; break; + case ERROR_DIR_NOT_EMPTY: error = ENOTEMPTY; break; + case ERROR_DISK_CHANGE: error = EIO; break; + case ERROR_DISK_FULL: error = ENOSPC; break; + case ERROR_DRIVE_LOCKED: error = EBUSY; break; + case ERROR_ENVVAR_NOT_FOUND: error = EINVAL; break; + case ERROR_EXE_MARKED_INVALID: error = ENOEXEC; break; + case ERROR_FILENAME_EXCED_RANGE: error = ENAMETOOLONG; break; + case ERROR_FILE_EXISTS: error = EEXIST; break; + case ERROR_FILE_INVALID: error = ENODEV; break; + case ERROR_FILE_NOT_FOUND: error = ENOENT; break; + case ERROR_GEN_FAILURE: error = EIO; break; + case ERROR_HANDLE_DISK_FULL: error = ENOSPC; break; + case ERROR_INSUFFICIENT_BUFFER: error = ENOMEM; break; + case ERROR_INVALID_ACCESS: error = EACCES; break; + case ERROR_INVALID_ADDRESS: error = EFAULT; break; + case ERROR_INVALID_BLOCK: error = EFAULT; break; + case ERROR_INVALID_DATA: error = EINVAL; break; + case ERROR_INVALID_DRIVE: error = ENODEV; break; + case ERROR_INVALID_EXE_SIGNATURE: error = ENOEXEC; break; + case ERROR_INVALID_FLAGS: error = EINVAL; break; + case ERROR_INVALID_FUNCTION: error = ENOSYS; break; + case ERROR_INVALID_HANDLE: error = EBADF; break; + case ERROR_INVALID_LOGON_HOURS: error = EACCES; break; + case ERROR_INVALID_NAME: error = EINVAL; break; + case ERROR_INVALID_OWNER: error = EINVAL; break; + case ERROR_INVALID_PARAMETER: error = EINVAL; break; + case ERROR_INVALID_PASSWORD: error = EPERM; break; + case ERROR_INVALID_PRIMARY_GROUP: error = EINVAL; break; + case ERROR_INVALID_SIGNAL_NUMBER: error = EINVAL; break; + case ERROR_INVALID_TARGET_HANDLE: error = EIO; break; + case ERROR_INVALID_WORKSTATION: error = EACCES; break; + case ERROR_IO_DEVICE: error = EIO; break; + case ERROR_IO_INCOMPLETE: error = EINTR; break; + case ERROR_LOCKED: error = EBUSY; break; + case ERROR_LOCK_VIOLATION: error = EACCES; break; + case ERROR_LOGON_FAILURE: error = EACCES; break; + case ERROR_MAPPED_ALIGNMENT: error = EINVAL; break; + case ERROR_META_EXPANSION_TOO_LONG: error = E2BIG; break; + case ERROR_MORE_DATA: error = EPIPE; break; + case ERROR_NEGATIVE_SEEK: error = ESPIPE; break; + case ERROR_NOACCESS: error = EFAULT; break; + case ERROR_NONE_MAPPED: error = EINVAL; break; + case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM; break; + case ERROR_NOT_READY: error = EAGAIN; break; + case ERROR_NOT_SAME_DEVICE: error = EXDEV; break; + case ERROR_NO_DATA: error = EPIPE; break; + case ERROR_NO_MORE_SEARCH_HANDLES: error = EIO; break; + case ERROR_NO_PROC_SLOTS: error = EAGAIN; break; + case ERROR_NO_SUCH_PRIVILEGE: error = EACCES; break; + case ERROR_OPEN_FAILED: error = EIO; break; + case ERROR_OPEN_FILES: error = EBUSY; break; + case ERROR_OPERATION_ABORTED: error = EINTR; break; + case ERROR_OUTOFMEMORY: error = ENOMEM; break; + case ERROR_PASSWORD_EXPIRED: error = EACCES; break; + case ERROR_PATH_BUSY: error = EBUSY; break; + case ERROR_PATH_NOT_FOUND: error = ENOENT; break; + case ERROR_PIPE_BUSY: error = EBUSY; break; + case ERROR_PIPE_CONNECTED: error = EPIPE; break; + case ERROR_PIPE_LISTENING: error = EPIPE; break; + case ERROR_PIPE_NOT_CONNECTED: error = EPIPE; break; + case ERROR_PRIVILEGE_NOT_HELD: error = EACCES; break; + case ERROR_READ_FAULT: error = EIO; break; + case ERROR_SEEK: error = EIO; break; + case ERROR_SEEK_ON_DEVICE: error = ESPIPE; break; + case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break; + case ERROR_SHARING_VIOLATION: error = EACCES; break; + case ERROR_STACK_OVERFLOW: error = ENOMEM; break; + case ERROR_SWAPERROR: error = ENOENT; break; + case ERROR_TOO_MANY_MODULES: error = EMFILE; break; + case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break; + case ERROR_UNRECOGNIZED_MEDIA: error = ENXIO; break; + case ERROR_UNRECOGNIZED_VOLUME: error = ENODEV; break; + case ERROR_WAIT_NO_CHILDREN: error = ECHILD; break; + case ERROR_WRITE_FAULT: error = EIO; break; + case ERROR_WRITE_PROTECT: error = EROFS; break; + } + return error; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { From 7be401e069758cc36d335241d9b80f9aeebf58c7 Mon Sep 17 00:00:00 2001 From: Petr Kodl <petrkodl@gmail.com> Date: Sat, 24 Jan 2009 15:04:39 +0100 Subject: [PATCH 189/654] MinGW: a hardlink implementation Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- compat/mingw.c | 21 +++++++++++++++++++++ compat/mingw.h | 3 +-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index f66ad56aae..171fa85e4a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1118,3 +1118,24 @@ void mingw_open_html(const char *unixpath) printf("Launching default browser to display HTML ...\n"); ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); } + +int link(const char *oldpath, const char *newpath) +{ + typedef BOOL WINAPI (*T)(const char*, const char*, LPSECURITY_ATTRIBUTES); + static T create_hard_link = NULL; + if (!create_hard_link) { + create_hard_link = (T) GetProcAddress( + GetModuleHandle("kernel32.dll"), "CreateHardLinkA"); + if (!create_hard_link) + create_hard_link = (T)-1; + } + if (create_hard_link == (T)-1) { + errno = ENOSYS; + return -1; + } + if (!create_hard_link(newpath, oldpath, NULL)) { + errno = err_win_to_posix(GetLastError()); + return -1; + } + return 0; +} diff --git a/compat/mingw.h b/compat/mingw.h index 6e24686442..7e52f3607f 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -67,8 +67,6 @@ static inline int readlink(const char *path, char *buf, size_t bufsiz) { errno = ENOSYS; return -1; } static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } -static inline int link(const char *oldpath, const char *newpath) -{ errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } static inline int fork(void) @@ -134,6 +132,7 @@ int getpagesize(void); /* defined in MinGW's libgcc.a */ struct passwd *getpwuid(int uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); +int link(const char *oldpath, const char *newpath); /* * replacements of existing functions From bf71b4b3ee07291e97c4dabfb97e7397eec904e0 Mon Sep 17 00:00:00 2001 From: Carlos Rica <jasampler@gmail.com> Date: Tue, 17 Mar 2009 10:46:37 +0100 Subject: [PATCH 190/654] config: test for --replace-all with one argument and fix documentation. Option --replace-all only allows at least two arguments, so documentation was needing to be updated accordingly. A test showing that the command fails with only one parameter is also provided. Signed-off-by: Carlos Rica <jasampler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-config.txt | 2 +- builtin-config.c | 2 +- t/t1300-repo-config.sh | 9 ++++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index 7d140073b1..8b94f19b17 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -11,7 +11,7 @@ SYNOPSIS [verse] 'git config' [<file-option>] [type] [-z|--null] name [value [value_regex]] 'git config' [<file-option>] [type] --add name value -'git config' [<file-option>] [type] --replace-all name [value [value_regex]] +'git config' [<file-option>] [type] --replace-all name value [value_regex] 'git config' [<file-option>] [type] [-z|--null] --get name [value_regex] 'git config' [<file-option>] [type] [-z|--null] --get-all name [value_regex] 'git config' [<file-option>] [type] [-z|--null] --get-regexp name_regex [value_regex] diff --git a/builtin-config.c b/builtin-config.c index 1a3baa1f46..d8da72cf20 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -55,7 +55,7 @@ static struct option builtin_config_options[] = { OPT_BIT(0, "get", &actions, "get value: name [value-regex]", ACTION_GET), OPT_BIT(0, "get-all", &actions, "get all values: key [value-regex]", ACTION_GET_ALL), OPT_BIT(0, "get-regexp", &actions, "get values for regexp: name-regex [value-regex]", ACTION_GET_REGEXP), - OPT_BIT(0, "replace-all", &actions, "replace all matching variables: name [value [value_regex]", ACTION_REPLACE_ALL), + OPT_BIT(0, "replace-all", &actions, "replace all matching variables: name value [value_regex]", ACTION_REPLACE_ALL), OPT_BIT(0, "add", &actions, "adds a new variable: name value", ACTION_ADD), OPT_BIT(0, "unset", &actions, "removes a variable: name [value-regex]", ACTION_UNSET), OPT_BIT(0, "unset-all", &actions, "removes all matches: name [value-regex]", ACTION_UNSET_ALL), diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 11b82f43dd..f0a75380b3 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -118,7 +118,14 @@ EOF test_expect_success 'multiple unset is correct' 'cmp .git/config expect' -mv .git/config2 .git/config +cp .git/config2 .git/config + +test_expect_success '--replace-all missing value' ' + test_must_fail git config --replace-all beta.haha && + test_cmp .git/config2 .git/config +' + +rm .git/config2 test_expect_success '--replace-all' \ 'git config --replace-all beta.haha gamma' From 381b920b8ac1440962f340cba9030e2dc3130c49 Mon Sep 17 00:00:00 2001 From: Kjetil Barvik <barvik@broadpark.no> Date: Tue, 17 Mar 2009 19:20:29 +0100 Subject: [PATCH 191/654] Revert "lstat_cache(): print a warning if doing ping-pong between cache types" This reverts commit 7734f04873cfaddd0b148074a633f1f824fd961f. I guess that the reverted commit, 7734f048, has been in test long enough, and should now be reverted. I have not received any info regarding any debug output of the reverted commit, so lets hope that the lstat_cache() function do not cause any ping-pong. Signed-off-by: Kjetil Barvik <barvik@broadpark.no> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- symlinks.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/symlinks.c b/symlinks.c index cb255a3187..1d6b35b858 100644 --- a/symlinks.c +++ b/symlinks.c @@ -51,11 +51,6 @@ static inline void reset_lstat_cache(void) */ } -#define SWITCHES_BEFORE_WARNING 10 -static unsigned int cache_switches, number_of_warnings; -static unsigned int current_cache_func, last_cache_func; -static unsigned int total_calls; - #define FL_DIR (1 << 0) #define FL_NOENT (1 << 1) #define FL_SYMLINK (1 << 2) @@ -82,7 +77,6 @@ static int lstat_cache(const char *name, int len, int match_flags, ret_flags, save_flags, max_len, ret; struct stat st; - total_calls++; if (cache.track_flags != track_flags || cache.prefix_len_stat_func != prefix_len_stat_func) { /* @@ -94,17 +88,6 @@ static int lstat_cache(const char *name, int len, cache.track_flags = track_flags; cache.prefix_len_stat_func = prefix_len_stat_func; match_len = last_slash = 0; - cache_switches++; - if (cache_switches > SWITCHES_BEFORE_WARNING) { - if (number_of_warnings < 10 || number_of_warnings % 1000 == 0) - printf("warning from %s:%d cache_switches:%u > %u "\ - "(current:%u last:%u total:%u)\n", - __FILE__, __LINE__, - cache_switches, SWITCHES_BEFORE_WARNING, - current_cache_func, last_cache_func, - total_calls); - number_of_warnings++; - } } else { /* * Check to see if we have a match from the cache for @@ -233,8 +216,6 @@ void clear_lstat_cache(void) */ int has_symlink_leading_path(const char *name, int len) { - last_cache_func = current_cache_func; - current_cache_func = 1; return lstat_cache(name, len, FL_SYMLINK|FL_DIR, USE_ONLY_LSTAT) & FL_SYMLINK; @@ -246,8 +227,6 @@ int has_symlink_leading_path(const char *name, int len) */ int has_symlink_or_noent_leading_path(const char *name, int len) { - last_cache_func = current_cache_func; - current_cache_func = 2; return lstat_cache(name, len, FL_SYMLINK|FL_NOENT|FL_DIR, USE_ONLY_LSTAT) & (FL_SYMLINK|FL_NOENT); @@ -262,8 +241,6 @@ int has_symlink_or_noent_leading_path(const char *name, int len) */ int has_dirs_only_path(const char *name, int len, int prefix_len) { - last_cache_func = current_cache_func; - current_cache_func = 3; return lstat_cache(name, len, FL_DIR|FL_FULLPATH, prefix_len) & FL_DIR; From d42ec126aa717d00549e387d5a95fd55683c2e2c Mon Sep 17 00:00:00 2001 From: Alex Riesen <raa.lkml@gmail.com> Date: Tue, 17 Mar 2009 17:22:53 +0100 Subject: [PATCH 192/654] disable post-checkout test on Cygwin It is broken because of the tricks we have to play with lstat to get the bearable perfomance out of the call. Sadly, it disables access to Cygwin's executable attribute, which Windows filesystems do not have at all. Signed-off-by: Alex Riesen <raa.lkml@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t5403-post-checkout-hook.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh index 4fdb418550..5858b868ed 100755 --- a/t/t5403-post-checkout-hook.sh +++ b/t/t5403-post-checkout-hook.sh @@ -71,6 +71,7 @@ test_expect_success 'post-checkout receives the right args when not switching br test $old = $new -a $flag = 0 ' +if test "$(git config --bool core.filemode)" = true; then mkdir -p templates/hooks cat >templates/hooks/post-checkout <<'EOF' #!/bin/sh @@ -82,5 +83,6 @@ test_expect_success 'post-checkout hook is triggered by clone' ' git clone --template=templates . clone3 && test -f clone3/.git/post-checkout.args ' +fi test_done From d6aba61f88dafc10cfb874b91e7864419fa81fd7 Mon Sep 17 00:00:00 2001 From: Chris Johnsen <chris_johnsen@pobox.com> Date: Sat, 14 Mar 2009 21:32:01 -0500 Subject: [PATCH 193/654] git-push.txt: describe how to default to pushing only current branch Signed-off-by: Chris Johnsen <chris_johnsen@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-push.txt | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index 4e7e5a719a..fd53c49fb8 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -24,8 +24,8 @@ every time you push into it, by setting up 'hooks' there. See documentation for linkgit:git-receive-pack[1]. -OPTIONS -------- +OPTIONS[[OPTIONS]] +------------------ <repository>:: The "remote" repository that is destination of a push operation. This parameter can be either a URL @@ -187,6 +187,28 @@ reason:: Examples -------- +git push:: + Works like `git push <remote>`, where <remote> is the + current branch's remote (or `origin`, if no remote is + configured for the current branch). + +git push origin:: + Without additional configuration, works like + `git push origin :`. ++ +The default behavior of this command when no <refspec> is given can be +configured by setting the `push` option of the remote. ++ +For example, to default to pushing only the current branch to `origin` +use `git config remote.origin.push HEAD`. Any valid <refspec> (like +the ones in the examples below) can be configured as the default for +`git push origin`. + +git push origin ::: + Push "matching" branches to `origin`. See + <refspec> in the <<OPTIONS,OPTIONS>> section above for a + description of "matching" branches. + git push origin master:: Find a ref that matches `master` in the source repository (most likely, it would find `refs/heads/master`), and update From dcb11263bcdbf31955dd00777392249bf1624226 Mon Sep 17 00:00:00 2001 From: Chris Johnsen <chris_johnsen@pobox.com> Date: Sun, 15 Mar 2009 06:30:52 -0500 Subject: [PATCH 194/654] Documentation: remove extra quoting/emphasis around literal texts If literal text (asciidoc `...`) can be rendered in a differently from normal text for each output format (man, HTML), then we do not need extra quotes or other wrapping around inline literal text segments. config.txt Change '`...`' to `...`. In asciidoc, the single quotes provide emphasis, literal text should be distintive enough. Change "`...`" to `...`. These double quotes do not work if present in the described config value, so drop them. git-checkout.txt Change "`...`" to `...` or `"..."`. All instances are command line argument examples. One "`-`" becomes `-`. Two others are involve curly braces, so move the double quotes inside the literal region to indicate that they might need to be quoted on the command line of certain shells (tcsh). git-merge.txt Change "`...`" to `...`. All instances are used to describe merge conflict markers. The quotes should are not important. git-rev-parse.txt Change "`...`" to `...`. All instances are around command line arguments where no in-shell quoting should be necessary. gitcli.txt Change `"..."` to `...`. All instances are around command line examples or single command arguments. They do not semanticly belong inside the literal text, and they are not needed outside it. glossary-content.txt user-manual.txt Change "`...`" to `...`. All instances were around command lines. Signed-off-by: Chris Johnsen <chris_johnsen@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 24 ++++++++++++------------ Documentation/git-checkout.txt | 4 ++-- Documentation/git-merge.txt | 6 +++--- Documentation/git-rev-parse.txt | 8 ++++---- Documentation/gitcli.txt | 24 ++++++++++++------------ Documentation/glossary-content.txt | 2 +- Documentation/user-manual.txt | 6 +++--- 7 files changed, 37 insertions(+), 37 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 56bd781a16..70fd172c6b 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -25,7 +25,7 @@ blank lines are ignored. The file consists of sections and variables. A section begins with the name of the section in square brackets and continues until the next section begins. Section names are not case sensitive. Only alphanumeric -characters, '`-`' and '`.`' are allowed in section names. Each variable +characters, `-` and `.` are allowed in section names. Each variable must belong to some section, which means that there must be section header before first setting of a variable. @@ -39,7 +39,7 @@ in the section header, like in example below: -------- Subsection names can contain any characters except newline (doublequote -'`"`' and backslash have to be escaped as '`\"`' and '`\\`', +`"` and backslash have to be escaped as `\"` and `\\`, respectively) and are case sensitive. Section header cannot span multiple lines. Variables may belong directly to a section or to a given subsection. You can have `[section]` if you have `[section "subsection"]`, but you @@ -53,7 +53,7 @@ All the other lines are recognized as setting variables, in the form 'name = value'. If there is no equal sign on the line, the entire line is taken as 'name' and the variable is recognized as boolean "true". The variable names are case-insensitive and only alphanumeric -characters and '`-`' are allowed. There can be more than one value +characters and `-` are allowed. There can be more than one value for a given variable; we say then that variable is multivalued. Leading and trailing whitespace in a variable value is discarded. @@ -69,15 +69,15 @@ String values may be entirely or partially enclosed in double quotes. You need to enclose variable value in double quotes if you want to preserve leading or trailing whitespace, or if variable value contains beginning of comment characters (if it contains '#' or ';'). -Double quote '`"`' and backslash '`\`' characters in variable value must -be escaped: use '`\"`' for '`"`' and '`\\`' for '`\`'. +Double quote `"` and backslash `\` characters in variable value must +be escaped: use `\"` for `"` and `\\` for `\`. -The following escape sequences (beside '`\"`' and '`\\`') are recognized: -'`\n`' for newline character (NL), '`\t`' for horizontal tabulation (HT, TAB) -and '`\b`' for backspace (BS). No other char escape sequence, nor octal +The following escape sequences (beside `\"` and `\\`) are recognized: +`\n` for newline character (NL), `\t` for horizontal tabulation (HT, TAB) +and `\b` for backspace (BS). No other char escape sequence, nor octal char sequences are valid. -Variable value ending in a '`\`' is continued on the next line in the +Variable value ending in a `\` is continued on the next line in the customary UNIX fashion. Some variables may require special value format. @@ -382,9 +382,9 @@ core.pager:: to override git's default settings this way, you need to be explicit. For example, to disable the S option in a backward compatible manner, set `core.pager` - to "`less -+$LESS -FRX`". This will be passed to the + to `less -+$LESS -FRX`. This will be passed to the shell by git, which will translate the final command to - "`LESS=FRSX less -+FRSX -FRX`". + `LESS=FRSX less -+FRSX -FRX`. core.whitespace:: A comma separated list of common whitespace problems to @@ -1161,7 +1161,7 @@ pager.<cmd>:: particular git subcommand when writing to a tty. If `\--paginate` or `\--no-pager` is specified on the command line, it takes precedence over this option. To disable pagination for - all commands, set `core.pager` or 'GIT_PAGER' to "`cat`". + all commands, set `core.pager` or `GIT_PAGER` to `cat`. pull.octopus:: The default merge strategy to use when pulling multiple branches diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 125d8f3c32..1a6c19e5c3 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -133,9 +133,9 @@ the conflicted merge in the specified paths. When this parameter names a non-branch (but still a valid commit object), your HEAD becomes 'detached'. + -As a special case, the "`@\{-N\}`" syntax for the N-th last branch +As a special case, the `"@\{-N\}"` syntax for the N-th last branch checks out the branch (instead of detaching). You may also specify -"`-`" which is synonymous with "`@\{-1\}`". +`-` which is synonymous with `"@\{-1\}"`. Detached HEAD diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt index f7be5846a6..cc0d30fe7e 100644 --- a/Documentation/git-merge.txt +++ b/Documentation/git-merge.txt @@ -146,7 +146,7 @@ And here is another line that is cleanly resolved or unmodified. ------------ The area where a pair of conflicting changes happened is marked with markers -"`<<<<<<<`", "`=======`", and "`>>>>>>>`". The part before the "`=======`" +`<<<<<<<`, `=======`, and `>>>>>>>`. The part before the `=======` is typically your side, and the part afterwards is typically their side. The default format does not show what the original said in the conflicting @@ -173,8 +173,8 @@ Git makes conflict resolution easy. And here is another line that is cleanly resolved or unmodified. ------------ -In addition to the "`<<<<<<<`", "`=======`", and "`>>>>>>>`" markers, it uses -another "`|||||||`" marker that is followed by the original text. You can +In addition to the `<<<<<<<`, `=======`, and `>>>>>>>` markers, it uses +another `|||||||` marker that is followed by the original text. You can tell that the original just stated a fact, and your side simply gave in to that statement and gave up, while the other side tried to have a more positive attitude. You can sometimes come up with a better resolution by diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index 3ccef2f2b3..5ed2bc840f 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -299,18 +299,18 @@ previous section means the set of commits reachable from that commit, following the commit ancestry chain. To exclude commits reachable from a commit, a prefix `{caret}` -notation is used. E.g. "`{caret}r1 r2`" means commits reachable +notation is used. E.g. `{caret}r1 r2` means commits reachable from `r2` but exclude the ones reachable from `r1`. This set operation appears so often that there is a shorthand for it. When you have two commits `r1` and `r2` (named according to the syntax explained in SPECIFYING REVISIONS above), you can ask for commits that are reachable from r2 excluding those that are reachable -from r1 by "`{caret}r1 r2`" and it can be written as "`r1..r2`". +from r1 by `{caret}r1 r2` and it can be written as `r1..r2`. -A similar notation "`r1\...r2`" is called symmetric difference +A similar notation `r1\...r2` is called symmetric difference of `r1` and `r2` and is defined as -"`r1 r2 --not $(git merge-base --all r1 r2)`". +`r1 r2 --not $(git merge-base --all r1 r2)`. It is the set of commits that are reachable from either one of `r1` or `r2` but not from both. diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt index 29e5929db2..be39ed7c15 100644 --- a/Documentation/gitcli.txt +++ b/Documentation/gitcli.txt @@ -46,20 +46,20 @@ Here are the rules regarding the "flags" that you should follow when you are scripting git: * it's preferred to use the non dashed form of git commands, which means that - you should prefer `"git foo"` to `"git-foo"`. + you should prefer `git foo` to `git-foo`. - * splitting short options to separate words (prefer `"git foo -a -b"` - to `"git foo -ab"`, the latter may not even work). + * splitting short options to separate words (prefer `git foo -a -b` + to `git foo -ab`, the latter may not even work). * when a command line option takes an argument, use the 'sticked' form. In - other words, write `"git foo -oArg"` instead of `"git foo -o Arg"` for short - options, and `"git foo --long-opt=Arg"` instead of `"git foo --long-opt Arg"` + other words, write `git foo -oArg` instead of `git foo -o Arg` for short + options, and `git foo --long-opt=Arg` instead of `git foo --long-opt Arg` for long options. An option that takes optional option-argument must be written in the 'sticked' form. * when you give a revision parameter to a command, make sure the parameter is not ambiguous with a name of a file in the work tree. E.g. do not write - `"git log -1 HEAD"` but write `"git log -1 HEAD --"`; the former will not work + `git log -1 HEAD` but write `git log -1 HEAD --`; the former will not work if you happen to have a file called `HEAD` in the work tree. @@ -99,17 +99,17 @@ usage: git-describe [options] <committish>* Negating options ~~~~~~~~~~~~~~~~ -Options with long option names can be negated by prefixing `"--no-"`. For -example, `"git branch"` has the option `"--track"` which is 'on' by default. You -can use `"--no-track"` to override that behaviour. The same goes for `"--color"` -and `"--no-color"`. +Options with long option names can be negated by prefixing `--no-`. For +example, `git branch` has the option `--track` which is 'on' by default. You +can use `--no-track` to override that behaviour. The same goes for `--color` +and `--no-color`. Aggregating short options ~~~~~~~~~~~~~~~~~~~~~~~~~ Commands that support the enhanced option parser allow you to aggregate short -options. This means that you can for example use `"git rm -rf"` or -`"git clean -fdx"`. +options. This means that you can for example use `git rm -rf` or +`git clean -fdx`. Separating argument from the option diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt index 9afca755ed..4fc1cf1184 100644 --- a/Documentation/glossary-content.txt +++ b/Documentation/glossary-content.txt @@ -262,7 +262,7 @@ This commit is referred to as a "merge commit", or sometimes just a 'origin' is used for that purpose. New upstream updates will be fetched into remote <<def_tracking_branch,tracking branches>> named origin/name-of-upstream-branch, which you can see using - "`git branch -r`". + `git branch -r`. [[def_pack]]pack:: A set of objects which have been compressed into one file (to save space diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt index 96af8977f6..e33b29b1dd 100644 --- a/Documentation/user-manual.txt +++ b/Documentation/user-manual.txt @@ -1136,10 +1136,10 @@ Ignoring files A project will often generate files that you do 'not' want to track with git. This typically includes files generated by a build process or temporary backup files made by your editor. Of course, 'not' tracking files with git -is just a matter of 'not' calling "`git-add`" on them. But it quickly becomes +is just a matter of 'not' calling `git-add` on them. But it quickly becomes annoying to have these untracked files lying around; e.g. they make -"`git add .`" practically useless, and they keep showing up in the output of -"`git status`". +`git add .` practically useless, and they keep showing up in the output of +`git status`. You can tell git to ignore certain files by creating a file called .gitignore in the top level of your working directory, with contents such as: From 188c3827c10f5a04588ef7af8b63a7b5dbcc38ed Mon Sep 17 00:00:00 2001 From: Miklos Vajna <vmiklos@frugalware.org> Date: Mon, 16 Mar 2009 21:18:42 +0100 Subject: [PATCH 195/654] Tests: use test_cmp instead of diff where possible Several old tests were written before test_cmp was introduced, convert these to test_cmp. If were are at it, fix the order of the arguments where necessary to make expected come first, so the command shows how the test result deviates from the correct output. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t0000-basic.sh | 8 ++++---- t/t1100-commit-tree-options.sh | 2 +- t/t1400-update-ref.sh | 6 +++--- t/t3000-ls-files-others.sh | 4 ++-- t/t3010-ls-files-killed-modified.sh | 4 ++-- t/t5000-tar-tree.sh | 22 +++++++++++----------- t/t9001-send-email.sh | 2 +- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 70df15cbd8..ddcd5b0efb 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -127,7 +127,7 @@ cat >expected <<\EOF EOF test_expect_success \ 'validate git ls-files output for a known tree.' \ - 'diff current expected' + 'test_cmp expected current' test_expect_success \ 'writing tree out with git write-tree.' \ @@ -147,7 +147,7 @@ cat >expected <<\EOF EOF test_expect_success \ 'git ls-tree output for a known tree.' \ - 'diff current expected' + 'test_cmp expected current' # This changed in ls-tree pathspec change -- recursive does # not show tree nodes anymore. @@ -166,7 +166,7 @@ cat >expected <<\EOF EOF test_expect_success \ 'git ls-tree -r output for a known tree.' \ - 'diff current expected' + 'test_cmp expected current' # But with -r -t we can have both. test_expect_success \ @@ -187,7 +187,7 @@ cat >expected <<\EOF EOF test_expect_success \ 'git ls-tree -r output for a known tree.' \ - 'diff current expected' + 'test_cmp expected current' test_expect_success \ 'writing partial tree out with git write-tree --prefix.' \ diff --git a/t/t1100-commit-tree-options.sh b/t/t1100-commit-tree-options.sh index 7f7fc36734..c4414ff576 100755 --- a/t/t1100-commit-tree-options.sh +++ b/t/t1100-commit-tree-options.sh @@ -40,6 +40,6 @@ test_expect_success \ test_expect_success \ 'compare commit' \ - 'diff expected commit' + 'test_cmp expected commit' test_done diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index bd589268fc..54ba3df95f 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -137,7 +137,7 @@ $B $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150860 +0000 EOF test_expect_success \ "verifying $m's log" \ - "diff expect .git/logs/$m" + "test_cmp expect .git/logs/$m" rm -rf .git/$m .git/logs expect test_expect_success \ @@ -168,7 +168,7 @@ $B $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150980 +0000 EOF test_expect_success \ "verifying $m's log" \ - 'diff expect .git/logs/$m' + 'test_cmp expect .git/logs/$m' rm -f .git/$m .git/logs/$m expect git update-ref $m $D @@ -272,7 +272,7 @@ $h_FIXED $h_MERGED $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117151100 +0000 c EOF test_expect_success \ 'git commit logged updates' \ - "diff expect .git/logs/$m" + "test_cmp expect .git/logs/$m" unset h_TEST h_OTHER h_FIXED h_MERGED test_expect_success \ diff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh index bc0a351392..36eee0f8ae 100755 --- a/t/t3000-ls-files-others.sh +++ b/t/t3000-ls-files-others.sh @@ -42,7 +42,7 @@ test_expect_success \ test_expect_success \ 'git ls-files --others should pick up symlinks.' \ - 'diff output expected1' + 'test_cmp expected1 output' test_expect_success \ 'git ls-files --others --directory to show output.' \ @@ -51,6 +51,6 @@ test_expect_success \ test_expect_success \ 'git ls-files --others --directory should not get confused.' \ - 'diff output expected2' + 'test_cmp expected2 output' test_done diff --git a/t/t3010-ls-files-killed-modified.sh b/t/t3010-ls-files-killed-modified.sh index ec14040637..e4f02a0968 100755 --- a/t/t3010-ls-files-killed-modified.sh +++ b/t/t3010-ls-files-killed-modified.sh @@ -75,7 +75,7 @@ EOF test_expect_success \ 'validate git ls-files -k output.' \ - 'diff .output .expected' + 'test_cmp .expected .output' test_expect_success \ 'git ls-files -m to show modified files.' \ @@ -91,6 +91,6 @@ EOF test_expect_success \ 'validate git ls-files -m output.' \ - 'diff .output .expected' + 'test_cmp .expected .output' test_done diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index b7e362834b..e1ed073f95 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -76,7 +76,7 @@ test_expect_success \ test_expect_success \ 'git archive vs. git tar-tree' \ - 'diff b.tar b2.tar' + 'test_cmp b.tar b2.tar' test_expect_success \ 'git archive in a bare repo' \ @@ -96,12 +96,12 @@ test_expect_success \ "$TAR" xf b.tar -C extract a/a && test-chmtime -v +0 extract/a/a |cut -f 1 >b.mtime && echo "1117231200" >expected.mtime && - diff expected.mtime b.mtime' + test_cmp expected.mtime b.mtime' test_expect_success \ 'git get-tar-commit-id' \ 'git get-tar-commit-id <b.tar >b.commitid && - diff .git/$(git symbolic-ref HEAD) b.commitid' + test_cmp .git/$(git symbolic-ref HEAD) b.commitid' test_expect_success \ 'extract tar archive' \ @@ -110,7 +110,7 @@ test_expect_success \ test_expect_success \ 'validate filenames' \ '(cd b/a && find .) | sort >b.lst && - diff a.lst b.lst' + test_cmp a.lst b.lst' test_expect_success \ 'validate file contents' \ @@ -127,7 +127,7 @@ test_expect_success \ test_expect_success \ 'validate filenames with prefix' \ '(cd c/prefix/a && find .) | sort >c.lst && - diff a.lst c.lst' + test_cmp a.lst c.lst' test_expect_success \ 'validate file contents with prefix' \ @@ -148,8 +148,8 @@ test_expect_success \ 'validate substfile contents' \ 'git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \ >f/a/substfile1.expected && - diff f/a/substfile1.expected f/a/substfile1 && - diff a/substfile2 f/a/substfile2 + test_cmp f/a/substfile1.expected f/a/substfile1 && + test_cmp a/substfile2 f/a/substfile2 ' test_expect_success \ @@ -160,8 +160,8 @@ test_expect_success \ 'validate substfile contents from archive with prefix' \ 'git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \ >g/prefix/a/substfile1.expected && - diff g/prefix/a/substfile1.expected g/prefix/a/substfile1 && - diff a/substfile2 g/prefix/a/substfile2 + test_cmp g/prefix/a/substfile1.expected g/prefix/a/substfile1 && + test_cmp a/substfile2 g/prefix/a/substfile2 ' test_expect_success \ @@ -194,7 +194,7 @@ test_expect_success \ test_expect_success \ 'validate filenames' \ '(cd d/a && find .) | sort >d.lst && - diff a.lst d.lst' + test_cmp a.lst d.lst' test_expect_success \ 'validate file contents' \ @@ -211,7 +211,7 @@ test_expect_success \ test_expect_success \ 'validate filenames with prefix' \ '(cd e/prefix/a && find .) | sort >e.lst && - diff a.lst e.lst' + test_cmp a.lst e.lst' test_expect_success \ 'validate file contents with prefix' \ diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 08d5b91c91..9523305304 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -88,7 +88,7 @@ cat >expected <<\EOF EOF test_expect_success \ 'Verify commandline' \ - 'diff commandline1 expected' + 'test_cmp expected commandline1' cat >expected-show-all-headers <<\EOF 0001-Second.patch From 01d386121758ac72aedd5f268feb763d53fc3cdf Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Mon, 16 Mar 2009 00:44:57 -0700 Subject: [PATCH 196/654] git-send-email.txt: describe --compose better Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-send-email.txt | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index 14dfb501eb..10dfd667b2 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -60,14 +60,13 @@ The --cc option must be repeated for each user you want on the cc list. Use $GIT_EDITOR, core.editor, $VISUAL, or $EDITOR to edit an introductory message for the patch series. + -When '--compose' is used, git send-email gets less interactive will use the -values of the headers you set there. If the body of the email (what you type -after the headers and a blank line) only contains blank (or GIT: prefixed) -lines, the summary won't be sent, but git-send-email will still use the -Headers values if you don't removed them. +When '--compose' is used, git send-email will use the From, Subject, and +In-Reply-To headers specified in the message. If the body of the message +(what you type after the headers and a blank line) only contains blank +(or GIT: prefixed) lines the summary won't be sent, but From, Subject, +and In-Reply-To headers will be used unless they are removed. + -If it wasn't able to see a header in the summary it will ask you about it -interactively after quitting your editor. +Missing From or In-Reply-To headers will be prompted for. --from:: Specify the sender of the emails. This will default to From 521537476fe99b97bfcdf1b8f0c579061af5fd3e Mon Sep 17 00:00:00 2001 From: Finn Arne Gangstad <finnag@pvv.org> Date: Mon, 16 Mar 2009 16:42:51 +0100 Subject: [PATCH 197/654] New config push.default to decide default behavior for push When "git push" is not told what refspecs to push, it pushes all matching branches to the current remote. For some workflows this default is not useful, and surprises new users. Some have even found that this default behaviour is too easy to trigger by accident with unwanted consequences. Introduce a new configuration variable "push.default" that decides what action git push should take if no refspecs are given or implied by the command line arguments or the current remote configuration. Possible values are: 'nothing' : Push nothing; 'matching' : Current default behaviour, push all branches that already exist in the current remote; 'tracking' : Push the current branch to whatever it is tracking; 'current' : Push the current branch to a branch of the same name, i.e. HEAD. Signed-off-by: Finn Arne Gangstad <finnag@pvv.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 18 ++++++++++++++ builtin-push.c | 53 ++++++++++++++++++++++++++++++++++++---- cache.h | 9 +++++++ config.c | 28 +++++++++++++++++++++ environment.c | 1 + 5 files changed, 104 insertions(+), 5 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index f5152c5038..7b2b3f44aa 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1160,6 +1160,24 @@ pull.octopus:: pull.twohead:: The default merge strategy to use when pulling a single branch. +push.default:: + Defines the action git push should take if no refspec is given + on the command line, no refspec is configured in the remote, and + no refspec is implied by any of the options given on the command + line. ++ +The term `current remote` means the remote configured for the current +branch, or `origin` if no remote is configured. `origin` is also used +if you are not on any branch. Possible values are: ++ +* `nothing` do not push anything. +* `matching` push all matching branches to the current remote. + All branches having the same name in both ends are considered to be + matching. This is the current default value. +* `tracking` push the current branch to the branch it is tracking. +* `current` push the current branch to a branch of the same name on the + current remote. + receive.fsckObjects:: If it is set to true, git-receive-pack will check all received objects. It will abort in the case of a malformed object or a diff --git a/builtin-push.c b/builtin-push.c index 122fdcfbdc..45fe843b20 100644 --- a/builtin-push.c +++ b/builtin-push.c @@ -48,6 +48,48 @@ static void set_refspecs(const char **refs, int nr) } } +static void setup_push_tracking(void) +{ + struct strbuf refspec = STRBUF_INIT; + struct branch *branch = branch_get(NULL); + if (!branch) + die("You are not currently on a branch."); + if (!branch->merge_nr) + die("The current branch %s is not tracking anything.", + branch->name); + if (branch->merge_nr != 1) + die("The current branch %s is tracking multiple branches, " + "refusing to push.", branch->name); + strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src); + add_refspec(refspec.buf); +} + +static void setup_default_push_refspecs(void) +{ + git_config(git_default_config, NULL); + switch (push_default) { + case PUSH_DEFAULT_UNSPECIFIED: + /* fallthrough */ + + case PUSH_DEFAULT_MATCHING: + add_refspec(":"); + break; + + case PUSH_DEFAULT_TRACKING: + setup_push_tracking(); + break; + + case PUSH_DEFAULT_CURRENT: + add_refspec("HEAD"); + break; + + case PUSH_DEFAULT_NOTHING: + die("You didn't specify any refspecs to push, and " + "push.default is \"nothing\"."); + break; + } +} + static int do_push(const char *repo, int flags) { int i, errs; @@ -76,11 +118,12 @@ static int do_push(const char *repo, int flags) return error("--all and --mirror are incompatible"); } - if (!refspec - && !(flags & TRANSPORT_PUSH_ALL) - && remote->push_refspec_nr) { - refspec = remote->push_refspec; - refspec_nr = remote->push_refspec_nr; + if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) { + if (remote->push_refspec_nr) { + refspec = remote->push_refspec; + refspec_nr = remote->push_refspec_nr; + } else if (!(flags & TRANSPORT_PUSH_MIRROR)) + setup_default_push_refspecs(); } errs = 0; for (i = 0; i < remote->url_nr; i++) { diff --git a/cache.h b/cache.h index 189151de25..df4f117ac6 100644 --- a/cache.h +++ b/cache.h @@ -541,8 +541,17 @@ enum rebase_setup_type { AUTOREBASE_ALWAYS, }; +enum push_default_type { + PUSH_DEFAULT_UNSPECIFIED = -1, + PUSH_DEFAULT_NOTHING = 0, + PUSH_DEFAULT_MATCHING, + PUSH_DEFAULT_TRACKING, + PUSH_DEFAULT_CURRENT, +}; + extern enum branch_track git_branch_track; extern enum rebase_setup_type autorebase; +extern enum push_default_type push_default; #define GIT_REPO_VERSION 0 extern int repository_format_version; diff --git a/config.c b/config.c index 0c8c76f13b..30443e3279 100644 --- a/config.c +++ b/config.c @@ -565,6 +565,31 @@ static int git_default_branch_config(const char *var, const char *value) return 0; } +static int git_default_push_config(const char *var, const char *value) +{ + if (!strcmp(var, "push.default")) { + if (!value) + return config_error_nonbool(var); + else if (!strcmp(value, "nothing")) + push_default = PUSH_DEFAULT_NOTHING; + else if (!strcmp(value, "matching")) + push_default = PUSH_DEFAULT_MATCHING; + else if (!strcmp(value, "tracking")) + push_default = PUSH_DEFAULT_TRACKING; + else if (!strcmp(value, "current")) + push_default = PUSH_DEFAULT_CURRENT; + else { + error("Malformed value for %s: %s", var, value); + return error("Must be one of nothing, matching, " + "tracking or current."); + } + return 0; + } + + /* Add other config variables here and to Documentation/config.txt. */ + return 0; +} + static int git_default_mailmap_config(const char *var, const char *value) { if (!strcmp(var, "mailmap.file")) @@ -588,6 +613,9 @@ int git_default_config(const char *var, const char *value, void *dummy) if (!prefixcmp(var, "branch.")) return git_default_branch_config(var, value); + if (!prefixcmp(var, "push.")) + return git_default_push_config(var, value); + if (!prefixcmp(var, "mailmap.")) return git_default_mailmap_config(var, value); diff --git a/environment.c b/environment.c index e278bce0ea..4696885b22 100644 --- a/environment.c +++ b/environment.c @@ -42,6 +42,7 @@ enum safe_crlf safe_crlf = SAFE_CRLF_WARN; unsigned whitespace_rule_cfg = WS_DEFAULT_RULE; enum branch_track git_branch_track = BRANCH_TRACK_REMOTE; enum rebase_setup_type autorebase = AUTOREBASE_NEVER; +enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED; /* Parallel index stat data preload? */ int core_preload_index = 0; From 665d3e8f057b90d7b43d70db75b9ac5506bd204d Mon Sep 17 00:00:00 2001 From: Finn Arne Gangstad <finnag@pvv.org> Date: Mon, 16 Mar 2009 16:42:52 +0100 Subject: [PATCH 198/654] Display warning for default git push with no push.default config If a git push without any refspecs is attempted, display a warning. The current default behavior is to push all matching refspecs, which may come as a surprise to new users, so the warning shows how push.default can be configured and what the possible values are. Traditionalists who wish to keep the current behaviour are also told how to configure this once and never see the warning again. Signed-off-by: Finn Arne Gangstad <finnag@pvv.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/RelNotes-1.6.3.txt | 7 +++++++ builtin-push.c | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/Documentation/RelNotes-1.6.3.txt b/Documentation/RelNotes-1.6.3.txt index ee1fddb76a..7c02b2a305 100644 --- a/Documentation/RelNotes-1.6.3.txt +++ b/Documentation/RelNotes-1.6.3.txt @@ -22,6 +22,13 @@ branch pointed at by its HEAD, gets a large warning. You can choose what should happen upon such a push by setting the configuration variable receive.denyDeleteCurrent in the receiving repository. +In a future release, the default of "git push" without further +arguments might be changed. Currently, it will push all matching +refspecs to the current remote. A configuration variable push.default +has been introduced to select the default behaviour. To ease the +transition, a big warning is issued if this is not configured and a +git push without arguments is attempted. + Updates since v1.6.2 -------------------- diff --git a/builtin-push.c b/builtin-push.c index 45fe843b20..8f4fa5b09e 100644 --- a/builtin-push.c +++ b/builtin-push.c @@ -64,11 +64,34 @@ static void setup_push_tracking(void) add_refspec(refspec.buf); } +static const char *warn_unconfigured_push_msg[] = { + "You did not specify any refspecs to push, and the current remote", + "has not configured any push refspecs. The default action in this", + "case is to push all matching refspecs, that is, all branches", + "that exist both locally and remotely will be updated. This may", + "not necessarily be what you want to happen.", + "", + "You can specify what action you want to take in this case, and", + "avoid seeing this message again, by configuring 'push.default' to:", + " 'nothing' : Do not push anythig", + " 'matching' : Push all matching branches (default)", + " 'tracking' : Push the current branch to whatever it is tracking", + " 'current' : Push the current branch" +}; + +static void warn_unconfigured_push(void) +{ + int i; + for (i = 0; i < ARRAY_SIZE(warn_unconfigured_push_msg); i++) + warning("%s", warn_unconfigured_push_msg[i]); +} + static void setup_default_push_refspecs(void) { git_config(git_default_config, NULL); switch (push_default) { case PUSH_DEFAULT_UNSPECIFIED: + warn_unconfigured_push(); /* fallthrough */ case PUSH_DEFAULT_MATCHING: From 50fd6997c60f926efe4b3591f6c0a37568d02185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Mon, 16 Mar 2009 19:38:42 +0100 Subject: [PATCH 199/654] pickaxe: count regex matches only once When --pickaxe-regex is used, forward past the end of matches instead of advancing to the byte after their start. This way matches count only once, even if the regular expression matches their tail -- like in the fixed-string fork of the code. E.g.: /.*/ used to count the number of bytes instead of the number of lines. /aa/ resulted in a count of two in "aaa" instead of one. Also document the fact that regexec() needs a NUL-terminated string as its second argument by adding an assert(). Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- diffcore-pickaxe.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c index 574b3e8337..d0ef839700 100644 --- a/diffcore-pickaxe.c +++ b/diffcore-pickaxe.c @@ -25,10 +25,12 @@ static unsigned int contains(struct diff_filespec *one, regmatch_t regmatch; int flags = 0; + assert(data[sz] == '\0'); while (*data && !regexec(regexp, data, 1, ®match, flags)) { flags |= REG_NOTBOL; - data += regmatch.rm_so; - if (*data) data++; + data += regmatch.rm_eo; + if (*data && regmatch.rm_so == regmatch.rm_eo) + data++; cnt++; } From fcfdf797db015e13623645c0be049db679d5daaa Mon Sep 17 00:00:00 2001 From: Michael J Gruber <git@drmicha.warpmail.net> Date: Tue, 17 Mar 2009 15:06:20 +0100 Subject: [PATCH 200/654] git-branch.txt: document -f correctly 'git branch -f a b' resets a to b when a exists, rather then deleting a. Say so in the documentation. Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-branch.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index 6103d62fe3..27b73bcf9e 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -76,8 +76,8 @@ OPTIONS based sha1 expressions such as "<branchname>@\{yesterday}". -f:: - Force the creation of a new branch even if it means deleting - a branch that already exists with the same name. + Reset <branchname> to <startpoint> if <branchname> exists + already. Without `-f` 'git-branch' refuses to change an existing branch. -m:: Move/rename a branch and the corresponding reflog. From 8ad3dae3a76ee42983da89ea9b5d9a4688f58f93 Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Tue, 17 Mar 2009 05:03:19 -0400 Subject: [PATCH 201/654] ls-files: require worktree when --deleted is given The code will end up calling lstat() to check whether the file still exists; obviously this doesn't work if we're not in the worktree. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-ls-files.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin-ls-files.c b/builtin-ls-files.c index 9dec282fba..ca6f33d046 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -419,6 +419,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) } if (!strcmp(arg, "-d") || !strcmp(arg, "--deleted")) { show_deleted = 1; + require_work_tree = 1; continue; } if (!strcmp(arg, "-m") || !strcmp(arg, "--modified")) { From 642d0844b9795ca7b1424f4afc8d8c86abd7bf34 Mon Sep 17 00:00:00 2001 From: Emil Sit <sit@emilsit.net> Date: Tue, 17 Mar 2009 13:31:42 -0400 Subject: [PATCH 202/654] config.txt: Describe special 'none' handling in core.gitProxy. Signed-off-by: Emil Sit <sit@emilsit.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/config.txt b/Documentation/config.txt index 70fd172c6b..44916b9e7f 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -221,6 +221,11 @@ core.gitProxy:: Can be overridden by the 'GIT_PROXY_COMMAND' environment variable (which always applies universally, without the special "for" handling). ++ +The special string `none` can be used as the proxy command to +specify that no proxy be used for a given domain pattern. +This is useful for excluding servers inside a firewall from +proxy use, while defaulting to a common proxy for external domains. core.ignoreStat:: If true, commands which modify both the working tree and the index From 6e89ec0f1e716c11bf7fa214b4c7b975ea77c736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= <pclouds@gmail.com> Date: Mon, 16 Mar 2009 13:20:04 +1100 Subject: [PATCH 203/654] grep: prefer builtin over external one when coloring results MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As far as I know, not all grep programs support coloring, so we should rely on builtin grep. If you want external grep, set color.grep.external to empty string. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-grep.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builtin-grep.c b/builtin-grep.c index 9e7e766a49..89489ddcf8 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -825,6 +825,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } } + if (opt.color && !opt.color_external) + builtin_grep = 1; if (!opt.pattern_list) die("no pattern given."); if ((opt.regflags != REG_NEWLINE) && opt.fixed) From e986ceb05a118944d2638fba4cd09678c1afa6b3 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Tue, 17 Mar 2009 20:26:24 -0700 Subject: [PATCH 204/654] Update draft release notes to 1.6.3 Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/RelNotes-1.6.3.txt | 37 ++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/Documentation/RelNotes-1.6.3.txt b/Documentation/RelNotes-1.6.3.txt index 679ad28b9d..4353cbf8c3 100644 --- a/Documentation/RelNotes-1.6.3.txt +++ b/Documentation/RelNotes-1.6.3.txt @@ -30,8 +30,18 @@ Updates since v1.6.2 (performance) +* many uses of lstat(2) in the codepath for "git checkout" have been + optimized out. + (usability, bells and whistles) +* rsync:/path/to/repo can be used to run git over rsync for local + repositories. It may not be useful in practice; meant primarily for + testing. + +* (msysgit) progress output that is sent over the sideband protocol can + be handled appropriately in Windows console. + * "--pretty=<style>" option to the log family of commands can now be spelled as "--format=<style>". In addition, --format=%formatstring is a short-hand for --pretty=tformat:%formatstring. @@ -62,6 +72,8 @@ Updates since v1.6.2 * git-format-patch can be told to produce deep or shallow message threads. +* git-grep learned to highlight the found substrings in color. + * git-imap-send learned to work around Thunderbird's inability to easily disable format=flowed with a new configuration, imap.preformattedHTML. @@ -71,6 +83,8 @@ Updates since v1.6.2 * git-rebase can be told to report diffstat with the --stat option. +* Output from git-remote command has been vastly improved. + * git-send-email learned --confirm option to review the Cc: list before sending the messages out. @@ -90,15 +104,30 @@ release, unless otherwise noted. Here are fixes that this release has, but have not been backported to v1.6.2.X series. -* 'git-submodule add' did not tolerate extra slashes and ./ in the - path it accepted from the command line; it now is more lenient - (if needed, backport by merging db75ada). +* "git diff --pickaxe-regexp" did not count overlapping matches + correctly (backport by cherry-picking 50fd699). + +* "git-fetch" in a repository that was not cloned from anywhere said + it cannot find 'origin', which was hard to understand for new people. * git-gc spent excessive amount of time to decide if an object appears in a locally existing pack (if needed, backport by merging 69e020a). +* "git-ls-files --deleted" did not work well with GIT_DIR&GIT_WORK_TREE + (backport by cherry-picking 8ad3dae). + +* "git-read-tree A B C..." without -m option has been broken for a long time + (backport by merging jc/maint-1.6.0-read-tree-overlay) + +* 'git-submodule add' did not tolerate extra slashes and ./ in the + path it accepted from the command line; it now is more lenient + (if needed, backport by merging db75ada). + +* git-send-email ignored --in-reply-to when --no-thread was given + (backport by merging tr/maint-1.6.0-send-email-irt) + --- exec >/var/tmp/1 -O=v1.6.2.1-135-g7d65c21 +O=v1.6.2.1-213-g7d4e3a7 echo O=$(git describe master) git shortlog --no-merges $O..master ^maint From 7fd3ef1fd73dffdb9b3445893ab579723ce08e74 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Sat, 7 Mar 2009 00:04:09 +0100 Subject: [PATCH 205/654] t9400, t9401: Do not force hard-linked clone The tests do not depend on that the clones are hard-linked, but used --local only as an optimization: At the time that --local was used first in t9400 hard-linked clones were not the default, yet. By removing --local, we help filesystems that do not support hard-links. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t9400-git-cvsserver-server.sh | 4 ++-- t/t9401-git-cvsserver-crlf.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index 6a37f71d11..9ccb1232bb 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -44,7 +44,7 @@ test_expect_success 'setup' ' git add secondrootfile && git commit -m "second root") && git pull secondroot master && - git clone -q --local --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 && + git clone -q --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 && GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true && GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" ' @@ -267,7 +267,7 @@ test_expect_success 'gitcvs.ext.dbname' \ rm -fr "$SERVERDIR" cd "$WORKDIR" && -git clone -q --local --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 && +git clone -q --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 && GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true && GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" || exit 1 diff --git a/t/t9401-git-cvsserver-crlf.sh b/t/t9401-git-cvsserver-crlf.sh index e27a1c5f85..5d6200c4df 100755 --- a/t/t9401-git-cvsserver-crlf.sh +++ b/t/t9401-git-cvsserver-crlf.sh @@ -84,7 +84,7 @@ test_expect_success 'setup' ' echo "subdir/file.h crlf" >> .gitattributes && git add .gitattributes textfile.c binfile.bin mixedUp.c subdir/* && git commit -q -m "First Commit" && - git clone -q --local --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 && + git clone -q --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 && GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true && GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" ' From ec2956df592338ccd789428e9232fe6b709dc2be Mon Sep 17 00:00:00 2001 From: Nate Case <ncase@xes-inc.com> Date: Wed, 18 Mar 2009 12:00:45 -0500 Subject: [PATCH 206/654] format-patch: Respect --quiet option Hide the patch filename output from 'git format-patch' when --quiet is used. The man pages suggested that this should have already worked. Signed-off-by: Nate Case <ncase@xes-inc.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-log.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/builtin-log.c b/builtin-log.c index 8684fcdb67..8af55d2879 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -573,7 +573,7 @@ static FILE *realstdout = NULL; static const char *output_directory = NULL; static int outdir_offset; -static int reopen_stdout(const char *oneline, int nr, int total) +static int reopen_stdout(const char *oneline, int nr, struct rev_info *rev) { char filename[PATH_MAX]; int len = 0; @@ -598,7 +598,9 @@ static int reopen_stdout(const char *oneline, int nr, int total) strcpy(filename + len, fmt_patch_suffix); } - fprintf(realstdout, "%s\n", filename + outdir_offset); + if (!DIFF_OPT_TST(&rev->diffopt, QUIET)) + fprintf(realstdout, "%s\n", filename + outdir_offset); + if (freopen(filename, "w", stdout) == NULL) return error("Cannot open patch file %s",filename); @@ -687,7 +689,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, die("Cover letter needs email format"); if (!use_stdout && reopen_stdout(numbered_files ? - NULL : "cover-letter", 0, rev->total)) + NULL : "cover-letter", 0, rev)) return; head_sha1 = sha1_to_hex(head->object.sha1); @@ -1106,7 +1108,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) } if (!use_stdout && reopen_stdout(numbered_files ? NULL : get_oneline_for_filename(commit, keep_subject), - rev.nr, rev.total)) + rev.nr, &rev)) die("Failed to create output files"); shown = log_tree_commit(&rev, commit); free(commit->buffer); From 40bac1512b0063ad3e235bca3cb66644ccf7e510 Mon Sep 17 00:00:00 2001 From: Michele Ballabio <barra_cuda@katamail.com> Date: Wed, 18 Mar 2009 19:05:39 +0100 Subject: [PATCH 207/654] apply: consistent spelling of "don't" Signed-off-by: Michele Ballabio <barra_cuda@katamail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-apply.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-apply.c b/builtin-apply.c index 106be94105..1a02c7ce75 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -3212,7 +3212,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix) struct option builtin_apply_options[] = { { OPTION_CALLBACK, 0, "exclude", NULL, "path", - "don´t apply changes matching the given path", + "don't apply changes matching the given path", 0, option_parse_exclude }, { OPTION_CALLBACK, 0, "include", NULL, "path", "apply changes matching the given path", From 092927c1b01632d030d9d746d36ad6dd02bc3967 Mon Sep 17 00:00:00 2001 From: Michele Ballabio <barra_cuda@katamail.com> Date: Wed, 18 Mar 2009 19:05:40 +0100 Subject: [PATCH 208/654] apply: hide unused options from short help The options "--binary" and "--allow-binary-replacement" of git-apply are no-op and maintained for backward compatibility, so avoid to show them in the short help screen. Signed-off-by: Michele Ballabio <barra_cuda@katamail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-apply.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/builtin-apply.c b/builtin-apply.c index 1a02c7ce75..b52aa20cfa 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -3224,10 +3224,10 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix) "ignore additions made by the patch"), OPT_BOOLEAN(0, "stat", &diffstat, "instead of applying the patch, output diffstat for the input"), - OPT_BOOLEAN(0, "allow-binary-replacement", &binary, - "now no-op"), - OPT_BOOLEAN(0, "binary", &binary, - "now no-op"), + { OPTION_BOOLEAN, 0, "allow-binary-replacement", &binary, + NULL, "old option, now no-op", PARSE_OPT_HIDDEN }, + { OPTION_BOOLEAN, 0, "binary", &binary, + NULL, "old option, now no-op", PARSE_OPT_HIDDEN }, OPT_BOOLEAN(0, "numstat", &numstat, "shows number of added and deleted lines in decimal notation"), OPT_BOOLEAN(0, "summary", &summary, From ba150a3fdce48e4b973db6e153e6b3ffb28a0cea Mon Sep 17 00:00:00 2001 From: Michele Ballabio <barra_cuda@katamail.com> Date: Wed, 18 Mar 2009 21:53:27 +0100 Subject: [PATCH 209/654] git log: avoid segfault with --all-match Avoid a segfault when the command git log --all-match was issued, by ignoring the option. Signed-off-by: Michele Ballabio <barra_cuda@katamail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- grep.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/grep.c b/grep.c index be99b34168..f3a27d7d6e 100644 --- a/grep.c +++ b/grep.c @@ -192,7 +192,8 @@ void compile_grep_patterns(struct grep_opt *opt) * A classic recursive descent parser would do. */ p = opt->pattern_list; - opt->pattern_expression = compile_pattern_expr(&p); + if (p) + opt->pattern_expression = compile_pattern_expr(&p); if (p) die("incomplete pattern expression: %s", p->pattern); } From 1c192f3442414a6ce83f9a524806fc26a0861d2d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <Johannes.Schindelin@gmx.de> Date: Thu, 6 Dec 2007 12:03:38 +0000 Subject: [PATCH 210/654] gc --aggressive: make it really aggressive The default was not to change the window or depth at all. As suggested by Jon Smirl, Linus Torvalds and others, default to --window=250 --depth=250 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Acked-by: Nicolas Pitre <nico@cam.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-gc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/builtin-gc.c b/builtin-gc.c index 8d990ed493..fc556ed7f3 100644 --- a/builtin-gc.c +++ b/builtin-gc.c @@ -23,7 +23,7 @@ static const char * const builtin_gc_usage[] = { }; static int pack_refs = 1; -static int aggressive_window = -1; +static int aggressive_window = 250; static int gc_auto_threshold = 6700; static int gc_auto_pack_limit = 50; static const char *prune_expire = "2.weeks.ago"; @@ -200,6 +200,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix) if (aggressive) { append_option(argv_repack, "-f", MAX_ADD); + append_option(argv_repack, "--depth=250", MAX_ADD); if (aggressive_window > 0) { sprintf(buf, "--window=%d", aggressive_window); append_option(argv_repack, buf, MAX_ADD); From b130a72b274441bb5d687de93efef4d990c40c0a Mon Sep 17 00:00:00 2001 From: Janos Laube <janos.dev@gmail.com> Date: Fri, 13 Mar 2009 16:50:45 +0100 Subject: [PATCH 211/654] MinGW: implement mmap Add USE_WIN32_MMAP which triggers the use of windows' native file memory mapping functionality in git_mmap()/git_munmap() functions. As git functions currently use mmap with MAP_PRIVATE set only, this implementation supports only that mode for now. On Windows, offsets for memory mapped files need to match the allocation granularity. Take this into account when calculating the packed git- windowsize and file offsets. At the moment, the only function which makes use of offsets in conjunction with mmap is use_pack() in sha1-file.c. Git fast-import's code path tries to map a portion of the temporary packfile that exceeds the current filesize, i.e. offset+length is greater than the filesize. The NO_MMAP code worked with that since pread() just reads the file content until EOF and returns gracefully, while MapViewOfFile() aborts the mapping and returns 'Access Denied'. Working around that by determining the filesize and adjusting the length parameter. Signed-off-by: Janos Laube <janos.dev@gmail.com> Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 7 +++++- compat/mingw.h | 5 +++++ compat/win32mmap.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 12 ++++++++--- 4 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 compat/win32mmap.c diff --git a/Makefile b/Makefile index b96c2b316f..aae3b09411 100644 --- a/Makefile +++ b/Makefile @@ -784,7 +784,6 @@ ifneq (,$(findstring CYGWIN,$(uname_S))) COMPAT_OBJS += compat/cygwin.o endif ifneq (,$(findstring MINGW,$(uname_S))) - NO_MMAP = YesPlease NO_PREAD = YesPlease NO_OPENSSL = YesPlease NO_CURL = YesPlease @@ -808,6 +807,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_POSIX_ONLY_PROGRAMS = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease NO_NSEC = YesPlease + USE_WIN32_MMAP = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" @@ -985,6 +985,11 @@ endif ifdef NO_MMAP COMPAT_CFLAGS += -DNO_MMAP COMPAT_OBJS += compat/mmap.o +else + ifdef USE_WIN32_MMAP + COMPAT_CFLAGS += -DUSE_WIN32_MMAP + COMPAT_OBJS += compat/win32mmap.o + endif endif ifdef NO_PREAD COMPAT_CFLAGS += -DNO_PREAD diff --git a/compat/mingw.h b/compat/mingw.h index 7e52f3607f..762eb143a7 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -159,6 +159,11 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz); int mingw_rename(const char*, const char*); #define rename mingw_rename +#ifdef USE_WIN32_MMAP +int mingw_getpagesize(void); +#define getpagesize mingw_getpagesize +#endif + /* Use mingw_lstat() instead of lstat()/stat() and * mingw_fstat() instead of fstat() on Windows. */ diff --git a/compat/win32mmap.c b/compat/win32mmap.c new file mode 100644 index 0000000000..779d796cd5 --- /dev/null +++ b/compat/win32mmap.c @@ -0,0 +1,53 @@ +#include "../git-compat-util.h" + +/* + * Note that this doesn't return the actual pagesize, but + * the allocation granularity. If future Windows specific git code + * needs the real getpagesize function, we need to find another solution. + */ +int mingw_getpagesize(void) +{ + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwAllocationGranularity; +} + +void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) +{ + HANDLE hmap; + void *temp; + size_t len; + struct stat st; + uint64_t o = offset; + uint32_t l = o & 0xFFFFFFFF; + uint32_t h = (o >> 32) & 0xFFFFFFFF; + + if (!fstat(fd, &st)) + len = xsize_t(st.st_size); + else + die("mmap: could not determine filesize"); + + if ((length + offset) > len) + length = len - offset; + + if (!(flags & MAP_PRIVATE)) + die("Invalid usage of mmap when built with USE_WIN32_MMAP"); + + hmap = CreateFileMapping((HANDLE)_get_osfhandle(fd), 0, PAGE_WRITECOPY, + 0, 0, 0); + + if (!hmap) + return MAP_FAILED; + + temp = MapViewOfFileEx(hmap, FILE_MAP_COPY, h, l, length, start); + + if (!CloseHandle(hmap)) + warning("unable to close file mapping handle\n"); + + return temp ? temp : MAP_FAILED; +} + +int git_munmap(void *start, size_t length) +{ + return !UnmapViewOfFile(start); +} diff --git a/git-compat-util.h b/git-compat-util.h index 19062534a1..f09f244061 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -166,7 +166,7 @@ static inline const char *skip_prefix(const char *str, const char *prefix) return strncmp(str, prefix, len) ? NULL : str + len; } -#ifdef NO_MMAP +#if defined(NO_MMAP) || defined(USE_WIN32_MMAP) #ifndef PROT_READ #define PROT_READ 1 @@ -180,13 +180,19 @@ static inline const char *skip_prefix(const char *str, const char *prefix) extern void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); extern int git_munmap(void *start, size_t length); +#else /* NO_MMAP || USE_WIN32_MMAP */ + +#include <sys/mman.h> + +#endif /* NO_MMAP || USE_WIN32_MMAP */ + +#ifdef NO_MMAP + /* This value must be multiple of (pagesize * 2) */ #define DEFAULT_PACKED_GIT_WINDOW_SIZE (1 * 1024 * 1024) #else /* NO_MMAP */ -#include <sys/mman.h> - /* This value must be multiple of (pagesize * 2) */ #define DEFAULT_PACKED_GIT_WINDOW_SIZE \ (sizeof(void*) >= 8 \ From 5e75d56f1182c99364c9f5375665c814985f384d Mon Sep 17 00:00:00 2001 From: Michele Ballabio <barra_cuda@katamail.com> Date: Wed, 18 Mar 2009 21:53:39 +0100 Subject: [PATCH 212/654] document --force-rebase Signed-off-by: Michele Ballabio <barra_cuda@katamail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-rebase.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 57bd333f0b..276f1510c6 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -258,6 +258,13 @@ OPTIONS context exist they all must match. By default no context is ever ignored. +-f:: +--force-rebase:: + Force the rebase even if the current branch is a descendant + of the commit you are rebasing onto. Normally the command will + exit with the message "Current branch is up to date" in such a + situation. + --whitespace=<option>:: This flag is passed to the 'git-apply' program (see linkgit:git-apply[1]) that applies the patch. From 570ccad33e067616865aa9697b90c7b927d6dcf4 Mon Sep 17 00:00:00 2001 From: Michele Ballabio <barra_cuda@katamail.com> Date: Wed, 18 Mar 2009 21:53:49 +0100 Subject: [PATCH 213/654] rebase: add options passed to git-am Add the options --committer-date-is-author-date and --ignore-date to git-rebase. They were introduced in commit a79ec62d0 for git-am. These options imply --force-rebase. Signed-off-by: Michele Ballabio <barra_cuda@katamail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-rebase.txt | 5 +++++ git-rebase.sh | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 276f1510c6..3d5a066c31 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -270,6 +270,11 @@ OPTIONS (see linkgit:git-apply[1]) that applies the patch. Incompatible with the --interactive option. +--committer-date-is-author-date:: +--ignore-date:: + These flags are passed to 'git-am' to easily change the dates + of the rebased commits (see linkgit:git-am[1]). + -i:: --interactive:: Make a list of the commits which are about to be rebased. Let the diff --git a/git-rebase.sh b/git-rebase.sh index d38ab0b83f..0ade699228 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -309,6 +309,10 @@ do ;; esac ;; + --committer-date-is-author-date|--ignore-date) + git_am_opt="$git_am_opt $1" + force_rebase=t + ;; -C*) git_am_opt="$git_am_opt $1" ;; From 7b5201a60d8f00e7026a3fc4cfdd7852caa9882f Mon Sep 17 00:00:00 2001 From: Amos King <amos.l.king@gmail.com> Date: Wed, 18 Mar 2009 18:43:53 -0500 Subject: [PATCH 214/654] Do not name "repo" struct "remote" in push_http.c This patch is a first step in getting http-push to use http authentication via prompts. The patch renames remote to repo so that it doesn't get confusing with the same remote that is passed around when using http. Signed-off-by: Amos King <amos.l.king@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- http-push.c | 152 ++++++++++++++++++++++++++-------------------------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/http-push.c b/http-push.c index 30d2d34041..dfbb247cfc 100644 --- a/http-push.c +++ b/http-push.c @@ -97,7 +97,7 @@ struct repo struct remote_lock *locks; }; -static struct repo *remote; +static struct repo *repo; enum transfer_state { NEED_FETCH, @@ -324,7 +324,7 @@ static void start_fetch_loose(struct transfer_request *request) git_SHA1_Init(&request->c); - url = get_remote_object_url(remote->url, hex, 0); + url = get_remote_object_url(repo->url, hex, 0); request->url = xstrdup(url); /* If a previous temp file is present, process what was already @@ -389,7 +389,7 @@ static void start_fetch_loose(struct transfer_request *request) request->state = RUN_FETCH_LOOSE; if (!start_active_slot(slot)) { fprintf(stderr, "Unable to start GET request\n"); - remote->can_update_info_refs = 0; + repo->can_update_info_refs = 0; release_request(request); } } @@ -399,7 +399,7 @@ static void start_mkcol(struct transfer_request *request) char *hex = sha1_to_hex(request->obj->sha1); struct active_request_slot *slot; - request->url = get_remote_object_url(remote->url, hex, 1); + request->url = get_remote_object_url(repo->url, hex, 1); slot = get_active_slot(); slot->callback_func = process_response; @@ -434,10 +434,10 @@ static void start_fetch_packed(struct transfer_request *request) struct transfer_request *check_request = request_queue_head; struct active_request_slot *slot; - target = find_sha1_pack(request->obj->sha1, remote->packs); + target = find_sha1_pack(request->obj->sha1, repo->packs); if (!target) { fprintf(stderr, "Unable to fetch %s, will not be able to update server info refs\n", sha1_to_hex(request->obj->sha1)); - remote->can_update_info_refs = 0; + repo->can_update_info_refs = 0; release_request(request); return; } @@ -450,9 +450,9 @@ static void start_fetch_packed(struct transfer_request *request) snprintf(request->tmpfile, sizeof(request->tmpfile), "%s.temp", filename); - url = xmalloc(strlen(remote->url) + 64); + url = xmalloc(strlen(repo->url) + 64); sprintf(url, "%sobjects/pack/pack-%s.pack", - remote->url, sha1_to_hex(target->sha1)); + repo->url, sha1_to_hex(target->sha1)); /* Make sure there isn't another open request for this pack */ while (check_request) { @@ -469,7 +469,7 @@ static void start_fetch_packed(struct transfer_request *request) if (!packfile) { fprintf(stderr, "Unable to open local file %s for pack", request->tmpfile); - remote->can_update_info_refs = 0; + repo->can_update_info_refs = 0; free(url); return; } @@ -505,7 +505,7 @@ static void start_fetch_packed(struct transfer_request *request) request->state = RUN_FETCH_PACKED; if (!start_active_slot(slot)) { fprintf(stderr, "Unable to start GET request\n"); - remote->can_update_info_refs = 0; + repo->can_update_info_refs = 0; release_request(request); } } @@ -554,10 +554,10 @@ static void start_put(struct transfer_request *request) request->buffer.buf.len = stream.total_out; strbuf_addstr(&buf, "Destination: "); - append_remote_object_url(&buf, remote->url, hex, 0); + append_remote_object_url(&buf, repo->url, hex, 0); request->dest = strbuf_detach(&buf, NULL); - append_remote_object_url(&buf, remote->url, hex, 0); + append_remote_object_url(&buf, repo->url, hex, 0); strbuf_add(&buf, request->lock->tmpfile_suffix, 41); request->url = strbuf_detach(&buf, NULL); @@ -648,7 +648,7 @@ static int refresh_lock(struct remote_lock *lock) static void check_locks(void) { - struct remote_lock *lock = remote->locks; + struct remote_lock *lock = repo->locks; time_t current_time = time(NULL); int time_remaining; @@ -788,7 +788,7 @@ static void finish_request(struct transfer_request *request) if (request->curl_result != CURLE_OK) { fprintf(stderr, "Unable to get pack file %s\n%s", request->url, curl_errorstr); - remote->can_update_info_refs = 0; + repo->can_update_info_refs = 0; } else { off_t pack_size = ftell(request->local_stream); @@ -798,7 +798,7 @@ static void finish_request(struct transfer_request *request) request->filename)) { target = (struct packed_git *)request->userData; target->pack_size = pack_size; - lst = &remote->packs; + lst = &repo->packs; while (*lst != target) lst = &((*lst)->next); *lst = (*lst)->next; @@ -806,7 +806,7 @@ static void finish_request(struct transfer_request *request) if (!verify_pack(target)) install_packed_git(target); else - remote->can_update_info_refs = 0; + repo->can_update_info_refs = 0; } } release_request(request); @@ -889,7 +889,7 @@ static int add_send_request(struct object *obj, struct remote_lock *lock) get_remote_object_list(obj->sha1[0]); if (obj->flags & (REMOTE | PUSHING)) return 0; - target = find_sha1_pack(obj->sha1, remote->packs); + target = find_sha1_pack(obj->sha1, repo->packs); if (target) { obj->flags |= REMOTE; return 0; @@ -930,8 +930,8 @@ static int fetch_index(unsigned char *sha1) struct slot_results results; /* Don't use the index if the pack isn't there */ - url = xmalloc(strlen(remote->url) + 64); - sprintf(url, "%sobjects/pack/pack-%s.pack", remote->url, hex); + url = xmalloc(strlen(repo->url) + 64); + sprintf(url, "%sobjects/pack/pack-%s.pack", repo->url, hex); slot = get_active_slot(); slot->results = &results; curl_easy_setopt(slot->curl, CURLOPT_URL, url); @@ -956,7 +956,7 @@ static int fetch_index(unsigned char *sha1) if (push_verbosely) fprintf(stderr, "Getting index for pack %s\n", hex); - sprintf(url, "%sobjects/pack/pack-%s.idx", remote->url, hex); + sprintf(url, "%sobjects/pack/pack-%s.idx", repo->url, hex); filename = sha1_pack_index_name(sha1); snprintf(tmpfile, sizeof(tmpfile), "%s.temp", filename); @@ -1018,8 +1018,8 @@ static int setup_index(unsigned char *sha1) return -1; new_pack = parse_pack_index(sha1); - new_pack->next = remote->packs; - remote->packs = new_pack; + new_pack->next = repo->packs; + repo->packs = new_pack; return 0; } @@ -1037,8 +1037,8 @@ static int fetch_indices(void) if (push_verbosely) fprintf(stderr, "Getting pack list\n"); - url = xmalloc(strlen(remote->url) + 20); - sprintf(url, "%sobjects/info/packs", remote->url); + url = xmalloc(strlen(repo->url) + 20); + sprintf(url, "%sobjects/info/packs", repo->url); slot = get_active_slot(); slot->results = &results; @@ -1223,11 +1223,11 @@ static struct remote_lock *lock_remote(const char *path, long timeout) struct curl_slist *dav_headers = NULL; struct xml_ctx ctx; - url = xmalloc(strlen(remote->url) + strlen(path) + 1); - sprintf(url, "%s%s", remote->url, path); + url = xmalloc(strlen(repo->url) + strlen(path) + 1); + sprintf(url, "%s%s", repo->url, path); /* Make sure leading directories exist for the remote ref */ - ep = strchr(url + strlen(remote->url) + 1, '/'); + ep = strchr(url + strlen(repo->url) + 1, '/'); while (ep) { char saved_character = ep[1]; ep[1] = '\0'; @@ -1319,8 +1319,8 @@ static struct remote_lock *lock_remote(const char *path, long timeout) } else { lock->url = url; lock->start_time = time(NULL); - lock->next = remote->locks; - remote->locks = lock; + lock->next = repo->locks; + repo->locks = lock; } return lock; @@ -1330,7 +1330,7 @@ static int unlock_remote(struct remote_lock *lock) { struct active_request_slot *slot; struct slot_results results; - struct remote_lock *prev = remote->locks; + struct remote_lock *prev = repo->locks; struct curl_slist *dav_headers; int rc = 0; @@ -1356,8 +1356,8 @@ static int unlock_remote(struct remote_lock *lock) curl_slist_free_all(dav_headers); - if (remote->locks == lock) { - remote->locks = lock->next; + if (repo->locks == lock) { + repo->locks = lock->next; } else { while (prev && prev->next != lock) prev = prev->next; @@ -1375,7 +1375,7 @@ static int unlock_remote(struct remote_lock *lock) static void remove_locks(void) { - struct remote_lock *lock = remote->locks; + struct remote_lock *lock = repo->locks; fprintf(stderr, "Removing remote locks...\n"); while (lock) { @@ -1457,7 +1457,7 @@ static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed) } } if (path) { - path += remote->path_len; + path += repo->path_len; ls->dentry_name = xstrdup(path); } } else if (!strcmp(ctx->name, DAV_PROPFIND_COLLECTION)) { @@ -1480,7 +1480,7 @@ static void remote_ls(const char *path, int flags, void (*userFunc)(struct remote_ls_ctx *ls), void *userData) { - char *url = xmalloc(strlen(remote->url) + strlen(path) + 1); + char *url = xmalloc(strlen(repo->url) + strlen(path) + 1); struct active_request_slot *slot; struct slot_results results; struct strbuf in_buffer = STRBUF_INIT; @@ -1496,7 +1496,7 @@ static void remote_ls(const char *path, int flags, ls.userData = userData; ls.userFunc = userFunc; - sprintf(url, "%s%s", remote->url, path); + sprintf(url, "%s%s", repo->url, path); strbuf_addf(&out_buffer.buf, PROPFIND_ALL_REQUEST); @@ -1574,7 +1574,7 @@ static int locking_available(void) struct xml_ctx ctx; int lock_flags = 0; - strbuf_addf(&out_buffer.buf, PROPFIND_SUPPORTEDLOCK_REQUEST, remote->url); + strbuf_addf(&out_buffer.buf, PROPFIND_SUPPORTEDLOCK_REQUEST, repo->url); dav_headers = curl_slist_append(dav_headers, "Depth: 0"); dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml"); @@ -1586,7 +1586,7 @@ static int locking_available(void) curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer); curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer); curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); - curl_easy_setopt(slot->curl, CURLOPT_URL, remote->url); + curl_easy_setopt(slot->curl, CURLOPT_URL, repo->url); curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1); curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PROPFIND); curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers); @@ -1617,15 +1617,15 @@ static int locking_available(void) XML_ParserFree(parser); if (!lock_flags) error("Error: no DAV locking support on %s", - remote->url); + repo->url); } else { error("Cannot access URL %s, return code %d", - remote->url, results.curl_result); + repo->url, results.curl_result); lock_flags = 0; } } else { - error("Unable to start PROPFIND request on %s", remote->url); + error("Unable to start PROPFIND request on %s", repo->url); } strbuf_release(&out_buffer.buf); @@ -1814,10 +1814,10 @@ static void one_remote_ref(char *refname) ref = alloc_ref(refname); - if (http_fetch_ref(remote->url, ref) != 0) { + if (http_fetch_ref(repo->url, ref) != 0) { fprintf(stderr, "Unable to fetch ref %s from %s\n", - refname, remote->url); + refname, repo->url); free(ref); return; } @@ -1826,7 +1826,7 @@ static void one_remote_ref(char *refname) * Fetch a copy of the object if it doesn't exist locally - it * may be required for updating server info later. */ - if (remote->can_update_info_refs && !has_sha1_file(ref->old_sha1)) { + if (repo->can_update_info_refs && !has_sha1_file(ref->old_sha1)) { obj = lookup_unknown_object(ref->old_sha1); if (obj) { fprintf(stderr, " fetch %s for %s\n", @@ -1921,10 +1921,10 @@ static void add_remote_info_ref(struct remote_ls_ctx *ls) ref = alloc_ref(ls->dentry_name); - if (http_fetch_ref(remote->url, ref) != 0) { + if (http_fetch_ref(repo->url, ref) != 0) { fprintf(stderr, "Unable to fetch ref %s from %s\n", - ls->dentry_name, remote->url); + ls->dentry_name, repo->url); aborted = 1; free(ref); return; @@ -1999,12 +1999,12 @@ static void update_remote_info_refs(struct remote_lock *lock) static int remote_exists(const char *path) { - char *url = xmalloc(strlen(remote->url) + strlen(path) + 1); + char *url = xmalloc(strlen(repo->url) + strlen(path) + 1); struct active_request_slot *slot; struct slot_results results; int ret = -1; - sprintf(url, "%s%s", remote->url, path); + sprintf(url, "%s%s", repo->url, path); slot = get_active_slot(); slot->results = &results; @@ -2034,8 +2034,8 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1) struct active_request_slot *slot; struct slot_results results; - url = xmalloc(strlen(remote->url) + strlen(path) + 1); - sprintf(url, "%s%s", remote->url, path); + url = xmalloc(strlen(repo->url) + strlen(path) + 1); + sprintf(url, "%s%s", repo->url, path); slot = get_active_slot(); slot->results = &results; @@ -2150,7 +2150,7 @@ static int delete_remote_branch(char *pattern, int force) "of your current HEAD.\n" "If you are sure you want to delete it," " run:\n\t'git http-push -D %s %s'", - remote_ref->name, remote->url, pattern); + remote_ref->name, repo->url, pattern); } } @@ -2158,8 +2158,8 @@ static int delete_remote_branch(char *pattern, int force) fprintf(stderr, "Removing remote branch '%s'\n", remote_ref->name); if (dry_run) return 0; - url = xmalloc(strlen(remote->url) + strlen(remote_ref->name) + 1); - sprintf(url, "%s%s", remote->url, remote_ref->name); + url = xmalloc(strlen(repo->url) + strlen(remote_ref->name) + 1); + sprintf(url, "%s%s", repo->url, remote_ref->name); slot = get_active_slot(); slot->results = &results; curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); @@ -2202,7 +2202,7 @@ int main(int argc, char **argv) setup_git_directory(); - remote = xcalloc(sizeof(*remote), 1); + repo = xcalloc(sizeof(*repo), 1); argv++; for (i = 1; i < argc; i++, argv++) { @@ -2235,14 +2235,14 @@ int main(int argc, char **argv) continue; } } - if (!remote->url) { + if (!repo->url) { char *path = strstr(arg, "//"); - remote->url = arg; - remote->path_len = strlen(arg); + repo->url = arg; + repo->path_len = strlen(arg); if (path) { - remote->path = strchr(path+2, '/'); - if (remote->path) - remote->path_len = strlen(remote->path); + repo->path = strchr(path+2, '/'); + if (repo->path) + repo->path_len = strlen(repo->path); } continue; } @@ -2255,7 +2255,7 @@ int main(int argc, char **argv) die("git-push is not available for http/https repository when not compiled with USE_CURL_MULTI"); #endif - if (!remote->url) + if (!repo->url) usage(http_push_usage); if (delete_branch && nr_refspec != 1) @@ -2267,13 +2267,13 @@ int main(int argc, char **argv) no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:"); - if (remote->url && remote->url[strlen(remote->url)-1] != '/') { - rewritten_url = xmalloc(strlen(remote->url)+2); - strcpy(rewritten_url, remote->url); + if (repo->url && repo->url[strlen(repo->url)-1] != '/') { + rewritten_url = xmalloc(strlen(repo->url)+2); + strcpy(rewritten_url, repo->url); strcat(rewritten_url, "/"); - remote->path = rewritten_url + (remote->path - remote->url); - remote->path_len++; - remote->url = rewritten_url; + repo->path = rewritten_url + (repo->path - repo->url); + repo->path_len++; + repo->url = rewritten_url; } /* Verify DAV compliance/lock support */ @@ -2285,20 +2285,20 @@ int main(int argc, char **argv) sigchain_push_common(remove_locks_on_signal); /* Check whether the remote has server info files */ - remote->can_update_info_refs = 0; - remote->has_info_refs = remote_exists("info/refs"); - remote->has_info_packs = remote_exists("objects/info/packs"); - if (remote->has_info_refs) { + repo->can_update_info_refs = 0; + repo->has_info_refs = remote_exists("info/refs"); + repo->has_info_packs = remote_exists("objects/info/packs"); + if (repo->has_info_refs) { info_ref_lock = lock_remote("info/refs", LOCK_TIME); if (info_ref_lock) - remote->can_update_info_refs = 1; + repo->can_update_info_refs = 1; else { fprintf(stderr, "Error: cannot lock existing info/refs\n"); rc = 1; goto cleanup; } } - if (remote->has_info_packs) + if (repo->has_info_packs) fetch_indices(); /* Get a list of all local and remote heads to validate refspecs */ @@ -2456,8 +2456,8 @@ int main(int argc, char **argv) } /* Update remote server info if appropriate */ - if (remote->has_info_refs && new_refs) { - if (info_ref_lock && remote->can_update_info_refs) { + if (repo->has_info_refs && new_refs) { + if (info_ref_lock && repo->can_update_info_refs) { fprintf(stderr, "Updating remote server info\n"); if (!dry_run) update_remote_info_refs(info_ref_lock); @@ -2470,7 +2470,7 @@ int main(int argc, char **argv) free(rewritten_url); if (info_ref_lock) unlock_remote(info_ref_lock); - free(remote); + free(repo); curl_slist_free_all(no_pragma_header); From 44d808c238f0817fc3ae7caea8f3b625b6180e37 Mon Sep 17 00:00:00 2001 From: Amos King <amos.l.king@gmail.com> Date: Wed, 18 Mar 2009 18:46:41 -0500 Subject: [PATCH 215/654] http-push.c: use a faux remote to pass to http_init This patch allows http_push to use http authentication via prompts. You may notice that there is a remote struct that only contains the url from the repo struct. This struct is a temporary fix for a larger issue, but gets http authentication via prompts out the door, and keeps users from having to store passwords in plain text files. Signed-off-by: Amos King <amos.l.king@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- http-push.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/http-push.c b/http-push.c index dfbb247cfc..962934858e 100644 --- a/http-push.c +++ b/http-push.c @@ -2196,6 +2196,7 @@ int main(int argc, char **argv) int i; int new_refs; struct ref *ref; + struct remote *remote; char *rewritten_url = NULL; git_extract_argv0_path(argv[0]); @@ -2263,7 +2264,14 @@ int main(int argc, char **argv) memset(remote_dir_exists, -1, 256); - http_init(NULL); + /* + * Create a minimum remote by hand to give to http_init(), + * primarily to allow it to look at the URL. + */ + remote = xcalloc(sizeof(*remote), 1); + ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc); + remote->url[remote->url_nr++] = repo->url; + http_init(remote); no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:"); From fae74a04d75e820c5150cfb0cb4c044bf4488007 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Sun, 1 Mar 2009 19:52:51 +0100 Subject: [PATCH 216/654] test suite: Use 'say' to say something instead of 'test_expect_success' Some tests report that some tests will be skipped. They used 'test_expect_success' with a trivially successful test. Nowadays we have the helper function 'say' for this purpose. In on case, 'say_color skip' is replaced by 'say' because the former is not intended as a public API. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/lib-git-svn.sh | 6 +++--- t/t0024-crlf-archive.sh | 2 +- t/t3600-rm.sh | 2 +- t/t5000-tar-tree.sh | 2 +- t/t7004-tag.sh | 4 ++-- t/t9200-git-cvsexportcommit.sh | 2 +- t/t9400-git-cvsserver-server.sh | 4 ++-- t/t9401-git-cvsserver-crlf.sh | 4 ++-- t/t9500-gitweb-standalone-no-errors.sh | 2 +- t/t9700-perl-git.sh | 2 +- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh index 67c431d4eb..de384e6ac3 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -5,7 +5,7 @@ git_svn_id=git""-svn-id if test -n "$NO_SVN_TESTS" then - test_expect_success 'skipping git svn tests, NO_SVN_TESTS defined' : + say 'skipping git svn tests, NO_SVN_TESTS defined' test_done exit fi @@ -17,7 +17,7 @@ SVN_TREE=$GIT_SVN_DIR/svn-tree svn >/dev/null 2>&1 if test $? -ne 1 then - test_expect_success 'skipping git svn tests, svn not found' : + say 'skipping git svn tests, svn not found' test_done exit fi @@ -41,7 +41,7 @@ then else err='Perl SVN libraries not found or unusable, skipping test' fi - test_expect_success "$err" : + say "$err" test_done exit fi diff --git a/t/t0024-crlf-archive.sh b/t/t0024-crlf-archive.sh index e5330395fc..ae90d34f6c 100755 --- a/t/t0024-crlf-archive.sh +++ b/t/t0024-crlf-archive.sh @@ -28,7 +28,7 @@ test_expect_success 'tar archive' ' "$UNZIP" -v >/dev/null 2>&1 if [ $? -eq 127 ]; then - echo "Skipping ZIP test, because unzip was not found" + say "Skipping ZIP test, because unzip was not found" test_done exit fi diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index 95542e9cfe..74ea8e09f8 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -112,7 +112,7 @@ test_expect_success \ 'test_must_fail git rm -f baz' chmod 775 . else - test_expect_success 'skipping removal failure (perhaps running as root?)' : + say 'skipping removal failure test (perhaps running as root?)' fi test_expect_success \ diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index e1ed073f95..7a84ab61d0 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -182,7 +182,7 @@ test_expect_success 'git archive --format=zip with --output' \ $UNZIP -v >/dev/null 2>&1 if [ $? -eq 127 ]; then - echo "Skipping ZIP tests, because unzip was not found" + say "Skipping ZIP tests, because unzip was not found" test_done exit fi diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 69501e2711..06e6e179f3 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -582,7 +582,7 @@ test_expect_success \ # subsequent tests require gpg; check if it is available gpg --version >/dev/null if [ $? -eq 127 ]; then - echo "gpg not found - skipping tag signing and verification tests" + say "gpg not found - skipping tag signing and verification tests" test_done exit fi @@ -614,7 +614,7 @@ test_expect_success \ # that version, creation of signed tags using the generated key fails. case "$(gpg --version)" in 'gpg (GnuPG) 1.0.6'*) - echo "Skipping signed tag tests, because a bug in 1.0.6 version" + say "Skipping signed tag tests, because a bug in 1.0.6 version" test_done exit ;; diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index 245a7c3662..d28b71b8cf 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -9,7 +9,7 @@ test_description='Test export of commits to CVS' cvs >/dev/null 2>&1 if test $? -ne 1 then - test_expect_success 'skipping git cvsexportcommit tests, cvs not found' : + say 'skipping git cvsexportcommit tests, cvs not found' test_done exit fi diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index 9ccb1232bb..466240cd41 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -13,12 +13,12 @@ cvs CLI client via git-cvsserver server' cvs >/dev/null 2>&1 if test $? -ne 1 then - test_expect_success 'skipping git-cvsserver tests, cvs not found' : + say 'skipping git-cvsserver tests, cvs not found' test_done exit fi perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || { - test_expect_success 'skipping git-cvsserver tests, Perl SQLite interface unavailable' : + say 'skipping git-cvsserver tests, Perl SQLite interface unavailable' test_done exit } diff --git a/t/t9401-git-cvsserver-crlf.sh b/t/t9401-git-cvsserver-crlf.sh index 5d6200c4df..8882230134 100755 --- a/t/t9401-git-cvsserver-crlf.sh +++ b/t/t9401-git-cvsserver-crlf.sh @@ -49,12 +49,12 @@ not_present() { cvs >/dev/null 2>&1 if test $? -ne 1 then - test_expect_success 'skipping git-cvsserver tests, cvs not found' : + say 'skipping git-cvsserver tests, cvs not found' test_done exit fi perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || { - test_expect_success 'skipping git-cvsserver tests, Perl SQLite interface unavailable' : + say 'skipping git-cvsserver tests, Perl SQLite interface unavailable' test_done exit } diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 6ed10d0933..1b78e28c44 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -74,7 +74,7 @@ safe_chmod () { . ./test-lib.sh perl -MEncode -e 'decode_utf8("", Encode::FB_CROAK)' >/dev/null 2>&1 || { - test_expect_success 'skipping gitweb tests, perl version is too old' : + say 'skipping gitweb tests, perl version is too old' test_done exit } diff --git a/t/t9700-perl-git.sh b/t/t9700-perl-git.sh index b81d5dfc34..4a501c6847 100755 --- a/t/t9700-perl-git.sh +++ b/t/t9700-perl-git.sh @@ -7,7 +7,7 @@ test_description='perl interface (Git.pm)' . ./test-lib.sh perl -MTest::More -e 0 2>/dev/null || { - say_color skip "Perl Test::More unavailable, skipping test" + say "Perl Test::More unavailable, skipping test" test_done } From 5b46a4285f3588eaa7e53d513025b28f9f5bfec7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Tue, 17 Mar 2009 22:45:22 +0100 Subject: [PATCH 217/654] Call 'say' outside test_expect_success There were some uses of 'say' inside test_expect_success. But if the tests were not run in verbose mode, this message went to /dev/null. Pull them out of test_expect_success. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t0050-filesystem.sh | 9 +++++++-- t/t3600-rm.sh | 3 ++- t/t7005-editor.sh | 29 +++++++++++++---------------- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh index 7edf49db3c..a449580c8a 100755 --- a/t/t0050-filesystem.sh +++ b/t/t0050-filesystem.sh @@ -8,6 +8,7 @@ auml=`printf '\xc3\xa4'` aumlcdiar=`printf '\x61\xcc\x88'` case_insensitive= +unibad= test_expect_success 'see if we expect ' ' test_case=test_expect_success @@ -19,7 +20,6 @@ test_expect_success 'see if we expect ' ' then test_case=test_expect_failure case_insensitive=t - say "will test on a case insensitive filesystem" fi && rm -fr junk && mkdir junk && @@ -27,13 +27,18 @@ test_expect_success 'see if we expect ' ' case "$(cd junk && echo *)" in "$aumlcdiar") test_unicode=test_expect_failure - say "will test on a unicode corrupting filesystem" + unibad=t ;; *) ;; esac && rm -fr junk ' +test "$case_insensitive" && + say "will test on a case insensitive filesystem" +test "$unibad" && + say "will test on a unicode corrupting filesystem" + if test "$case_insensitive" then test_expect_success "detection of case insensitive filesystem during repo init" ' diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index 74ea8e09f8..2aefbcf471 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -21,10 +21,11 @@ embedded' embedded' && git commit -m 'add files with tabs and newlines' else - say 'Your filesystem does not allow tabs in filenames.' test_tabs=n fi" +test "$test_tabs" = n && say 'Your filesystem does not allow tabs in filenames.' + # Later we will try removing an unremovable path to make sure # git rm barfs, but if the test is run as root that cannot be # arranged. diff --git a/t/t7005-editor.sh b/t/t7005-editor.sh index 2d919d69ef..2f8404afbb 100755 --- a/t/t7005-editor.sh +++ b/t/t7005-editor.sh @@ -87,30 +87,27 @@ do ' done +if ! echo 'echo space > "$1"' > "e space.sh" +then + say "Skipping; FS does not support spaces in filenames" + test_done + exit +fi + test_expect_success 'editor with a space' ' - if echo "echo space > \"\$1\"" > "e space.sh" - then - chmod a+x "e space.sh" && - GIT_EDITOR="./e\ space.sh" git commit --amend && - test space = "$(git show -s --pretty=format:%s)" - else - say "Skipping; FS does not support spaces in filenames" - fi + chmod a+x "e space.sh" && + GIT_EDITOR="./e\ space.sh" git commit --amend && + test space = "$(git show -s --pretty=format:%s)" ' unset GIT_EDITOR test_expect_success 'core.editor with a space' ' - if test -f "e space.sh" - then - git config core.editor \"./e\ space.sh\" && - git commit --amend && - test space = "$(git show -s --pretty=format:%s)" - else - say "Skipping; FS does not support spaces in filenames" - fi + git config core.editor \"./e\ space.sh\" && + git commit --amend && + test space = "$(git show -s --pretty=format:%s)" ' From d5d9de1b10f478b57803f5f2868ed2334c84e09b Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Thu, 5 Feb 2009 20:59:27 +0100 Subject: [PATCH 218/654] test-lib: Replace uses of $(expr ...) by POSIX shell features. In particular: - Test case counting can be achieved by arithmetic expansion. - The name of the test, e.g. t1234, can be computed with ${0%%} and ${0##}. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/test-lib.sh | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index 1e01a912ab..bd8cba1ce2 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -242,14 +242,14 @@ test_merge () { # the text_expect_* functions instead. test_ok_ () { - test_count=$(expr "$test_count" + 1) - test_success=$(expr "$test_success" + 1) + test_count=$(($test_count + 1)) + test_success=$(($test_success + 1)) say_color "" " ok $test_count: $@" } test_failure_ () { - test_count=$(expr "$test_count" + 1) - test_failure=$(expr "$test_failure" + 1); + test_count=$(($test_count + 1)) + test_failure=$(($test_failure + 1)) say_color error "FAIL $test_count: $1" shift echo "$@" | sed -e 's/^/ /' @@ -257,13 +257,13 @@ test_failure_ () { } test_known_broken_ok_ () { - test_count=$(expr "$test_count" + 1) + test_count=$(($test_count+1)) test_fixed=$(($test_fixed+1)) say_color "" " FIXED $test_count: $@" } test_known_broken_failure_ () { - test_count=$(expr "$test_count" + 1) + test_count=$(($test_count+1)) test_broken=$(($test_broken+1)) say_color skip " still broken $test_count: $@" } @@ -279,12 +279,10 @@ test_run_ () { } test_skip () { - this_test=$(expr "./$0" : '.*/\(t[0-9]*\)-[^/]*$') - this_test="$this_test.$(expr "$test_count" + 1)" to_skip= for skp in $GIT_SKIP_TESTS do - case "$this_test" in + case $this_test.$(($test_count+1)) in $skp) to_skip=t esac @@ -292,7 +290,7 @@ test_skip () { case "$to_skip" in t) say_color skip >&3 "skipping test: $@" - test_count=$(expr "$test_count" + 1) + test_count=$(($test_count+1)) say_color skip "skip $test_count: $1" : true ;; @@ -370,7 +368,7 @@ test_external () { then # Announce the script to reduce confusion about the # test output that follows. - say_color "" " run $(expr "$test_count" + 1): $descr ($*)" + say_color "" " run $(($test_count+1)): $descr ($*)" # Run command; redirect its stderr to &4 as in # test_run_, but keep its stdout on our stdout even in # non-verbose mode. @@ -613,7 +611,8 @@ test_create_repo "$test" # in subprocesses like git equals our $PWD (for pathname comparisons). cd -P "$test" || exit 1 -this_test=$(expr "./$0" : '.*/\(t[0-9]*\)-[^/]*$') +this_test=${0##*/} +this_test=${this_test%%-*} for skp in $GIT_SKIP_TESTS do to_skip= From 8586f98bd29bd4ad3d0e62a3be4a4d59ff8b27cd Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Thu, 5 Feb 2009 21:20:56 +0100 Subject: [PATCH 219/654] test-lib: Simplify test counting. Since the test case counter was incremented very late, there were a few users of the counter had to do their own incrementing. Now we increment it early and simplify these users. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t4013-diff-various.sh | 3 +-- t/t5515-fetch-merge-logic.sh | 3 +-- t/test-lib.sh | 10 +++------- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 9cd5a6e685..426e64e828 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -101,8 +101,7 @@ do '' | '#'*) continue ;; esac test=`echo "$cmd" | sed -e 's|[/ ][/ ]*|_|g'` - cnt=`expr $test_count + 1` - pfx=`printf "%04d" $cnt` + pfx=`printf "%04d" $test_count` expect="$TEST_DIRECTORY/t4013/diff.$test" actual="$pfx-diff.$test" diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh index 1f4608d8ba..dbb927dec8 100755 --- a/t/t5515-fetch-merge-logic.sh +++ b/t/t5515-fetch-merge-logic.sh @@ -129,8 +129,7 @@ do '' | '#'*) continue ;; esac test=`echo "$cmd" | sed -e 's|[/ ][/ ]*|_|g'` - cnt=`expr $test_count + 1` - pfx=`printf "%04d" $cnt` + pfx=`printf "%04d" $test_count` expect_f="$TEST_DIRECTORY/t5515/fetch.$test" actual_f="$pfx-fetch.$test" expect_r="$TEST_DIRECTORY/t5515/refs.$test" diff --git a/t/test-lib.sh b/t/test-lib.sh index bd8cba1ce2..ace440cb36 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -242,13 +242,11 @@ test_merge () { # the text_expect_* functions instead. test_ok_ () { - test_count=$(($test_count + 1)) test_success=$(($test_success + 1)) say_color "" " ok $test_count: $@" } test_failure_ () { - test_count=$(($test_count + 1)) test_failure=$(($test_failure + 1)) say_color error "FAIL $test_count: $1" shift @@ -257,13 +255,11 @@ test_failure_ () { } test_known_broken_ok_ () { - test_count=$(($test_count+1)) test_fixed=$(($test_fixed+1)) say_color "" " FIXED $test_count: $@" } test_known_broken_failure_ () { - test_count=$(($test_count+1)) test_broken=$(($test_broken+1)) say_color skip " still broken $test_count: $@" } @@ -279,10 +275,11 @@ test_run_ () { } test_skip () { + test_count=$(($test_count+1)) to_skip= for skp in $GIT_SKIP_TESTS do - case $this_test.$(($test_count+1)) in + case $this_test.$test_count in $skp) to_skip=t esac @@ -290,7 +287,6 @@ test_skip () { case "$to_skip" in t) say_color skip >&3 "skipping test: $@" - test_count=$(($test_count+1)) say_color skip "skip $test_count: $1" : true ;; @@ -368,7 +364,7 @@ test_external () { then # Announce the script to reduce confusion about the # test output that follows. - say_color "" " run $(($test_count+1)): $descr ($*)" + say_color "" " run $test_count: $descr ($*)" # Run command; redirect its stderr to &4 as in # test_run_, but keep its stdout on our stdout even in # non-verbose mode. From 1f553918a8482ea792e8cd4d5d2c75fe60f68aae Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Sat, 28 Feb 2009 21:12:57 +0100 Subject: [PATCH 220/654] test-lib: Introduce test_chmod and use it instead of update-index --chmod This function replaces sequences of 'chmod +x' and 'git update-index --chmod=+x' in the test suite, whose purpose is to help filesystems that need core.filemode=false. Two places where only 'chmod +x' was used we also use this new function. The function calls 'git update-index --chmod' without checking core.filemode (unlike some of the call sites did). We do this because the call sites *expect* that the executable bit ends up in the index (ie. it is not the purpose of the call sites to *test* whether git treats 'chmod +x' and 'update-index --chmod=+x' correctly). Therefore, on filesystems with core.filemode=true the 'git update-index --chmod' is a no-op. The function uses --add with update-index to help one call site in t6031-merge-recursive. It makes no difference for the other callers. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t1410-reflog.sh | 4 +--- t/t3400-rebase.sh | 4 ++-- t/t4006-diff-mode.sh | 19 ++++--------------- t/t4014-format-patch.sh | 4 +--- t/t6031-merge-recursive.sh | 9 ++------- t/t9500-gitweb-standalone-no-errors.sh | 18 +++++------------- t/test-lib.sh | 9 +++++++++ 7 files changed, 24 insertions(+), 43 deletions(-) diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh index 5b24f05573..80af6b9b7e 100755 --- a/t/t1410-reflog.sh +++ b/t/t1410-reflog.sh @@ -70,9 +70,7 @@ test_expect_success setup ' E=`git rev-parse --verify HEAD:A/B/E` && check_fsck && - chmod +x C && - ( test "`git config --bool core.filemode`" != false || - echo executable >>C ) && + test_chmod +x C && git add C && test_tick && git commit -m dragon && L=`git rev-parse --verify HEAD` && diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index be7ae5a004..6e391a3702 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -83,9 +83,9 @@ test_expect_success 'rebase a single mode change' ' git checkout -b modechange HEAD^ && echo 1 > X && git add X && - chmod a+x A && + test_chmod +x A && test_tick && - git commit -m modechange A X && + git commit -m modechange && GIT_TRACE=1 git rebase master ' diff --git a/t/t4006-diff-mode.sh b/t/t4006-diff-mode.sh index 4e92fce1d0..8c1b81e248 100755 --- a/t/t4006-diff-mode.sh +++ b/t/t4006-diff-mode.sh @@ -15,21 +15,10 @@ test_expect_success \ tree=`git write-tree` && echo $tree' -if [ "$(git config --get core.filemode)" = false ] -then - say 'filemode disabled on the filesystem, using update-index --chmod=+x' - test_expect_success \ - 'git update-index --chmod=+x' \ - 'git update-index rezrov && - git update-index --chmod=+x rezrov && - git diff-index $tree >current' -else - test_expect_success \ - 'chmod' \ - 'chmod +x rezrov && - git update-index rezrov && - git diff-index $tree >current' -fi +test_expect_success \ + 'chmod' \ + 'test_chmod +x rezrov && + git diff-index $tree >current' _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index ebfc4a6590..f187d15e32 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -16,9 +16,7 @@ test_expect_success setup ' git checkout -b side && for i in 1 2 5 6 A B C 7 8 9 10; do echo "$i"; done >file && - chmod +x elif && - git update-index file elif && - git update-index --chmod=+x elif && + test_chmod +x elif && git commit -m "Side changes #1" && for i in D E F; do echo "$i"; done >>file && diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh index 8073e0c3ef..41c6860be2 100755 --- a/t/t6031-merge-recursive.sh +++ b/t/t6031-merge-recursive.sh @@ -3,9 +3,6 @@ test_description='merge-recursive: handle file mode' . ./test-lib.sh -# Note that we follow "chmod +x F" with "update-index --chmod=+x F" to -# help filesystems that do not have the executable bit. - test_expect_success 'mode change in one branch: keep changed version' ' : >file1 && git add file1 && @@ -15,8 +12,7 @@ test_expect_success 'mode change in one branch: keep changed version' ' git add dummy && git commit -m a && git checkout -b b1 master && - chmod +x file1 && - git update-index --chmod=+x file1 && + test_chmod +x file1 && git commit -m b1 && git checkout a1 && git merge-recursive master -- a1 b1 && @@ -28,8 +24,7 @@ test_expect_success 'mode change in both branches: expect conflict' ' git checkout -b a2 master && : >file2 && H=$(git hash-object file2) && - chmod +x file2 && - git update-index --add --chmod=+x file2 && + test_chmod +x file2 && git commit -m a2 && git checkout -b b2 master && : >file2 && diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 1b78e28c44..dce06bcc97 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -63,14 +63,6 @@ gitweb_run () { # gitweb.log is left for debugging } -safe_chmod () { - chmod "$1" "$2" && - if [ "$(git config --get core.filemode)" = false ] - then - git update-index --chmod="$1" "$2" - fi -} - . ./test-lib.sh perl -MEncode -e 'decode_utf8("", Encode::FB_CROAK)' >/dev/null 2>&1 || { @@ -242,7 +234,7 @@ test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(0): mode change' \ - 'safe_chmod +x new_file && + 'test_chmod +x new_file && git commit -a -m "Mode changed." && gitweb_run "p=.git;a=commitdiff"' test_debug 'cat gitweb.log' @@ -281,7 +273,7 @@ test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(0): mode change and modified' \ 'echo "New line" >> file2 && - safe_chmod +x file2 && + test_chmod +x file2 && git commit -a -m "Mode change and modification." && gitweb_run "p=.git;a=commitdiff"' test_debug 'cat gitweb.log' @@ -308,7 +300,7 @@ test_expect_success \ 'commitdiff(0): renamed, mode change and modified' \ 'git mv file3 file2 && echo "Propter nomen suum." >> file2 && - safe_chmod +x file2 && + test_chmod +x file2 && git commit -a -m "File rename, mode change and modification." && gitweb_run "p=.git;a=commitdiff"' test_debug 'cat gitweb.log' @@ -425,10 +417,10 @@ test_expect_success \ git add 03-new && git mv 04-rename-from 04-rename-to && echo "Changed" >> 04-rename-to && - safe_chmod +x 05-mode-change && + test_chmod +x 05-mode-change && rm -f 06-file-or-symlink && ln -s 01-change 06-file-or-symlink && echo "Changed and have mode changed" > 07-change-mode-change && - safe_chmod +x 07-change-mode-change && + test_chmod +x 07-change-mode-change && git commit -a -m "Large commit" && git checkout master' diff --git a/t/test-lib.sh b/t/test-lib.sh index ace440cb36..638cca41e3 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -238,6 +238,15 @@ test_merge () { git tag "$1" } +# This function helps systems where core.filemode=false is set. +# Use it instead of plain 'chmod +x' to set or unset the executable bit +# of a file in the working directory and add it to the index. + +test_chmod () { + chmod "$@" && + git update-index --add "--chmod=$@" +} + # You are not expected to call test_ok_ and test_failure_ directly, use # the text_expect_* functions instead. From e2c2407683bf51c30004d2804623f2eb8e831b7a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Wed, 11 Mar 2009 17:58:32 +0100 Subject: [PATCH 221/654] t7300: fix clean up on Windows On Windows, you cannot remove files that are in use, not even with 'rm -rf'. So we need to run 'exec <foo/bar' inside a subshell lest removing the whole test repository fail. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t7300-clean.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index 1636fac2a4..929d5d4d3b 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -373,9 +373,9 @@ test_expect_success 'removal failure' ' mkdir foo && touch foo/bar && - exec <foo/bar && - chmod 0 foo && - test_must_fail git clean -f -d + (exec <foo/bar && + chmod 0 foo && + test_must_fail git clean -f -d) ' chmod 755 foo From 0aaaef7b0f83ccd97d586b5c951adcb912af2664 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Mon, 9 Feb 2009 10:24:51 +0100 Subject: [PATCH 222/654] t2200, t7004: Avoid glob pattern that also matches files On Windows, there is an unfortunate interaction between the MSYS bash and git's command line processing: - Since Windows's CMD does not do the wildcard expansion, but passes arguments like path* through to the programs, the programs must do the expansion themselves. This happens in the startup code before main() is entered. - bash, however, passes the argument "path*" to git, assuming that git will see the unquoted word unchanged as a single argument. But actually git expands the unquoted word before main() is entered. In t2200, not all names that the test case is interested in exist as files at the time when 'git ls-files' is invoked. git expands "path?" to only the subset of files the exist, and only that subset was listed, so that the test failed. We now list all interesting paths explicitly. In t7004, git exanded the pattern "*a*" to "actual" (the file that stdout was redirected to), which is not what the was tested for. We fix it by renaming the output file (and removing any existing files matching *a*). This was originally fixed by Johannes Schindelin. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t2200-add-update.sh | 2 +- t/t7004-tag.sh | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh index b2ddf5ace3..5a8d52f2ff 100755 --- a/t/t2200-add-update.sh +++ b/t/t2200-add-update.sh @@ -150,7 +150,7 @@ test_expect_success 'add -u resolves unmerged paths' ' echo 2 >path3 && echo 2 >path5 && git add -u && - git ls-files -s "path?" >actual && + git ls-files -s path1 path2 path3 path4 path5 path6 >actual && { echo "100644 $three 0 path1" echo "100644 $one 1 path3" diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 06e6e179f3..1c27ffb45e 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -185,8 +185,9 @@ cba EOF test_expect_success \ 'listing tags with substring as pattern must print those matching' ' - git tag -l "*a*" > actual && - test_cmp expect actual + rm *a* && + git tag -l "*a*" > current && + test_cmp expect current ' cat >expect <<EOF From b689ccf6c9eecb9811f60ac69a24cadacf84da44 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Mon, 17 Nov 2008 09:21:30 +0100 Subject: [PATCH 223/654] t5300, t5302, t5303: Do not use /dev/zero We do not have /dev/zero on Windows. This replaces it by data generated with printf, perl, or echo. Most of the cases do not depend on that the data is a stream of zero bytes, so we use something printable; nor is an unlimited stream of data needed, so we produce only as many bytes as the test cases need. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t5300-pack-object.sh | 17 ++++++++--------- t/t5302-pack-index.sh | 2 +- t/t5303-pack-corruption-resilience.sh | 12 +++++++----- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index ccfc64c6ee..e2aa254eae 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -13,11 +13,10 @@ TRASH=`pwd` test_expect_success \ 'setup' \ 'rm -f .git/index* - for i in a b c - do - dd if=/dev/zero bs=4k count=1 | perl -pe "y/\\000/$i/" >$i && - git update-index --add $i || return 1 - done && + perl -e "print \"a\" x 4096;" > a && + perl -e "print \"b\" x 4096;" > b && + perl -e "print \"c\" x 4096;" > c && + git update-index --add a b c && cat c >d && echo foo >>d && git update-index --add d && tree=`git write-tree` && commit=`git commit-tree $tree </dev/null` && { @@ -221,7 +220,7 @@ test_expect_success \ test_expect_success \ 'verify-pack catches a corrupted pack signature' \ 'cat test-1-${packname_1}.pack >test-3.pack && - dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=2 && + echo | dd of=test-3.pack count=1 bs=1 conv=notrunc seek=2 && if git verify-pack test-3.idx then false else :; @@ -230,7 +229,7 @@ test_expect_success \ test_expect_success \ 'verify-pack catches a corrupted pack version' \ 'cat test-1-${packname_1}.pack >test-3.pack && - dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=7 && + echo | dd of=test-3.pack count=1 bs=1 conv=notrunc seek=7 && if git verify-pack test-3.idx then false else :; @@ -239,7 +238,7 @@ test_expect_success \ test_expect_success \ 'verify-pack catches a corrupted type/size of the 1st packed object data' \ 'cat test-1-${packname_1}.pack >test-3.pack && - dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=12 && + echo | dd of=test-3.pack count=1 bs=1 conv=notrunc seek=12 && if git verify-pack test-3.idx then false else :; @@ -250,7 +249,7 @@ test_expect_success \ 'l=`wc -c <test-3.idx` && l=`expr $l - 20` && cat test-1-${packname_1}.pack >test-3.pack && - dd if=/dev/zero of=test-3.idx count=20 bs=1 conv=notrunc seek=$l && + printf "%20s" "" | dd of=test-3.idx count=20 bs=1 conv=notrunc seek=$l && if git verify-pack test-3.pack then false else :; diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index e6f70d474f..77982cdeac 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -208,7 +208,7 @@ test_expect_success \ obj=`git hash-object file_001` && nr=`index_obj_nr ".git/objects/pack/pack-${pack1}.idx" $obj` && chmod +w ".git/objects/pack/pack-${pack1}.idx" && - dd if=/dev/zero of=".git/objects/pack/pack-${pack1}.idx" conv=notrunc \ + printf xxxx | dd of=".git/objects/pack/pack-${pack1}.idx" conv=notrunc \ bs=1 count=4 seek=$((8 + 256 * 4 + `wc -l <obj-list` * 20 + $nr * 4)) && ( while read obj do git cat-file -p $obj >/dev/null || exit 1 diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh index d4e30fc43c..5132d41309 100755 --- a/t/t5303-pack-corruption-resilience.sh +++ b/t/t5303-pack-corruption-resilience.sh @@ -55,6 +55,8 @@ do_corrupt_object() { test_must_fail git verify-pack ${pack}.pack } +printf '\0' > zero + test_expect_success \ 'initial setup validation' \ 'create_test_files && @@ -66,7 +68,7 @@ test_expect_success \ test_expect_success \ 'create corruption in header of first object' \ - 'do_corrupt_object $blob_1 0 < /dev/zero && + 'do_corrupt_object $blob_1 0 < zero && test_must_fail git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null' @@ -125,7 +127,7 @@ test_expect_success \ 'create corruption in header of first delta' \ 'create_new_pack && git prune-packed && - do_corrupt_object $blob_2 0 < /dev/zero && + do_corrupt_object $blob_2 0 < zero && git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null' @@ -180,7 +182,7 @@ test_expect_success \ 'corruption in delta base reference of first delta (OBJ_REF_DELTA)' \ 'create_new_pack && git prune-packed && - do_corrupt_object $blob_2 2 < /dev/zero && + do_corrupt_object $blob_2 2 < zero && git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null' @@ -207,7 +209,7 @@ test_expect_success \ 'corruption #0 in delta base reference of first delta (OBJ_OFS_DELTA)' \ 'create_new_pack --delta-base-offset && git prune-packed && - do_corrupt_object $blob_2 2 < /dev/zero && + do_corrupt_object $blob_2 2 < zero && git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null' @@ -259,7 +261,7 @@ test_expect_success \ test_expect_success \ '... and a redundant pack allows for full recovery too' \ - 'do_corrupt_object $blob_2 2 < /dev/zero && + 'do_corrupt_object $blob_2 2 < zero && git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null && From a8cbc9ab027dce3d99d0039a02ec9df0f0c7ebb1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Thu, 12 Mar 2009 20:32:43 +0100 Subject: [PATCH 224/654] t5602: Work around path mangling on MSYS MSYS's bash rewrites /something/bin/... into a Windows path that looks like c:/msysgit/something/bin/... before git sees it. But later the test case verifies that the path was used and compares it to the unmangled version. This fails, of course. This make the path relative so that the path mangling is not triggered. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t5602-clone-remote-exec.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t5602-clone-remote-exec.sh b/t/t5602-clone-remote-exec.sh index 82b1d1e2b3..deffdaee49 100755 --- a/t/t5602-clone-remote-exec.sh +++ b/t/t5602-clone-remote-exec.sh @@ -18,8 +18,8 @@ test_expect_success 'clone calls git upload-pack unqualified with no -u option' ' test_expect_success 'clone calls specified git upload-pack with -u option' ' - GIT_SSH=./not_ssh git clone -u /something/bin/git-upload-pack localhost:/path/to/repo junk - echo "localhost /something/bin/git-upload-pack '\''/path/to/repo'\''" >expected + GIT_SSH=./not_ssh git clone -u ./something/bin/git-upload-pack localhost:/path/to/repo junk + echo "localhost ./something/bin/git-upload-pack '\''/path/to/repo'\''" >expected test_cmp expected not_ssh_output ' From f17e9fbbe919bc1f4ecaa35a9cb0869a5ec47fc0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Wed, 11 Mar 2009 21:17:26 +0100 Subject: [PATCH 225/654] test-lib: Work around incompatible sort and find on Windows If the PATH lists the Windows system directories before the MSYS directories, Windows's own incompatible sort and find commands would be picked up. We implement these commands as functions and call the real tools by absolute path. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/test-lib.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 638cca41e3..4eda5aba4b 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -635,3 +635,16 @@ do test_done esac done + +# Fix some commands on Windows +case $(uname -s) in +*MINGW*) + # Windows has its own (incompatible) sort and find + sort () { + /usr/bin/sort "$@" + } + find () { + /usr/bin/find "$@" + } + ;; +esac From 5397ea314f612eaaacfb13d978319afd2c724817 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Sat, 14 Mar 2009 22:21:27 +0100 Subject: [PATCH 226/654] test-lib: Work around missing sum on Windows t1002-read-tree-m-u-2way.sh uses 'sum', but it does not rely on the exact form of the sum, only that it is a hash digest. Therefore, we can sneak in 'md5sum' under the name 'sum'. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/test-lib.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 4eda5aba4b..4720b9a92b 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -646,5 +646,8 @@ case $(uname -s) in find () { /usr/bin/find "$@" } + sum () { + md5sum "$@" + } ;; esac From 4114156ae959a8ecfea62213df35fd8f778d9c4e Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Fri, 13 Mar 2009 23:35:24 +0100 Subject: [PATCH 227/654] Tests on Windows: $(pwd) must return Windows-style paths Many tests pass $(pwd) in some form to git and later test that the output of git contains the correct value of $(pwd). For example, the test of 'git remote show' sets up a remote that contains $(pwd) and then the expected result must contain $(pwd). Again, MSYS-bash's path mangling kicks in: Plain $(pwd) uses the MSYS style absolute path /c/path/to/git. The test case would write this name into the 'expect' file. But when git is invoked, MSYS-bash converts this name to the Windows style path c:/path/to/git, and git would produce this form in the result; the test would fail. We fix this by passing -W to bash's pwd that produces the Windows-style path. There are a two cases that need an accompanying change: - In t1504 the value of $(pwd) becomes part of a path list. In this case, the lone 'c' in something like /foo:c:/path/to/git:/bar inhibits MSYS-bashes path mangling; IOW in this case we want the /c/path/to/git form to allow path mangling. We use $PWD instead of $(pwd), which always has the latter form. - In t6200, $(pwd) - the Windows style path - must be used to construct the expected result because that is the path form that git sees. (The change in the test itself is just for consistency: 'git fetch' always sees the Windows-style path, with or without the change.) Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t1504-ceiling-dirs.sh | 2 +- t/t6200-fmt-merge-msg.sh | 4 ++-- t/test-lib.sh | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/t/t1504-ceiling-dirs.sh b/t/t1504-ceiling-dirs.sh index e377d48902..df5ad8c686 100755 --- a/t/t1504-ceiling-dirs.sh +++ b/t/t1504-ceiling-dirs.sh @@ -13,7 +13,7 @@ test_fail() { "git rev-parse --show-prefix" } -TRASH_ROOT="$(pwd)" +TRASH_ROOT="$PWD" ROOT_PARENT=$(dirname "$TRASH_ROOT") diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh index 8f5a06f7dd..2049ab6cf8 100755 --- a/t/t6200-fmt-merge-msg.sh +++ b/t/t6200-fmt-merge-msg.sh @@ -83,13 +83,13 @@ test_expect_success 'merge-msg test #1' ' ' cat >expected <<EOF -Merge branch 'left' of $TEST_DIRECTORY/$test +Merge branch 'left' of $(pwd) EOF test_expect_success 'merge-msg test #2' ' git checkout master && - git fetch "$TEST_DIRECTORY/$test" left && + git fetch "$(pwd)" left && git fmt-merge-msg <.git/FETCH_HEAD >actual && test_cmp expected actual diff --git a/t/test-lib.sh b/t/test-lib.sh index 4720b9a92b..0a0696abc9 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -649,5 +649,9 @@ case $(uname -s) in sum () { md5sum "$@" } + # git sees Windows-style pwd + pwd () { + builtin pwd -W + } ;; esac From 64e61f2d173b0172d9dbaa9667486764224568fb Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Wed, 4 Mar 2009 19:40:27 +0100 Subject: [PATCH 228/654] t0050: Check whether git init detected symbolic link support correctly Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t0050-filesystem.sh | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh index a449580c8a..89282ccf7a 100755 --- a/t/t0050-filesystem.sh +++ b/t/t0050-filesystem.sh @@ -9,7 +9,8 @@ aumlcdiar=`printf '\x61\xcc\x88'` case_insensitive= unibad= -test_expect_success 'see if we expect ' ' +no_symlinks= +test_expect_success 'see what we expect' ' test_case=test_expect_success test_unicode=test_expect_success @@ -31,13 +32,21 @@ test_expect_success 'see if we expect ' ' ;; *) ;; esac && - rm -fr junk + rm -fr junk && + { + ln -s x y 2> /dev/null && + test -h y 2> /dev/null || + no_symlinks=1 + rm -f y + } ' test "$case_insensitive" && say "will test on a case insensitive filesystem" test "$unibad" && say "will test on a unicode corrupting filesystem" +test "$no_symlinks" && + say "will test on a filesystem lacking symbolic links" if test "$case_insensitive" then @@ -53,6 +62,21 @@ test_expect_success "detection of case insensitive filesystem during repo init" ' fi +if test "$no_symlinks" +then +test_expect_success "detection of filesystem w/o symlink support during repo init" ' + + v=$(git config --bool core.symlinks) && + test "$v" = false +' +else +test_expect_success "detection of filesystem w/o symlink support during repo init" ' + + test_must_fail git config --bool core.symlinks || + test "$(git config --bool core.symlinks)" = true +' +fi + test_expect_success "setup case tests" ' git config core.ignorecase true && From cd4371208a0e9f882f6fd4b4dd28d6911848ec79 Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Fri, 20 Mar 2009 02:00:43 -0400 Subject: [PATCH 229/654] make oneline reflog dates more consistent with multiline format The multiline reflog format (e.g., as shown by "git log -g") will show HEAD@{<date>} rather than HEAD@{<count>} in two situations: 1. If the user gave branch@{<date>} syntax to specify the reflog 2. If the user gave a --date=<format> specifier It uses the "normal" date format in case 1, and the user-specified format in case 2. The oneline reflog format (e.g., "git reflog show" or "git log -g --oneline") will show the date in the same two circumstances. However, it _always_ shows the date as a relative date, and it always ignores the timezone. In case 2, it seems ridiculous to trigger the date but use a format totally different from what the user requested. For case 1, it is arguable that the user might want to see the relative date by default; however, the multiline version shows the normal format. This patch does three things: - refactors the "relative_date" parameter to show_reflog_message to be an actual date_mode enum, since this is how it is used (it is passed to show_date) - uses the passed date_mode parameter in the oneline format (making it consistent with the multiline format) - does not ignore the timezone parameter in oneline mode Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- reflog-walk.c | 12 ++++---- reflog-walk.h | 5 +++- t/t1411-reflog-show.sh | 67 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 6 deletions(-) create mode 100755 t/t1411-reflog-show.sh diff --git a/reflog-walk.c b/reflog-walk.c index f751fdc8d8..fd065f4e1a 100644 --- a/reflog-walk.c +++ b/reflog-walk.c @@ -242,7 +242,7 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit) } void show_reflog_message(struct reflog_walk_info* info, int oneline, - int relative_date) + enum date_mode dmode) { if (info && info->last_commit_reflog) { struct commit_reflog *commit_reflog = info->last_commit_reflog; @@ -251,8 +251,10 @@ void show_reflog_message(struct reflog_walk_info* info, int oneline, info = &commit_reflog->reflogs->items[commit_reflog->recno+1]; if (oneline) { printf("%s@{", commit_reflog->reflogs->ref); - if (commit_reflog->flag || relative_date) - printf("%s", show_date(info->timestamp, 0, 1)); + if (commit_reflog->flag || dmode) + printf("%s", show_date(info->timestamp, + info->tz, + dmode)); else printf("%d", commit_reflog->reflogs->nr - 2 - commit_reflog->recno); @@ -260,10 +262,10 @@ void show_reflog_message(struct reflog_walk_info* info, int oneline, } else { printf("Reflog: %s@{", commit_reflog->reflogs->ref); - if (commit_reflog->flag || relative_date) + if (commit_reflog->flag || dmode) printf("%s", show_date(info->timestamp, info->tz, - relative_date)); + dmode)); else printf("%d", commit_reflog->reflogs->nr - 2 - commit_reflog->recno); diff --git a/reflog-walk.h b/reflog-walk.h index 7ca1438f4d..74c90964bd 100644 --- a/reflog-walk.h +++ b/reflog-walk.h @@ -1,11 +1,14 @@ #ifndef REFLOG_WALK_H #define REFLOG_WALK_H +#include "cache.h" + extern void init_reflog_walk(struct reflog_walk_info** info); extern int add_reflog_for_walk(struct reflog_walk_info *info, struct commit *commit, const char *name); extern void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit); -extern void show_reflog_message(struct reflog_walk_info *info, int, int); +extern void show_reflog_message(struct reflog_walk_info *info, int, + enum date_mode); #endif diff --git a/t/t1411-reflog-show.sh b/t/t1411-reflog-show.sh new file mode 100755 index 0000000000..c18ed8edf9 --- /dev/null +++ b/t/t1411-reflog-show.sh @@ -0,0 +1,67 @@ +#!/bin/sh + +test_description='Test reflog display routines' +. ./test-lib.sh + +test_expect_success 'setup' ' + echo content >file && + git add file && + test_tick && + git commit -m one +' + +cat >expect <<'EOF' +Reflog: HEAD@{0} (C O Mitter <committer@example.com>) +Reflog message: commit (initial): one +EOF +test_expect_success 'log -g shows reflog headers' ' + git log -g -1 >tmp && + grep ^Reflog <tmp >actual && + test_cmp expect actual +' + +cat >expect <<'EOF' +e46513e HEAD@{0}: commit (initial): one +EOF +test_expect_success 'oneline reflog format' ' + git log -g -1 --oneline >actual && + test_cmp expect actual +' + +cat >expect <<'EOF' +Reflog: HEAD@{Thu Apr 7 15:13:13 2005 -0700} (C O Mitter <committer@example.com>) +Reflog message: commit (initial): one +EOF +test_expect_success 'using @{now} syntax shows reflog date (multiline)' ' + git log -g -1 HEAD@{now} >tmp && + grep ^Reflog <tmp >actual && + test_cmp expect actual +' + +cat >expect <<'EOF' +e46513e HEAD@{Thu Apr 7 15:13:13 2005 -0700}: commit (initial): one +EOF +test_expect_success 'using @{now} syntax shows reflog date (oneline)' ' + git log -g -1 --oneline HEAD@{now} >actual && + test_cmp expect actual +' + +cat >expect <<'EOF' +Reflog: HEAD@{1112911993 -0700} (C O Mitter <committer@example.com>) +Reflog message: commit (initial): one +EOF +test_expect_success 'using --date= shows reflog date (multiline)' ' + git log -g -1 --date=raw >tmp && + grep ^Reflog <tmp >actual && + test_cmp expect actual +' + +cat >expect <<'EOF' +e46513e HEAD@{1112911993 -0700}: commit (initial): one +EOF +test_expect_success 'using --date= shows reflog date (oneline)' ' + git log -g -1 --oneline --date=raw >actual && + test_cmp expect actual +' + +test_done From 6872f606d9bc9a0ab0b3252bd4175af7732b6135 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta <giuseppe.bilotta@gmail.com> Date: Fri, 20 Mar 2009 10:57:50 +0100 Subject: [PATCH 230/654] import-tars: separate author from committer The import-tars script is typically employed to (re)create the past history of a project from stored tars. Although assigning authorship in these cases can be a somewhat arbitrary process, it makes sense to set the author to whoever created the tars in the first place (if it's known), and (s)he can in general be different from the committer (whoever is running the script). Implement this by having separate author and committer data, making them settable from the usual GIT_* environment variables. Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/fast-import/import-tars.perl | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/contrib/fast-import/import-tars.perl b/contrib/fast-import/import-tars.perl index 23aeb257b9..6309d146e7 100755 --- a/contrib/fast-import/import-tars.perl +++ b/contrib/fast-import/import-tars.perl @@ -14,13 +14,18 @@ die "usage: import-tars *.tar.{gz,bz2,Z}\n" unless @ARGV; my $branch_name = 'import-tars'; my $branch_ref = "refs/heads/$branch_name"; -my $committer_name = 'T Ar Creator'; -my $committer_email = 'tar@example.com'; +my $author_name = $ENV{'GIT_AUTHOR_NAME'} || 'T Ar Creator'; +my $author_email = $ENV{'GIT_AUTHOR_EMAIL'} || 'tar@example.com'; +my $committer_name = $ENV{'GIT_COMMITTER_NAME'} || `git config --get user.name`; +my $committer_email = $ENV{'GIT_COMMITTER_EMAIL'} || `git config --get user.email`; + +chomp($committer_name, $committer_email); open(FI, '|-', 'git', 'fast-import', '--quiet') or die "Unable to start git fast-import: $!\n"; foreach my $tar_file (@ARGV) { + my $commit_time = time; $tar_file =~ m,([^/]+)$,; my $tar_name = $1; @@ -39,7 +44,7 @@ foreach my $tar_file (@ARGV) die "Unrecognized compression format: $tar_file\n"; } - my $commit_time = 0; + my $author_time = 0; my $next_mark = 1; my $have_top_dir = 1; my ($top_dir, %files); @@ -92,7 +97,7 @@ foreach my $tar_file (@ARGV) } $files{$path} = [$next_mark++, $mode]; - $commit_time = $mtime if $mtime > $commit_time; + $author_time = $mtime if $mtime > $author_time; $path =~ m,^([^/]+)/,; $top_dir = $1 unless $top_dir; $have_top_dir = 0 if $top_dir ne $1; @@ -100,6 +105,7 @@ foreach my $tar_file (@ARGV) print FI <<EOF; commit $branch_ref +author $author_name <$author_email> $author_time +0000 committer $committer_name <$committer_email> $commit_time +0000 data <<END_OF_COMMIT_MESSAGE Imported from $tar_file. @@ -119,7 +125,7 @@ EOF print FI <<EOF; tag $tar_name from $branch_ref -tagger $committer_name <$committer_email> $commit_time +0000 +tagger $author_name <$author_email> $author_time +0000 data <<END_OF_TAG_MESSAGE Package $tar_name END_OF_TAG_MESSAGE From e392a852364e375e916c1dd4f87a7584b348410a Mon Sep 17 00:00:00 2001 From: Alex Riesen <raa.lkml@gmail.com> Date: Thu, 19 Mar 2009 23:54:29 +0100 Subject: [PATCH 231/654] Produce a nicer output in case of sha1_object_info failures in ls-tree -l An error message is already printed by sha1_object_info itself, and the failed entries are additionally marked in the listing. Signed-off-by: Alex Riesen <raa.lkml@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-ls-tree.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/builtin-ls-tree.c b/builtin-ls-tree.c index fca46312f6..22008dfa8f 100644 --- a/builtin-ls-tree.c +++ b/builtin-ls-tree.c @@ -60,7 +60,6 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen, { int retval = 0; const char *type = blob_type; - unsigned long size; if (S_ISGITLINK(mode)) { /* @@ -90,17 +89,20 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen, if (!(ls_options & LS_NAME_ONLY)) { if (ls_options & LS_SHOW_SIZE) { + char size_text[24]; if (!strcmp(type, blob_type)) { - sha1_object_info(sha1, &size); - printf("%06o %s %s %7lu\t", mode, type, - abbrev ? find_unique_abbrev(sha1, abbrev) - : sha1_to_hex(sha1), - size); + unsigned long size; + if (sha1_object_info(sha1, &size) == OBJ_BAD) + strcpy(size_text, "BAD"); + else + snprintf(size_text, sizeof(size_text), + "%lu", size); } else - printf("%06o %s %s %7c\t", mode, type, - abbrev ? find_unique_abbrev(sha1, abbrev) - : sha1_to_hex(sha1), - '-'); + strcpy(size_text, "-"); + printf("%06o %s %s %7s\t", mode, type, + abbrev ? find_unique_abbrev(sha1, abbrev) + : sha1_to_hex(sha1), + size_text); } else printf("%06o %s %s\t", mode, type, abbrev ? find_unique_abbrev(sha1, abbrev) From 8f0246551c3964eeb16d9c9f39845bd53af8bda8 Mon Sep 17 00:00:00 2001 From: Alex Riesen <raa.lkml@gmail.com> Date: Thu, 19 Mar 2009 23:27:32 +0100 Subject: [PATCH 232/654] Microoptimize strbuf_cmp It can be less object code and may be even faster, even if at the moment there is no callers to take an advantage of that. This implementation can be trivially made inlinable later. Signed-off-by: Alex Riesen <raa.lkml@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- strbuf.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/strbuf.c b/strbuf.c index 6ed06840b8..bfbd81632e 100644 --- a/strbuf.c +++ b/strbuf.c @@ -139,14 +139,11 @@ void strbuf_list_free(struct strbuf **sbs) int strbuf_cmp(const struct strbuf *a, const struct strbuf *b) { - int cmp; - if (a->len < b->len) { - cmp = memcmp(a->buf, b->buf, a->len); - return cmp ? cmp : -1; - } else { - cmp = memcmp(a->buf, b->buf, b->len); - return cmp ? cmp : a->len != b->len; - } + int len = a->len < b->len ? a->len: b->len; + int cmp = memcmp(a->buf, b->buf, len); + if (cmp) + return cmp; + return a->len < b->len ? -1: a->len != b->len; } void strbuf_splice(struct strbuf *sb, size_t pos, size_t len, From b997045e01c2f12ac7dc44c487915f8e50da4d4d Mon Sep 17 00:00:00 2001 From: Kristian Amlie <kristian.amlie@nokia.com> Date: Fri, 20 Mar 2009 10:32:09 +0100 Subject: [PATCH 233/654] Add a test for checking whether gitattributes is honored by checkout. The original bug will not honor new entries in gitattributes if they are changed in the same checkout as the files they affect. It will also keep using .gitattributes, even if it is deleted in the same commit as the files it affects. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t0020-crlf.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/t/t0020-crlf.sh b/t/t0020-crlf.sh index 1be7446d8d..4e72b53140 100755 --- a/t/t0020-crlf.sh +++ b/t/t0020-crlf.sh @@ -429,6 +429,37 @@ test_expect_success 'in-tree .gitattributes (4)' ' } ' +test_expect_success 'checkout with existing .gitattributes' ' + + git config core.autocrlf true && + git config --unset core.safecrlf && + echo ".file2 -crlfQ" | q_to_cr >> .gitattributes && + git add .gitattributes && + git commit -m initial && + echo ".file -crlfQ" | q_to_cr >> .gitattributes && + echo "contents" > .file && + git add .gitattributes .file && + git commit -m second && + + git checkout master~1 && + git checkout master && + test "$(git diff-files --raw)" = "" + +' + +test_expect_success 'checkout when deleting .gitattributes' ' + + git rm .gitattributes && + echo "contentsQ" | q_to_cr > .file2 && + git add .file2 && + git commit -m third + + git checkout master~1 && + git checkout master && + remove_cr .file2 >/dev/null + +' + test_expect_success 'invalid .gitattributes (must not crash)' ' echo "three +crlf" >>.gitattributes && From a797b02f3925c4a6324472e2edaf4a58d4ffc097 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Wed, 11 Mar 2009 13:13:38 -0700 Subject: [PATCH 234/654] http tests: Darwin is not that special We have PidFile definition in the file already, and we have added necessary LoadModule for log_config_module recently. This patch will end up giving LockFile to everybody not just limited to Darwin, but why not? Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/lib-httpd/apache.conf | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf index f460e40416..21aa42f1c6 100644 --- a/t/lib-httpd/apache.conf +++ b/t/lib-httpd/apache.conf @@ -1,4 +1,5 @@ ServerName dummy +LockFile accept.lock PidFile httpd.pid DocumentRoot www LogFormat "%h %l %u %t \"%r\" %>s %b" common @@ -8,12 +9,6 @@ ErrorLog error.log LoadModule log_config_module modules/mod_log_config.so </IfModule> -<IfDefine Darwin> - LoadModule log_config_module modules/mod_log_config.so - LockFile accept.lock - PidFile httpd.pid -</IfDefine> - <IfDefine SSL> LoadModule ssl_module modules/mod_ssl.so From e27430e777edeb777cdd02a777e1e3a4608a0b41 Mon Sep 17 00:00:00 2001 From: Jens Lehmann <Jens.Lehmann@web.de> Date: Fri, 20 Mar 2009 08:48:55 +0100 Subject: [PATCH 235/654] git-gui: Fix merge conflict display error when filename contains spaces When a merge conflict occurs in a file with spaces in the filename, git-gui showed wrongly "LOCAL: deleted". Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- lib/mergetool.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mergetool.tcl b/lib/mergetool.tcl index eb2b4b56a4..3e1b42beb0 100644 --- a/lib/mergetool.tcl +++ b/lib/mergetool.tcl @@ -88,7 +88,7 @@ proc merge_load_stages {path cont} { set merge_stages(3) {} set merge_stages_buf {} - set merge_stages_fd [eval git_read ls-files -u -z -- $path] + set merge_stages_fd [eval git_read ls-files -u -z -- {$path}] fconfigure $merge_stages_fd -blocking 0 -translation binary -encoding binary fileevent $merge_stages_fd readable [list read_merge_stages $merge_stages_fd $cont] From a7bb394037e1c32d47d0b04da025bdbe2eb78d66 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Sun, 1 Mar 2009 21:04:46 +0100 Subject: [PATCH 236/654] test-lib: Infrastructure to test and check for prerequisites Some tests can be run only if a particular prerequisite is available. For example, some tests require that an UTF-8 locale is available. Here we introduce functions that are used in this way: 1. Insert code that checks whether the prerequisite is available. If it is, call test_set_prereq with an arbitrary tag name that subsequently can be used to check for the prerequisite: case $LANG in *.utf-8) test_set_prereq UTF8 ;; esac 2. In the calls to test_expect_success pass the tag name: test_expect_success UTF8 '...description...' '...tests...' 3. There is an auxiliary predicate that can be used anywhere to test for a prerequisite explicitly: if test_have_prereq UTF8 then ...code to be skipped if prerequisite is not available... fi Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t0000-basic.sh | 15 +++++++++++++++ t/test-lib.sh | 44 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index ddcd5b0efb..c53de1f212 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -57,6 +57,21 @@ test_expect_failure 'pretend we have a known breakage' ' test_expect_failure 'pretend we have fixed a known breakage' ' : ' +test_set_prereq HAVEIT +haveit=no +test_expect_success HAVEIT 'test runs if prerequisite is satisfied' ' + test_have_prereq HAVEIT && + haveit=yes +' +donthaveit=yes +test_expect_success DONTHAVEIT 'unmet prerequisite causes test to be skipped' ' + donthaveit=no +' +if test $haveit$donthaveit != yesyes +then + say "bug in test framework: prerequisite tags do not work reliably" + exit 1 +fi ################################################################ # Basics of the basics diff --git a/t/test-lib.sh b/t/test-lib.sh index 0a0696abc9..3c65cfe1ab 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -247,6 +247,31 @@ test_chmod () { git update-index --add "--chmod=$@" } +# Use test_set_prereq to tell that a particular prerequisite is available. +# The prerequisite can later be checked for in two ways: +# +# - Explicitly using test_have_prereq. +# +# - Implicitly by specifying the prerequisite tag in the calls to +# test_expect_{success,failure,code}. +# +# The single parameter is the prerequisite tag (a simple word, in all +# capital letters by convention). + +test_set_prereq () { + satisfied="$satisfied$1 " +} +satisfied=" " + +test_have_prereq () { + case $satisfied in + *" $1 "*) + : yes, have it ;; + *) + ! : nope ;; + esac +} + # You are not expected to call test_ok_ and test_failure_ directly, use # the text_expect_* functions instead. @@ -293,6 +318,11 @@ test_skip () { to_skip=t esac done + if test -z "$to_skip" && test -n "$prereq" && + ! test_have_prereq "$prereq" + then + to_skip=t + fi case "$to_skip" in t) say_color skip >&3 "skipping test: $@" @@ -306,8 +336,9 @@ test_skip () { } test_expect_failure () { + test "$#" = 3 && { prereq=$1; shift; } || prereq= test "$#" = 2 || - error "bug in the test script: not 2 parameters to test-expect-failure" + error "bug in the test script: not 2 or 3 parameters to test-expect-failure" if ! test_skip "$@" then say >&3 "checking known breakage: $2" @@ -323,8 +354,9 @@ test_expect_failure () { } test_expect_success () { + test "$#" = 3 && { prereq=$1; shift; } || prereq= test "$#" = 2 || - error "bug in the test script: not 2 parameters to test-expect-success" + error "bug in the test script: not 2 or 3 parameters to test-expect-success" if ! test_skip "$@" then say >&3 "expecting success: $2" @@ -340,8 +372,9 @@ test_expect_success () { } test_expect_code () { + test "$#" = 4 && { prereq=$1; shift; } || prereq= test "$#" = 3 || - error "bug in the test script: not 3 parameters to test-expect-code" + error "bug in the test script: not 3 or 4 parameters to test-expect-code" if ! test_skip "$@" then say >&3 "expecting exit code $1: $3" @@ -365,8 +398,9 @@ test_expect_code () { # Usage: test_external description command arguments... # Example: test_external 'Perl API' perl ../path/to/test.pl test_external () { - test "$#" -eq 3 || - error >&5 "bug in the test script: not 3 parameters to test_external" + test "$#" = 4 && { prereq=$1; shift; } || prereq= + test "$#" = 3 || + error >&5 "bug in the test script: not 3 or 4 parameters to test_external" descr="$1" shift if ! test_skip "$descr" "$@" From 56e78bfb299207213ff170238c34a1dc8fa67c09 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Thu, 26 Feb 2009 23:09:00 +0100 Subject: [PATCH 237/654] t3600: Use test prerequisite tags There are two prerequisites: - The filesystem supports names with tabs or new-lines. - Files cannot be removed if their containing directory is read-only. Previously, whether these preconditions are satisified was tested inside test_expect_success. We move these tests outside because, strictly speaking, they are not part of the tests. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t3600-rm.sh | 58 ++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index 2aefbcf471..76b1bb4545 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -12,31 +12,37 @@ test_expect_success \ 'Initialize test directory' \ "touch -- foo bar baz 'space embedded' -q && git add -- foo bar baz 'space embedded' -q && - git commit -m 'add normal files' && - test_tabs=y && - if touch -- 'tab embedded' 'newline -embedded' - then + git commit -m 'add normal files'" + +if touch -- 'tab embedded' 'newline +embedded' 2>/dev/null +then + test_set_prereq FUNNYNAMES +else + say 'Your filesystem does not allow tabs in filenames.' +fi + +test_expect_success FUNNYNAMES 'add files with funny names' " git add -- 'tab embedded' 'newline embedded' && git commit -m 'add files with tabs and newlines' - else - test_tabs=n - fi" - -test "$test_tabs" = n && say 'Your filesystem does not allow tabs in filenames.' +" +# Determine rm behavior # Later we will try removing an unremovable path to make sure # git rm barfs, but if the test is run as root that cannot be # arranged. -test_expect_success \ - 'Determine rm behavior' \ - ': >test-file - chmod a-w . - rm -f test-file - test -f test-file && test_failed_remove=y - chmod 775 . - rm -f test-file' +: >test-file +chmod a-w . +rm -f test-file 2>/dev/null +if test -f test-file +then + test_set_prereq RO_DIR +else + say 'skipping removal failure test (perhaps running as root?)' +fi +chmod 775 . +rm -f test-file test_expect_success \ 'Pre-check that foo exists and is in index before git rm foo' \ @@ -101,20 +107,16 @@ test_expect_success \ 'Test that "git rm -- -q" succeeds (remove a file that looks like an option)' \ 'git rm -- -q' -test "$test_tabs" = y && test_expect_success \ +test_expect_success FUNNYNAMES \ "Test that \"git rm -f\" succeeds with embedded space, tab, or newline characters." \ "git rm -f 'space embedded' 'tab embedded' 'newline embedded'" -if test "$test_failed_remove" = y; then -chmod a-w . -test_expect_success \ - 'Test that "git rm -f" fails if its rm fails' \ - 'test_must_fail git rm -f baz' -chmod 775 . -else - say 'skipping removal failure test (perhaps running as root?)' -fi +test_expect_success RO_DIR 'Test that "git rm -f" fails if its rm fails' ' + chmod a-w . && + test_must_fail git rm -f baz && + chmod 775 . +' test_expect_success \ 'When the rm in "git rm -f" fails, it should not remove the file from the index' \ From 872f349e7b119fcef7306f5dd7e4492ee3598318 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Fri, 27 Feb 2009 22:20:57 +0100 Subject: [PATCH 238/654] Skip tests that fail if the executable bit is not handled by the filesystem Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t3701-add-interactive.sh | 9 +++++---- t/t4102-apply-rename.sh | 8 +++++--- t/t4129-apply-samemode.sh | 19 +++++++++++++------ t/t6031-merge-recursive.sh | 13 +++++++++++++ t/t9200-git-cvsexportcommit.sh | 13 ++++++------- 5 files changed, 42 insertions(+), 20 deletions(-) diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index e95663d8e6..fe017839c4 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -135,10 +135,12 @@ test_expect_success 'real edit works' ' if test "$(git config --bool core.filemode)" = false then - say 'skipping filemode tests (filesystem does not properly support modes)' + say 'skipping filemode tests (filesystem does not properly support modes)' else + test_set_prereq FILEMODE +fi -test_expect_success 'patch does not affect mode' ' +test_expect_success FILEMODE 'patch does not affect mode' ' git reset --hard && echo content >>file && chmod +x file && @@ -147,7 +149,7 @@ test_expect_success 'patch does not affect mode' ' git diff file | grep "new mode" ' -test_expect_success 'stage mode but not hunk' ' +test_expect_success FILEMODE 'stage mode but not hunk' ' git reset --hard && echo content >>file && chmod +x file && @@ -156,7 +158,6 @@ test_expect_success 'stage mode but not hunk' ' git diff file | grep "+content" ' -fi # end of tests disabled when filemode is not usable test_done diff --git a/t/t4102-apply-rename.sh b/t/t4102-apply-rename.sh index d42abff1ad..1597965241 100755 --- a/t/t4102-apply-rename.sh +++ b/t/t4102-apply-rename.sh @@ -31,14 +31,16 @@ test_expect_success setup \ test_expect_success apply \ 'git apply --index --stat --summary --apply test-patch' -if [ "$(git config --get core.filemode)" = false ] +if test "$(git config --bool core.filemode)" = false then say 'filemode disabled on the filesystem' else - test_expect_success validate \ - 'test -f bar && ls -l bar | grep "^-..x......"' + test_set_prereq FILEMODE fi +test_expect_success FILEMODE validate \ + 'test -f bar && ls -l bar | grep "^-..x......"' + test_expect_success 'apply reverse' \ 'git apply -R --index --stat --summary --apply test-patch && test "$(cat foo)" = "This is foo"' diff --git a/t/t4129-apply-samemode.sh b/t/t4129-apply-samemode.sh index adfcbb5a3b..fc7af04931 100755 --- a/t/t4129-apply-samemode.sh +++ b/t/t4129-apply-samemode.sh @@ -4,6 +4,13 @@ test_description='applying patch with mode bits' . ./test-lib.sh +if test "$(git config --bool core.filemode)" = false +then + say 'filemode disabled on the filesystem' +else + test_set_prereq FILEMODE +fi + test_expect_success setup ' echo original >file && git add file && @@ -16,14 +23,14 @@ test_expect_success setup ' git diff --stat -p >patch-1.txt ' -test_expect_success 'same mode (no index)' ' +test_expect_success FILEMODE 'same mode (no index)' ' git reset --hard && chmod +x file && git apply patch-0.txt && test -x file ' -test_expect_success 'same mode (with index)' ' +test_expect_success FILEMODE 'same mode (with index)' ' git reset --hard && chmod +x file && git add file && @@ -32,7 +39,7 @@ test_expect_success 'same mode (with index)' ' git diff --exit-code ' -test_expect_success 'same mode (index only)' ' +test_expect_success FILEMODE 'same mode (index only)' ' git reset --hard && chmod +x file && git add file && @@ -40,20 +47,20 @@ test_expect_success 'same mode (index only)' ' git ls-files -s file | grep "^100755" ' -test_expect_success 'mode update (no index)' ' +test_expect_success FILEMODE 'mode update (no index)' ' git reset --hard && git apply patch-1.txt && test -x file ' -test_expect_success 'mode update (with index)' ' +test_expect_success FILEMODE 'mode update (with index)' ' git reset --hard && git apply --index patch-1.txt && test -x file && git diff --exit-code ' -test_expect_success 'mode update (index only)' ' +test_expect_success FILEMODE 'mode update (index only)' ' git reset --hard && git apply --cached patch-1.txt && git ls-files -s file | grep "^100755" diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh index 41c6860be2..8a3304fb0b 100755 --- a/t/t6031-merge-recursive.sh +++ b/t/t6031-merge-recursive.sh @@ -3,6 +3,11 @@ test_description='merge-recursive: handle file mode' . ./test-lib.sh +if ! test "$(git config --bool core.filemode)" = false +then + test_set_prereq FILEMODE +fi + test_expect_success 'mode change in one branch: keep changed version' ' : >file1 && git add file1 && @@ -16,6 +21,10 @@ test_expect_success 'mode change in one branch: keep changed version' ' git commit -m b1 && git checkout a1 && git merge-recursive master -- a1 b1 && + git ls-files -s file1 | grep ^100755 +' + +test_expect_success FILEMODE 'verify executable bit on file' ' test -x file1 ' @@ -41,6 +50,10 @@ test_expect_success 'mode change in both branches: expect conflict' ' echo "100644 $H 3 file2" ) >expect && test_cmp actual expect && + git ls-files -s file2 | grep ^100755 +' + +test_expect_success FILEMODE 'verify executable bit on file' ' test -x file2 ' diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index d28b71b8cf..995f60771a 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -225,11 +225,12 @@ test_expect_success \ test_must_fail git cvsexportcommit -c $id )' -case "$(git config --bool core.filemode)" in -false) - ;; -*) -test_expect_success \ +if ! test "$(git config --bool core.filemode)" = false +then + test_set_prereq FILEMODE +fi + +test_expect_success FILEMODE \ 'Retain execute bit' \ 'mkdir G && echo executeon >G/on && @@ -243,8 +244,6 @@ test_expect_success \ test -x G/on && ! test -x G/off )' - ;; -esac test_expect_success '-w option should work with relative GIT_DIR' ' mkdir W && From 18bf879817a725c1312059c91d18c9848acb3dfc Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Wed, 25 Feb 2009 22:34:34 +0100 Subject: [PATCH 239/654] t5302: Use prerequisite tags to skip 64-bit offset tests The effects of this patch can be tested on Linux by commenting out #define _FILE_OFFSET_BITS 64 in git-compat-util.h. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t5302-pack-index.sh | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index 77982cdeac..4360e77d31 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -69,32 +69,27 @@ test_expect_success \ 'index v2: force some 64-bit offsets with pack-objects' \ 'pack3=$(git pack-objects --index-version=2,0x40000 test-3 <obj-list)' -have_64bits= if msg=$(git verify-pack -v "test-3-${pack3}.pack" 2>&1) || ! (echo "$msg" | grep "pack too large .* off_t") then - have_64bits=t + test_set_prereq OFF64_T else say "skipping tests concerning 64-bit offsets" fi -test "$have_64bits" && -test_expect_success \ +test_expect_success OFF64_T \ 'index v2: verify a pack with some 64-bit offsets' \ 'git verify-pack -v "test-3-${pack3}.pack"' -test "$have_64bits" && -test_expect_success \ +test_expect_success OFF64_T \ '64-bit offsets: should be different from previous index v2 results' \ '! cmp "test-2-${pack2}.idx" "test-3-${pack3}.idx"' -test "$have_64bits" && -test_expect_success \ +test_expect_success OFF64_T \ 'index v2: force some 64-bit offsets with index-pack' \ 'git index-pack --index-version=2,0x40000 -o 3.idx "test-1-${pack1}.pack"' -test "$have_64bits" && -test_expect_success \ +test_expect_success OFF64_T \ '64-bit offsets: index-pack result should match pack-objects one' \ 'cmp "test-3-${pack3}.idx" "3.idx"' From 7b7247b0d7cb6a105d87574642343480707414b3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Tue, 24 Feb 2009 21:13:39 +0100 Subject: [PATCH 240/654] t9100, t9129: Use prerequisite tags for UTF-8 tests Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t9100-git-svn-basic.sh | 43 ++++++++++++-------------- t/t9129-git-svn-i18n-commitencoding.sh | 34 ++++++++++---------- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh index bb921af56a..4eee2e9fa6 100755 --- a/t/t9100-git-svn-basic.sh +++ b/t/t9100-git-svn-basic.sh @@ -6,19 +6,19 @@ test_description='git svn basic tests' GIT_SVN_LC_ALL=${LC_ALL:-$LANG} -case "$GIT_SVN_LC_ALL" in -*.UTF-8) - have_utf8=t - ;; -*) - have_utf8= - ;; -esac - . ./lib-git-svn.sh say 'define NO_SVN_TESTS to skip git svn tests' +case "$GIT_SVN_LC_ALL" in +*.UTF-8) + test_set_prereq UTF8 + ;; +*) + say "UTF-8 locale not set, some tests skipped ($GIT_SVN_LC_ALL)" + ;; +esac + test_expect_success \ 'initialize git svn' ' mkdir import && @@ -171,20 +171,15 @@ test_expect_success "$name" ' test ! -L "$SVN_TREE"/exec-2.sh && test_cmp help "$SVN_TREE"/exec-2.sh' -if test "$have_utf8" = t -then - name="commit with UTF-8 message: locale: $GIT_SVN_LC_ALL" - LC_ALL="$GIT_SVN_LC_ALL" - export LC_ALL - test_expect_success "$name" " - echo '# hello' >> exec-2.sh && - git update-index exec-2.sh && - git commit -m 'éï∏' && - git svn set-tree HEAD" - unset LC_ALL -else - say "UTF-8 locale not set, test skipped ($GIT_SVN_LC_ALL)" -fi +name="commit with UTF-8 message: locale: $GIT_SVN_LC_ALL" +LC_ALL="$GIT_SVN_LC_ALL" +export LC_ALL +test_expect_success UTF8 "$name" " + echo '# hello' >> exec-2.sh && + git update-index exec-2.sh && + git commit -m 'éï∏' && + git svn set-tree HEAD" +unset LC_ALL name='test fetch functionality (svn => git) with alternate GIT_SVN_ID' GIT_SVN_ID=alt @@ -197,7 +192,7 @@ test_expect_success "$name" \ name='check imported tree checksums expected tree checksums' rm -f expected -if test "$have_utf8" = t +if test_have_prereq UTF8 then echo tree bf522353586b1b883488f2bc73dab0d9f774b9a9 > expected fi diff --git a/t/t9129-git-svn-i18n-commitencoding.sh b/t/t9129-git-svn-i18n-commitencoding.sh index 9c7b1ad18b..3200ab38ef 100755 --- a/t/t9129-git-svn-i18n-commitencoding.sh +++ b/t/t9129-git-svn-i18n-commitencoding.sh @@ -70,24 +70,26 @@ do done if locale -a |grep -q en_US.utf8; then - test_expect_success 'ISO-8859-1 should match UTF-8 in svn' ' - ( - cd ISO-8859-1 && - compare_svn_head_with "$TEST_DIRECTORY"/t3900/1-UTF-8.txt - ) - ' - - for H in EUCJP ISO-2022-JP - do - test_expect_success '$H should match UTF-8 in svn' ' - ( - cd $H && - compare_svn_head_with "$TEST_DIRECTORY"/t3900/2-UTF-8.txt - ) - ' - done + test_set_prereq UTF8 else say "UTF-8 locale not available, test skipped" fi +test_expect_success UTF8 'ISO-8859-1 should match UTF-8 in svn' ' + ( + cd ISO-8859-1 && + compare_svn_head_with "$TEST_DIRECTORY"/t3900/1-UTF-8.txt + ) +' + +for H in EUCJP ISO-2022-JP +do + test_expect_success UTF8 "$H should match UTF-8 in svn" ' + ( + cd $H && + compare_svn_head_with "$TEST_DIRECTORY"/t3900/2-UTF-8.txt + ) + ' +done + test_done From 704a3143d5ba0709727430154ef3dad600aad4de Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Wed, 4 Mar 2009 22:38:24 +0100 Subject: [PATCH 241/654] Use prerequisite tags to skip tests that depend on symbolic links Many tests depend on that symbolic links work. This introduces a check that sets the prerequisite tag SYMLINKS if the file system supports symbolic links. Since so many tests have to check for this prerequisite, we do the check in test-lib.sh, so that we don't need to repeat the test in many scripts. To check for 'ln -s' failures, you can use a FAT partition on Linux: $ mkdosfs -C git-on-fat 1000000 $ sudo mount -o loop,uid=j6t,gid=users,shortname=winnt git-on-fat /mnt Clone git to /mnt and $ GIT_SKIP_TESTS='t0001.1[34] t0010 t1301 t403[34] t4129.[47] t5701.7 t7701.3 t9100 t9101.26 t9119 t9124.[67] t9200.10 t9600.6' \ make test (These additionally skipped tests depend on POSIX permissions that FAT on Linux does not provide.) Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t0000-basic.sh | 43 +++++++++++++++++++------- t/t0055-beyond-symlinks.sh | 6 ++-- t/t1004-read-tree-m-u-wf.sh | 6 ++-- t/t1020-subdirectory.sh | 2 +- t/t1300-repo-config.sh | 2 +- t/t2001-checkout-cache-clash.sh | 6 ++-- t/t2003-checkout-cache-mkdir.sh | 8 ++--- t/t2004-checkout-cache-temp.sh | 2 +- t/t2007-checkout-symlink.sh | 6 ++++ t/t2100-update-cache-badpath.sh | 14 +++++++-- t/t2200-add-update.sh | 2 +- t/t2201-add-update-typechange.sh | 16 ++++++++-- t/t2300-cd-to-toplevel.sh | 14 ++++----- t/t3000-ls-files-others.sh | 7 ++++- t/t3010-ls-files-killed-modified.sh | 17 ++++++++-- t/t3100-ls-tree-restrict.sh | 40 +++++++++++++++--------- t/t3200-branch.sh | 2 +- t/t3700-add.sh | 6 ++-- t/t4004-diff-rename-symlink.sh | 7 +++++ t/t4008-diff-break-rewrite.sh | 8 ++--- t/t4011-diff-symlink.sh | 7 +++++ t/t4023-diff-rename-typechange.sh | 7 +++++ t/t4114-apply-typechange.sh | 7 +++++ t/t4115-apply-symlink.sh | 7 +++++ t/t4122-apply-symlink-inside.sh | 7 +++++ t/t5000-tar-tree.sh | 6 +++- t/t5522-pull-symlink.sh | 7 +++++ t/t7001-mv.sh | 4 +-- t/t9131-git-svn-empty-symlink.sh | 2 +- t/t9132-git-svn-broken-symlink.sh | 4 +-- t/t9500-gitweb-standalone-no-errors.sh | 11 +++++-- t/test-lib.sh | 4 +++ 32 files changed, 211 insertions(+), 76 deletions(-) diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index c53de1f212..f4ca4fc85c 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -115,12 +115,31 @@ test_expect_success \ 'test "$tree" = 4b825dc642cb6eb9a060e54bf8d69288fbee4904' # Various types of objects +# Some filesystems do not support symblic links; on such systems +# some expected values are different mkdir path2 path3 path3/subp3 -for p in path0 path2/file2 path3/file3 path3/subp3/file3 +paths='path0 path2/file2 path3/file3 path3/subp3/file3' +for p in $paths do echo "hello $p" >$p - ln -s "hello $p" ${p}sym done +if test_have_prereq SYMLINKS +then + for p in $paths + do + ln -s "hello $p" ${p}sym + done + expectfilter=cat + expectedtree=087704a96baf1c2d1c869a8b084481e121c88b5b + expectedptree1=21ae8269cacbe57ae09138dcc3a2887f904d02b3 + expectedptree2=3c5e5399f3a333eddecce7a9b9465b63f65f51e2 +else + expectfilter='grep -v sym' + expectedtree=8e18edf7d7edcf4371a3ac6ae5f07c2641db7c46 + expectedptree1=cfb8591b2f65de8b8cc1020cd7d9e67e7793b325 + expectedptree2=ce580448f0148b985a513b693fdf7d802cacb44f +fi + test_expect_success \ 'adding various types of objects with git update-index --add.' \ 'find path* ! -type d -print | xargs git update-index --add' @@ -130,7 +149,7 @@ test_expect_success \ 'showing stage with git ls-files --stage' \ 'git ls-files --stage >current' -cat >expected <<\EOF +$expectfilter >expected <<\EOF 100644 f87290f8eb2cbbea7857214459a0739927eab154 0 path0 120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0 path0sym 100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0 path2/file2 @@ -149,7 +168,7 @@ test_expect_success \ 'tree=$(git write-tree)' test_expect_success \ 'validate object ID for a known tree.' \ - 'test "$tree" = 087704a96baf1c2d1c869a8b084481e121c88b5b' + 'test "$tree" = "$expectedtree"' test_expect_success \ 'showing tree with git ls-tree' \ @@ -160,7 +179,7 @@ cat >expected <<\EOF 040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2 040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3 EOF -test_expect_success \ +test_expect_success SYMLINKS \ 'git ls-tree output for a known tree.' \ 'test_cmp expected current' @@ -169,7 +188,7 @@ test_expect_success \ test_expect_success \ 'showing tree with git ls-tree -r' \ 'git ls-tree -r $tree >current' -cat >expected <<\EOF +$expectfilter >expected <<\EOF 100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym 100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2 @@ -200,7 +219,7 @@ cat >expected <<\EOF 100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3 120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym EOF -test_expect_success \ +test_expect_success SYMLINKS \ 'git ls-tree -r output for a known tree.' \ 'test_cmp expected current' @@ -209,14 +228,14 @@ test_expect_success \ 'ptree=$(git write-tree --prefix=path3)' test_expect_success \ 'validate object ID for a known tree.' \ - 'test "$ptree" = 21ae8269cacbe57ae09138dcc3a2887f904d02b3' + 'test "$ptree" = "$expectedptree1"' test_expect_success \ 'writing partial tree out with git write-tree --prefix.' \ 'ptree=$(git write-tree --prefix=path3/subp3)' test_expect_success \ 'validate object ID for a known tree.' \ - 'test "$ptree" = 3c5e5399f3a333eddecce7a9b9465b63f65f51e2' + 'test "$ptree" = "$expectedptree2"' cat >badobjects <<EOF 100644 blob 1000000000000000000000000000000000000000 dir/file1 @@ -249,7 +268,7 @@ test_expect_success \ newtree=$(git write-tree) && test "$newtree" = "$tree"' -cat >expected <<\EOF +$expectfilter >expected <<\EOF :100644 100644 f87290f8eb2cbbea7857214459a0739927eab154 0000000000000000000000000000000000000000 M path0 :120000 120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0000000000000000000000000000000000000000 M path0sym :100644 100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0000000000000000000000000000000000000000 M path2/file2 @@ -272,7 +291,7 @@ test_expect_success \ 'git diff-files >current && cmp -s current /dev/null' ################################################################ -P=087704a96baf1c2d1c869a8b084481e121c88b5b +P=$expectedtree test_expect_success \ 'git commit-tree records the correct tree in a commit.' \ 'commit0=$(echo NO | git commit-tree $P) && @@ -308,7 +327,7 @@ test_expect_success 'update-index D/F conflict' ' test $numpath0 = 1 ' -test_expect_success 'absolute path works as expected' ' +test_expect_success SYMLINKS 'absolute path works as expected' ' mkdir first && ln -s ../.git first/.git && mkdir second && diff --git a/t/t0055-beyond-symlinks.sh b/t/t0055-beyond-symlinks.sh index b29c37a5a4..0c6ff567a1 100755 --- a/t/t0055-beyond-symlinks.sh +++ b/t/t0055-beyond-symlinks.sh @@ -4,7 +4,7 @@ test_description='update-index and add refuse to add beyond symlinks' . ./test-lib.sh -test_expect_success setup ' +test_expect_success SYMLINKS setup ' >a && mkdir b && ln -s b c && @@ -12,12 +12,12 @@ test_expect_success setup ' git update-index --add a b/d ' -test_expect_success 'update-index --add beyond symlinks' ' +test_expect_success SYMLINKS 'update-index --add beyond symlinks' ' test_must_fail git update-index --add c/d && ! ( git ls-files | grep c/d ) ' -test_expect_success 'add beyond symlinks' ' +test_expect_success SYMLINKS 'add beyond symlinks' ' test_must_fail git add c/d && ! ( git ls-files | grep c/d ) ' diff --git a/t/t1004-read-tree-m-u-wf.sh b/t/t1004-read-tree-m-u-wf.sh index 570d3729bd..f19b4a2a4a 100755 --- a/t/t1004-read-tree-m-u-wf.sh +++ b/t/t1004-read-tree-m-u-wf.sh @@ -157,7 +157,7 @@ test_expect_success '3-way not overwriting local changes (their side)' ' ' -test_expect_success 'funny symlink in work tree' ' +test_expect_success SYMLINKS 'funny symlink in work tree' ' git reset --hard && git checkout -b sym-b side-b && @@ -177,7 +177,7 @@ test_expect_success 'funny symlink in work tree' ' ' -test_expect_success 'funny symlink in work tree, un-unlink-able' ' +test_expect_success SYMLINKS 'funny symlink in work tree, un-unlink-able' ' rm -fr a b && git reset --hard && @@ -189,7 +189,7 @@ test_expect_success 'funny symlink in work tree, un-unlink-able' ' ' # clean-up from the above test -chmod a+w a +chmod a+w a 2>/dev/null rm -fr a b test_expect_success 'D/F setup' ' diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh index fc386ba033..210e594f6f 100755 --- a/t/t1020-subdirectory.sh +++ b/t/t1020-subdirectory.sh @@ -126,7 +126,7 @@ test_expect_success 'no file/rev ambiguity check inside a bare repo' ' cd foo.git && git show -s HEAD ' -test_expect_success 'detection should not be fooled by a symlink' ' +test_expect_success SYMLINKS 'detection should not be fooled by a symlink' ' cd "$HERE" && rm -fr foo.git && git clone -s .git another && diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 3c06842d99..64663e1886 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -726,7 +726,7 @@ echo >>result test_expect_success '--null --get-regexp' 'cmp result expect' -test_expect_success 'symlinked configuration' ' +test_expect_success SYMLINKS 'symlinked configuration' ' ln -s notyet myconfig && GIT_CONFIG=myconfig git config test.frotz nitfol && diff --git a/t/t2001-checkout-cache-clash.sh b/t/t2001-checkout-cache-clash.sh index ef007532b1..98aa73e823 100755 --- a/t/t2001-checkout-cache-clash.sh +++ b/t/t2001-checkout-cache-clash.sh @@ -59,10 +59,10 @@ test_expect_success \ 'git read-tree -m $tree1 && git checkout-index -f -a' test_debug 'show_files $tree1' -ln -s path0 path1 -test_expect_success \ +test_expect_success SYMLINKS \ 'git update-index --add a symlink.' \ - 'git update-index --add path1' + 'ln -s path0 path1 && + git update-index --add path1' test_expect_success \ 'writing tree out with git write-tree' \ 'tree3=$(git write-tree)' diff --git a/t/t2003-checkout-cache-mkdir.sh b/t/t2003-checkout-cache-mkdir.sh index 71894b3743..02a4fc5d36 100755 --- a/t/t2003-checkout-cache-mkdir.sh +++ b/t/t2003-checkout-cache-mkdir.sh @@ -19,7 +19,7 @@ test_expect_success \ echo rezrov >path1/file1 && git update-index --add path0 path1/file1' -test_expect_success \ +test_expect_success SYMLINKS \ 'have symlink in place where dir is expected.' \ 'rm -fr path0 path1 && mkdir path2 && @@ -59,7 +59,7 @@ test_expect_success \ test ! -f path1/file1' # Linus fix #1 -test_expect_success \ +test_expect_success SYMLINKS \ 'use --prefix=tmp/orary/ where tmp is a symlink' \ 'rm -fr path0 path1 path2 tmp* && mkdir tmp1 tmp1/orary && @@ -71,7 +71,7 @@ test_expect_success \ test -h tmp' # Linus fix #2 -test_expect_success \ +test_expect_success SYMLINKS \ 'use --prefix=tmp/orary- where tmp is a symlink' \ 'rm -fr path0 path1 path2 tmp* && mkdir tmp1 && @@ -82,7 +82,7 @@ test_expect_success \ test -h tmp' # Linus fix #3 -test_expect_success \ +test_expect_success SYMLINKS \ 'use --prefix=tmp- where tmp-path1 is a symlink' \ 'rm -fr path0 path1 path2 tmp* && mkdir tmp1 && diff --git a/t/t2004-checkout-cache-temp.sh b/t/t2004-checkout-cache-temp.sh index 39133b8c7a..36cca14d95 100755 --- a/t/t2004-checkout-cache-temp.sh +++ b/t/t2004-checkout-cache-temp.sh @@ -194,7 +194,7 @@ test_expect_success \ test $(cat ../$s1) = tree1asubdir/path5) )' -test_expect_success \ +test_expect_success SYMLINKS \ 'checkout --temp symlink' ' rm -f path* .merge_* out .git/index && ln -s b a && diff --git a/t/t2007-checkout-symlink.sh b/t/t2007-checkout-symlink.sh index 0526fce163..20f33436d0 100755 --- a/t/t2007-checkout-symlink.sh +++ b/t/t2007-checkout-symlink.sh @@ -6,6 +6,12 @@ test_description='git checkout to switch between branches with symlink<->dir' . ./test-lib.sh +if ! test_have_prereq SYMLINKS +then + say "symbolic links not supported - skipping tests" + test_done +fi + test_expect_success setup ' mkdir frotz && diff --git a/t/t2100-update-cache-badpath.sh b/t/t2100-update-cache-badpath.sh index 6ef2dcfd8a..2df3fdde8b 100755 --- a/t/t2100-update-cache-badpath.sh +++ b/t/t2100-update-cache-badpath.sh @@ -26,7 +26,12 @@ All of the attempts should fail. mkdir path2 path3 date >path0 -ln -s xyzzy path1 +if test_have_prereq SYMLINKS +then + ln -s xyzzy path1 +else + date > path1 +fi date >path2/file2 date >path3/file3 @@ -38,7 +43,12 @@ rm -fr path? mkdir path0 path1 date >path2 -ln -s frotz path3 +if test_have_prereq SYMLINKS +then + ln -s frotz path3 +else + date > path3 +fi date >path0/file0 date >path1/file1 diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh index 5a8d52f2ff..912075063b 100755 --- a/t/t2200-add-update.sh +++ b/t/t2200-add-update.sh @@ -80,7 +80,7 @@ test_expect_success 'change gets noticed' ' ' -test_expect_success 'replace a file with a symlink' ' +test_expect_success SYMLINKS 'replace a file with a symlink' ' rm foo && ln -s top foo && diff --git a/t/t2201-add-update-typechange.sh b/t/t2201-add-update-typechange.sh index d24c7d9e5f..2e8f702452 100755 --- a/t/t2201-add-update-typechange.sh +++ b/t/t2201-add-update-typechange.sh @@ -11,7 +11,13 @@ test_expect_success setup ' _empty=$(git hash-object --stdin <xyzzy) && >yomin && >caskly && - ln -s frotz nitfol && + if test_have_prereq SYMLINKS; then + ln -s frotz nitfol && + T_letter=T + else + printf %s frotz > nitfol && + T_letter=M + fi && mkdir rezrov && >rezrov/bozbar && git add caskly xyzzy yomin nitfol rezrov/bozbar && @@ -29,7 +35,11 @@ test_expect_success modify ' >nitfol && # rezrov/bozbar disappears rm -fr rezrov && - ln -s xyzzy rezrov && + if test_have_prereq SYMLINKS; then + ln -s xyzzy rezrov + else + printf %s xyzzy > rezrov + fi && # xyzzy disappears (not a submodule) mkdir xyzzy && echo gnusto >xyzzy/bozbar && @@ -71,7 +81,7 @@ test_expect_success modify ' s/blob/000000/ } / nitfol/{ - s/ nitfol/ $_z40 T&/ + s/ nitfol/ $_z40 $T_letter&/ s/blob/100644/ } / rezrov.bozbar/{ diff --git a/t/t2300-cd-to-toplevel.sh b/t/t2300-cd-to-toplevel.sh index 293dc353b1..3b01ad2e4d 100755 --- a/t/t2300-cd-to-toplevel.sh +++ b/t/t2300-cd-to-toplevel.sh @@ -5,7 +5,7 @@ test_description='cd_to_toplevel' . ./test-lib.sh test_cd_to_toplevel () { - test_expect_success "$2" ' + test_expect_success $3 "$2" ' ( cd '"'$1'"' && . git-sh-setup && @@ -24,14 +24,14 @@ test_cd_to_toplevel repo 'at physical root' test_cd_to_toplevel repo/sub/dir 'at physical subdir' -ln -s repo symrepo -test_cd_to_toplevel symrepo 'at symbolic root' +ln -s repo symrepo 2>/dev/null +test_cd_to_toplevel symrepo 'at symbolic root' SYMLINKS -ln -s repo/sub/dir subdir-link -test_cd_to_toplevel subdir-link 'at symbolic subdir' +ln -s repo/sub/dir subdir-link 2>/dev/null +test_cd_to_toplevel subdir-link 'at symbolic subdir' SYMLINKS cd repo -ln -s sub/dir internal-link -test_cd_to_toplevel internal-link 'at internal symbolic subdir' +ln -s sub/dir internal-link 2>/dev/null +test_cd_to_toplevel internal-link 'at internal symbolic subdir' SYMLINKS test_done diff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh index 36eee0f8ae..b7e0306316 100755 --- a/t/t3000-ls-files-others.sh +++ b/t/t3000-ls-files-others.sh @@ -17,7 +17,12 @@ filesystem. . ./test-lib.sh date >path0 -ln -s xyzzy path1 +if test_have_prereq SYMLINKS +then + ln -s xyzzy path1 +else + date > path1 +fi mkdir path2 path3 date >path2/file2 date >path2-junk diff --git a/t/t3010-ls-files-killed-modified.sh b/t/t3010-ls-files-killed-modified.sh index e4f02a0968..95671c2053 100755 --- a/t/t3010-ls-files-killed-modified.sh +++ b/t/t3010-ls-files-killed-modified.sh @@ -38,7 +38,12 @@ modified without reporting path9 and path10. . ./test-lib.sh date >path0 -ln -s xyzzy path1 +if test_have_prereq SYMLINKS +then + ln -s xyzzy path1 +else + date > path1 +fi mkdir path2 path3 date >path2/file2 date >path3/file3 @@ -52,8 +57,14 @@ test_expect_success \ rm -fr path? ;# leave path10 alone date >path2 -ln -s frotz path3 -ln -s nitfol path5 +if test_have_prereq SYMLINKS +then + ln -s frotz path3 + ln -s nitfol path5 +else + date > path3 + date > path5 +fi mkdir path0 path1 path6 date >path0/file0 date >path1/file1 diff --git a/t/t3100-ls-tree-restrict.sh b/t/t3100-ls-tree-restrict.sh index 6e6a2542a2..ee60d03fe8 100755 --- a/t/t3100-ls-tree-restrict.sh +++ b/t/t3100-ls-tree-restrict.sh @@ -22,9 +22,21 @@ test_expect_success \ 'setup' \ 'mkdir path2 path2/baz && echo Hi >path0 && - ln -s path0 path1 && + if test_have_prereq SYMLINKS + then + ln -s path0 path1 && + ln -s ../path1 path2/bazbo + make_expected () { + cat >expected + } + else + printf path0 > path1 && + printf ../path1 > path2/bazbo + make_expected () { + sed -e "s/120000 /100644 /" >expected + } + fi && echo Lo >path2/foo && - ln -s ../path1 path2/bazbo && echo Mi >path2/baz/b && find path? \( -type f -o -type l \) -print | xargs git update-index --add && @@ -41,7 +53,7 @@ test_output () { test_expect_success \ 'ls-tree plain' \ 'git ls-tree $tree >current && - cat >expected <<\EOF && + make_expected <<\EOF && 100644 blob X path0 120000 blob X path1 040000 tree X path2 @@ -51,7 +63,7 @@ EOF test_expect_success \ 'ls-tree recursive' \ 'git ls-tree -r $tree >current && - cat >expected <<\EOF && + make_expected <<\EOF && 100644 blob X path0 120000 blob X path1 100644 blob X path2/baz/b @@ -63,7 +75,7 @@ EOF test_expect_success \ 'ls-tree recursive with -t' \ 'git ls-tree -r -t $tree >current && - cat >expected <<\EOF && + make_expected <<\EOF && 100644 blob X path0 120000 blob X path1 040000 tree X path2 @@ -77,7 +89,7 @@ EOF test_expect_success \ 'ls-tree recursive with -d' \ 'git ls-tree -r -d $tree >current && - cat >expected <<\EOF && + make_expected <<\EOF && 040000 tree X path2 040000 tree X path2/baz EOF @@ -86,7 +98,7 @@ EOF test_expect_success \ 'ls-tree filtered with path' \ 'git ls-tree $tree path >current && - cat >expected <<\EOF && + make_expected <<\EOF && EOF test_output' @@ -96,7 +108,7 @@ EOF test_expect_success \ 'ls-tree filtered with path1 path0' \ 'git ls-tree $tree path1 path0 >current && - cat >expected <<\EOF && + make_expected <<\EOF && 100644 blob X path0 120000 blob X path1 EOF @@ -105,7 +117,7 @@ EOF test_expect_success \ 'ls-tree filtered with path0/' \ 'git ls-tree $tree path0/ >current && - cat >expected <<\EOF && + make_expected <<\EOF && EOF test_output' @@ -114,7 +126,7 @@ EOF test_expect_success \ 'ls-tree filtered with path2' \ 'git ls-tree $tree path2 >current && - cat >expected <<\EOF && + make_expected <<\EOF && 040000 tree X path2 EOF test_output' @@ -123,7 +135,7 @@ EOF test_expect_success \ 'ls-tree filtered with path2/' \ 'git ls-tree $tree path2/ >current && - cat >expected <<\EOF && + make_expected <<\EOF && 040000 tree X path2/baz 120000 blob X path2/bazbo 100644 blob X path2/foo @@ -135,7 +147,7 @@ EOF test_expect_success \ 'ls-tree filtered with path2/baz' \ 'git ls-tree $tree path2/baz >current && - cat >expected <<\EOF && + make_expected <<\EOF && 040000 tree X path2/baz EOF test_output' @@ -143,14 +155,14 @@ EOF test_expect_success \ 'ls-tree filtered with path2/bak' \ 'git ls-tree $tree path2/bak >current && - cat >expected <<\EOF && + make_expected <<\EOF && EOF test_output' test_expect_success \ 'ls-tree -t filtered with path2/bak' \ 'git ls-tree -t $tree path2/bak >current && - cat >expected <<\EOF && + make_expected <<\EOF && 040000 tree X path2 EOF test_output' diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 61a2010f5b..f82bcdbd46 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -121,7 +121,7 @@ test_expect_success 'renaming a symref is not allowed' \ ! test -f .git/refs/heads/master3 ' -test_expect_success \ +test_expect_success SYMLINKS \ 'git branch -m u v should fail when the reflog for u is a symlink' ' git branch -l u && mv .git/logs/refs/heads/u real-u && diff --git a/t/t3700-add.sh b/t/t3700-add.sh index 9f6454d2ff..e98f9825cf 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -30,7 +30,7 @@ test_expect_success \ *) echo fail; git ls-files --stage xfoo1; (exit 1);; esac' -test_expect_success 'git add: filemode=0 should not get confused by symlink' ' +test_expect_success SYMLINKS 'git add: filemode=0 should not get confused by symlink' ' rm -f xfoo1 && ln -s foo xfoo1 && git add xfoo1 && @@ -51,7 +51,7 @@ test_expect_success \ *) echo fail; git ls-files --stage xfoo2; (exit 1);; esac' -test_expect_success 'git add: filemode=0 should not get confused by symlink' ' +test_expect_success SYMLINKS 'git add: filemode=0 should not get confused by symlink' ' rm -f xfoo2 && ln -s foo xfoo2 && git update-index --add xfoo2 && @@ -61,7 +61,7 @@ test_expect_success 'git add: filemode=0 should not get confused by symlink' ' esac ' -test_expect_success \ +test_expect_success SYMLINKS \ 'git update-index --add: Test that executable bit is not used...' \ 'git config core.filemode 0 && ln -s xfoo2 xfoo3 && diff --git a/t/t4004-diff-rename-symlink.sh b/t/t4004-diff-rename-symlink.sh index b35af9b42d..3db74443f8 100755 --- a/t/t4004-diff-rename-symlink.sh +++ b/t/t4004-diff-rename-symlink.sh @@ -12,6 +12,13 @@ by an edit for them. . ./test-lib.sh . "$TEST_DIRECTORY"/diff-lib.sh +if ! test_have_prereq SYMLINKS +then + say 'Symbolic links not supported, skipping tests.' + test_done + exit +fi + test_expect_success \ 'prepare reference tree' \ 'echo xyzzy | tr -d '\\\\'012 >yomin && diff --git a/t/t4008-diff-break-rewrite.sh b/t/t4008-diff-break-rewrite.sh index 7e343a9cd1..e19ca65885 100755 --- a/t/t4008-diff-break-rewrite.sh +++ b/t/t4008-diff-break-rewrite.sh @@ -99,7 +99,7 @@ test_expect_success \ 'validate result of -B -M (#4)' \ 'compare_diff_raw expected current' -test_expect_success \ +test_expect_success SYMLINKS \ 'make file0 into something completely different' \ 'rm -f file0 && ln -s frotz file0 && @@ -114,7 +114,7 @@ cat >expected <<\EOF :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 M100 file1 EOF -test_expect_success \ +test_expect_success SYMLINKS \ 'validate result of -B (#5)' \ 'compare_diff_raw expected current' @@ -129,7 +129,7 @@ cat >expected <<\EOF :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 R file0 file1 EOF -test_expect_success \ +test_expect_success SYMLINKS \ 'validate result of -B -M (#6)' \ 'compare_diff_raw expected current' @@ -144,7 +144,7 @@ cat >expected <<\EOF :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 M file1 EOF -test_expect_success \ +test_expect_success SYMLINKS \ 'validate result of -M (#7)' \ 'compare_diff_raw expected current' diff --git a/t/t4011-diff-symlink.sh b/t/t4011-diff-symlink.sh index 9055c8b318..3a81309967 100755 --- a/t/t4011-diff-symlink.sh +++ b/t/t4011-diff-symlink.sh @@ -9,6 +9,13 @@ test_description='Test diff of symlinks. . ./test-lib.sh . "$TEST_DIRECTORY"/diff-lib.sh +if ! test_have_prereq SYMLINKS +then + say 'Symbolic links not supported, skipping tests.' + test_done + exit +fi + cat > expected << EOF diff --git a/frotz b/frotz new file mode 120000 diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh index 297ddb5a25..5099862eba 100755 --- a/t/t4023-diff-rename-typechange.sh +++ b/t/t4023-diff-rename-typechange.sh @@ -4,6 +4,13 @@ test_description='typechange rename detection' . ./test-lib.sh +if ! test_have_prereq SYMLINKS +then + say 'Symbolic links not supported, skipping tests.' + test_done + exit +fi + test_expect_success setup ' rm -f foo bar && diff --git a/t/t4114-apply-typechange.sh b/t/t4114-apply-typechange.sh index 0f185caa44..7dc35dea38 100755 --- a/t/t4114-apply-typechange.sh +++ b/t/t4114-apply-typechange.sh @@ -9,6 +9,13 @@ test_description='git apply should not get confused with type changes. . ./test-lib.sh +if ! test_have_prereq SYMLINKS +then + say 'Symbolic links not supported, skipping tests.' + test_done + exit +fi + test_expect_success 'setup repository and commits' ' echo "hello world" > foo && echo "hi planet" > bar && diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh index 9ace578f17..1a3aea34ce 100755 --- a/t/t4115-apply-symlink.sh +++ b/t/t4115-apply-symlink.sh @@ -9,6 +9,13 @@ test_description='git apply symlinks and partial files . ./test-lib.sh +if ! test_have_prereq SYMLINKS +then + say 'Symbolic links not supported, skipping tests.' + test_done + exit +fi + test_expect_success setup ' ln -s path1/path2/path3/path4/path5 link1 && diff --git a/t/t4122-apply-symlink-inside.sh b/t/t4122-apply-symlink-inside.sh index 841773f75f..8aad20bfcc 100755 --- a/t/t4122-apply-symlink-inside.sh +++ b/t/t4122-apply-symlink-inside.sh @@ -3,6 +3,13 @@ test_description='apply to deeper directory without getting fooled with symlink' . ./test-lib.sh +if ! test_have_prereq SYMLINKS +then + say 'Symbolic links not supported, skipping tests.' + test_done + exit +fi + lecho () { for l_ do diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 7a84ab61d0..60a4b8dc0d 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -37,7 +37,11 @@ test_expect_success \ cp /bin/sh a/bin && printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile1 && printf "A not substituted O" >a/substfile2 && - ln -s a a/l1 && + if test_have_prereq SYMLINKS; then + ln -s a a/l1 + else + printf %s a > a/l1 + fi && (p=long_path_to_a_file && cd a && for depth in 1 2 3 4 5; do mkdir $p && cd $p; done && echo text >file_with_long_path) && diff --git a/t/t5522-pull-symlink.sh b/t/t5522-pull-symlink.sh index 5672b51e2e..d887eb6c1a 100755 --- a/t/t5522-pull-symlink.sh +++ b/t/t5522-pull-symlink.sh @@ -4,6 +4,13 @@ test_description='pulling from symlinked subdir' . ./test-lib.sh +if ! test_have_prereq SYMLINKS +then + say 'Symbolic links not supported, skipping tests.' + test_done + exit +fi + # The scenario we are building: # # trash\ directory/ diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index 8fb3a56838..10b8f8c44b 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -206,7 +206,7 @@ test_expect_success 'git mv should not change sha1 of moved cache entry' ' rm -f dirty dirty2 -test_expect_success 'git mv should overwrite symlink to a file' ' +test_expect_success SYMLINKS 'git mv should overwrite symlink to a file' ' rm -fr .git && git init && @@ -225,7 +225,7 @@ test_expect_success 'git mv should overwrite symlink to a file' ' rm -f moved symlink -test_expect_success 'git mv should overwrite file with a symlink' ' +test_expect_success SYMLINKS 'git mv should overwrite file with a symlink' ' rm -fr .git && git init && diff --git a/t/t9131-git-svn-empty-symlink.sh b/t/t9131-git-svn-empty-symlink.sh index 8f35e294aa..9a24a65b64 100755 --- a/t/t9131-git-svn-empty-symlink.sh +++ b/t/t9131-git-svn-empty-symlink.sh @@ -88,7 +88,7 @@ test_expect_success 'enable broken symlink workaround' \ test_expect_success '"bar" is an empty file' 'test -f x/bar && ! test -s x/bar' test_expect_success 'get "bar" => symlink fix from svn' \ '(cd x && git svn rebase)' -test_expect_success '"bar" becomes a symlink' 'test -L x/bar' +test_expect_success SYMLINKS '"bar" becomes a symlink' 'test -L x/bar' test_expect_success 'clone using git svn' 'git svn clone -r1 "$svnrepo" y' diff --git a/t/t9132-git-svn-broken-symlink.sh b/t/t9132-git-svn-broken-symlink.sh index b8de59e493..6c4c90b036 100755 --- a/t/t9132-git-svn-broken-symlink.sh +++ b/t/t9132-git-svn-broken-symlink.sh @@ -85,7 +85,7 @@ EOF test_expect_success 'clone using git svn' 'git svn clone -r1 "$svnrepo" x' -test_expect_success '"bar" is a symlink that points to "asdf"' ' +test_expect_success SYMLINKS '"bar" is a symlink that points to "asdf"' ' test -L x/bar && (cd x && test xasdf = x"`git cat-file blob HEAD:bar`") ' @@ -94,7 +94,7 @@ test_expect_success 'get "bar" => symlink fix from svn' ' (cd x && git svn rebase) ' -test_expect_success '"bar" remains a proper symlink' ' +test_expect_success SYMLINKS '"bar" remains a proper symlink' ' test -L x/bar && (cd x && test xdoink = x"`git cat-file blob HEAD:bar`") ' diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index dce06bcc97..9ec5030a91 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -246,7 +246,7 @@ test_expect_success \ gitweb_run "p=.git;a=commitdiff"' test_debug 'cat gitweb.log' -test_expect_success \ +test_expect_success SYMLINKS \ 'commitdiff(0): file to symlink' \ 'rm renamed_file && ln -s file renamed_file && @@ -308,7 +308,7 @@ test_debug 'cat gitweb.log' # ---------------------------------------------------------------------- # commitdiff testing (taken from t4114-apply-typechange.sh) -test_expect_success 'setup typechange commits' ' +test_expect_success SYMLINKS 'setup typechange commits' ' echo "hello world" > foo && echo "hi planet" > bar && git update-index --add foo bar && @@ -418,7 +418,12 @@ test_expect_success \ git mv 04-rename-from 04-rename-to && echo "Changed" >> 04-rename-to && test_chmod +x 05-mode-change && - rm -f 06-file-or-symlink && ln -s 01-change 06-file-or-symlink && + rm -f 06-file-or-symlink && + if test_have_prereq SYMLINKS; then + ln -s 01-change 06-file-or-symlink + else + printf %s 01-change > 06-file-or-symlink + fi && echo "Changed and have mode changed" > 07-change-mode-change && test_chmod +x 07-change-mode-change && git commit -a -m "Large commit" && diff --git a/t/test-lib.sh b/t/test-lib.sh index 3c65cfe1ab..5337e89202 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -689,3 +689,7 @@ case $(uname -s) in } ;; esac + +# test whether the filesystem supports symbolic links +ln -s x y 2>/dev/null && test -h y 2>/dev/null && test_set_prereq SYMLINKS +rm -f y From 2718e852e9baf98c128aafc508e85b610decad25 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Wed, 11 Mar 2009 22:15:10 +0100 Subject: [PATCH 242/654] t0060: Fix tests on Windows Since the MSYS bash mangles absolute paths that it passes as command line arguments to non-MSYS progams (such as git or test-path-utils), we have to bend over backwards to squeeze some usefulness out of the existing tests. In particular, a set of path normalization tests is added that test relative paths. Some paths in the ancestor path tests are adjusted to help MSYS bash's path mangling heuristics. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t0060-path-utils.sh | 116 ++++++++++++++++++++++++++++++------------ 1 file changed, 83 insertions(+), 33 deletions(-) diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index 8336114f98..86000e26c1 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -7,41 +7,91 @@ test_description='Test various path utilities' . ./test-lib.sh -norm_abs() { - test_expect_success "normalize absolute: $1 => $2" \ +norm_path() { + test_expect_success $3 "normalize path: $1 => $2" \ "test \"\$(test-path-utils normalize_path_copy '$1')\" = '$2'" } +# On Windows, we are using MSYS's bash, which mangles the paths. +# Absolute paths are anchored at the MSYS installation directory, +# which means that the path / accounts for this many characters: +rootoff=$(test-path-utils normalize_path_copy / | wc -c) +# Account for the trailing LF: +if test "$rootoff" = 2; then + rootoff= # we are on Unix +else + rootoff=$(($rootoff-1)) +fi + ancestor() { - test_expect_success "longest ancestor: $1 $2 => $3" \ - "test \"\$(test-path-utils longest_ancestor_length '$1' '$2')\" = '$3'" + # We do some math with the expected ancestor length. + expected=$3 + if test -n "$rootoff" && test "x$expected" != x-1; then + expected=$(($expected+$rootoff)) + fi + test_expect_success "longest ancestor: $1 $2 => $expected" \ + "actual=\$(test-path-utils longest_ancestor_length '$1' '$2') && + test \"\$actual\" = '$expected'" } -norm_abs "" "" -norm_abs / / -norm_abs // / -norm_abs /// / -norm_abs /. / -norm_abs /./ / -norm_abs /./.. ++failed++ -norm_abs /../. ++failed++ -norm_abs /./../.// ++failed++ -norm_abs /dir/.. / -norm_abs /dir/sub/../.. / -norm_abs /dir/sub/../../.. ++failed++ -norm_abs /dir /dir -norm_abs /dir// /dir/ -norm_abs /./dir /dir -norm_abs /dir/. /dir/ -norm_abs /dir///./ /dir/ -norm_abs /dir//sub/.. /dir/ -norm_abs /dir/sub/../ /dir/ -norm_abs //dir/sub/../. /dir/ -norm_abs /dir/s1/../s2/ /dir/s2/ -norm_abs /d1/s1///s2/..//../s3/ /d1/s3/ -norm_abs /d1/s1//../s2/../../d2 /d2 -norm_abs /d1/.../d2 /d1/.../d2 -norm_abs /d1/..././../d2 /d1/d2 +# Absolute path tests must be skipped on Windows because due to path mangling +# the test program never sees a POSIX-style absolute path +case $(uname -s) in +*MINGW*) + ;; +*) + test_set_prereq POSIX + ;; +esac + +norm_path "" "" +norm_path . "" +norm_path ./ "" +norm_path ./. "" +norm_path ./.. ++failed++ +norm_path ../. ++failed++ +norm_path ./../.// ++failed++ +norm_path dir/.. "" +norm_path dir/sub/../.. "" +norm_path dir/sub/../../.. ++failed++ +norm_path dir dir +norm_path dir// dir/ +norm_path ./dir dir +norm_path dir/. dir/ +norm_path dir///./ dir/ +norm_path dir//sub/.. dir/ +norm_path dir/sub/../ dir/ +norm_path dir/sub/../. dir/ +norm_path dir/s1/../s2/ dir/s2/ +norm_path d1/s1///s2/..//../s3/ d1/s3/ +norm_path d1/s1//../s2/../../d2 d2 +norm_path d1/.../d2 d1/.../d2 +norm_path d1/..././../d2 d1/d2 + +norm_path / / POSIX +norm_path // / POSIX +norm_path /// / POSIX +norm_path /. / POSIX +norm_path /./ / POSIX +norm_path /./.. ++failed++ POSIX +norm_path /../. ++failed++ POSIX +norm_path /./../.// ++failed++ POSIX +norm_path /dir/.. / POSIX +norm_path /dir/sub/../.. / POSIX +norm_path /dir/sub/../../.. ++failed++ POSIX +norm_path /dir /dir POSIX +norm_path /dir// /dir/ POSIX +norm_path /./dir /dir POSIX +norm_path /dir/. /dir/ POSIX +norm_path /dir///./ /dir/ POSIX +norm_path /dir//sub/.. /dir/ POSIX +norm_path /dir/sub/../ /dir/ POSIX +norm_path //dir/sub/../. /dir/ POSIX +norm_path /dir/s1/../s2/ /dir/s2/ POSIX +norm_path /d1/s1///s2/..//../s3/ /d1/s3/ POSIX +norm_path /d1/s1//../s2/../../d2 /d2 POSIX +norm_path /d1/.../d2 /d1/.../d2 POSIX +norm_path /d1/..././../d2 /d1/d2 POSIX ancestor / "" -1 ancestor / / -1 @@ -80,10 +130,10 @@ ancestor /foo/bar /:/foo:/bar/ 4 ancestor /foo/bar /foo:/:/bar/ 4 ancestor /foo/bar /:/bar/:/fo 0 ancestor /foo/bar /:/bar/ 0 -ancestor /foo/bar :://foo/. 4 -ancestor /foo/bar :://foo/.:: 4 -ancestor /foo/bar //foo/./::/bar 4 -ancestor /foo/bar ::/bar -1 +ancestor /foo/bar .:/foo/. 4 +ancestor /foo/bar .:/foo/.:.: 4 +ancestor /foo/bar /foo/./:.:/bar 4 +ancestor /foo/bar .:/bar -1 test_expect_success 'strip_path_suffix' ' test c:/msysgit = $(test-path-utils strip_path_suffix \ From ee9fb68c392cc76cf2a56762eb1c0712ae722f08 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Fri, 13 Mar 2009 22:55:27 +0100 Subject: [PATCH 243/654] Skip tests that require a filesystem that obeys POSIX permissions Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t0004-unwritable.sh | 8 ++++---- t/t1301-shared-repo.sh | 10 +++++----- t/t3700-add.sh | 8 ++++---- t/t7503-pre-commit-hook.sh | 4 ++-- t/t7504-commit-msg-hook.sh | 8 ++++---- t/test-lib.sh | 4 ++++ 6 files changed, 23 insertions(+), 19 deletions(-) diff --git a/t/t0004-unwritable.sh b/t/t0004-unwritable.sh index 63e1217e71..2342ac5788 100755 --- a/t/t0004-unwritable.sh +++ b/t/t0004-unwritable.sh @@ -15,7 +15,7 @@ test_expect_success setup ' ' -test_expect_success 'write-tree should notice unwritable repository' ' +test_expect_success POSIXPERM 'write-tree should notice unwritable repository' ' ( chmod a-w .git/objects .git/objects/?? && @@ -27,7 +27,7 @@ test_expect_success 'write-tree should notice unwritable repository' ' ' -test_expect_success 'commit should notice unwritable repository' ' +test_expect_success POSIXPERM 'commit should notice unwritable repository' ' ( chmod a-w .git/objects .git/objects/?? && @@ -39,7 +39,7 @@ test_expect_success 'commit should notice unwritable repository' ' ' -test_expect_success 'update-index should notice unwritable repository' ' +test_expect_success POSIXPERM 'update-index should notice unwritable repository' ' ( echo 6O >file && @@ -52,7 +52,7 @@ test_expect_success 'update-index should notice unwritable repository' ' ' -test_expect_success 'add should notice unwritable repository' ' +test_expect_success POSIXPERM 'add should notice unwritable repository' ' ( echo b >file && diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh index 653362ba22..dc4485409d 100755 --- a/t/t1301-shared-repo.sh +++ b/t/t1301-shared-repo.sh @@ -26,7 +26,7 @@ modebits () { for u in 002 022 do - test_expect_success "shared=1 does not clear bits preset by umask $u" ' + test_expect_success POSIXPERM "shared=1 does not clear bits preset by umask $u" ' mkdir sub && ( cd sub && umask $u && @@ -54,7 +54,7 @@ test_expect_success 'shared=all' ' test 2 = $(git config core.sharedrepository) ' -test_expect_success 'update-server-info honors core.sharedRepository' ' +test_expect_success POSIXPERM 'update-server-info honors core.sharedRepository' ' : > a1 && git add a1 && test_tick && @@ -85,7 +85,7 @@ do git config core.sharedrepository "$u" && umask 0277 && - test_expect_success "shared = $u ($y) ro" ' + test_expect_success POSIXPERM "shared = $u ($y) ro" ' rm -f .git/info/refs && git update-server-info && @@ -97,7 +97,7 @@ do ' umask 077 && - test_expect_success "shared = $u ($x) rw" ' + test_expect_success POSIXPERM "shared = $u ($x) rw" ' rm -f .git/info/refs && git update-server-info && @@ -111,7 +111,7 @@ do done -test_expect_success 'git reflog expire honors core.sharedRepository' ' +test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' ' git config core.sharedRepository group && git reflog expire --all && actual="$(ls -l .git/logs/refs/heads/master)" && diff --git a/t/t3700-add.sh b/t/t3700-add.sh index e98f9825cf..dc17d9f715 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -179,7 +179,7 @@ test_expect_success 'git add --refresh' ' test -z "`git diff-index HEAD -- foo`" ' -test_expect_success 'git add should fail atomically upon an unreadable file' ' +test_expect_success POSIXPERM 'git add should fail atomically upon an unreadable file' ' git reset --hard && date >foo1 && date >foo2 && @@ -190,7 +190,7 @@ test_expect_success 'git add should fail atomically upon an unreadable file' ' rm -f foo2 -test_expect_success 'git add --ignore-errors' ' +test_expect_success POSIXPERM 'git add --ignore-errors' ' git reset --hard && date >foo1 && date >foo2 && @@ -201,7 +201,7 @@ test_expect_success 'git add --ignore-errors' ' rm -f foo2 -test_expect_success 'git add (add.ignore-errors)' ' +test_expect_success POSIXPERM 'git add (add.ignore-errors)' ' git config add.ignore-errors 1 && git reset --hard && date >foo1 && @@ -212,7 +212,7 @@ test_expect_success 'git add (add.ignore-errors)' ' ' rm -f foo2 -test_expect_success 'git add (add.ignore-errors = false)' ' +test_expect_success POSIXPERM 'git add (add.ignore-errors = false)' ' git config add.ignore-errors 0 && git reset --hard && date >foo1 && diff --git a/t/t7503-pre-commit-hook.sh b/t/t7503-pre-commit-hook.sh index b069095995..8528f64c8d 100755 --- a/t/t7503-pre-commit-hook.sh +++ b/t/t7503-pre-commit-hook.sh @@ -69,7 +69,7 @@ test_expect_success '--no-verify with failing hook' ' ' chmod -x "$HOOK" -test_expect_success 'with non-executable hook' ' +test_expect_success POSIXPERM 'with non-executable hook' ' echo "content" >> file && git add file && @@ -77,7 +77,7 @@ test_expect_success 'with non-executable hook' ' ' -test_expect_success '--no-verify with non-executable hook' ' +test_expect_success POSIXPERM '--no-verify with non-executable hook' ' echo "more content" >> file && git add file && diff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh index 47680e6df4..1f53ea8090 100755 --- a/t/t7504-commit-msg-hook.sh +++ b/t/t7504-commit-msg-hook.sh @@ -136,7 +136,7 @@ test_expect_success '--no-verify with failing hook (editor)' ' ' chmod -x "$HOOK" -test_expect_success 'with non-executable hook' ' +test_expect_success POSIXPERM 'with non-executable hook' ' echo "content" >> file && git add file && @@ -144,7 +144,7 @@ test_expect_success 'with non-executable hook' ' ' -test_expect_success 'with non-executable hook (editor)' ' +test_expect_success POSIXPERM 'with non-executable hook (editor)' ' echo "content again" >> file && git add file && @@ -153,7 +153,7 @@ test_expect_success 'with non-executable hook (editor)' ' ' -test_expect_success '--no-verify with non-executable hook' ' +test_expect_success POSIXPERM '--no-verify with non-executable hook' ' echo "more content" >> file && git add file && @@ -161,7 +161,7 @@ test_expect_success '--no-verify with non-executable hook' ' ' -test_expect_success '--no-verify with non-executable hook (editor)' ' +test_expect_success POSIXPERM '--no-verify with non-executable hook (editor)' ' echo "even more content" >> file && git add file && diff --git a/t/test-lib.sh b/t/test-lib.sh index 5337e89202..f134e73566 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -687,6 +687,10 @@ case $(uname -s) in pwd () { builtin pwd -W } + # no POSIX permissions + ;; +*) + test_set_prereq POSIXPERM ;; esac From 6fd1106aa4f921dd8e80895ed837072adfd665f1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Fri, 13 Mar 2009 23:00:15 +0100 Subject: [PATCH 244/654] t3700: Skip a test with backslashes in pathspec The test verifies that glob special characters can be escaped with backslashes. In particular, the string fo\[ou\]bar is given to git. On Windows, this does not work because backslashes are first of all directory separators, and first thing git does with a pathspec from the command line is to convert backslashes to forward slashes. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t3700-add.sh | 2 +- t/test-lib.sh | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/t/t3700-add.sh b/t/t3700-add.sh index dc17d9f715..050de42ef4 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -222,7 +222,7 @@ test_expect_success POSIXPERM 'git add (add.ignore-errors = false)' ' ! ( git ls-files foo1 | grep foo1 ) ' -test_expect_success 'git add '\''fo\[ou\]bar'\'' ignores foobar' ' +test_expect_success BSLASHPSPEC "git add 'fo\\[ou\\]bar' ignores foobar" ' git reset --hard && touch fo\[ou\]bar foobar && git add '\''fo\[ou\]bar'\'' && diff --git a/t/test-lib.sh b/t/test-lib.sh index f134e73566..b4b626e837 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -688,9 +688,11 @@ case $(uname -s) in builtin pwd -W } # no POSIX permissions + # backslashes in pathspec are converted to '/' ;; *) test_set_prereq POSIXPERM + test_set_prereq BSLASHPSPEC ;; esac From 552a26c8c069c582d2572399eb4ac176634a03cb Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Mon, 16 Mar 2009 14:44:56 +0100 Subject: [PATCH 245/654] Use prerequisites to skip tests that need unzip Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t0024-crlf-archive.sh | 6 +++--- t/t5000-tar-tree.sh | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/t/t0024-crlf-archive.sh b/t/t0024-crlf-archive.sh index ae90d34f6c..c7d0324374 100755 --- a/t/t0024-crlf-archive.sh +++ b/t/t0024-crlf-archive.sh @@ -29,11 +29,11 @@ test_expect_success 'tar archive' ' "$UNZIP" -v >/dev/null 2>&1 if [ $? -eq 127 ]; then say "Skipping ZIP test, because unzip was not found" - test_done - exit +else + test_set_prereq UNZIP fi -test_expect_success 'zip archive' ' +test_expect_success UNZIP 'zip archive' ' git archive --format=zip HEAD >test.zip && diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 60a4b8dc0d..7641e0dd46 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -187,20 +187,20 @@ test_expect_success 'git archive --format=zip with --output' \ $UNZIP -v >/dev/null 2>&1 if [ $? -eq 127 ]; then say "Skipping ZIP tests, because unzip was not found" - test_done - exit +else + test_set_prereq UNZIP fi -test_expect_success \ +test_expect_success UNZIP \ 'extract ZIP archive' \ '(mkdir d && cd d && $UNZIP ../d.zip)' -test_expect_success \ +test_expect_success UNZIP \ 'validate filenames' \ '(cd d/a && find .) | sort >d.lst && test_cmp a.lst d.lst' -test_expect_success \ +test_expect_success UNZIP \ 'validate file contents' \ 'diff -r a d/a' @@ -208,16 +208,16 @@ test_expect_success \ 'git archive --format=zip with prefix' \ 'git archive --format=zip --prefix=prefix/ HEAD >e.zip' -test_expect_success \ +test_expect_success UNZIP \ 'extract ZIP archive with prefix' \ '(mkdir e && cd e && $UNZIP ../e.zip)' -test_expect_success \ +test_expect_success UNZIP \ 'validate filenames with prefix' \ '(cd e/prefix/a && find .) | sort >e.lst && test_cmp a.lst e.lst' -test_expect_success \ +test_expect_success UNZIP \ 'validate file contents with prefix' \ 'diff -r a e/prefix/a' From a4df22ce49d0457f3dbec5083064f9d24e4d17dd Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Mon, 16 Mar 2009 15:09:23 +0100 Subject: [PATCH 246/654] t7004: Use prerequisite tags to skip tests that need gpg The tests are skipped if no gpg was found or if gpg is version 1.0.6. Previously, the latter condition was checked a bit later in the test file so that the tag verification tests would be exercised. These are now skipped as well, but only because we would need a facility to revoke a test prerequisite, which we do not have. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t7004-tag.sh | 97 +++++++++++++++++++++++++------------------------- 1 file changed, 48 insertions(+), 49 deletions(-) diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 1c27ffb45e..73dbc4360b 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -581,28 +581,38 @@ test_expect_success \ ' # subsequent tests require gpg; check if it is available -gpg --version >/dev/null +gpg --version >/dev/null 2>/dev/null if [ $? -eq 127 ]; then say "gpg not found - skipping tag signing and verification tests" - test_done - exit +else + # As said here: http://www.gnupg.org/documentation/faqs.html#q6.19 + # the gpg version 1.0.6 didn't parse trust packets correctly, so for + # that version, creation of signed tags using the generated key fails. + case "$(gpg --version)" in + 'gpg (GnuPG) 1.0.6'*) + say "Skipping signed tag tests, because a bug in 1.0.6 version" + ;; + *) + test_set_prereq GPG + ;; + esac fi # trying to verify annotated non-signed tags: -test_expect_success \ +test_expect_success GPG \ 'trying to verify an annotated non-signed tag should fail' ' tag_exists annotated-tag && test_must_fail git tag -v annotated-tag ' -test_expect_success \ +test_expect_success GPG \ 'trying to verify a file-annotated non-signed tag should fail' ' tag_exists file-annotated-tag && test_must_fail git tag -v file-annotated-tag ' -test_expect_success \ +test_expect_success GPG \ 'trying to verify two annotated non-signed tags should fail' ' tag_exists annotated-tag file-annotated-tag && test_must_fail git tag -v annotated-tag file-annotated-tag @@ -610,17 +620,6 @@ test_expect_success \ # creating and verifying signed tags: -# As said here: http://www.gnupg.org/documentation/faqs.html#q6.19 -# the gpg version 1.0.6 didn't parse trust packets correctly, so for -# that version, creation of signed tags using the generated key fails. -case "$(gpg --version)" in -'gpg (GnuPG) 1.0.6'*) - say "Skipping signed tag tests, because a bug in 1.0.6 version" - test_done - exit - ;; -esac - # key generation info: gpg --homedir t/t7004 --gen-key # Type DSA and Elgamal, size 2048 bits, no expiration date. # Name and email: C O Mitter <committer@example.com> @@ -634,7 +633,7 @@ export GNUPGHOME get_tag_header signed-tag $commit commit $time >expect echo 'A signed tag message' >>expect echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success 'creating a signed tag with -m message should succeed' ' +test_expect_success GPG 'creating a signed tag with -m message should succeed' ' git tag -s -m "A signed tag message" signed-tag && get_tag_msg signed-tag >actual && test_cmp expect actual @@ -643,7 +642,7 @@ test_expect_success 'creating a signed tag with -m message should succeed' ' get_tag_header u-signed-tag $commit commit $time >expect echo 'Another message' >>expect echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success 'sign with a given key id' ' +test_expect_success GPG 'sign with a given key id' ' git tag -u committer@example.com -m "Another message" u-signed-tag && get_tag_msg u-signed-tag >actual && @@ -651,14 +650,14 @@ test_expect_success 'sign with a given key id' ' ' -test_expect_success 'sign with an unknown id (1)' ' +test_expect_success GPG 'sign with an unknown id (1)' ' test_must_fail git tag -u author@example.com \ -m "Another message" o-signed-tag ' -test_expect_success 'sign with an unknown id (2)' ' +test_expect_success GPG 'sign with an unknown id (2)' ' test_must_fail git tag -u DEADBEEF -m "Another message" o-signed-tag @@ -675,7 +674,7 @@ chmod +x fakeeditor get_tag_header implied-sign $commit commit $time >expect ./fakeeditor >>expect echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success '-u implies signed tag' ' +test_expect_success GPG '-u implies signed tag' ' GIT_EDITOR=./fakeeditor git tag -u CDDE430D implied-sign && get_tag_msg implied-sign >actual && test_cmp expect actual @@ -688,7 +687,7 @@ EOF get_tag_header file-signed-tag $commit commit $time >expect cat sigmsgfile >>expect echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success \ +test_expect_success GPG \ 'creating a signed tag with -F messagefile should succeed' ' git tag -s -F sigmsgfile file-signed-tag && get_tag_msg file-signed-tag >actual && @@ -702,7 +701,7 @@ EOF get_tag_header stdin-signed-tag $commit commit $time >expect cat siginputmsg >>expect echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success 'creating a signed tag with -F - should succeed' ' +test_expect_success GPG 'creating a signed tag with -F - should succeed' ' git tag -s -F - stdin-signed-tag <siginputmsg && get_tag_msg stdin-signed-tag >actual && test_cmp expect actual @@ -711,13 +710,13 @@ test_expect_success 'creating a signed tag with -F - should succeed' ' get_tag_header implied-annotate $commit commit $time >expect ./fakeeditor >>expect echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success '-s implies annotated tag' ' +test_expect_success GPG '-s implies annotated tag' ' GIT_EDITOR=./fakeeditor git tag -s implied-annotate && get_tag_msg implied-annotate >actual && test_cmp expect actual ' -test_expect_success \ +test_expect_success GPG \ 'trying to create a signed tag with non-existing -F file should fail' ' ! test -f nonexistingfile && ! tag_exists nosigtag && @@ -725,13 +724,13 @@ test_expect_success \ ! tag_exists nosigtag ' -test_expect_success 'verifying a signed tag should succeed' \ +test_expect_success GPG 'verifying a signed tag should succeed' \ 'git tag -v signed-tag' -test_expect_success 'verifying two signed tags in one command should succeed' \ +test_expect_success GPG 'verifying two signed tags in one command should succeed' \ 'git tag -v signed-tag file-signed-tag' -test_expect_success \ +test_expect_success GPG \ 'verifying many signed and non-signed tags should fail' ' test_must_fail git tag -v signed-tag annotated-tag && test_must_fail git tag -v file-annotated-tag file-signed-tag && @@ -740,7 +739,7 @@ test_expect_success \ test_must_fail git tag -v signed-tag annotated-tag file-signed-tag ' -test_expect_success 'verifying a forged tag should fail' ' +test_expect_success GPG 'verifying a forged tag should fail' ' forged=$(git cat-file tag signed-tag | sed -e "s/signed-tag/forged-tag/" | git mktag) && @@ -752,7 +751,7 @@ test_expect_success 'verifying a forged tag should fail' ' get_tag_header empty-signed-tag $commit commit $time >expect echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success \ +test_expect_success GPG \ 'creating a signed tag with an empty -m message should succeed' ' git tag -s -m "" empty-signed-tag && get_tag_msg empty-signed-tag >actual && @@ -763,7 +762,7 @@ test_expect_success \ >sigemptyfile get_tag_header emptyfile-signed-tag $commit commit $time >expect echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success \ +test_expect_success GPG \ 'creating a signed tag with an empty -F messagefile should succeed' ' git tag -s -F sigemptyfile emptyfile-signed-tag && get_tag_msg emptyfile-signed-tag >actual && @@ -786,7 +785,7 @@ Trailing spaces Trailing blank lines EOF echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success \ +test_expect_success GPG \ 'extra blanks in the message for a signed tag should be removed' ' git tag -s -F sigblanksfile blanks-signed-tag && get_tag_msg blanks-signed-tag >actual && @@ -796,7 +795,7 @@ test_expect_success \ get_tag_header blank-signed-tag $commit commit $time >expect echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success \ +test_expect_success GPG \ 'creating a signed tag with a blank -m message should succeed' ' git tag -s -m " " blank-signed-tag && get_tag_msg blank-signed-tag >actual && @@ -809,7 +808,7 @@ echo '' >>sigblankfile echo ' ' >>sigblankfile get_tag_header blankfile-signed-tag $commit commit $time >expect echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success \ +test_expect_success GPG \ 'creating a signed tag with blank -F file with spaces should succeed' ' git tag -s -F sigblankfile blankfile-signed-tag && get_tag_msg blankfile-signed-tag >actual && @@ -820,7 +819,7 @@ test_expect_success \ printf ' ' >sigblanknonlfile get_tag_header blanknonlfile-signed-tag $commit commit $time >expect echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success \ +test_expect_success GPG \ 'creating a signed tag with spaces and no newline should succeed' ' git tag -s -F sigblanknonlfile blanknonlfile-signed-tag && get_tag_msg blanknonlfile-signed-tag >actual && @@ -857,7 +856,7 @@ Another line. Last line. EOF echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success \ +test_expect_success GPG \ 'creating a signed tag with a -F file with #comments should succeed' ' git tag -s -F sigcommentsfile comments-signed-tag && get_tag_msg comments-signed-tag >actual && @@ -867,7 +866,7 @@ test_expect_success \ get_tag_header comment-signed-tag $commit commit $time >expect echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success \ +test_expect_success GPG \ 'creating a signed tag with #commented -m message should succeed' ' git tag -s -m "#comment" comment-signed-tag && get_tag_msg comment-signed-tag >actual && @@ -880,7 +879,7 @@ echo '' >>sigcommentfile echo '####' >>sigcommentfile get_tag_header commentfile-signed-tag $commit commit $time >expect echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success \ +test_expect_success GPG \ 'creating a signed tag with #commented -F messagefile should succeed' ' git tag -s -F sigcommentfile commentfile-signed-tag && get_tag_msg commentfile-signed-tag >actual && @@ -891,7 +890,7 @@ test_expect_success \ printf '#comment' >sigcommentnonlfile get_tag_header commentnonlfile-signed-tag $commit commit $time >expect echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success \ +test_expect_success GPG \ 'creating a signed tag with a #comment and no newline should succeed' ' git tag -s -F sigcommentnonlfile commentnonlfile-signed-tag && get_tag_msg commentnonlfile-signed-tag >actual && @@ -901,7 +900,7 @@ test_expect_success \ # listing messages for signed tags: -test_expect_success \ +test_expect_success GPG \ 'listing the one-line message of a signed tag should succeed' ' git tag -s -m "A message line signed" stag-one-line && @@ -926,7 +925,7 @@ test_expect_success \ test_cmp expect actual ' -test_expect_success \ +test_expect_success GPG \ 'listing the zero-lines message of a signed tag should succeed' ' git tag -s -m "" stag-zero-lines && @@ -954,7 +953,7 @@ test_expect_success \ echo 'stag line one' >sigtagmsg echo 'stag line two' >>sigtagmsg echo 'stag line three' >>sigtagmsg -test_expect_success \ +test_expect_success GPG \ 'listing many message lines of a signed tag should succeed' ' git tag -s -F sigtagmsg stag-lines && @@ -999,12 +998,12 @@ test_expect_success \ tree=$(git rev-parse HEAD^{tree}) blob=$(git rev-parse HEAD:foo) -tag=$(git rev-parse signed-tag) +tag=$(git rev-parse signed-tag 2>/dev/null) get_tag_header tree-signed-tag $tree tree $time >expect echo "A message for a tree" >>expect echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success \ +test_expect_success GPG \ 'creating a signed tag pointing to a tree should succeed' ' git tag -s -m "A message for a tree" tree-signed-tag HEAD^{tree} && get_tag_msg tree-signed-tag >actual && @@ -1014,7 +1013,7 @@ test_expect_success \ get_tag_header blob-signed-tag $blob blob $time >expect echo "A message for a blob" >>expect echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success \ +test_expect_success GPG \ 'creating a signed tag pointing to a blob should succeed' ' git tag -s -m "A message for a blob" blob-signed-tag HEAD:foo && get_tag_msg blob-signed-tag >actual && @@ -1024,7 +1023,7 @@ test_expect_success \ get_tag_header tag-signed-tag $tag tag $time >expect echo "A message for another tag" >>expect echo '-----BEGIN PGP SIGNATURE-----' >>expect -test_expect_success \ +test_expect_success GPG \ 'creating a signed tag pointing to another tag should succeed' ' git tag -s -m "A message for another tag" tag-signed-tag signed-tag && get_tag_msg tag-signed-tag >actual && @@ -1033,7 +1032,7 @@ test_expect_success \ # try to sign with bad user.signingkey git config user.signingkey BobTheMouse -test_expect_success \ +test_expect_success GPG \ 'git tag -s fails if gpg is misconfigured' \ 'test_must_fail git tag -s -m tail tag-gpg-failure' git config --unset user.signingkey @@ -1041,7 +1040,7 @@ git config --unset user.signingkey # try to verify without gpg: rm -rf gpghome -test_expect_success \ +test_expect_success GPG \ 'verify signed tag fails when public key is not present' \ 'test_must_fail git tag -v signed-tag' From 8b02c64a3cb3a494ca5d704e3e05c4a2c45867c7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Fri, 20 Mar 2009 22:03:33 +0100 Subject: [PATCH 247/654] t5503: GIT_DEBUG_SEND_PACK is not supported on MinGW The test opens fd 3 and instructs git-upload-pack (via GIT_DEBUG_SEND_PACK) to log information to that channel. The way in which new processes are spawned by git on MinGW does not inherit all file descriptors to the child processes, but only 0, 1, and 2. The tests in t5503 require that file descriptor 3 is inherited from git-fetch to git-upload-pack. A complete implementation is non-trivial and not warranted just to satisfy this test. Note that the incompleteness applies only to the executables that use compat/mingw.c; bash and perl (the other important executables used by git) are complete, of course. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t5503-tagfollow.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh index 4074e23ffa..e75ccbcaeb 100755 --- a/t/t5503-tagfollow.sh +++ b/t/t5503-tagfollow.sh @@ -4,6 +4,13 @@ test_description='test automatic tag following' . ./test-lib.sh +case $(uname -s) in +*MINGW*) + say "GIT_DEBUG_SEND_PACK not supported - skipping tests" + test_done + exit +esac + # End state of the repository: # # T - tag1 S - tag2 From 48ef563641d1904f8da2c6fffe700fe6276af8dd Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Sun, 22 Mar 2009 04:59:20 -0400 Subject: [PATCH 248/654] remote: improve sorting of "configure for git push" list The data structure used to store this list is a string_list of sources with the destination in the util member. The current code just sorts on the source; if a single source is pushed to two different destination refs at a remote, then the order in which they are printed is non-deterministic. This patch implements a comparison using both fields. Besides being a little nicer on the eyes, giving a stable sort prevents false negatives in the test suite when comparing output. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-remote.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/builtin-remote.c b/builtin-remote.c index 7b31e554e9..9fdbb6c103 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -931,6 +931,20 @@ int add_push_to_show_info(struct string_list_item *push_item, void *cb_data) return 0; } +/* + * Sorting comparison for a string list that has push_info + * structs in its util field + */ +static int cmp_string_with_push(const void *va, const void *vb) +{ + const struct string_list_item *a = va; + const struct string_list_item *b = vb; + const struct push_info *a_push = a->util; + const struct push_info *b_push = b->util; + int cmp = strcmp(a->string, b->string); + return cmp ? cmp : strcmp(a_push->dest, b_push->dest); +} + int show_push_info_item(struct string_list_item *item, void *cb_data) { struct show_info *show_info = cb_data; @@ -1041,7 +1055,8 @@ static int show(int argc, const char **argv) info.width = info.width2 = 0; for_each_string_list(add_push_to_show_info, &states.push, &info); - sort_string_list(info.list); + qsort(info.list->items, info.list->nr, + sizeof(*info.list->items), cmp_string_with_push); if (info.list->nr) printf(" Local ref%s configured for 'git push'%s:\n", info.list->nr > 1 ? "s" : "", From 24c11552cb3bd7ec343c8061c87b07aa7abbad00 Mon Sep 17 00:00:00 2001 From: Jens Lehmann <Jens.Lehmann@web.de> Date: Sun, 22 Mar 2009 19:46:38 +0100 Subject: [PATCH 249/654] githooks documentation: post-checkout hook is also called after clone The documentation of the post-checkout hook just talks about git-checkout. But recently git-clone was changed to call it too, unless the -no-checkout (-n) option is used. Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/githooks.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt index 1fd512bca2..1c736738cc 100644 --- a/Documentation/githooks.txt +++ b/Documentation/githooks.txt @@ -151,6 +151,10 @@ indicating whether the checkout was a branch checkout (changing branches, flag=1) or a file checkout (retrieving a file from the index, flag=0). This hook cannot affect the outcome of 'git-checkout'. +It is also run after 'git-clone', unless the --no-checkout (-n) option is +used. The first parameter given to the hook is the null-ref, the second the +ref of the new HEAD and the flag is always 1. + This hook can be used to perform repository validity checks, auto-display differences from the previous HEAD if different, or set working dir metadata properties. From 26284f9356f4c4d8865db8bb024121311a1f90ff Mon Sep 17 00:00:00 2001 From: Alex Riesen <raa.lkml@gmail.com> Date: Sun, 22 Mar 2009 23:07:33 +0100 Subject: [PATCH 250/654] Improve error message about fetch into current branch Otherwise, it is hard to guess why the fetch failed. Make sure we at least mention that the repository must be bare. Also the current branch is printed. Signed-off-by: Alex Riesen <raa.lkml@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-fetch.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/builtin-fetch.c b/builtin-fetch.c index 7fb35fca9d..7293146525 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -544,7 +544,8 @@ static void check_not_current_branch(struct ref *ref_map) for (; ref_map; ref_map = ref_map->next) if (ref_map->peer_ref && !strcmp(current_branch->refname, ref_map->peer_ref->name)) - die("Refusing to fetch into current branch"); + die("Refusing to fetch into current branch %s " + "of non-bare repository", current_branch->refname); } static int do_fetch(struct transport *transport, From ebd15bf0d732db7dec4cfd8bbfa2c7430b6e875c Mon Sep 17 00:00:00 2001 From: Kevin McConnell <kevin.mcconnell@gmail.com> Date: Sat, 21 Mar 2009 16:29:27 -0700 Subject: [PATCH 251/654] Add --staged to bash completion for git diff The --staged option (synonym for --cached) isn't listed in the completion choices for git diff. This tiny patch adds it. Trivially-Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index ed235f7596..6bc32df178 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -899,7 +899,7 @@ _git_diff () local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) - __gitcomp "--cached --pickaxe-all --pickaxe-regex + __gitcomp "--cached --staged --pickaxe-all --pickaxe-regex --base --ours --theirs $__git_diff_common_options " From 4bca86367bff80ad3c04e282a1aa9ed66db26aa1 Mon Sep 17 00:00:00 2001 From: Arto Jonsson <ajonsson@kapsi.fi> Date: Sun, 22 Mar 2009 20:49:07 +0200 Subject: [PATCH 252/654] bash completion: add options for 'git fsck' Signed-off-by: Arto Jonsson <ajonsson@kapsi.fi> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 6bc32df178..10e36a7b0d 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -952,6 +952,21 @@ _git_format_patch () __git_complete_revlist } +_git_fsck () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + case "$cur" in + --*) + __gitcomp " + --tags --root --unreachable --cache --no-reflogs --full + --strict --verbose --lost-found + " + return + ;; + esac + COMPREPLY=() +} + _git_gc () { local cur="${COMP_WORDS[COMP_CWORD]}" @@ -1880,6 +1895,7 @@ _git () diff) _git_diff ;; fetch) _git_fetch ;; format-patch) _git_format_patch ;; + fsck) _git_fsck ;; gc) _git_gc ;; grep) _git_grep ;; help) _git_help ;; From 91408042768c05347c1b9f081a00387ca07b26fe Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Sun, 22 Mar 2009 04:08:48 -0400 Subject: [PATCH 253/654] Makefile: turn on USE_ST_TIMESPEC for FreeBSD Fixes broken compilation on FreeBSD 6.1. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index aae3b09411..320c89786c 100644 --- a/Makefile +++ b/Makefile @@ -713,6 +713,7 @@ ifeq ($(uname_S),FreeBSD) BASIC_CFLAGS += -I/usr/local/include BASIC_LDFLAGS += -L/usr/local/lib DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease + USE_ST_TIMESPEC = YesPlease THREADED_DELTA_SEARCH = YesPlease ifeq ($(shell expr "$(uname_R)" : '4\.'),2) PTHREAD_LIBS = -pthread From 46d164b0cd1d5d254047d7573c53e368e42bf5e5 Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Sun, 22 Mar 2009 19:14:01 -0700 Subject: [PATCH 254/654] pretty.c: add %f format specifier to format_commit_message() This specifier represents the sanitized and filename friendly subject line of a commit. No checks are made against the length of the string, so users may need to trim the result to the desired length if using as a filename. This is commonly used by format-patch to massage commit subjects into filenames and output patches to files. Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/pretty-formats.txt | 1 + pretty.c | 35 ++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt index 5c6e678aa3..2a845b1e57 100644 --- a/Documentation/pretty-formats.txt +++ b/Documentation/pretty-formats.txt @@ -121,6 +121,7 @@ The placeholders are: - '%d': ref names, like the --decorate option of linkgit:git-log[1] - '%e': encoding - '%s': subject +- '%f': sanitized subject line, suitable for a filename - '%b': body - '%Cred': switch color to red - '%Cgreen': switch color to green diff --git a/pretty.c b/pretty.c index efa70245f1..c57cef47c9 100644 --- a/pretty.c +++ b/pretty.c @@ -493,6 +493,38 @@ static void parse_commit_header(struct format_commit_context *context) context->commit_header_parsed = 1; } +static int istitlechar(char c) +{ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || c == '.' || c == '_'; +} + +static void format_sanitized_subject(struct strbuf *sb, const char *msg) +{ + size_t trimlen; + int space = 2; + + for (; *msg && *msg != '\n'; msg++) { + if (istitlechar(*msg)) { + if (space == 1) + strbuf_addch(sb, '-'); + space = 0; + strbuf_addch(sb, *msg); + if (*msg == '.') + while (*(msg+1) == '.') + msg++; + } else + space |= 1; + } + + /* trim any trailing '.' or '-' characters */ + trimlen = 0; + while (sb->buf[sb->len - 1 - trimlen] == '.' + || sb->buf[sb->len - 1 - trimlen] == '-') + trimlen++; + strbuf_remove(sb, sb->len - trimlen, trimlen); +} + const char *format_subject(struct strbuf *sb, const char *msg, const char *line_separator) { @@ -683,6 +715,9 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder, case 's': /* subject */ format_subject(sb, msg + c->subject_off, " "); return 1; + case 'f': /* sanitized subject */ + format_sanitized_subject(sb, msg + c->subject_off); + return 1; case 'b': /* body */ strbuf_addstr(sb, msg + c->body_off); return 1; From 6df514af9dfb44f104baa9b581e91de22af89b8d Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Sun, 22 Mar 2009 19:14:02 -0700 Subject: [PATCH 255/654] format-patch: construct patch filename in one function reopen_stdout() usually takes the oneline subject of a commit, appends the patch suffix, prepends the output directory (if any) and then reopens stdout as the resulting file. Now the patch filename (the oneline subject and the patch suffix) is created in get_patch_filename() and passed to reopen_stdout() which prepends the output directory and reopens stdout as that file. The original function to get the oneline description, get_oneline_for_filename(), has been renamed to get_patch_filename() to reflect its new functionality. Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-log.c | 98 +++++++++++++++++---------------------------------- 1 file changed, 33 insertions(+), 65 deletions(-) diff --git a/builtin-log.c b/builtin-log.c index c7a5772594..193de3ff2e 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -419,12 +419,6 @@ int cmd_log(int argc, const char **argv, const char *prefix) /* format-patch */ #define FORMAT_PATCH_NAME_MAX 64 -static int istitlechar(char c) -{ - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9') || c == '.' || c == '_'; -} - static const char *fmt_patch_suffix = ".patch"; static int numbered = 0; static int auto_number = 1; @@ -519,61 +513,33 @@ static int git_format_config(const char *var, const char *value, void *cb) } -static const char *get_oneline_for_filename(struct commit *commit, - int keep_subject) +static void get_patch_filename(struct commit *commit, int nr, + const char *suffix, struct strbuf *buf) { - static char filename[PATH_MAX]; - char *sol; - int len = 0; - int suffix_len = strlen(fmt_patch_suffix) + 1; + int suffix_len = strlen(suffix) + 1; + int start_len = buf->len; - sol = strstr(commit->buffer, "\n\n"); - if (!sol) - filename[0] = '\0'; - else { - int j, space = 0; - - sol += 2; - /* strip [PATCH] or [PATCH blabla] */ - if (!keep_subject && !prefixcmp(sol, "[PATCH")) { - char *eos = strchr(sol + 6, ']'); - if (eos) { - while (isspace(*eos)) - eos++; - sol = eos; - } - } - - for (j = 0; - j < FORMAT_PATCH_NAME_MAX - suffix_len - 5 && - len < sizeof(filename) - suffix_len && - sol[j] && sol[j] != '\n'; - j++) { - if (istitlechar(sol[j])) { - if (space) { - filename[len++] = '-'; - space = 0; - } - filename[len++] = sol[j]; - if (sol[j] == '.') - while (sol[j + 1] == '.') - j++; - } else - space = 1; - } - while (filename[len - 1] == '.' - || filename[len - 1] == '-') - len--; - filename[len] = '\0'; + strbuf_addf(buf, commit ? "%04d-" : "%d", nr); + if (commit) { + format_commit_message(commit, "%f", buf, DATE_NORMAL); + /* + * Replace characters at the end with the suffix if the + * filename is too long + */ + if (buf->len + suffix_len > FORMAT_PATCH_NAME_MAX + start_len) + strbuf_splice(buf, + start_len + FORMAT_PATCH_NAME_MAX - suffix_len, + suffix_len, suffix, suffix_len); + else + strbuf_addstr(buf, suffix); } - return filename; } static FILE *realstdout = NULL; static const char *output_directory = NULL; static int outdir_offset; -static int reopen_stdout(const char *oneline, int nr, struct rev_info *rev) +static int reopen_stdout(const char *oneline, struct rev_info *rev) { char filename[PATH_MAX]; int len = 0; @@ -589,14 +555,7 @@ static int reopen_stdout(const char *oneline, int nr, struct rev_info *rev) filename[len++] = '/'; } - if (!oneline) - len += sprintf(filename + len, "%d", nr); - else { - len += sprintf(filename + len, "%04d-", nr); - len += snprintf(filename + len, sizeof(filename) - len - 1 - - suffix_len, "%s", oneline); - strcpy(filename + len, fmt_patch_suffix); - } + strncpy(filename + len, oneline, PATH_MAX - len); if (!DIFF_OPT_TST(&rev->diffopt, QUIET)) fprintf(realstdout, "%s\n", filename + outdir_offset); @@ -684,12 +643,17 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, const char *encoding = "utf-8"; struct diff_options opts; int need_8bit_cte = 0; + char filename[PATH_MAX]; if (rev->commit_format != CMIT_FMT_EMAIL) die("Cover letter needs email format"); - if (!use_stdout && reopen_stdout(numbered_files ? - NULL : "cover-letter", 0, rev)) + if (numbered_files) + sprintf(filename, "0"); + else + sprintf(filename, "%04d-cover-letter%s", 0, fmt_patch_suffix); + + if (!use_stdout && reopen_stdout(filename, rev)) return; head_sha1 = sha1_to_hex(head->object.sha1); @@ -802,6 +766,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) struct patch_ids ids; char *add_signoff = NULL; struct strbuf buf = STRBUF_INIT; + struct strbuf patch_filename = STRBUF_INIT; git_config(git_format_config, NULL); init_revisions(&rev, prefix); @@ -1104,10 +1069,12 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) } gen_message_id(&rev, sha1_to_hex(commit->object.sha1)); } - if (!use_stdout && reopen_stdout(numbered_files ? NULL : - get_oneline_for_filename(commit, keep_subject), - rev.nr, &rev)) + + get_patch_filename(numbered_files ? NULL : commit, rev.nr, + fmt_patch_suffix, &patch_filename); + if (!use_stdout && reopen_stdout(patch_filename.buf, &rev)) die("Failed to create output files"); + strbuf_setlen(&patch_filename, 0); shown = log_tree_commit(&rev, commit); free(commit->buffer); commit->buffer = NULL; @@ -1131,6 +1098,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (!use_stdout) fclose(stdout); } + strbuf_release(&patch_filename); free(list); if (ignore_if_in_upstream) free_patch_ids(&ids); From cd2ef591c8e753fe5295ac3c6f1dee481f00a185 Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Sun, 22 Mar 2009 19:14:03 -0700 Subject: [PATCH 256/654] format-patch: pass a commit to reopen_stdout() We use the commit to generate the patch filename in reopen_stdout() before we redirect stdout. The cover letter codepath creates a dummy commit with the desired subject line 'cover letter'. Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-log.c | 67 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/builtin-log.c b/builtin-log.c index 193de3ff2e..6a27ce6958 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -539,30 +539,29 @@ static FILE *realstdout = NULL; static const char *output_directory = NULL; static int outdir_offset; -static int reopen_stdout(const char *oneline, struct rev_info *rev) +static int reopen_stdout(struct commit *commit, struct rev_info *rev) { - char filename[PATH_MAX]; - int len = 0; + struct strbuf filename = STRBUF_INIT; int suffix_len = strlen(fmt_patch_suffix) + 1; if (output_directory) { - len = snprintf(filename, sizeof(filename), "%s", - output_directory); - if (len >= - sizeof(filename) - FORMAT_PATCH_NAME_MAX - suffix_len) + strbuf_addstr(&filename, output_directory); + if (filename.len >= + PATH_MAX - FORMAT_PATCH_NAME_MAX - suffix_len) return error("name of output directory is too long"); - if (filename[len - 1] != '/') - filename[len++] = '/'; + if (filename.buf[filename.len - 1] != '/') + strbuf_addch(&filename, '/'); } - strncpy(filename + len, oneline, PATH_MAX - len); + get_patch_filename(commit, rev->nr, fmt_patch_suffix, &filename); if (!DIFF_OPT_TST(&rev->diffopt, QUIET)) - fprintf(realstdout, "%s\n", filename + outdir_offset); + fprintf(realstdout, "%s\n", filename.buf + outdir_offset); - if (freopen(filename, "w", stdout) == NULL) - return error("Cannot open patch file %s",filename); + if (freopen(filename.buf, "w", stdout) == NULL) + return error("Cannot open patch file %s", filename.buf); + strbuf_release(&filename); return 0; } @@ -643,26 +642,42 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, const char *encoding = "utf-8"; struct diff_options opts; int need_8bit_cte = 0; - char filename[PATH_MAX]; + struct commit *commit = NULL; if (rev->commit_format != CMIT_FMT_EMAIL) die("Cover letter needs email format"); - if (numbered_files) - sprintf(filename, "0"); - else - sprintf(filename, "%04d-cover-letter%s", 0, fmt_patch_suffix); + committer = git_committer_info(0); + head_sha1 = sha1_to_hex(head->object.sha1); - if (!use_stdout && reopen_stdout(filename, rev)) + if (!numbered_files) { + /* + * We fake a commit for the cover letter so we get the filename + * desired. + */ + commit = xcalloc(1, sizeof(*commit)); + commit->buffer = xmalloc(400); + snprintf(commit->buffer, 400, + "tree 0000000000000000000000000000000000000000\n" + "parent %s\n" + "author %s\n" + "committer %s\n\n" + "cover letter\n", + head_sha1, committer, committer); + } + + if (!use_stdout && reopen_stdout(commit, rev)) return; - head_sha1 = sha1_to_hex(head->object.sha1); + if (commit) { + + free(commit->buffer); + free(commit); + } log_write_email_headers(rev, head_sha1, &subject_start, &extra_headers, &need_8bit_cte); - committer = git_committer_info(0); - msg = body; pp_user_info(NULL, CMIT_FMT_EMAIL, &sb, committer, DATE_RFC2822, encoding); @@ -766,7 +781,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) struct patch_ids ids; char *add_signoff = NULL; struct strbuf buf = STRBUF_INIT; - struct strbuf patch_filename = STRBUF_INIT; git_config(git_format_config, NULL); init_revisions(&rev, prefix); @@ -1070,11 +1084,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) gen_message_id(&rev, sha1_to_hex(commit->object.sha1)); } - get_patch_filename(numbered_files ? NULL : commit, rev.nr, - fmt_patch_suffix, &patch_filename); - if (!use_stdout && reopen_stdout(patch_filename.buf, &rev)) + if (!use_stdout && reopen_stdout(numbered_files ? NULL : commit, + &rev)) die("Failed to create output files"); - strbuf_setlen(&patch_filename, 0); shown = log_tree_commit(&rev, commit); free(commit->buffer); commit->buffer = NULL; @@ -1098,7 +1110,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (!use_stdout) fclose(stdout); } - strbuf_release(&patch_filename); free(list); if (ignore_if_in_upstream) free_patch_ids(&ids); From 6fa8e6278b210bfa56fcb54ed38d2b485350e7c6 Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Sun, 22 Mar 2009 19:14:04 -0700 Subject: [PATCH 257/654] format-patch: move get_patch_filename() into log-tree Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-log.c | 24 ------------------------ log-tree.c | 22 ++++++++++++++++++++++ log-tree.h | 4 ++++ 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/builtin-log.c b/builtin-log.c index 6a27ce6958..4f438db4c1 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -417,7 +417,6 @@ int cmd_log(int argc, const char **argv, const char *prefix) } /* format-patch */ -#define FORMAT_PATCH_NAME_MAX 64 static const char *fmt_patch_suffix = ".patch"; static int numbered = 0; @@ -512,29 +511,6 @@ static int git_format_config(const char *var, const char *value, void *cb) return git_log_config(var, value, cb); } - -static void get_patch_filename(struct commit *commit, int nr, - const char *suffix, struct strbuf *buf) -{ - int suffix_len = strlen(suffix) + 1; - int start_len = buf->len; - - strbuf_addf(buf, commit ? "%04d-" : "%d", nr); - if (commit) { - format_commit_message(commit, "%f", buf, DATE_NORMAL); - /* - * Replace characters at the end with the suffix if the - * filename is too long - */ - if (buf->len + suffix_len > FORMAT_PATCH_NAME_MAX + start_len) - strbuf_splice(buf, - start_len + FORMAT_PATCH_NAME_MAX - suffix_len, - suffix_len, suffix, suffix_len); - else - strbuf_addstr(buf, suffix); - } -} - static FILE *realstdout = NULL; static const char *output_directory = NULL; static int outdir_offset; diff --git a/log-tree.c b/log-tree.c index 9565c184db..aee9995531 100644 --- a/log-tree.c +++ b/log-tree.c @@ -179,6 +179,28 @@ static int has_non_ascii(const char *s) return 0; } +void get_patch_filename(struct commit *commit, int nr, const char *suffix, + struct strbuf *buf) +{ + int suffix_len = strlen(suffix) + 1; + int start_len = buf->len; + + strbuf_addf(buf, commit ? "%04d-" : "%d", nr); + if (commit) { + format_commit_message(commit, "%f", buf, DATE_NORMAL); + /* + * Replace characters at the end with the suffix if the + * filename is too long + */ + if (buf->len + suffix_len > FORMAT_PATCH_NAME_MAX + start_len) + strbuf_splice(buf, + start_len + FORMAT_PATCH_NAME_MAX - suffix_len, + suffix_len, suffix, suffix_len); + else + strbuf_addstr(buf, suffix); + } +} + void log_write_email_headers(struct rev_info *opt, const char *name, const char **subject_p, const char **extra_headers_p, diff --git a/log-tree.h b/log-tree.h index f2a90084ae..78dc5be76f 100644 --- a/log-tree.h +++ b/log-tree.h @@ -19,4 +19,8 @@ void log_write_email_headers(struct rev_info *opt, const char *name, int *need_8bit_cte_p); void load_ref_decorations(void); +#define FORMAT_PATCH_NAME_MAX 64 +void get_patch_filename(struct commit *commit, int nr, const char *suffix, + struct strbuf *buf); + #endif From 108dab2811701c20d6d6e8d9fe8af88e41d65d77 Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Sun, 22 Mar 2009 19:14:05 -0700 Subject: [PATCH 258/654] format-patch: --attach/inline uses filename instead of SHA1 Currently when format-patch is used with --attach or --inline the patch attachment has the SHA1 of the commit for its filename. This replaces the SHA1 with the filename used by format-patch when outputting to files. Fix tests relying on the SHA1 output and add a test showing how the --suffix option affects the attachment filename output. Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-log.c | 8 +-- log-tree.c | 18 +++--- log-tree.h | 2 +- revision.h | 2 + t/t4013-diff-various.sh | 1 + ...tach_--stdout_--suffix=.diff_initial..side | 61 +++++++++++++++++++ ...at-patch_--attach_--stdout_initial..master | 12 ++-- ...t-patch_--attach_--stdout_initial..master^ | 8 +-- ...rmat-patch_--attach_--stdout_initial..side | 4 +- ..._--subject-prefix=TESTCASE_initial..master | 12 ++-- ...at-patch_--inline_--stdout_initial..master | 12 ++-- ...t-patch_--inline_--stdout_initial..master^ | 8 +-- ...-patch_--inline_--stdout_initial..master^^ | 4 +- ...rmat-patch_--inline_--stdout_initial..side | 4 +- 14 files changed, 112 insertions(+), 44 deletions(-) create mode 100644 t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side diff --git a/builtin-log.c b/builtin-log.c index 4f438db4c1..3e3cbc11fd 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -607,7 +607,6 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, int nr, struct commit **list, struct commit *head) { const char *committer; - char *head_sha1; const char *subject_start = NULL; const char *body = "*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n"; const char *msg; @@ -624,7 +623,6 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, die("Cover letter needs email format"); committer = git_committer_info(0); - head_sha1 = sha1_to_hex(head->object.sha1); if (!numbered_files) { /* @@ -639,7 +637,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, "author %s\n" "committer %s\n\n" "cover letter\n", - head_sha1, committer, committer); + sha1_to_hex(head->object.sha1), committer, committer); } if (!use_stdout && reopen_stdout(commit, rev)) @@ -651,7 +649,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, free(commit); } - log_write_email_headers(rev, head_sha1, &subject_start, &extra_headers, + log_write_email_headers(rev, head, &subject_start, &extra_headers, &need_8bit_cte); msg = body; @@ -1011,6 +1009,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) const char *msgid = clean_message_id(in_reply_to); string_list_append(msgid, rev.ref_message_ids); } + rev.numbered_files = numbered_files; + rev.patch_suffix = fmt_patch_suffix; if (cover_letter) { if (thread) gen_message_id(&rev, "cover"); diff --git a/log-tree.c b/log-tree.c index aee9995531..56a3488592 100644 --- a/log-tree.c +++ b/log-tree.c @@ -201,13 +201,14 @@ void get_patch_filename(struct commit *commit, int nr, const char *suffix, } } -void log_write_email_headers(struct rev_info *opt, const char *name, +void log_write_email_headers(struct rev_info *opt, struct commit *commit, const char **subject_p, const char **extra_headers_p, int *need_8bit_cte_p) { const char *subject = NULL; const char *extra_headers = opt->extra_headers; + const char *name = sha1_to_hex(commit->object.sha1); *need_8bit_cte_p = 0; /* unknown */ if (opt->total > 0) { @@ -246,6 +247,7 @@ void log_write_email_headers(struct rev_info *opt, const char *name, if (opt->mime_boundary) { static char subject_buffer[1024]; static char buffer[1024]; + struct strbuf filename = STRBUF_INIT; *need_8bit_cte_p = -1; /* NEVER */ snprintf(subject_buffer, sizeof(subject_buffer) - 1, "%s" @@ -264,18 +266,21 @@ void log_write_email_headers(struct rev_info *opt, const char *name, mime_boundary_leader, opt->mime_boundary); extra_headers = subject_buffer; + get_patch_filename(opt->numbered_files ? NULL : commit, opt->nr, + opt->patch_suffix, &filename); snprintf(buffer, sizeof(buffer) - 1, "\n--%s%s\n" "Content-Type: text/x-patch;" - " name=\"%s.diff\"\n" + " name=\"%s\"\n" "Content-Transfer-Encoding: 8bit\n" "Content-Disposition: %s;" - " filename=\"%s.diff\"\n\n", + " filename=\"%s\"\n\n", mime_boundary_leader, opt->mime_boundary, - name, + filename.buf, opt->no_inline ? "attachment" : "inline", - name); + filename.buf); opt->diffopt.stat_sep = buffer; + strbuf_release(&filename); } *subject_p = subject; *extra_headers_p = extra_headers; @@ -355,8 +360,7 @@ void show_log(struct rev_info *opt) */ if (opt->commit_format == CMIT_FMT_EMAIL) { - log_write_email_headers(opt, sha1_to_hex(commit->object.sha1), - &subject, &extra_headers, + log_write_email_headers(opt, commit, &subject, &extra_headers, &need_8bit_cte); } else if (opt->commit_format != CMIT_FMT_USERFORMAT) { fputs(diff_get_color_opt(&opt->diffopt, DIFF_COMMIT), stdout); diff --git a/log-tree.h b/log-tree.h index 78dc5be76f..20b5caf1aa 100644 --- a/log-tree.h +++ b/log-tree.h @@ -13,7 +13,7 @@ int log_tree_commit(struct rev_info *, struct commit *); int log_tree_opt_parse(struct rev_info *, const char **, int); void show_log(struct rev_info *opt); void show_decorations(struct rev_info *opt, struct commit *commit); -void log_write_email_headers(struct rev_info *opt, const char *name, +void log_write_email_headers(struct rev_info *opt, struct commit *commit, const char **subject_p, const char **extra_headers_p, int *need_8bit_cte_p); diff --git a/revision.h b/revision.h index ad123d78c5..5259ed5192 100644 --- a/revision.h +++ b/revision.h @@ -86,6 +86,8 @@ struct rev_info { struct log_info *loginfo; int nr, total; const char *mime_boundary; + const char *patch_suffix; + int numbered_files; char *message_id; struct string_list *ref_message_ids; const char *add_signoff; diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 426e64e828..6592a4f29d 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -246,6 +246,7 @@ format-patch --stdout initial..master format-patch --stdout --no-numbered initial..master format-patch --stdout --numbered initial..master format-patch --attach --stdout initial..side +format-patch --attach --stdout --suffix=.diff initial..side format-patch --attach --stdout initial..master^ format-patch --attach --stdout initial..master format-patch --inline --stdout initial..side diff --git a/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side b/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side new file mode 100644 index 0000000000..52116d3ead --- /dev/null +++ b/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side @@ -0,0 +1,61 @@ +$ git format-patch --attach --stdout --suffix=.diff initial..side +From c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Mon Sep 17 00:00:00 2001 +From: A U Thor <author@example.com> +Date: Mon, 26 Jun 2006 00:03:00 +0000 +Subject: [PATCH] Side +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="------------g-i-t--v-e-r-s-i-o-n" + +This is a multi-part message in MIME format. +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit + +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + create mode 100644 file3 + + +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/x-patch; name="0001-Side.diff" +Content-Transfer-Encoding: 8bit +Content-Disposition: attachment; filename="0001-Side.diff" + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +--------------g-i-t--v-e-r-s-i-o-n-- + + +$ diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master b/t/t4013/diff.format-patch_--attach_--stdout_initial..master index e5ab74437e..ce49bd676e 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master @@ -22,9 +22,9 @@ This is the second commit. --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; name="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" +Content-Type: text/x-patch; name="0001-Second.patch" Content-Transfer-Encoding: 8bit -Content-Disposition: attachment; filename="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" +Content-Disposition: attachment; filename="0001-Second.patch" diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 @@ -80,9 +80,9 @@ Content-Transfer-Encoding: 8bit --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; name="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" +Content-Type: text/x-patch; name="0002-Third.patch" Content-Transfer-Encoding: 8bit -Content-Disposition: attachment; filename="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" +Content-Disposition: attachment; filename="0002-Third.patch" diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 @@ -129,9 +129,9 @@ Content-Transfer-Encoding: 8bit --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; name="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" +Content-Type: text/x-patch; name="0003-Side.patch" Content-Transfer-Encoding: 8bit -Content-Disposition: attachment; filename="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" +Content-Disposition: attachment; filename="0003-Side.patch" diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ index 2c71d20d37..5f1b23863b 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ @@ -22,9 +22,9 @@ This is the second commit. --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; name="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" +Content-Type: text/x-patch; name="0001-Second.patch" Content-Transfer-Encoding: 8bit -Content-Disposition: attachment; filename="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" +Content-Disposition: attachment; filename="0001-Second.patch" diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 @@ -80,9 +80,9 @@ Content-Transfer-Encoding: 8bit --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; name="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" +Content-Type: text/x-patch; name="0002-Third.patch" Content-Transfer-Encoding: 8bit -Content-Disposition: attachment; filename="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" +Content-Disposition: attachment; filename="0002-Third.patch" diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..side b/t/t4013/diff.format-patch_--attach_--stdout_initial..side index 38f790290a..4a2364abc2 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..side +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..side @@ -20,9 +20,9 @@ Content-Transfer-Encoding: 8bit --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; name="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" +Content-Type: text/x-patch; name="0001-Side.patch" Content-Transfer-Encoding: 8bit -Content-Disposition: attachment; filename="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" +Content-Disposition: attachment; filename="0001-Side.patch" diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master index 58f8a7b7d6..ca3f60bf0e 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master +++ b/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master @@ -22,9 +22,9 @@ This is the second commit. --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; name="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" +Content-Type: text/x-patch; name="0001-Second.patch" Content-Transfer-Encoding: 8bit -Content-Disposition: inline; filename="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" +Content-Disposition: inline; filename="0001-Second.patch" diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 @@ -80,9 +80,9 @@ Content-Transfer-Encoding: 8bit --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; name="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" +Content-Type: text/x-patch; name="0002-Third.patch" Content-Transfer-Encoding: 8bit -Content-Disposition: inline; filename="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" +Content-Disposition: inline; filename="0002-Third.patch" diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 @@ -129,9 +129,9 @@ Content-Transfer-Encoding: 8bit --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; name="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" +Content-Type: text/x-patch; name="0003-Side.patch" Content-Transfer-Encoding: 8bit -Content-Disposition: inline; filename="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" +Content-Disposition: inline; filename="0003-Side.patch" diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_initial..master index 9e7bbdffa2..08f23014bc 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_initial..master +++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master @@ -22,9 +22,9 @@ This is the second commit. --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; name="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" +Content-Type: text/x-patch; name="0001-Second.patch" Content-Transfer-Encoding: 8bit -Content-Disposition: inline; filename="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" +Content-Disposition: inline; filename="0001-Second.patch" diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 @@ -80,9 +80,9 @@ Content-Transfer-Encoding: 8bit --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; name="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" +Content-Type: text/x-patch; name="0002-Third.patch" Content-Transfer-Encoding: 8bit -Content-Disposition: inline; filename="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" +Content-Disposition: inline; filename="0002-Third.patch" diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 @@ -129,9 +129,9 @@ Content-Transfer-Encoding: 8bit --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; name="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" +Content-Type: text/x-patch; name="0003-Side.patch" Content-Transfer-Encoding: 8bit -Content-Disposition: inline; filename="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" +Content-Disposition: inline; filename="0003-Side.patch" diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ index f881f644cc..07f1230d31 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ +++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ @@ -22,9 +22,9 @@ This is the second commit. --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; name="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" +Content-Type: text/x-patch; name="0001-Second.patch" Content-Transfer-Encoding: 8bit -Content-Disposition: inline; filename="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" +Content-Disposition: inline; filename="0001-Second.patch" diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 @@ -80,9 +80,9 @@ Content-Transfer-Encoding: 8bit --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; name="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" +Content-Type: text/x-patch; name="0002-Third.patch" Content-Transfer-Encoding: 8bit -Content-Disposition: inline; filename="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" +Content-Disposition: inline; filename="0002-Third.patch" diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^^ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master^^ index 4f258b8858..29e00ab8af 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^^ +++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master^^ @@ -22,9 +22,9 @@ This is the second commit. --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; name="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" +Content-Type: text/x-patch; name="0001-Second.patch" Content-Transfer-Encoding: 8bit -Content-Disposition: inline; filename="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" +Content-Disposition: inline; filename="0001-Second.patch" diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..side b/t/t4013/diff.format-patch_--inline_--stdout_initial..side index e86dce69a3..67633d424a 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_initial..side +++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..side @@ -20,9 +20,9 @@ Content-Transfer-Encoding: 8bit --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; name="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" +Content-Type: text/x-patch; name="0001-Side.patch" Content-Transfer-Encoding: 8bit -Content-Disposition: inline; filename="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" +Content-Disposition: inline; filename="0001-Side.patch" diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 From 747e25050bfef8f3a7c882954b654cf6d97fc63e Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Sun, 22 Mar 2009 19:14:06 -0700 Subject: [PATCH 259/654] format-patch: --numbered-files and --stdout aren't mutually exclusive For example: git format-patch --numbered-files --stdout --attach HEAD~~ will create two messages with files 1 and 2 attached respectively. There is no effect when using --numbered-files and --stdout together without an --attach or --inline, the --numbered-files option will be ignored. Add a test to show this. Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t4013-diff-various.sh | 2 +- ..._--stdout_--numbered-files_initial..master | 170 ++++++++++++++++++ 2 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 6592a4f29d..8b33321f8c 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -251,7 +251,7 @@ format-patch --attach --stdout initial..master^ format-patch --attach --stdout initial..master format-patch --inline --stdout initial..side format-patch --inline --stdout initial..master^ -format-patch --inline --stdout initial..master +format-patch --inline --stdout --numbered-files initial..master format-patch --inline --stdout initial..master format-patch --inline --stdout --subject-prefix=TESTCASE initial..master config format.subjectprefix DIFFERENT_PREFIX diff --git a/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master new file mode 100644 index 0000000000..43b81eba54 --- /dev/null +++ b/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master @@ -0,0 +1,170 @@ +$ git format-patch --inline --stdout --numbered-files initial..master +From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 +From: A U Thor <author@example.com> +Date: Mon, 26 Jun 2006 00:01:00 +0000 +Subject: [PATCH 1/3] Second +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="------------g-i-t--v-e-r-s-i-o-n" + +This is a multi-part message in MIME format. +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit + + +This is the second commit. +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) + delete mode 100644 file2 + + +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/x-patch; name="1" +Content-Transfer-Encoding: 8bit +Content-Disposition: inline; filename="1" + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 + +--------------g-i-t--v-e-r-s-i-o-n-- + + + +From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001 +From: A U Thor <author@example.com> +Date: Mon, 26 Jun 2006 00:02:00 +0000 +Subject: [PATCH 2/3] Third +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="------------g-i-t--v-e-r-s-i-o-n" + +This is a multi-part message in MIME format. +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit + +--- + dir/sub | 2 ++ + file1 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + create mode 100644 file1 + + +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/x-patch; name="2" +Content-Transfer-Encoding: 8bit +Content-Disposition: inline; filename="2" + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +--------------g-i-t--v-e-r-s-i-o-n-- + + + +From c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Mon Sep 17 00:00:00 2001 +From: A U Thor <author@example.com> +Date: Mon, 26 Jun 2006 00:03:00 +0000 +Subject: [PATCH 3/3] Side +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="------------g-i-t--v-e-r-s-i-o-n" + +This is a multi-part message in MIME format. +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit + +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + create mode 100644 file3 + + +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/x-patch; name="3" +Content-Transfer-Encoding: 8bit +Content-Disposition: inline; filename="3" + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +--------------g-i-t--v-e-r-s-i-o-n-- + + +$ From 431b1969fcde69959a23355fba6894fb69c8fa0c Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Sat, 21 Mar 2009 12:51:34 -0700 Subject: [PATCH 260/654] Rename interpret/substitute nth_last_branch functions These allow you to say "git checkout @{-2}" to switch to the branch two "branch switching" ago by pretending as if you typed the name of that branch. As it is likely that we will be introducing more short-hands to write the name of a branch without writing it explicitly, rename the functions from "nth_last_branch" to more generic "branch_name", to prepare for different semantics. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- branch.c | 2 +- builtin-branch.c | 2 +- builtin-checkout.c | 2 +- builtin-merge.c | 2 +- cache.h | 2 +- sha1_name.c | 12 ++++++------ 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/branch.c b/branch.c index 5f889fee6b..313bcf1634 100644 --- a/branch.c +++ b/branch.c @@ -137,7 +137,7 @@ void create_branch(const char *head, int len; len = strlen(name); - if (interpret_nth_last_branch(name, &ref) != len) { + if (interpret_branch_name(name, &ref) != len) { strbuf_reset(&ref); strbuf_add(&ref, name, len); } diff --git a/builtin-branch.c b/builtin-branch.c index 14d4b917e5..cacd7daae7 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -123,7 +123,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds) for (i = 0; i < argc; i++, strbuf_release(&bname)) { int len = strlen(argv[i]); - if (interpret_nth_last_branch(argv[i], &bname) != len) + if (interpret_branch_name(argv[i], &bname) != len) strbuf_add(&bname, argv[i], len); if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) { diff --git a/builtin-checkout.c b/builtin-checkout.c index 9fdfc58d1a..a8d9d97da2 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -355,7 +355,7 @@ static void setup_branch_path(struct branch_info *branch) struct strbuf buf = STRBUF_INIT; int ret; - if ((ret = interpret_nth_last_branch(branch->name, &buf)) + if ((ret = interpret_branch_name(branch->name, &buf)) && ret == strlen(branch->name)) { branch->name = xstrdup(buf.buf); strbuf_splice(&buf, 0, 0, "refs/heads/", 11); diff --git a/builtin-merge.c b/builtin-merge.c index 4c119359e7..e94ea7c35f 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -361,7 +361,7 @@ static void merge_name(const char *remote, struct strbuf *msg) int len, early; len = strlen(remote); - if (interpret_nth_last_branch(remote, &bname) == len) + if (interpret_branch_name(remote, &bname) == len) remote = bname.buf; memset(branch_head, 0, sizeof(branch_head)); diff --git a/cache.h b/cache.h index 39789ee94a..d28fd74880 100644 --- a/cache.h +++ b/cache.h @@ -671,7 +671,7 @@ extern int read_ref(const char *filename, unsigned char *sha1); extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *); extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref); extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref); -extern int interpret_nth_last_branch(const char *str, struct strbuf *); +extern int interpret_branch_name(const char *str, struct strbuf *); extern int refname_match(const char *abbrev_name, const char *full_name, const char **rules); extern const char *ref_rev_parse_rules[]; diff --git a/sha1_name.c b/sha1_name.c index 2f75179f4c..904bcd96a5 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -242,10 +242,10 @@ static int ambiguous_path(const char *path, int len) * *string and *len will only be substituted, and *string returned (for * later free()ing) if the string passed in is of the form @{-<n>}. */ -static char *substitute_nth_last_branch(const char **string, int *len) +static char *substitute_branch_name(const char **string, int *len) { struct strbuf buf = STRBUF_INIT; - int ret = interpret_nth_last_branch(*string, &buf); + int ret = interpret_branch_name(*string, &buf); if (ret == *len) { size_t size; @@ -259,7 +259,7 @@ static char *substitute_nth_last_branch(const char **string, int *len) int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref) { - char *last_branch = substitute_nth_last_branch(&str, &len); + char *last_branch = substitute_branch_name(&str, &len); const char **p, *r; int refs_found = 0; @@ -288,7 +288,7 @@ int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref) int dwim_log(const char *str, int len, unsigned char *sha1, char **log) { - char *last_branch = substitute_nth_last_branch(&str, &len); + char *last_branch = substitute_branch_name(&str, &len); const char **p; int logs_found = 0; @@ -355,7 +355,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1) struct strbuf buf = STRBUF_INIT; int ret; /* try the @{-N} syntax for n-th checkout */ - ret = interpret_nth_last_branch(str+at, &buf); + ret = interpret_branch_name(str+at, &buf); if (ret > 0) { /* substitute this branch name and restart */ return get_sha1_1(buf.buf, buf.len, sha1); @@ -750,7 +750,7 @@ static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1, * If the input was ok but there are not N branch switches in the * reflog, it returns 0. */ -int interpret_nth_last_branch(const char *name, struct strbuf *buf) +int interpret_branch_name(const char *name, struct strbuf *buf) { long nth; int i, retval; From a552de75eb01f78046feaf7dc88e5e4833624ad5 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Sat, 21 Mar 2009 13:17:30 -0700 Subject: [PATCH 261/654] strbuf_branchname(): a wrapper for branch name shorthands The function takes a user-supplied string that is supposed to be a branch name, and puts it in a strbuf after expanding possible shorthand notation. A handful of open coded sequence to do this in the existing code have been changed to use this helper function. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- branch.c | 7 +------ builtin-branch.c | 6 +----- builtin-checkout.c | 11 +++-------- builtin-merge.c | 5 ++--- strbuf.c | 9 +++++++++ strbuf.h | 2 ++ 6 files changed, 18 insertions(+), 22 deletions(-) diff --git a/branch.c b/branch.c index 313bcf1634..558f092701 100644 --- a/branch.c +++ b/branch.c @@ -134,13 +134,8 @@ void create_branch(const char *head, char *real_ref, msg[PATH_MAX + 20]; struct strbuf ref = STRBUF_INIT; int forcing = 0; - int len; - len = strlen(name); - if (interpret_branch_name(name, &ref) != len) { - strbuf_reset(&ref); - strbuf_add(&ref, name, len); - } + strbuf_branchname(&ref, name); strbuf_splice(&ref, 0, 0, "refs/heads/", 11); if (check_ref_format(ref.buf)) diff --git a/builtin-branch.c b/builtin-branch.c index cacd7daae7..7452db13c8 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -121,11 +121,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds) die("Couldn't look up commit object for HEAD"); } for (i = 0; i < argc; i++, strbuf_release(&bname)) { - int len = strlen(argv[i]); - - if (interpret_branch_name(argv[i], &bname) != len) - strbuf_add(&bname, argv[i], len); - + strbuf_branchname(&bname, argv[i]); if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) { error("Cannot delete the branch '%s' " "which you are currently on.", bname.buf); diff --git a/builtin-checkout.c b/builtin-checkout.c index a8d9d97da2..b2680466d8 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -353,16 +353,11 @@ struct branch_info { static void setup_branch_path(struct branch_info *branch) { struct strbuf buf = STRBUF_INIT; - int ret; - if ((ret = interpret_branch_name(branch->name, &buf)) - && ret == strlen(branch->name)) { + strbuf_branchname(&buf, branch->name); + if (strcmp(buf.buf, branch->name)) branch->name = xstrdup(buf.buf); - strbuf_splice(&buf, 0, 0, "refs/heads/", 11); - } else { - strbuf_addstr(&buf, "refs/heads/"); - strbuf_addstr(&buf, branch->name); - } + strbuf_splice(&buf, 0, 0, "refs/heads/", 11); branch->path = strbuf_detach(&buf, NULL); } diff --git a/builtin-merge.c b/builtin-merge.c index e94ea7c35f..6a51823a55 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -360,9 +360,8 @@ static void merge_name(const char *remote, struct strbuf *msg) const char *ptr; int len, early; - len = strlen(remote); - if (interpret_branch_name(remote, &bname) == len) - remote = bname.buf; + strbuf_branchname(&bname, remote); + remote = bname.buf; memset(branch_head, 0, sizeof(branch_head)); remote_head = peel_to_type(remote, 0, NULL, OBJ_COMMIT); diff --git a/strbuf.c b/strbuf.c index bfbd81632e..a60b0ad67d 100644 --- a/strbuf.c +++ b/strbuf.c @@ -357,3 +357,12 @@ int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint) return len; } + +int strbuf_branchname(struct strbuf *sb, const char *name) +{ + int len = strlen(name); + if (interpret_branch_name(name, sb) == len) + return 0; + strbuf_add(sb, name, len); + return len; +} diff --git a/strbuf.h b/strbuf.h index 89bd36e15a..68923e1908 100644 --- a/strbuf.h +++ b/strbuf.h @@ -131,4 +131,6 @@ extern int strbuf_getline(struct strbuf *, FILE *, int); extern void stripspace(struct strbuf *buf, int skip_comments); extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env); +extern int strbuf_branchname(struct strbuf *sb, const char *name); + #endif /* STRBUF_H */ From a31dca0393fefae894b7a155ae24000107bcc383 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Sat, 21 Mar 2009 14:19:53 -0700 Subject: [PATCH 262/654] check-ref-format --branch: give Porcelain a way to grok branch shorthand The command may not be the best place to add this new feature, but $ git check-ref-format --branch "@{-1}" allows Porcelains to figure out what branch you were on before the last branch switching. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-check-ref-format.txt | 12 ++++++++++++ builtin-check-ref-format.c | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt index 034223cc5a..51579f6776 100644 --- a/Documentation/git-check-ref-format.txt +++ b/Documentation/git-check-ref-format.txt @@ -7,7 +7,9 @@ git-check-ref-format - Make sure ref name is well formed SYNOPSIS -------- +[verse] 'git check-ref-format' <refname> +'git check-ref-format' [--branch] <branchname-shorthand> DESCRIPTION ----------- @@ -49,6 +51,16 @@ refname expressions (see linkgit:git-rev-parse[1]). Namely: It may also be used to select a specific object such as with 'git-cat-file': "git cat-file blob v1.3.3:refs.c". +With the `--branch` option, it expands a branch name shorthand and +prints the name of the branch the shorthand refers to. + +EXAMPLE +------- + +git check-ref-format --branch @{-1}:: + +Print the name of the previous branch. + GIT --- diff --git a/builtin-check-ref-format.c b/builtin-check-ref-format.c index 701de439ae..39db6cbe47 100644 --- a/builtin-check-ref-format.c +++ b/builtin-check-ref-format.c @@ -5,9 +5,19 @@ #include "cache.h" #include "refs.h" #include "builtin.h" +#include "strbuf.h" int cmd_check_ref_format(int argc, const char **argv, const char *prefix) { + if (argc == 3 && !strcmp(argv[1], "--branch")) { + struct strbuf sb = STRBUF_INIT; + strbuf_branchname(&sb, argv[2]); + strbuf_splice(&sb, 0, 0, "refs/heads/", 11); + if (check_ref_format(sb.buf)) + die("'%s' is not a valid branch name", argv[2]); + printf("%s\n", sb.buf + 11); + exit(0); + } if (argc != 2) usage("git check-ref-format refname"); return !!check_ref_format(argv[1]); From 03d3aada5a2a68a7acdb6286fd72155f01626e41 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Sat, 21 Mar 2009 13:23:27 -0700 Subject: [PATCH 263/654] Fix branch -m @{-1} newname The command is supposed to rename the branch we were on before switched from to a new name, but was not aware of the short-hand notation we added recently. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-branch.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/builtin-branch.c b/builtin-branch.c index 7452db13c8..0df82bf96d 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -468,18 +468,18 @@ static void rename_branch(const char *oldname, const char *newname, int force) if (!oldname) die("cannot rename the current branch while not on any."); - strbuf_addf(&oldref, "refs/heads/%s", oldname); - + strbuf_branchname(&oldref, oldname); + strbuf_splice(&oldref, 0, 0, "refs/heads/", 11); if (check_ref_format(oldref.buf)) - die("Invalid branch name: %s", oldref.buf); - - strbuf_addf(&newref, "refs/heads/%s", newname); + die("Invalid branch name: '%s'", oldname); + strbuf_branchname(&newref, newname); + strbuf_splice(&newref, 0, 0, "refs/heads/", 11); if (check_ref_format(newref.buf)) - die("Invalid branch name: %s", newref.buf); + die("Invalid branch name: '%s'", newname); if (resolve_ref(newref.buf, sha1, 1, NULL) && !force) - die("A branch named '%s' already exists.", newname); + die("A branch named '%s' already exists.", newref.buf + 11); strbuf_addf(&logmsg, "Branch: renamed %s to %s", oldref.buf, newref.buf); From a2fab531bbb00ff64335906e22854365be2eb5c7 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Sat, 21 Mar 2009 14:35:51 -0700 Subject: [PATCH 264/654] strbuf_check_branch_ref(): a helper to check a refname for a branch This allows a common calling sequence strbuf_branchname(&ref, name); strbuf_splice(&ref, 0, 0, "refs/heads/", 11); if (check_ref_format(ref.buf)) die(...); to be refactored into if (strbuf_check_branch_ref(&ref, name)) die(...); Signed-off-by: Junio C Hamano <gitster@pobox.com> --- branch.c | 5 +---- builtin-branch.c | 8 ++------ builtin-check-ref-format.c | 5 ++--- builtin-checkout.c | 7 +++---- strbuf.c | 8 ++++++++ strbuf.h | 1 + 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/branch.c b/branch.c index 558f092701..62030af4b5 100644 --- a/branch.c +++ b/branch.c @@ -135,10 +135,7 @@ void create_branch(const char *head, struct strbuf ref = STRBUF_INIT; int forcing = 0; - strbuf_branchname(&ref, name); - strbuf_splice(&ref, 0, 0, "refs/heads/", 11); - - if (check_ref_format(ref.buf)) + if (strbuf_check_branch_ref(&ref, name)) die("'%s' is not a valid branch name.", name); if (resolve_ref(ref.buf, sha1, 1, NULL)) { diff --git a/builtin-branch.c b/builtin-branch.c index 0df82bf96d..afeed68cfd 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -468,14 +468,10 @@ static void rename_branch(const char *oldname, const char *newname, int force) if (!oldname) die("cannot rename the current branch while not on any."); - strbuf_branchname(&oldref, oldname); - strbuf_splice(&oldref, 0, 0, "refs/heads/", 11); - if (check_ref_format(oldref.buf)) + if (strbuf_check_branch_ref(&oldref, oldname)) die("Invalid branch name: '%s'", oldname); - strbuf_branchname(&newref, newname); - strbuf_splice(&newref, 0, 0, "refs/heads/", 11); - if (check_ref_format(newref.buf)) + if (strbuf_check_branch_ref(&newref, newname)) die("Invalid branch name: '%s'", newname); if (resolve_ref(newref.buf, sha1, 1, NULL) && !force) diff --git a/builtin-check-ref-format.c b/builtin-check-ref-format.c index 39db6cbe47..f9381e07ea 100644 --- a/builtin-check-ref-format.c +++ b/builtin-check-ref-format.c @@ -11,9 +11,8 @@ int cmd_check_ref_format(int argc, const char **argv, const char *prefix) { if (argc == 3 && !strcmp(argv[1], "--branch")) { struct strbuf sb = STRBUF_INIT; - strbuf_branchname(&sb, argv[2]); - strbuf_splice(&sb, 0, 0, "refs/heads/", 11); - if (check_ref_format(sb.buf)) + + if (strbuf_check_branch_ref(&sb, argv[2])) die("'%s' is not a valid branch name", argv[2]); printf("%s\n", sb.buf + 11); exit(0); diff --git a/builtin-checkout.c b/builtin-checkout.c index b2680466d8..66df0c072c 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -733,12 +733,11 @@ no_reference: if (opts.new_branch) { struct strbuf buf = STRBUF_INIT; - strbuf_addstr(&buf, "refs/heads/"); - strbuf_addstr(&buf, opts.new_branch); + if (strbuf_check_branch_ref(&buf, opts.new_branch)) + die("git checkout: we do not like '%s' as a branch name.", + opts.new_branch); if (!get_sha1(buf.buf, rev)) die("git checkout: branch %s already exists", opts.new_branch); - if (check_ref_format(buf.buf)) - die("git checkout: we do not like '%s' as a branch name.", opts.new_branch); strbuf_release(&buf); } diff --git a/strbuf.c b/strbuf.c index a60b0ad67d..a88496030b 100644 --- a/strbuf.c +++ b/strbuf.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "refs.h" int prefixcmp(const char *str, const char *prefix) { @@ -366,3 +367,10 @@ int strbuf_branchname(struct strbuf *sb, const char *name) strbuf_add(sb, name, len); return len; } + +int strbuf_check_branch_ref(struct strbuf *sb, const char *name) +{ + strbuf_branchname(sb, name); + strbuf_splice(sb, 0, 0, "refs/heads/", 11); + return check_ref_format(sb->buf); +} diff --git a/strbuf.h b/strbuf.h index 68923e1908..9ee908a3ec 100644 --- a/strbuf.h +++ b/strbuf.h @@ -132,5 +132,6 @@ extern void stripspace(struct strbuf *buf, int skip_comments); extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env); extern int strbuf_branchname(struct strbuf *sb, const char *name); +extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name); #endif /* STRBUF_H */ From 28baf82ea359d9f2579fd3a7e7e2e5e2bd5da2a9 Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Mon, 23 Mar 2009 02:22:29 -0400 Subject: [PATCH 265/654] t0060: fix whitespace in "wc -c" invocation Some platforms like to stick extra whitespace in the output of "wc -c"; using the result without quotes gets the shell to collapse the whitespace. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t0060-path-utils.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index 86000e26c1..53cf1f8dc4 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -17,7 +17,7 @@ norm_path() { # which means that the path / accounts for this many characters: rootoff=$(test-path-utils normalize_path_copy / | wc -c) # Account for the trailing LF: -if test "$rootoff" = 2; then +if test $rootoff = 2; then rootoff= # we are on Unix else rootoff=$(($rootoff-1)) From 681c3290e379e61f9dd762039f140296434d1d9f Mon Sep 17 00:00:00 2001 From: Pat Thoyts <patthoyts@users.sourceforge.net> Date: Mon, 16 Mar 2009 10:24:40 +0000 Subject: [PATCH 266/654] gitk: Handle blobs containing a DOS end-of-file marker If a patchset contains an EOF marker (Ctrl-Z) the blob diff terminates at that point. This permits gitk to ignore the eof and continue to display any subsequent blobs and also displays a sensible representation of the eof char. Signed-off-by: Pat Thoyts <patthoyts@users.sourceforge.net> Signed-off-by: Paul Mackerras <paulus@samba.org> --- gitk | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gitk b/gitk index 1773ae63eb..d7de27e75d 100755 --- a/gitk +++ b/gitk @@ -7216,7 +7216,7 @@ proc getblobdiffs {ids} { set diffnparents 0 set diffinhdr 0 set diffencoding [get_path_encoding {}] - fconfigure $bdf -blocking 0 -encoding binary + fconfigure $bdf -blocking 0 -encoding binary -eofchar {} set blobdifffd($ids) $bdf filerun $bdf [list getblobdiffline $bdf $diffids] } @@ -7367,7 +7367,8 @@ proc getblobdiffline {bdf ids} { $ctext insert end "$line\n" filesep } else { - set line [encoding convertfrom $diffencoding $line] + set line [string map {\x1A ^Z} \ + [encoding convertfrom $diffencoding $line]] # parse the prefix - one ' ', '-' or '+' for each parent set prefix [string range $line 0 [expr {$diffnparents - 1}]] set tag [expr {$diffnparents > 1? "m": "d"}] From 37871b735aa427c440590966d4cacaf219a21292 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta <giuseppe.bilotta@gmail.com> Date: Thu, 19 Mar 2009 01:54:17 -0700 Subject: [PATCH 267/654] gitk: Provide a window icon if possible Try to set up a 16x16 Tk photo image (based on the git logo) and use it as window icon. The code is wrapped in a catch because it may fail in earlier Tcl/Tk 8.4 releases that don't provide 'wm iconphoto'. Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com> Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Paul Mackerras <paulus@samba.org> --- gitk | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/gitk b/gitk index d7de27e75d..82bc2af761 100755 --- a/gitk +++ b/gitk @@ -10884,6 +10884,26 @@ set lserial 0 set isworktree [expr {[exec git rev-parse --is-inside-work-tree] == "true"}] setcoords makewindow +catch { + image create photo gitlogo -width 16 -height 16 + + image create photo gitlogominus -width 4 -height 2 + gitlogominus put #C00000 -to 0 0 4 2 + gitlogo copy gitlogominus -to 1 5 + gitlogo copy gitlogominus -to 6 5 + gitlogo copy gitlogominus -to 11 5 + image delete gitlogominus + + image create photo gitlogoplus -width 4 -height 4 + gitlogoplus put #008000 -to 1 0 3 4 + gitlogoplus put #008000 -to 0 1 4 3 + gitlogo copy gitlogoplus -to 1 9 + gitlogo copy gitlogoplus -to 6 9 + gitlogo copy gitlogoplus -to 11 9 + image delete gitlogoplus + + wm iconphoto . -default gitlogo +} # wait for the window to become visible tkwait visibility . wm title . "[file tail $argv0]: [file tail [pwd]]" From d38d7d4954601966fe86573bf698c5bd4f37cb64 Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Thu, 19 Mar 2009 01:54:18 -0700 Subject: [PATCH 268/654] gitk: Provide a 32x32 window icon based on the git logo This simply expands the 16x16 logo image to 32x32 and provides it as an alternative icon image. Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Paul Mackerras <paulus@samba.org> --- gitk | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gitk b/gitk index 82bc2af761..0dcfbf1b4a 100755 --- a/gitk +++ b/gitk @@ -10902,7 +10902,10 @@ catch { gitlogo copy gitlogoplus -to 11 9 image delete gitlogoplus - wm iconphoto . -default gitlogo + image create photo gitlogo32 -width 32 -height 32 + gitlogo32 copy gitlogo -zoom 2 2 + + wm iconphoto . -default gitlogo gitlogo32 } # wait for the window to become visible tkwait visibility . From 5fdcbb13904e6447cad9611b9c75943bbbcc7db4 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" <das@users.sourceforge.net> Date: Mon, 23 Mar 2009 12:17:38 +0100 Subject: [PATCH 269/654] gitk: Fixes for Mac OS X TkAqua - middle button is B3 on TkAqua - add horizontal mousehweel scrolling - nicer default fonts - use OSX-specific extdifftool - remove quit menu item, call doquit on quit event - move about & preferences menu items into apple menu - don't set menu font Signed-off-by: Daniel A. Steffen <das@users.sourceforge.net> Signed-off-by: Paul Mackerras <paulus@samba.org> --- gitk | 62 ++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/gitk b/gitk index 0dcfbf1b4a..a7294a1476 100755 --- a/gitk +++ b/gitk @@ -1830,7 +1830,9 @@ proc setoptions {} { option add *Button.font uifont startupFile option add *Checkbutton.font uifont startupFile option add *Radiobutton.font uifont startupFile - option add *Menu.font uifont startupFile + if {[tk windowingsystem] ne "aqua"} { + option add *Menu.font uifont startupFile + } option add *Menubutton.font uifont startupFile option add *Label.font uifont startupFile option add *Message.font uifont startupFile @@ -1910,8 +1912,8 @@ proc makewindow {} { # The "mc" arguments here are purely so that xgettext # sees the following string as needing to be translated - makemenu .bar { - {mc "File" cascade { + set file { + mc "File" cascade { {mc "Update" command updatecommits -accelerator F5} {mc "Reload" command reloadcommits -accelerator Meta1-F5} {mc "Reread references" command rereadrefs} @@ -1921,21 +1923,41 @@ proc makewindow {} { {xx "" separator} {mc "Quit" command doquit -accelerator Meta1-Q} }} - {mc "Edit" cascade { + set edit { + mc "Edit" cascade { {mc "Preferences" command doprefs} }} - {mc "View" cascade { + set view { + mc "View" cascade { {mc "New view..." command {newview 0} -accelerator Shift-F4} {mc "Edit view..." command editview -state disabled -accelerator F4} {mc "Delete view" command delview -state disabled} {xx "" separator} {mc "All files" radiobutton {selectedview 0} -command {showview 0}} }} - {mc "Help" cascade { + if {[tk windowingsystem] ne "aqua"} { + set help { + mc "Help" cascade { {mc "About gitk" command about} {mc "Key bindings" command keys} }} + set bar [list $file $edit $view $help] + } else { + proc ::tk::mac::ShowPreferences {} {doprefs} + proc ::tk::mac::Quit {} {doquit} + lset file end [lreplace [lindex $file end] end-1 end] + set apple { + xx "Apple" cascade { + {mc "About gitk" command about} + {xx "" separator} + }} + set help { + mc "Help" cascade { + {mc "Key bindings" command keys} + }} + set bar [list $apple $file $view $help] } + makemenu .bar $bar . configure -menu .bar # the gui has upper and lower half, parts of a paned window. @@ -2231,8 +2253,10 @@ proc makewindow {} { if {[tk windowingsystem] eq {aqua}} { set M1B M1 + set ::BM "3" } else { set M1B Control + set ::BM "2" } bind .pwbottom <Configure> {resizecdetpanes %W %w} @@ -2250,10 +2274,14 @@ proc makewindow {} { set delta [expr {- (%D)}] allcanvs yview scroll $delta units } + bindall <Shift-MouseWheel> { + set delta [expr {- (%D)}] + $canv xview scroll $delta units + } } } - bindall <2> "canvscan mark %W %x %y" - bindall <B2-Motion> "canvscan dragto %W %x %y" + bindall <$::BM> "canvscan mark %W %x %y" + bindall <B$::BM-Motion> "canvscan dragto %W %x %y" bindkey <Home> selfirstline bindkey <End> sellastline bind . <Key-Up> "selnextline -1" @@ -10690,9 +10718,15 @@ catch { } } -set mainfont {Helvetica 9} -set textfont {Courier 9} -set uifont {Helvetica 9 bold} +if {[tk windowingsystem] eq "aqua"} { + set mainfont {{Lucida Grande} 9} + set textfont {Monaco 9} + set uifont {{Lucida Grande} 9 bold} +} else { + set mainfont {Helvetica 9} + set textfont {Courier 9} + set uifont {Helvetica 9 bold} +} set tabstop 8 set findmergefiles 0 set maxgraphpct 50 @@ -10713,7 +10747,11 @@ set datetimeformat "%Y-%m-%d %H:%M:%S" set autoselect 1 set perfile_attrs 0 -set extdifftool "meld" +if {[tk windowingsystem] eq "aqua"} { + set extdifftool "opendiff" +} else { + set extdifftool "meld" +} set colors {green red blue magenta darkgrey brown orange} set bgcolor white From d5c87cb4ffc411fc12dbc261af3ed29633e49fba Mon Sep 17 00:00:00 2001 From: Miklos Vajna <vmiklos@frugalware.org> Date: Tue, 24 Mar 2009 02:09:09 +0100 Subject: [PATCH 270/654] http-push: using error() and warning() as appropriate Change three occurences of using inconsistent error/warning reporting by using the relevant error() / warning() calls to be consitent with the rest of the code. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- http-push.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/http-push.c b/http-push.c index 48e5f38fe0..e6bd01a516 100644 --- a/http-push.c +++ b/http-push.c @@ -759,7 +759,7 @@ static void finish_request(struct transfer_request *request) } } else { if (request->http_code == 416) - fprintf(stderr, "Warning: requested range invalid; we may already have all the data.\n"); + warning("requested range invalid; we may already have all the data."); git_inflate_end(&request->stream); git_SHA1_Final(request->real_sha1, &request->c); @@ -1616,7 +1616,7 @@ static int locking_available(void) } XML_ParserFree(parser); if (!lock_flags) - error("Error: no DAV locking support on %s", + error("no DAV locking support on %s", remote->url); } else { @@ -2225,7 +2225,7 @@ int main(int argc, char **argv) if (info_ref_lock) remote->can_update_info_refs = 1; else { - fprintf(stderr, "Error: cannot lock existing info/refs\n"); + error("cannot lock existing info/refs"); rc = 1; goto cleanup; } From eca2a8f0236a3b5b2c3afca2643d433a51a205fe Mon Sep 17 00:00:00 2001 From: Miklos Vajna <vmiklos@frugalware.org> Date: Tue, 24 Mar 2009 02:09:10 +0100 Subject: [PATCH 271/654] builtin-apply: use warning() instead of fprintf(stderr, "warning: ") Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-apply.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/builtin-apply.c b/builtin-apply.c index b52aa20cfa..1926cd8055 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2451,7 +2451,7 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s if ((st_mode ^ patch->old_mode) & S_IFMT) return error("%s: wrong type", old_name); if (st_mode != patch->old_mode) - fprintf(stderr, "warning: %s has type %o, expected %o\n", + warning("%s has type %o, expected %o", old_name, st_mode, patch->old_mode); if (!patch->new_mode && !patch->is_delete) patch->new_mode = st_mode; @@ -2932,8 +2932,7 @@ static int write_out_one_reject(struct patch *patch) cnt = strlen(patch->new_name); if (ARRAY_SIZE(namebuf) <= cnt + 5) { cnt = ARRAY_SIZE(namebuf) - 5; - fprintf(stderr, - "warning: truncating .rej filename to %.*s.rej", + warning("truncating .rej filename to %.*s.rej", cnt - 1, patch->new_name); } memcpy(namebuf, patch->new_name, cnt); @@ -3315,8 +3314,8 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix) squelch_whitespace_errors < whitespace_error) { int squelched = whitespace_error - squelch_whitespace_errors; - fprintf(stderr, "warning: squelched %d " - "whitespace error%s\n", + warning("squelched %d " + "whitespace error%s", squelched, squelched == 1 ? "" : "s"); } @@ -3326,12 +3325,12 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix) whitespace_error == 1 ? "" : "s", whitespace_error == 1 ? "s" : ""); if (applied_after_fixing_ws && apply) - fprintf(stderr, "warning: %d line%s applied after" - " fixing whitespace errors.\n", + warning("%d line%s applied after" + " fixing whitespace errors.", applied_after_fixing_ws, applied_after_fixing_ws == 1 ? "" : "s"); else if (whitespace_error) - fprintf(stderr, "warning: %d line%s add%s whitespace errors.\n", + warning("%d line%s add%s whitespace errors.", whitespace_error, whitespace_error == 1 ? "" : "s", whitespace_error == 1 ? "s" : ""); From f198e218494800787909af0f3985350c3ecc27b2 Mon Sep 17 00:00:00 2001 From: Miklos Vajna <vmiklos@frugalware.org> Date: Tue, 24 Mar 2009 02:09:11 +0100 Subject: [PATCH 272/654] builtin-checkout: use warning() instead of fprintf(stderr, "warning: ") Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-checkout.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin-checkout.c b/builtin-checkout.c index 9fdfc58d1a..fc55bbe14d 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -558,8 +558,8 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new) if (!old.commit && !opts->force) { if (!opts->quiet) { - fprintf(stderr, "warning: You appear to be on a branch yet to be born.\n"); - fprintf(stderr, "warning: Forcing checkout of %s.\n", new->name); + warning("You appear to be on a branch yet to be born."); + warning("Forcing checkout of %s.", new->name); } opts->force = 1; } From 78509d2197ff18d1de02c27a5406328f75b95306 Mon Sep 17 00:00:00 2001 From: Miklos Vajna <vmiklos@frugalware.org> Date: Tue, 24 Mar 2009 02:09:12 +0100 Subject: [PATCH 273/654] builtin-fetch-pack: use warning() instead of fprintf(stderr, "warning: ") Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-fetch-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index d571253a56..5d134be47c 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -605,7 +605,7 @@ static struct ref *do_fetch_pack(int fd[2], /* When cloning, it is not unusual to have * no common commit. */ - fprintf(stderr, "warning: no common commits\n"); + warning("no common commits"); if (get_pack(fd, pack_lockfile)) die("git fetch-pack: fetch failed."); From 2fd8c0a5dbc614a6a7853558e4af8298acefc96a Mon Sep 17 00:00:00 2001 From: Miklos Vajna <vmiklos@frugalware.org> Date: Tue, 24 Mar 2009 02:09:13 +0100 Subject: [PATCH 274/654] builtin-init-db: use warning() instead of fprintf(stderr, "warning: ") Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-init-db.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/builtin-init-db.c b/builtin-init-db.c index ee3911f8ee..fc63d0fce5 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -130,8 +130,7 @@ static void copy_templates(const char *template_dir) } dir = opendir(template_path); if (!dir) { - fprintf(stderr, "warning: templates not found %s\n", - template_dir); + warning("templates not found %s", template_dir); return; } @@ -144,8 +143,8 @@ static void copy_templates(const char *template_dir) if (repository_format_version && repository_format_version != GIT_REPO_VERSION) { - fprintf(stderr, "warning: not copying templates of " - "a wrong format version %d from '%s'\n", + warning("not copying templates of " + "a wrong format version %d from '%s'", repository_format_version, template_dir); closedir(dir); From c36d785da022cb7f7860ed85d78add3f102c4969 Mon Sep 17 00:00:00 2001 From: Miklos Vajna <vmiklos@frugalware.org> Date: Tue, 24 Mar 2009 02:09:14 +0100 Subject: [PATCH 275/654] builtin-rm: use warning() instead of fprintf(stderr, "warning: ") Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-rm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/builtin-rm.c b/builtin-rm.c index c11f455858..269d60890a 100644 --- a/builtin-rm.c +++ b/builtin-rm.c @@ -59,8 +59,7 @@ static int check_local_mod(unsigned char *head, int index_only) if (lstat(ce->name, &st) < 0) { if (errno != ENOENT) - fprintf(stderr, "warning: '%s': %s", - ce->name, strerror(errno)); + warning("'%s': %s", ce->name, strerror(errno)); /* It already vanished from the working tree */ continue; } From 33fa4d3dfe71dec05da35e187433101486f4eac2 Mon Sep 17 00:00:00 2001 From: Miklos Vajna <vmiklos@frugalware.org> Date: Tue, 24 Mar 2009 02:09:15 +0100 Subject: [PATCH 276/654] builtin-show-branch: use warning() instead of fprintf(stderr, "warning: ") Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-show-branch.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/builtin-show-branch.c b/builtin-show-branch.c index 306b850c72..828e6f86de 100644 --- a/builtin-show-branch.c +++ b/builtin-show-branch.c @@ -365,8 +365,7 @@ static int append_ref(const char *refname, const unsigned char *sha1, return 0; } if (MAX_REVS <= ref_name_cnt) { - fprintf(stderr, "warning: ignoring %s; " - "cannot handle more than %d refs\n", + warning("ignoring %s; cannot handle more than %d refs", refname, MAX_REVS); return 0; } From 5620e77e30b72e674a6bec55fd4bfdac2d5a75fd Mon Sep 17 00:00:00 2001 From: Miklos Vajna <vmiklos@frugalware.org> Date: Tue, 24 Mar 2009 02:09:16 +0100 Subject: [PATCH 277/654] builtin-show-ref: use warning() instead of fprintf(stderr, "warning: ") Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-show-ref.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-show-ref.c b/builtin-show-ref.c index 572b114119..dc76c5090f 100644 --- a/builtin-show-ref.c +++ b/builtin-show-ref.c @@ -140,7 +140,7 @@ static int exclude_existing(const char *match) continue; } if (check_ref_format(ref)) { - fprintf(stderr, "warning: ref '%s' ignored\n", ref); + warning("ref '%s' ignored", ref); continue; } if (!string_list_has_string(&existing_refs, ref)) { From edbc25c5b377d6fe768cefcc8614cd254a9fc4ff Mon Sep 17 00:00:00 2001 From: Miklos Vajna <vmiklos@frugalware.org> Date: Tue, 24 Mar 2009 02:09:17 +0100 Subject: [PATCH 278/654] refs: use warning() instead of fprintf(stderr, "warning: ") Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- refs.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/refs.c b/refs.c index 8d3c502a15..aeef257ee3 100644 --- a/refs.c +++ b/refs.c @@ -996,7 +996,7 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt) err = unlink(git_path("logs/%s", lock->ref_name)); if (err && errno != ENOENT) - fprintf(stderr, "warning: unlink(%s) failed: %s", + warning("unlink(%s) failed: %s", git_path("logs/%s", lock->ref_name), strerror(errno)); invalidate_cached_refs(); unlock_ref(lock); @@ -1438,8 +1438,7 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char * if (get_sha1_hex(rec + 41, sha1)) die("Log %s is corrupt.", logfile); if (hashcmp(logged_sha1, sha1)) { - fprintf(stderr, - "warning: Log %s has gap after %s.\n", + warning("Log %s has gap after %s.", logfile, show_date(date, tz, DATE_RFC2822)); } } @@ -1451,8 +1450,7 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char * if (get_sha1_hex(rec + 41, logged_sha1)) die("Log %s is corrupt.", logfile); if (hashcmp(logged_sha1, sha1)) { - fprintf(stderr, - "warning: Log %s unexpectedly ended on %s.\n", + warning("Log %s unexpectedly ended on %s.", logfile, show_date(date, tz, DATE_RFC2822)); } } From cbdffe4093be77bbb1408e54eead7865dd3bc33f Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Sat, 21 Mar 2009 13:27:31 -0700 Subject: [PATCH 279/654] check_ref_format(): tighten refname rules This changes the rules for refnames to forbid: (1) a refname that contains "@{" in it. Some people and foreign SCM converter may have named their branches as frotz@24 and we still want to keep supporting it. However, "git branch frotz@{24}" is a disaster. It cannot even checked out because "git checkout frotz@{24}" will interpret it as "detach the HEAD at twenty-fourth reflog entry of the frotz branch". (2) a refname that ends with a dot. We already reject a path component that begins with a dot, primarily to avoid ambiguous range interpretation. If we allowed ".B" as a valid ref, it is unclear if "A...B" means "in dot-B but not in A" or "either in A or B but not in both". But for this to be complete, we need also to forbid "A." to avoid "in B but not in A-dot". This was not a problem in the original range notation, but we should have added this restriction when three-dot notation was introduced. Unlike "no dot at the beginning of any path component" rule, this rule does not have to be "no dot at the end of any path component", because you cannot abbreviate the tail end away, similar to you can say "dot-B" to mean "refs/heads/dot-B". For these reasons, it is not likely people created branches with these names on purpose, but we have allowed such names to be used for quite some time, and it is possible that people created such branches by mistake or by accident. To help people with branches with such unfortunate names to recover, we still allow "branch -d 'bad.'" to delete such branches, and also allow "branch -m bad. good" to rename them. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-check-ref-format.txt | 6 +++++- builtin-branch.c | 16 ++++++++++++++-- refs.c | 13 +++++++++---- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt index 51579f6776..d23fd219da 100644 --- a/Documentation/git-check-ref-format.txt +++ b/Documentation/git-check-ref-format.txt @@ -32,7 +32,9 @@ imposes the following rules on how refs are named: caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`, or open bracket `[` anywhere; -. It cannot end with a slash `/`. +. They cannot end with a slash `/` nor a dot `.`. + +. They cannot contain a sequence `@{`. These rules makes it easy for shell script based tools to parse refnames, pathname expansion by the shell when a refname is used @@ -51,6 +53,8 @@ refname expressions (see linkgit:git-rev-parse[1]). Namely: It may also be used to select a specific object such as with 'git-cat-file': "git cat-file blob v1.3.3:refs.c". +. at-open-brace `@{` is used as a notation to access a reflog entry. + With the `--branch` option, it expands a branch name shorthand and prints the name of the branch the shorthand refers to. diff --git a/builtin-branch.c b/builtin-branch.c index afeed68cfd..330e0c3f16 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -464,12 +464,21 @@ static void rename_branch(const char *oldname, const char *newname, int force) struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT; unsigned char sha1[20]; struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT; + int recovery = 0; if (!oldname) die("cannot rename the current branch while not on any."); - if (strbuf_check_branch_ref(&oldref, oldname)) - die("Invalid branch name: '%s'", oldname); + if (strbuf_check_branch_ref(&oldref, oldname)) { + /* + * Bad name --- this could be an attempt to rename a + * ref that we used to allow to be created by accident. + */ + if (resolve_ref(oldref.buf, sha1, 1, NULL)) + recovery = 1; + else + die("Invalid branch name: '%s'", oldname); + } if (strbuf_check_branch_ref(&newref, newname)) die("Invalid branch name: '%s'", newname); @@ -484,6 +493,9 @@ static void rename_branch(const char *oldname, const char *newname, int force) die("Branch rename failed"); strbuf_release(&logmsg); + if (recovery) + warning("Renamed a misnamed branch '%s' away", oldref.buf + 11); + /* no need to pass logmsg here as HEAD didn't really move */ if (!strcmp(oldname, head) && create_symref("HEAD", newref.buf, NULL)) die("Branch renamed to %s, but HEAD is not updated!", newname); diff --git a/refs.c b/refs.c index 8d3c502a15..e355489e51 100644 --- a/refs.c +++ b/refs.c @@ -693,7 +693,7 @@ static inline int bad_ref_char(int ch) int check_ref_format(const char *ref) { - int ch, level, bad_type; + int ch, level, bad_type, last; int ret = CHECK_REF_FORMAT_OK; const char *cp = ref; @@ -717,19 +717,24 @@ int check_ref_format(const char *ref) return CHECK_REF_FORMAT_ERROR; } + last = ch; /* scan the rest of the path component */ while ((ch = *cp++) != 0) { bad_type = bad_ref_char(ch); - if (bad_type) { + if (bad_type) return CHECK_REF_FORMAT_ERROR; - } if (ch == '/') break; - if (ch == '.' && *cp == '.') + if (last == '.' && ch == '.') return CHECK_REF_FORMAT_ERROR; + if (last == '@' && ch == '{') + return CHECK_REF_FORMAT_ERROR; + last = ch; } level++; if (!ch) { + if (ref <= cp - 2 && cp[-2] == '.') + return CHECK_REF_FORMAT_ERROR; if (level < 2) return CHECK_REF_FORMAT_ONELEVEL; return ret; From 3aea1a5a899f5ff34f12d0cd6d8e903ddcfeef3a Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Tue, 24 Mar 2009 21:43:02 +0100 Subject: [PATCH 280/654] MinGW: Quote arguments for subprocesses that contain a single-quote Before a process can be spawned by mingw_spawnve, arguments must be surrounded by double-quotes if special characters are present. This is necessary because the startup code of the spawned process will expand arguments that look like glob patterns. "Normal" Windows command line utilities expand only * and ?, but MSYS programs, including bash, are different: They also expand braces, and this has already been taken care of by compat/mingw.c:quote_arg(). But MSYS programs also treat single-quotes in a special way: Arguments between single-quotes are spliced together (with spaces) into a word. With this patch this treatment is avoided by quoting arguments that contain single-quotes. This lets t4252 pass on Windows. Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 171fa85e4a..2839d9df6e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -457,7 +457,7 @@ static const char *quote_arg(const char *arg) const char *p = arg; if (!*p) force_quotes = 1; while (*p) { - if (isspace(*p) || *p == '*' || *p == '?' || *p == '{') + if (isspace(*p) || *p == '*' || *p == '?' || *p == '{' || *p == '\'') force_quotes = 1; else if (*p == '"') n++; From b59f091d803c2842bc7e51595551c04adde8ce82 Mon Sep 17 00:00:00 2001 From: Sam Hocevar <sam@zoy.org> Date: Wed, 25 Mar 2009 00:15:38 +0100 Subject: [PATCH 281/654] git-gui: various French translation fixes Mostly grammar, spelling and typography fixes, but also a few wording enhancements here and there. Signed-off-by: Sam Hocevar <sam@zoy.org> Acked-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- po/fr.po | 192 +++++++++++++++++++++++++++---------------------------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/po/fr.po b/po/fr.po index 45773ab3d8..a56aad7668 100644 --- a/po/fr.po +++ b/po/fr.po @@ -62,7 +62,7 @@ msgstr "" "\n" "%s nécessite au moins Git 1.5.0.\n" "\n" -"Peut'on considérer que '%s' est en version 1.5.0 ?\n" +"Peut-on considérer que '%s' est en version 1.5.0 ?\n" #: git-gui.sh:1062 msgid "Git directory not found:" @@ -82,7 +82,7 @@ msgstr "Aucun répertoire de travail" #: git-gui.sh:1247 lib/checkout_op.tcl:305 msgid "Refreshing file status..." -msgstr "Rafraichissement du status des fichiers..." +msgstr "Rafraîchissement du statut des fichiers..." #: git-gui.sh:1303 msgid "Scanning for modified files ..." @@ -163,7 +163,7 @@ msgstr "Dépôt" #: git-gui.sh:2281 msgid "Edit" -msgstr "Edition" +msgstr "Édition" #: git-gui.sh:2283 lib/choose_rev.tcl:561 msgid "Branch" @@ -199,7 +199,7 @@ msgstr "Naviguer dans la branche..." #: git-gui.sh:2316 msgid "Visualize Current Branch's History" -msgstr "Visualiser historique branche courante" +msgstr "Visualiser l'historique de la branche courante" #: git-gui.sh:2320 msgid "Visualize All Branch History" @@ -208,12 +208,12 @@ msgstr "Voir l'historique de toutes les branches" #: git-gui.sh:2327 #, tcl-format msgid "Browse %s's Files" -msgstr "Naviguer l'arborescence de %s" +msgstr "Parcourir l'arborescence de %s" #: git-gui.sh:2329 #, tcl-format msgid "Visualize %s's History" -msgstr "Voir l'historique de la branche: %s" +msgstr "Voir l'historique de la branche : %s" #: git-gui.sh:2334 lib/database.tcl:27 lib/database.tcl:67 msgid "Database Statistics" @@ -230,7 +230,7 @@ msgstr "Vérifier le dépôt" #: git-gui.sh:2347 git-gui.sh:2351 git-gui.sh:2355 lib/shortcut.tcl:7 #: lib/shortcut.tcl:39 lib/shortcut.tcl:71 msgid "Create Desktop Icon" -msgstr "Créer icône sur bureau" +msgstr "Créer une icône sur le bureau" #: git-gui.sh:2363 lib/choose_repository.tcl:183 lib/choose_repository.tcl:191 msgid "Quit" @@ -320,7 +320,7 @@ msgstr "Désindexer" #: git-gui.sh:2484 lib/index.tcl:410 msgid "Revert Changes" -msgstr "Annuler les modifications (revert)" +msgstr "Annuler les modifications" #: git-gui.sh:2491 git-gui.sh:3069 msgid "Show Less Context" @@ -382,7 +382,7 @@ msgstr "Documentation en ligne" #: git-gui.sh:2614 lib/choose_repository.tcl:47 lib/choose_repository.tcl:56 msgid "Show SSH Key" -msgstr "Montrer clé SSH" +msgstr "Montrer la clé SSH" #: git-gui.sh:2707 #, tcl-format @@ -445,7 +445,7 @@ msgstr "Fichier :" #: git-gui.sh:3078 msgid "Refresh" -msgstr "Rafraichir" +msgstr "Rafraîchir" #: git-gui.sh:3099 msgid "Decrease Font Size" @@ -457,7 +457,7 @@ msgstr "Agrandir la police" #: git-gui.sh:3111 lib/blame.tcl:281 msgid "Encoding" -msgstr "Encodage" +msgstr "Codage des caractères" #: git-gui.sh:3122 msgid "Apply/Reverse Hunk" @@ -469,7 +469,7 @@ msgstr "Appliquer/Inverser la ligne" #: git-gui.sh:3137 msgid "Run Merge Tool" -msgstr "Lancer outil de merge" +msgstr "Lancer l'outil de fusion" #: git-gui.sh:3142 msgid "Use Remote Version" @@ -527,7 +527,7 @@ msgid "" "Tcl binary distributed by Cygwin." msgstr "" "\n" -"Ceci est du à un problème connu avec\n" +"Ceci est dû à un problème connu avec\n" "le binaire Tcl distribué par Cygwin." #: git-gui.sh:3336 @@ -630,11 +630,11 @@ msgstr "Fichier original :" #: lib/blame.tcl:1021 msgid "Cannot find HEAD commit:" -msgstr "Impossible de trouver le commit HEAD:" +msgstr "Impossible de trouver le commit HEAD :" #: lib/blame.tcl:1076 msgid "Cannot find parent commit:" -msgstr "Impossible de trouver le commit parent:" +msgstr "Impossible de trouver le commit parent :" #: lib/blame.tcl:1091 msgid "Unable to display parent" @@ -646,7 +646,7 @@ msgstr "Erreur lors du chargement des différences :" #: lib/blame.tcl:1232 msgid "Originally By:" -msgstr "A l'origine par :" +msgstr "À l'origine par :" #: lib/blame.tcl:1238 msgid "In File:" @@ -691,11 +691,11 @@ msgstr "Détacher de la branche locale" #: lib/branch_create.tcl:22 msgid "Create Branch" -msgstr "Créer branche" +msgstr "Créer une branche" #: lib/branch_create.tcl:27 msgid "Create New Branch" -msgstr "Créer nouvelle branche" +msgstr "Créer une nouvelle branche" #: lib/branch_create.tcl:31 lib/choose_repository.tcl:377 msgid "Create" @@ -719,7 +719,7 @@ msgstr "Révision initiale" #: lib/branch_create.tcl:72 msgid "Update Existing Branch:" -msgstr "Mettre à jour branche existante :" +msgstr "Mettre à jour une branche existante :" #: lib/branch_create.tcl:75 msgid "No" @@ -727,7 +727,7 @@ msgstr "Non" #: lib/branch_create.tcl:80 msgid "Fast Forward Only" -msgstr "Mise-à-jour rectiligne seulement (fast-forward)" +msgstr "Mise à jour rectiligne seulement (fast-forward)" #: lib/branch_create.tcl:85 lib/checkout_op.tcl:536 msgid "Reset" @@ -769,7 +769,7 @@ msgstr "Branches locales" #: lib/branch_delete.tcl:52 msgid "Delete Only If Merged Into" -msgstr "Supprimer seulement si fusionnée dans:" +msgstr "Supprimer seulement si fusionnée dans :" #: lib/branch_delete.tcl:54 msgid "Always (Do not perform merge test.)" @@ -786,7 +786,7 @@ msgid "" "\n" " Delete the selected branches?" msgstr "" -"Récupérer des branches supprimées est difficile.\n" +"Il est difficile de récupérer des branches supprimées.\n" "\n" "Supprimer les branches sélectionnées ?" @@ -796,7 +796,7 @@ msgid "" "Failed to delete branches:\n" "%s" msgstr "" -"La suppression des branches suivantes a échouée :\n" +"La suppression des branches suivantes a échoué :\n" "%s" #: lib/branch_rename.tcl:14 lib/branch_rename.tcl:22 @@ -902,11 +902,11 @@ msgstr "La stratégie de fusion '%s' n'est pas supportée." #: lib/checkout_op.tcl:261 #, tcl-format msgid "Failed to update '%s'." -msgstr "La mise à jour de '%s' a échouée." +msgstr "La mise à jour de '%s' a échoué." #: lib/checkout_op.tcl:273 msgid "Staging area (index) is already locked." -msgstr "L'index (staging area) est déjà vérouillé" +msgstr "L'index (staging area) est déjà verrouillé." #: lib/checkout_op.tcl:288 msgid "" @@ -918,7 +918,7 @@ msgid "" "The rescan will be automatically started now.\n" msgstr "" "L'état lors de la dernière synchronisation ne correspond plus à l'état du " -"dépôt\n" +"dépôt.\n" "\n" "Un autre programme Git a modifié ce dépôt depuis la dernière " "synchronisation. Une resynchronisation doit être effectuée avant de pouvoir " @@ -956,9 +956,9 @@ msgid "" "If you wanted to be on a branch, create one now starting from 'This Detached " "Checkout'." msgstr "" -"Vous n'êtes plus ur une branche locale.\n" +"Vous n'êtes plus sur une branche locale.\n" "\n" -"Si vous vouliez être sur une branche, créez en une maintenant en partant de " +"Si vous vouliez être sur une branche, créez-en une maintenant en partant de " "'Cet emprunt détaché'." #: lib/checkout_op.tcl:468 lib/checkout_op.tcl:472 @@ -1000,7 +1000,7 @@ msgstr "" "mis à jour avec succès, mais la mise à jour d'un fichier interne à Git a " "échouée.\n" "\n" -"Cela n'aurait pas du se produire. %s va abandonner et se terminer." +"Cela n'aurait pas dû se produire. %s va abandonner et se terminer." #: lib/choose_font.tcl:39 msgid "Select" @@ -1023,8 +1023,8 @@ msgid "" "This is example text.\n" "If you like this text, it can be your font." msgstr "" -"C'est un texte d'exemple.\n" -"Si vous aimez ce texte, vous pouvez choisir cette police" +"Ceci est un texte d'exemple.\n" +"Si vous aimez ce texte, vous pouvez choisir cette police." #: lib/choose_repository.tcl:28 msgid "Git Gui" @@ -1040,7 +1040,7 @@ msgstr "Nouveau..." #: lib/choose_repository.tcl:100 lib/choose_repository.tcl:465 msgid "Clone Existing Repository" -msgstr "Cloner dépôt existant" +msgstr "Cloner un dépôt existant" #: lib/choose_repository.tcl:106 msgid "Clone..." @@ -1048,7 +1048,7 @@ msgstr "Cloner..." #: lib/choose_repository.tcl:113 lib/choose_repository.tcl:983 msgid "Open Existing Repository" -msgstr "Ouvrir dépôt existant" +msgstr "Ouvrir un dépôt existant" #: lib/choose_repository.tcl:119 msgid "Open..." @@ -1056,17 +1056,17 @@ msgstr "Ouvrir..." #: lib/choose_repository.tcl:132 msgid "Recent Repositories" -msgstr "Dépôt récemment utilisés" +msgstr "Dépôts récemment utilisés" #: lib/choose_repository.tcl:138 msgid "Open Recent Repository:" -msgstr "Ouvrir dépôt récent :" +msgstr "Ouvrir un dépôt récent :" #: lib/choose_repository.tcl:302 lib/choose_repository.tcl:309 #: lib/choose_repository.tcl:316 #, tcl-format msgid "Failed to create repository %s:" -msgstr "La création du dépôt %s a échouée :" +msgstr "La création du dépôt %s a échoué :" #: lib/choose_repository.tcl:387 msgid "Directory:" @@ -1093,11 +1093,11 @@ msgstr "Cloner" #: lib/choose_repository.tcl:473 msgid "Source Location:" -msgstr "Emplacement source:" +msgstr "Emplacement source :" #: lib/choose_repository.tcl:484 msgid "Target Directory:" -msgstr "Répertoire cible:" +msgstr "Répertoire cible :" #: lib/choose_repository.tcl:496 msgid "Clone Type:" @@ -1137,7 +1137,7 @@ msgstr "L'emplacement %s existe déjà." #: lib/choose_repository.tcl:622 msgid "Failed to configure origin" -msgstr "La configuration de l'origine a échouée." +msgstr "La configuration de l'origine a échoué." #: lib/choose_repository.tcl:634 msgid "Counting objects" @@ -1242,7 +1242,7 @@ msgstr "fichiers" #: lib/choose_repository.tcl:962 msgid "Initial file checkout failed." -msgstr "Chargement initial du fichier échoué." +msgstr "Le chargement initial du fichier a échoué." #: lib/choose_repository.tcl:978 msgid "Open" @@ -1284,7 +1284,7 @@ msgstr "Révision invalide : %s" #: lib/choose_rev.tcl:338 msgid "No revision selected." -msgstr "Pas de révision selectionnée." +msgstr "Pas de révision sélectionnée." #: lib/choose_rev.tcl:346 msgid "Revision expression is empty." @@ -1292,7 +1292,7 @@ msgstr "L'expression de révision est vide." #: lib/choose_rev.tcl:531 msgid "Updated" -msgstr "Mise-à-jour:" +msgstr "Mise à jour:" #: lib/choose_rev.tcl:559 msgid "URL" @@ -1320,8 +1320,8 @@ msgid "" msgstr "" "Impossible de corriger pendant une fusion.\n" "\n" -"Vous êtes actuellement au milieu d'une fusion qui n'a pas été completement " -"terminée. Vous ne pouvez pas corriger le commit précédant sauf si vous " +"Vous êtes actuellement au milieu d'une fusion qui n'a pas été complètement " +"terminée. Vous ne pouvez pas corriger le commit précédent sauf si vous " "abandonnez la fusion courante.\n" #: lib/commit.tcl:49 @@ -1409,7 +1409,7 @@ msgstr "" #: lib/commit.tcl:211 #, tcl-format msgid "warning: Tcl does not support encoding '%s'." -msgstr "attention : Tcl ne supporte pas l'encodage '%s'." +msgstr "attention : Tcl ne supporte pas le codage '%s'." #: lib/commit.tcl:227 msgid "Calling pre-commit hook..." @@ -1469,12 +1469,12 @@ msgstr "commit-tree a échoué :" #: lib/commit.tcl:373 msgid "update-ref failed:" -msgstr "update-ref a échoué" +msgstr "update-ref a échoué :" #: lib/commit.tcl:461 #, tcl-format msgid "Created commit %s: %s" -msgstr "Commit créé %s : %s" +msgstr "Commit %s créé : %s" #: lib/console.tcl:59 msgid "Working... please wait..." @@ -1581,24 +1581,24 @@ msgid "" "LOCAL: deleted\n" "REMOTE:\n" msgstr "" -"LOCAL: supprimé\n" -"DISTANT:\n" +"LOCAL : supprimé\n" +"DISTANT :\n" #: lib/diff.tcl:125 msgid "" "REMOTE: deleted\n" "LOCAL:\n" msgstr "" -"DISTANT: supprimé\n" -"LOCAL:\n" +"DISTANT : supprimé\n" +"LOCAL :\n" #: lib/diff.tcl:132 msgid "LOCAL:\n" -msgstr "LOCAL:\n" +msgstr "LOCAL :\n" #: lib/diff.tcl:135 msgid "REMOTE:\n" -msgstr "DISTANT:\n" +msgstr "DISTANT :\n" #: lib/diff.tcl:197 lib/diff.tcl:296 #, tcl-format @@ -1624,7 +1624,7 @@ msgid "" "* Showing only first %d bytes.\n" msgstr "" "* Le fichier non suivi fait %d octets.\n" -"* On montre seulement les premiers %d octets.\n" +"* Seuls les %d premiers octets sont montrés.\n" #: lib/diff.tcl:228 #, tcl-format @@ -1635,7 +1635,7 @@ msgid "" msgstr "" "\n" "* Fichier suivi raccourcis ici de %s.\n" -"* Pour voir le fichier entier, utiliser un éditeur externe.\n" +"* Pour voir le fichier entier, utilisez un éditeur externe.\n" #: lib/diff.tcl:436 msgid "Failed to unstage selected hunk." @@ -1680,7 +1680,7 @@ msgstr "Vous devez corriger les erreurs suivantes avant de pouvoir commiter." #: lib/index.tcl:6 msgid "Unable to unlock the index." -msgstr "Impossible de dévérouiller l'index." +msgstr "Impossible de déverrouiller l'index." #: lib/index.tcl:15 msgid "Index Error" @@ -1700,12 +1700,12 @@ msgstr "Continuer" #: lib/index.tcl:31 msgid "Unlock Index" -msgstr "Déverouiller l'index" +msgstr "Déverrouiller l'index" #: lib/index.tcl:287 #, tcl-format msgid "Unstaging %s from commit" -msgstr "Désindexation de: %s" +msgstr "Désindexation de : %s" #: lib/index.tcl:326 msgid "Ready to commit." @@ -1804,11 +1804,11 @@ msgid "" msgstr "" "Vous êtes au milieu d'une modification.\n" "\n" -"Le fichier %s est modifié.\n" +"Le fichier %s a été modifié.\n" "\n" "Vous devriez terminer le commit courant avant de lancer une fusion. En " "faisait comme cela, vous éviterez de devoir éventuellement abandonner une " -"fusion ayant échouée.\n" +"fusion ayant échoué.\n" #: lib/merge.tcl:107 #, tcl-format @@ -1826,7 +1826,7 @@ msgstr "La fusion s'est faite avec succès." #: lib/merge.tcl:133 msgid "Merge failed. Conflict resolution is required." -msgstr "La fusion a echouée. Il est nécessaire de résoudre les conflicts." +msgstr "La fusion a echoué. Il est nécessaire de résoudre les conflits." #: lib/merge.tcl:158 #, tcl-format @@ -1914,16 +1914,16 @@ msgid "" "\n" "This operation can be undone only by restarting the merge." msgstr "" -"Noter que le diff ne montre que les modifications en conflict.\n" +"Noter que le diff ne montre que les modifications en conflit.\n" "\n" "%s sera écrasé.\n" "\n" -"Cette opération ne peut être défaite qu'en relançant la fusion." +"Cette opération ne peut être inversée qu'en relançant la fusion." #: lib/mergetool.tcl:45 #, tcl-format msgid "File %s seems to have unresolved conflicts, still stage?" -msgstr "Le fichier %s semble avoir des conflicts non résolus, indéxer quand même ?" +msgstr "Le fichier %s semble avoir des conflits non résolus, indexer quand même ?" #: lib/mergetool.tcl:60 #, tcl-format @@ -1932,11 +1932,11 @@ msgstr "Ajouter une résolution pour %s" #: lib/mergetool.tcl:141 msgid "Cannot resolve deletion or link conflicts using a tool" -msgstr "Impossible de résoudre la suppression ou de relier des conflicts en utilisant un outil" +msgstr "Impossible de résoudre la suppression ou de relier des conflits en utilisant un outil" #: lib/mergetool.tcl:146 msgid "Conflict file does not exist" -msgstr "Le fichier en conflict n'existe pas." +msgstr "Le fichier en conflit n'existe pas." #: lib/mergetool.tcl:264 #, tcl-format @@ -1958,7 +1958,7 @@ msgid "" "Error retrieving versions:\n" "%s" msgstr "" -"Erreur lors de la récupération des versions:\n" +"Erreur lors de la récupération des versions :\n" "%s" #: lib/mergetool.tcl:343 @@ -1968,7 +1968,7 @@ msgid "" "\n" "%s" msgstr "" -"Impossible de lancer l'outil de fusion:\n" +"Impossible de lancer l'outil de fusion :\n" "\n" "%s" @@ -1983,12 +1983,12 @@ msgstr "L'outil de fusion a échoué." #: lib/option.tcl:11 #, tcl-format msgid "Invalid global encoding '%s'" -msgstr "Encodage global invalide '%s'" +msgstr "Codage global '%s' invalide" #: lib/option.tcl:19 #, tcl-format msgid "Invalid repo encoding '%s'" -msgstr "Encodage de dépôt invalide '%s'" +msgstr "Codage de dépôt '%s' invalide" #: lib/option.tcl:117 msgid "Restore Defaults" @@ -2001,7 +2001,7 @@ msgstr "Sauvegarder" #: lib/option.tcl:131 #, tcl-format msgid "%s Repository" -msgstr "Dépôt: %s" +msgstr "Dépôt : %s" #: lib/option.tcl:132 msgid "Global (All Repositories)" @@ -2069,7 +2069,7 @@ msgstr "Nouveau modèle de nom de branche" #: lib/option.tcl:155 msgid "Default File Contents Encoding" -msgstr "Encodage du contenu des fichiers par défaut" +msgstr "Codage du contenu des fichiers par défaut" #: lib/option.tcl:203 msgid "Change" @@ -2098,11 +2098,11 @@ msgstr "Préférences" #: lib/option.tcl:314 msgid "Failed to completely save options:" -msgstr "La sauvegarde complète des options a échouée :" +msgstr "La sauvegarde complète des options a échoué :" #: lib/remote.tcl:163 msgid "Remove Remote" -msgstr "Supprimer dépôt distant" +msgstr "Supprimer un dépôt distant" #: lib/remote.tcl:168 msgid "Prune from" @@ -2118,11 +2118,11 @@ msgstr "Pousser vers" #: lib/remote_add.tcl:19 msgid "Add Remote" -msgstr "Ajouter dépôt distant" +msgstr "Ajouter un dépôt distant" #: lib/remote_add.tcl:24 msgid "Add New Remote" -msgstr "Ajouter nouveau dépôt distant" +msgstr "Ajouter un nouveau dépôt distant" #: lib/remote_add.tcl:28 lib/tools_dlg.tcl:36 msgid "Add" @@ -2134,7 +2134,7 @@ msgstr "Détails des dépôts distants" #: lib/remote_add.tcl:50 msgid "Location:" -msgstr "Emplacement:" +msgstr "Emplacement :" #: lib/remote_add.tcl:62 msgid "Further Action" @@ -2146,7 +2146,7 @@ msgstr "Récupérer immédiatement" #: lib/remote_add.tcl:71 msgid "Initialize Remote Repository and Push" -msgstr "Initialiser dépôt distant et pousser" +msgstr "Initialiser un dépôt distant et pousser" #: lib/remote_add.tcl:77 msgid "Do Nothing Else Now" @@ -2193,7 +2193,7 @@ msgstr "Mise en place de %s (à %s)" #: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34 msgid "Delete Branch Remotely" -msgstr "Supprimer branche à distance" +msgstr "Supprimer une branche à distance" #: lib/remote_branch_delete.tcl:47 msgid "From Repository" @@ -2244,8 +2244,8 @@ msgid "" "One or more of the merge tests failed because you have not fetched the " "necessary commits. Try fetching from %s first." msgstr "" -"Une ou plusieurs des tests de fusion ont échoués parce que vous n'avez pas " -"récupéré les commits nécessaires. Essayez de récupéré à partir de %s d'abord." +"Un ou plusieurs des tests de fusion ont échoué parce que vous n'avez pas " +"récupéré les commits nécessaires. Essayez de récupérer à partir de %s d'abord." #: lib/remote_branch_delete.tcl:207 msgid "Please select one or more branches to delete." @@ -2257,14 +2257,14 @@ msgid "" "\n" "Delete the selected branches?" msgstr "" -"Récupérer des branches supprimées est difficile.\n" +"Il est difficile de récupérer des branches supprimées.\n" "\n" -"Souhaitez vous supprimer les branches sélectionnées ?" +"Supprimer les branches sélectionnées ?" #: lib/remote_branch_delete.tcl:226 #, tcl-format msgid "Deleting branches from %s" -msgstr "Supprimer les branches de %s" +msgstr "Suppression des branches de %s" #: lib/remote_branch_delete.tcl:286 msgid "No repository selected." @@ -2285,7 +2285,7 @@ msgstr "Suivant" #: lib/search.tcl:24 msgid "Prev" -msgstr "Précédant" +msgstr "Précédent" #: lib/search.tcl:25 msgid "Case-Sensitive" @@ -2293,7 +2293,7 @@ msgstr "Sensible à la casse" #: lib/shortcut.tcl:20 lib/shortcut.tcl:61 msgid "Cannot write shortcut:" -msgstr "Impossible d'écrire le raccourcis :" +msgstr "Impossible d'écrire le raccourci :" #: lib/shortcut.tcl:136 msgid "Cannot write icon:" @@ -2318,7 +2318,7 @@ msgstr "Réinitialisation du dictionnaire à %s." #: lib/spellcheck.tcl:73 msgid "Spell checker silently failed on startup" -msgstr "La vérification d'orthographe a échouée silentieusement au démarrage" +msgstr "La vérification d'orthographe a échoué silencieusement au démarrage" #: lib/spellcheck.tcl:80 msgid "Unrecognized spell checker" @@ -2351,11 +2351,11 @@ msgstr "Générer une clé" #: lib/sshkey.tcl:56 msgid "Copy To Clipboard" -msgstr "Copier dans le presse papier" +msgstr "Copier dans le presse-papier" #: lib/sshkey.tcl:70 msgid "Your OpenSSH Public Key" -msgstr "Votre clé publique Open SSH" +msgstr "Votre clé publique OpenSSH" #: lib/sshkey.tcl:78 msgid "Generating..." @@ -2368,7 +2368,7 @@ msgid "" "\n" "%s" msgstr "" -"Impossible de lancer ssh-keygen:\n" +"Impossible de lancer ssh-keygen :\n" "\n" "%s" @@ -2398,7 +2398,7 @@ msgstr "Lancer %s nécessite qu'un fichier soit sélectionné." #: lib/tools.tcl:90 #, tcl-format msgid "Are you sure you want to run %s?" -msgstr "Êtes vous sûr de vouloir lancer %s ?" +msgstr "Êtes-vous sûr de vouloir lancer %s ?" #: lib/tools.tcl:110 #, tcl-format @@ -2422,11 +2422,11 @@ msgstr "L'outil a échoué : %s" #: lib/tools_dlg.tcl:22 msgid "Add Tool" -msgstr "Ajouter outil" +msgstr "Ajouter un outil" #: lib/tools_dlg.tcl:28 msgid "Add New Tool Command" -msgstr "Ajouter nouvelle commande d'outil" +msgstr "Ajouter une nouvelle commande d'outil" #: lib/tools_dlg.tcl:33 msgid "Add globally" @@ -2438,7 +2438,7 @@ msgstr "Détails sur l'outil" #: lib/tools_dlg.tcl:48 msgid "Use '/' separators to create a submenu tree:" -msgstr "Utiliser les séparateurs '/' pour créer un arbre de sous menus :" +msgstr "Utiliser les séparateurs '/' pour créer un arbre de sous-menus :" #: lib/tools_dlg.tcl:61 msgid "Command:" @@ -2462,7 +2462,7 @@ msgstr "Ne pas montrer la fenêtre de sortie des commandes" #: lib/tools_dlg.tcl:97 msgid "Run only if a diff is selected ($FILENAME not empty)" -msgstr "Lancer seulement si un diff est selectionné ($FILENAME non vide)" +msgstr "Lancer seulement si un diff est sélectionné ($FILENAME non vide)" #: lib/tools_dlg.tcl:121 msgid "Please supply a name for the tool." @@ -2479,7 +2479,7 @@ msgid "" "Could not add tool:\n" "%s" msgstr "" -"Impossible d'ajouter l'outil:\n" +"Impossible d'ajouter l'outil :\n" "%s" #: lib/tools_dlg.tcl:190 From 966d0778db2e3b11f5fffa2312770ef534263058 Mon Sep 17 00:00:00 2001 From: Sam Hocevar <sam@zoy.org> Date: Tue, 24 Mar 2009 00:42:24 +0100 Subject: [PATCH 282/654] git-gui: minor spelling fix and string factorisation. Properly spell "successful" and slightly rewrite a couple of strings that actually say the same thing in order to reduce translation work. Update .pot and .po files accordingly since no new translation is required. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- lib/branch_delete.tcl | 4 ++-- lib/remote_branch_delete.tcl | 4 +--- lib/tools.tcl | 2 +- po/de.po | 12 +----------- po/fr.po | 12 +----------- po/git-gui.pot | 9 +-------- po/hu.po | 12 +----------- po/it.po | 12 +----------- po/ja.po | 12 +----------- po/nb.po | 12 +----------- po/ru.po | 10 ---------- po/sv.po | 12 +----------- po/zh_cn.po | 10 ---------- 13 files changed, 12 insertions(+), 111 deletions(-) diff --git a/lib/branch_delete.tcl b/lib/branch_delete.tcl index ef1930b491..20d5e42307 100644 --- a/lib/branch_delete.tcl +++ b/lib/branch_delete.tcl @@ -51,7 +51,7 @@ constructor dialog {} { $w.check \ [mc "Delete Only If Merged Into"] \ ] - $w_check none [mc "Always (Do not perform merge test.)"] + $w_check none [mc "Always (Do not perform merge checks)"] pack $w.check -anchor nw -fill x -pady 5 -padx 5 foreach h [load_all_heads] { @@ -112,7 +112,7 @@ method _delete {} { } if {$to_delete eq {}} return if {$check_cmt eq {}} { - set msg [mc "Recovering deleted branches is difficult. \n\n Delete the selected branches?"] + set msg [mc "Recovering deleted branches is difficult.\n\nDelete the selected branches?"] if {[tk_messageBox \ -icon warning \ -type yesno \ diff --git a/lib/remote_branch_delete.tcl b/lib/remote_branch_delete.tcl index 89eb0f70f2..4e02fc0d39 100644 --- a/lib/remote_branch_delete.tcl +++ b/lib/remote_branch_delete.tcl @@ -213,9 +213,7 @@ method _delete {} { -type yesno \ -title [wm title $w] \ -parent $w \ - -message [mc "Recovering deleted branches is difficult. - -Delete the selected branches?"]] ne yes} { + -message [mc "Recovering deleted branches is difficult.\n\nDelete the selected branches?"]] ne yes} { return } diff --git a/lib/tools.tcl b/lib/tools.tcl index 6ae63b6c7c..95e6e5553e 100644 --- a/lib/tools.tcl +++ b/lib/tools.tcl @@ -146,7 +146,7 @@ proc tools_complete {fullname w {ok 1}} { } if {$ok} { - set msg [mc "Tool completed succesfully: %s" $fullname] + set msg [mc "Tool completed successfully: %s" $fullname] } else { set msg [mc "Tool failed: %s" $fullname] } diff --git a/po/de.po b/po/de.po index a6f730b4eb..51abb50bb6 100644 --- a/po/de.po +++ b/po/de.po @@ -773,16 +773,6 @@ msgstr "Immer (ohne Zusammenführungstest)" msgid "The following branches are not completely merged into %s:" msgstr "Folgende Zweige sind noch nicht mit »%s« zusammengeführt:" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" -"Gelöschte Zweige können nur mit größerem Aufwand wiederhergestellt werden.\n" -"\n" -"Gewählte Zweige jetzt löschen?" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" @@ -2506,7 +2496,7 @@ msgstr "Starten: %s" #: lib/tools.tcl:149 #, tcl-format -msgid "Tool completed succesfully: %s" +msgid "Tool completed successfully: %s" msgstr "Werkzeug erfolgreich abgeschlossen: %s" #: lib/tools.tcl:151 diff --git a/po/fr.po b/po/fr.po index a56aad7668..a944ace6ce 100644 --- a/po/fr.po +++ b/po/fr.po @@ -780,16 +780,6 @@ msgstr "Toujours (Ne pas faire de test de fusion.)" msgid "The following branches are not completely merged into %s:" msgstr "Les branches suivantes ne sont pas complètement fusionnées dans %s :" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" -"Il est difficile de récupérer des branches supprimées.\n" -"\n" -"Supprimer les branches sélectionnées ?" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" @@ -2412,7 +2402,7 @@ msgstr "Lancement de : %s" #: lib/tools.tcl:149 #, tcl-format -msgid "Tool completed succesfully: %s" +msgid "Tool completed successfully: %s" msgstr "L'outil a terminé avec succès : %s" #: lib/tools.tcl:151 diff --git a/po/git-gui.pot b/po/git-gui.pot index 15aea0dc64..53b7d3634d 100644 --- a/po/git-gui.pot +++ b/po/git-gui.pot @@ -753,13 +753,6 @@ msgstr "" msgid "The following branches are not completely merged into %s:" msgstr "" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" @@ -2220,7 +2213,7 @@ msgstr "" #: lib/tools.tcl:149 #, tcl-format -msgid "Tool completed succesfully: %s" +msgid "Tool completed successfully: %s" msgstr "" #: lib/tools.tcl:151 diff --git a/po/hu.po b/po/hu.po index f761b64152..0f87bc1cbe 100644 --- a/po/hu.po +++ b/po/hu.po @@ -776,16 +776,6 @@ msgstr "Mindig (Ne legyen merge teszt.)" msgid "The following branches are not completely merged into %s:" msgstr "A következő branchek nem teljesen lettek merge-ölve ebbe: %s:" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" -"A törölt branchek visszaállítása bonyolult. \n" -"\n" -" Biztosan törli a kiválasztott brancheket?" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" @@ -2399,7 +2389,7 @@ msgstr "Futtatás: %s..." #: lib/tools.tcl:149 #, tcl-format -msgid "Tool completed succesfully: %s" +msgid "Tool completed successfully: %s" msgstr "Az eszköz sikeresen befejeződött: %s" #: lib/tools.tcl:151 diff --git a/po/it.po b/po/it.po index 294e595887..762632c22f 100644 --- a/po/it.po +++ b/po/it.po @@ -778,16 +778,6 @@ msgstr "Sempre (Non effettuare verifiche di fusione)." msgid "The following branches are not completely merged into %s:" msgstr "I rami seguenti non sono stati fusi completamente in %s:" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" -"Ricomporre rami cancellati può essere complicato. \n" -"\n" -" Eliminare i rami selezionati?" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" @@ -2418,7 +2408,7 @@ msgstr "Eseguo: %s" #: lib/tools.tcl:149 #, tcl-format -msgid "Tool completed succesfully: %s" +msgid "Tool completed successfully: %s" msgstr "Il programma esterno è terminato con successo: %s" #: lib/tools.tcl:151 diff --git a/po/ja.po b/po/ja.po index 09d60bef74..63c4695103 100644 --- a/po/ja.po +++ b/po/ja.po @@ -773,16 +773,6 @@ msgstr "無条件(マージテストしない)" msgid "The following branches are not completely merged into %s:" msgstr "以下のブランチは %s に完全にマージされていません:" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" -"ブランチを削除すると元に戻すのは困難です。 \n" -"\n" -" 選択したブランチを削除しますか?" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" @@ -2382,7 +2372,7 @@ msgstr "実行中: %s" #: lib/tools.tcl:149 #, tcl-format -msgid "Tool completed succesfully: %s" +msgid "Tool completed successfully: %s" msgstr "ツールが完了しました: %s" #: lib/tools.tcl:151 diff --git a/po/nb.po b/po/nb.po index 1c5137d84c..6de93c28c2 100644 --- a/po/nb.po +++ b/po/nb.po @@ -761,16 +761,6 @@ msgstr "Alltid (Ikke utfør sammenslåingstest.)" msgid "The following branches are not completely merged into %s:" msgstr "Følgende grener er ikke fullstendig slått sammen med %s:" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" -"Gjenoppretting av fjernede grener er vanskelig. \n" -"\n" -" Fjern valgte grener?" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" @@ -2331,7 +2321,7 @@ msgstr "Kjører: %s" #: lib/tools.tcl:149 #, tcl-format -msgid "Tool completed succesfully: %s" +msgid "Tool completed successfully: %s" msgstr "Verktøyet ble fullført med suksess: %s" #: lib/tools.tcl:151 diff --git a/po/ru.po b/po/ru.po index db55b3e0a6..04df2aac26 100644 --- a/po/ru.po +++ b/po/ru.po @@ -661,16 +661,6 @@ msgstr "Всегда (не выполнять проверку на объеди msgid "The following branches are not completely merged into %s:" msgstr "Следующие ветви объединены с %s не полностью:" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" -"Восстанавливать удаленные ветви сложно. \n" -"\n" -" Удалить выбранные ветви?" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" diff --git a/po/sv.po b/po/sv.po index 167654c709..c1535f94e8 100644 --- a/po/sv.po +++ b/po/sv.po @@ -780,16 +780,6 @@ msgstr "Alltid (utför inte sammanslagningstest)." msgid "The following branches are not completely merged into %s:" msgstr "Följande grenar är inte till fullo sammanslagna med %s:" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" -"Det är svårt att återställa borttagna grenar.\n" -"\n" -" Ta bort valda grenar?" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" @@ -2398,7 +2388,7 @@ msgstr "Exekverar: %s" #: lib/tools.tcl:149 #, tcl-format -msgid "Tool completed succesfully: %s" +msgid "Tool completed successfully: %s" msgstr "Verktyget avslutades framgångsrikt: %s" #: lib/tools.tcl:151 diff --git a/po/zh_cn.po b/po/zh_cn.po index d2c6866671..91c1be23c2 100644 --- a/po/zh_cn.po +++ b/po/zh_cn.po @@ -676,16 +676,6 @@ msgstr "总是合并 (不作合并测试.)" msgid "The following branches are not completely merged into %s:" msgstr "下列分支没有完全被合并到 %s:" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" -"恢复被删除的分支非常困难.\n" -"\n" -"是否要删除所选分支?" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" From 3e262b95c50991de12cc5e180b72256561606a19 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" <spearce@spearce.org> Date: Tue, 24 Mar 2009 16:31:01 -0700 Subject: [PATCH 283/654] Don't permit ref/branch names to end with ".lock" We already skip over loose refs under $GIT_DIR/refs if the name ends with ".lock", so creating a branch named "foo.lock" will not appear in the output of "git branch", "git for-each-ref", nor will its commit be considered reachable by "git rev-list --all". In the latter case this is especially evil, as it may cause repository corruption when objects reachable only through such a ref are deleted by "git prune". It should be reasonably safe to deny use of ".lock" as a ref suffix. In prior versions of Git such branches would be "phantom branches"; you can create it, but you can't see it in "git branch" output. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-check-ref-format.txt | 2 ++ refs.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt index d23fd219da..9b707a7030 100644 --- a/Documentation/git-check-ref-format.txt +++ b/Documentation/git-check-ref-format.txt @@ -34,6 +34,8 @@ imposes the following rules on how refs are named: . They cannot end with a slash `/` nor a dot `.`. +. They cannot end with the sequence `.lock`. + . They cannot contain a sequence `@{`. These rules makes it easy for shell script based tools to parse diff --git a/refs.c b/refs.c index e355489e51..f3fdcbd202 100644 --- a/refs.c +++ b/refs.c @@ -676,6 +676,7 @@ int for_each_rawref(each_ref_fn fn, void *cb_data) * - it has double dots "..", or * - it has ASCII control character, "~", "^", ":" or SP, anywhere, or * - it ends with a "/". + * - it ends with ".lock" */ static inline int bad_ref_char(int ch) @@ -737,6 +738,8 @@ int check_ref_format(const char *ref) return CHECK_REF_FORMAT_ERROR; if (level < 2) return CHECK_REF_FORMAT_ONELEVEL; + if (has_extension(ref, ".lock")) + return CHECK_REF_FORMAT_ERROR; return ret; } } From 77813151f983a77f5b5954fb7cb8094198db0567 Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Mon, 23 Mar 2009 03:26:49 -0700 Subject: [PATCH 284/654] completion: add --annotate option to send-email Signed-off-by: Stephen Boyd <bebarino@gmail.com> Trivially-Acked-By: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 10e36a7b0d..8719242498 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1264,8 +1264,8 @@ _git_send_email () local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) - __gitcomp "--bcc --cc --cc-cmd --chain-reply-to --compose - --dry-run --envelope-sender --from --identity + __gitcomp "--annotate --bcc --cc --cc-cmd --chain-reply-to + --compose --dry-run --envelope-sender --from --identity --in-reply-to --no-chain-reply-to --no-signed-off-by-cc --no-suppress-from --no-thread --quiet --signed-off-by-cc --smtp-pass --smtp-server From 3f7df3a71a9cbab3c27d84f2410e7d39407f9013 Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Mon, 23 Mar 2009 03:26:50 -0700 Subject: [PATCH 285/654] completion: add --cc and --no-attachment option to format-patch Signed-off-by: Stephen Boyd <bebarino@gmail.com> Trivially-Acked-By: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 8719242498..b96458f296 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -932,13 +932,13 @@ _git_format_patch () case "$cur" in --*) __gitcomp " - --stdout --attach --thread + --stdout --attach --no-attach --thread --output-directory --numbered --start-number --numbered-files --keep-subject --signoff - --in-reply-to= + --in-reply-to= --cc= --full-index --binary --not --all --cover-letter From e1d37937ac3c15898afdb6117349a30d0eae5e64 Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Mon, 23 Mar 2009 03:26:51 -0700 Subject: [PATCH 286/654] completion: add --thread=deep/shallow to format-patch Signed-off-by: Stephen Boyd <bebarino@gmail.com> Trivially-Acked-By: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index b96458f296..1c6b0e28ef 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -930,9 +930,15 @@ _git_format_patch () { local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in + --thread=*) + __gitcomp " + deep shallow + " "" "${cur##--thread=}" + return + ;; --*) __gitcomp " - --stdout --attach --no-attach --thread + --stdout --attach --no-attach --thread --thread= --output-directory --numbered --start-number --numbered-files From 7c98213abc2a834f16646b9fe842f6e63c7ddb81 Mon Sep 17 00:00:00 2001 From: Heiko Voigt <hvoigt@hvoigt.net> Date: Mon, 23 Mar 2009 20:53:05 +0100 Subject: [PATCH 287/654] Add warning about known issues to documentation of cvsimport The described issues are compiled from the tests by Michael Haggerty and me. Because it is not apparent that these can be fixed anytime soon at least warn unwary users not to rely on the inbuilt cvsimport to much. Signed-off-by: Heiko Voigt <hvoigt@hvoigt.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-cvsimport.txt | 34 +++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt index b7a8c10b87..31237259e4 100644 --- a/Documentation/git-cvsimport.txt +++ b/Documentation/git-cvsimport.txt @@ -24,6 +24,9 @@ repository, or incrementally import into an existing one. Splitting the CVS log into patch sets is done by 'cvsps'. At least version 2.1 is required. +*WARNING:* for certain situations the import leads to incorrect results. +Please see the section <<issues,ISSUES>> for further reference. + You should *never* do any work of your own on the branches that are created by 'git-cvsimport'. By default initial import will create and populate a "master" branch from the CVS repository's main branch which you're free @@ -164,6 +167,37 @@ If '-v' is specified, the script reports what it is doing. Otherwise, success is indicated the Unix way, i.e. by simply exiting with a zero exit status. +[[issues]] +ISSUES +------ +Problems related to timestamps: + + * If timestamps of commits in the cvs repository are not stable enough + to be used for ordering commits + * If any files were ever "cvs import"ed more than once (e.g., import of + more than one vendor release) + * If the timestamp order of different files cross the revision order + within the commit matching time window + +Problems related to branches: + + * Branches on which no commits have been made are not imported + * All files from the branching point are added to a branch even if + never added in cvs + * files added to the source branch *after* a daughter branch was + created: If previously no commit was made on the daugther branch they + will erroneously be added to the daughter branch in git + +Problems related to tags: + +* Multiple tags on the same revision are not imported + +If you suspect that any of these issues may apply to the repository you +want to import consider using these alternative tools which proved to be +more stable in practise: + +* cvs2git (part of cvs2svn), `http://cvs2svn.tigris.org` +* parsecvs, `http://cgit.freedesktop.org/~keithp/parsecvs` Author ------ From 5c928c06e251b651202f94aaac56cacd3f57c484 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Wed, 25 Mar 2009 17:27:28 +0100 Subject: [PATCH 288/654] Guard a few Makefile variables against user environments Some variables are not initialized in the Makefile, but appended to. If the user has those variables in her environment, it will break the build. The variable names were found using these commands: $ s='[ \t]'; $ S='[^ \t]'; $ comm -23 \ <(sed -n "s/^$s*\($S*\)$s$s*+=.*/\1/p" < Makefile | sort | uniq) \ <(sed -n "s/^$s*\($S*\)$s$s*=.*/\1/p" < Makefile | sort | uniq) This fixes msysGit issue 216. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Makefile b/Makefile index 320c89786c..7867eaccdb 100644 --- a/Makefile +++ b/Makefile @@ -263,6 +263,18 @@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ BASIC_CFLAGS = BASIC_LDFLAGS = +# Guard against environment variables +BUILTIN_OBJS = +BUILT_INS = +COMPAT_CFLAGS = +COMPAT_OBJS = +LIB_H = +LIB_OBJS = +PROGRAMS = +SCRIPT_PERL = +SCRIPT_SH = +TEST_PROGRAMS = + SCRIPT_SH += git-am.sh SCRIPT_SH += git-bisect.sh SCRIPT_SH += git-filter-branch.sh From 80f0e53d6bdde5d9be016e5cfbb5ff7c0257a00e Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Wed, 25 Mar 2009 12:48:30 +0100 Subject: [PATCH 289/654] t7005-editor: Use $SHELL_PATH in the editor scripts The test sets up various shell scripts and uses them as commit message editors. On Windows, we need a shebang line in order to recognize the files as executable shell scripts. This adds it. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t7005-editor.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t7005-editor.sh b/t/t7005-editor.sh index 2f8404afbb..e83bc8fd89 100755 --- a/t/t7005-editor.sh +++ b/t/t7005-editor.sh @@ -7,6 +7,7 @@ test_description='GIT_EDITOR, core.editor, and stuff' for i in GIT_EDITOR core_editor EDITOR VISUAL vi do cat >e-$i.sh <<-EOF + #!$SHELL_PATH echo "Edited by $i" >"\$1" EOF chmod +x e-$i.sh From fb9a2beab2002894fb970cba4e32ebb1c41176b2 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Wed, 25 Mar 2009 13:21:15 +0100 Subject: [PATCH 290/654] t7502-commit: Skip SIGTERM test on Windows The implementation of exec on Windows is just a rough approximation of the POSIX behavior. In particular, no real process "overlay" happens (a new process is spawned instead and the parent process waits until the child terminates). In particular, the process ID cannot be taken by the exec'd process. But there is one test in t7502-commit.sh that depends on this. We have to skip it on Windows. Signed-off-by: Johannes Sixt <j6t@kdbg.org> --- t/t7502-commit.sh | 2 +- t/test-lib.sh | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh index ad42c78d7c..56cd866019 100755 --- a/t/t7502-commit.sh +++ b/t/t7502-commit.sh @@ -234,7 +234,7 @@ cat >.git/FAKE_EDITOR <<EOF # kill -TERM command added below. EOF -test_expect_success 'a SIGTERM should break locks' ' +test_expect_success EXECKEEPSPID 'a SIGTERM should break locks' ' echo >>negative && ! "$SHELL_PATH" -c '\'' echo kill -TERM $$ >> .git/FAKE_EDITOR diff --git a/t/test-lib.sh b/t/test-lib.sh index b4b626e837..572301df1b 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -689,10 +689,12 @@ case $(uname -s) in } # no POSIX permissions # backslashes in pathspec are converted to '/' + # exec does not inherit the PID ;; *) test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC + test_set_prereq EXECKEEPSPID ;; esac From b2655cdae953d619d488b69b7d49e4204e5682dc Mon Sep 17 00:00:00 2001 From: Kevin Ballard <kevin@sb.org> Date: Wed, 25 Mar 2009 13:14:03 -0700 Subject: [PATCH 291/654] builtin-push.c: Fix typo: "anythig" -> "anything" Signed-off-by: Kevin Ballard <kevin@sb.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-push.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-push.c b/builtin-push.c index 8f4fa5b09e..bbf019850e 100644 --- a/builtin-push.c +++ b/builtin-push.c @@ -73,7 +73,7 @@ static const char *warn_unconfigured_push_msg[] = { "", "You can specify what action you want to take in this case, and", "avoid seeing this message again, by configuring 'push.default' to:", - " 'nothing' : Do not push anythig", + " 'nothing' : Do not push anything", " 'matching' : Push all matching branches (default)", " 'tracking' : Push the current branch to whatever it is tracking", " 'current' : Push the current branch" From d5b0c97d138201c59b30cb759cedabb70b7bae81 Mon Sep 17 00:00:00 2001 From: Elijah Newren <newren@gmail.com> Date: Wed, 25 Mar 2009 15:51:01 -0600 Subject: [PATCH 292/654] git-filter-branch: avoid collisions with variables in eval'ed commands Avoid using simple variable names like 'i', since user commands are eval'ed and may clash with and overwrite our values. Signed-off-by: Elijah Newren <newren@gmail.com> Acked-by: Petr Baudis <pasky@suse.cz> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-filter-branch.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/git-filter-branch.sh b/git-filter-branch.sh index 20f6f51750..b90d3df3a7 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -272,10 +272,10 @@ test $commits -eq 0 && die "Found nothing to rewrite" # Rewrite the commits -i=0 +git_filter_branch__commit_count=0 while read commit parents; do - i=$(($i+1)) - printf "\rRewrite $commit ($i/$commits)" + git_filter_branch__commit_count=$(($git_filter_branch__commit_count+1)) + printf "\rRewrite $commit ($git_filter_branch__commit_count/$commits)" case "$filter_subdir" in "") From 98e1a4186acd4b71da1daae5c522cb6ac6d1d904 Mon Sep 17 00:00:00 2001 From: Elijah Newren <newren@gmail.com> Date: Wed, 25 Mar 2009 15:22:13 -0600 Subject: [PATCH 293/654] Correct missing SP characters in grammar comment at top of fast-import.c Signed-off-by: Elijah Newren <newren@gmail.com> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- fast-import.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fast-import.c b/fast-import.c index beeac0d004..db44da3e09 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1,4 +1,5 @@ /* +(See Documentation/git-fast-import.txt for maintained documentation.) Format of STDIN stream: stream ::= cmd*; @@ -18,8 +19,8 @@ Format of STDIN stream: new_commit ::= 'commit' sp ref_str lf mark? - ('author' sp name '<' email '>' when lf)? - 'committer' sp name '<' email '>' when lf + ('author' sp name sp '<' email '>' sp when lf)? + 'committer' sp name sp '<' email '>' sp when lf commit_msg ('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)? ('merge' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)* @@ -43,7 +44,7 @@ Format of STDIN stream: new_tag ::= 'tag' sp tag_str lf 'from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf - ('tagger' sp name '<' email '>' when lf)? + ('tagger' sp name sp '<' email '>' sp when lf)? tag_msg; tag_msg ::= data; From 4fa535a179e771cd5a16d5ab05e97e7bb52739ef Mon Sep 17 00:00:00 2001 From: Wincent Colaiuta <win@wincent.com> Date: Wed, 25 Mar 2009 19:23:42 +0100 Subject: [PATCH 294/654] Grammar fixes to "merge" and "patch-id" docs Signed-off-by: Wincent Colaiuta <win@wincent.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-merge.txt | 2 +- Documentation/git-patch-id.txt | 2 +- Documentation/merge-strategies.txt | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt index cc0d30fe7e..427ad9083e 100644 --- a/Documentation/git-merge.txt +++ b/Documentation/git-merge.txt @@ -41,7 +41,7 @@ include::merge-strategies.txt[] If you tried a merge which resulted in a complex conflicts and -would want to start over, you can recover with 'git-reset'. +want to start over, you can recover with 'git-reset'. CONFIGURATION ------------- diff --git a/Documentation/git-patch-id.txt b/Documentation/git-patch-id.txt index 477785e134..253fc0fc25 100644 --- a/Documentation/git-patch-id.txt +++ b/Documentation/git-patch-id.txt @@ -20,7 +20,7 @@ IOW, you can use this thing to look for likely duplicate commits. When dealing with 'git-diff-tree' output, it takes advantage of the fact that the patch is prefixed with the object name of the -commit, and outputs two 40-byte hexadecimal string. The first +commit, and outputs two 40-byte hexadecimal strings. The first string is the patch ID, and the second string is the commit ID. This can be used to make a mapping from patch ID to commit ID. diff --git a/Documentation/merge-strategies.txt b/Documentation/merge-strategies.txt index 1276f858ad..4365b7e842 100644 --- a/Documentation/merge-strategies.txt +++ b/Documentation/merge-strategies.txt @@ -3,15 +3,15 @@ MERGE STRATEGIES resolve:: This can only resolve two heads (i.e. the current branch - and another branch you pulled from) using 3-way merge + and another branch you pulled from) using a 3-way merge algorithm. It tries to carefully detect criss-cross merge ambiguities and is considered generally safe and fast. recursive:: - This can only resolve two heads using 3-way merge - algorithm. When there are more than one common - ancestors that can be used for 3-way merge, it creates a + This can only resolve two heads using a 3-way merge + algorithm. When there is more than one common + ancestor that can be used for 3-way merge, it creates a merged tree of the common ancestors and uses that as the reference tree for the 3-way merge. This has been reported to result in fewer merge conflicts without @@ -22,11 +22,11 @@ recursive:: pulling or merging one branch. octopus:: - This resolves more than two-head case, but refuses to do - complex merge that needs manual resolution. It is + This resolves cases with more than two heads, but refuses to do + a complex merge that needs manual resolution. It is primarily meant to be used for bundling topic branch heads together. This is the default merge strategy when - pulling or merging more than one branches. + pulling or merging more than one branch. ours:: This resolves any number of heads, but the result of the From ebeec7dbc564cb83edd8faee87890c47b6f0da43 Mon Sep 17 00:00:00 2001 From: Elijah Newren <newren@gmail.com> Date: Wed, 25 Mar 2009 17:53:23 -0600 Subject: [PATCH 295/654] fast-export: Avoid dropping files from commits When exporting a subset of commits on a branch that do not go back to a root commit (e.g. master~2..master), we still want each exported commit to have the same files in the exported tree as in the original tree. Previously, when given such a range, we would omit master~2 as a parent of master~1, but we would still diff against master~2 when selecting the list of files to include in master~1. This would result in only files that had changed in the given range showing up in the resulting export. In such cases, we should diff master~1 against the root instead (i.e. use diff_root_tree_sha1 instead of diff_tree_sha1). There's a special case to consider here: incremental exports (i.e. exports where the --import-marks flag is specified). If master~2 is an imported mark, then we still want to diff master~1 against master~2 when selecting the list of files to include. We can handle all cases, including the special case, by just checking whether master~2 corresponds to a known object mark when deciding what to diff against. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-fast-export.c | 3 ++- t/t9301-fast-export.sh | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/builtin-fast-export.c b/builtin-fast-export.c index fdf4ae9ebd..34a419c38e 100644 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -221,7 +221,8 @@ static void handle_commit(struct commit *commit, struct rev_info *rev) if (message) message += 2; - if (commit->parents) { + if (commit->parents && + get_object_mark(&commit->parents->item->object) != 0) { parse_commit(commit->parents->item); diff_tree_sha1(commit->parents->item->tree->object.sha1, commit->tree->object.sha1, "", &rev->diffopt); diff --git a/t/t9301-fast-export.sh b/t/t9301-fast-export.sh index 86c376088c..b860626bee 100755 --- a/t/t9301-fast-export.sh +++ b/t/t9301-fast-export.sh @@ -8,6 +8,9 @@ test_description='git fast-export' test_expect_success 'setup' ' + echo break it > file0 && + git add file0 && + test_tick && echo Wohlauf > file && git add file && test_tick && @@ -57,8 +60,8 @@ test_expect_success 'fast-export master~2..master' ' (cd new && git fast-import && test $MASTER != $(git rev-parse --verify refs/heads/partial) && - git diff master..partial && - git diff master^..partial^ && + git diff --exit-code master partial && + git diff --exit-code master^ partial^ && test_must_fail git rev-parse partial~2) ' From 9fe00538c693929d4dec29690fe7660106fe056a Mon Sep 17 00:00:00 2001 From: Wincent Colaiuta <win@wincent.com> Date: Thu, 26 Mar 2009 10:39:04 +0100 Subject: [PATCH 296/654] Grammar fix for "git merge" man page As spotted by the eagle eyes of Jeff King. Signed-off-by: Wincent Colaiuta <win@wincent.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-merge.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt index 427ad9083e..c04ae739ed 100644 --- a/Documentation/git-merge.txt +++ b/Documentation/git-merge.txt @@ -40,7 +40,7 @@ include::merge-options.txt[] include::merge-strategies.txt[] -If you tried a merge which resulted in a complex conflicts and +If you tried a merge which resulted in complex conflicts and want to start over, you can recover with 'git-reset'. CONFIGURATION From 6828f72ffee0d603b96bcde080ec13504f617669 Mon Sep 17 00:00:00 2001 From: Brandon Casey <casey@nrlssc.navy.mil> Date: Thu, 26 Mar 2009 21:37:53 -0500 Subject: [PATCH 297/654] builtin-send-pack.c: avoid empty structure initialization The IRIX6.5 MIPSpro Compiler doesn't like it. Signed-off-by: Brandon Casey <casey@nrlssc.navy.mil> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-send-pack.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/builtin-send-pack.c b/builtin-send-pack.c index 91c36512a8..d5a1c48d0e 100644 --- a/builtin-send-pack.c +++ b/builtin-send-pack.c @@ -10,8 +10,7 @@ static const char send_pack_usage[] = "git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n" " --all and explicit <ref> specification are mutually exclusive."; -static struct send_pack_args args = { -}; +static struct send_pack_args args; static int feed_object(const unsigned char *sha1, int fd, int negative) { From bb2300976ba1491a54dc2b82819fae68d59d6e53 Mon Sep 17 00:00:00 2001 From: Chris Johnsen <chris_johnsen@pobox.com> Date: Fri, 27 Mar 2009 01:49:38 -0500 Subject: [PATCH 298/654] Documentation/Makefile: make most operations "quiet" This adapts the "quiet make" implementation from the main Makefile. Signed-off-by: Chris Johnsen <chris_johnsen@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/Makefile | 84 +++++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/Documentation/Makefile b/Documentation/Makefile index 144ec32f12..3e1d175ee6 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -76,6 +76,32 @@ endif # yourself - yes, all 6 characters of it! # +QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir +QUIET_SUBDIR1 = + +ifneq ($(findstring $(MAKEFLAGS),w),w) +PRINT_DIR = --no-print-directory +else # "make -w" +NO_SUBDIR = : +endif + +ifneq ($(findstring $(MAKEFLAGS),s),s) +ifndef V + QUIET_ASCIIDOC = @echo ' ' ASCIIDOC $@; + QUIET_XMLTO = @echo ' ' XMLTO $@; + QUIET_DB2TEXI = @echo ' ' DB2TEXI $@; + QUIET_MAKEINFO = @echo ' ' MAKEINFO $@; + QUIET_DBLATEX = @echo ' ' DBLATEX $@; + QUIET_XSLTPROC = @echo ' ' XSLTPROC $@; + QUIET_GEN = @echo ' ' GEN $@; + QUIET_STDERR = 2> /dev/null + QUIET_SUBDIR0 = +@subdir= + QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ + $(MAKE) $(PRINT_DIR) -C $$subdir + export V +endif +endif + all: html man html: $(DOC_HTML) @@ -119,7 +145,7 @@ install-html: html sh ./install-webdoc.sh $(DESTDIR)$(htmldir) ../GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE - $(MAKE) -C ../ GIT-VERSION-FILE + $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) GIT-VERSION-FILE -include ../GIT-VERSION-FILE @@ -127,8 +153,8 @@ install-html: html # Determine "include::" file references in asciidoc files. # doc.dep : $(wildcard *.txt) build-docdep.perl - $(RM) $@+ $@ - $(PERL_PATH) ./build-docdep.perl >$@+ + $(QUIET_GEN)$(RM) $@+ $@ && \ + $(PERL_PATH) ./build-docdep.perl >$@+ $(QUIET_STDERR) && \ mv $@+ $@ -include doc.dep @@ -146,8 +172,8 @@ cmds_txt = cmds-ancillaryinterrogators.txt \ $(cmds_txt): cmd-list.made cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT) - $(RM) $@ - $(PERL_PATH) ./cmd-list.perl ../command-list.txt + $(QUIET_GEN)$(RM) $@ && \ + $(PERL_PATH) ./cmd-list.perl ../command-list.txt $(QUIET_STDERR) && \ date >$@ clean: @@ -158,79 +184,79 @@ clean: $(RM) $(cmds_txt) *.made $(MAN_HTML): %.html : %.txt - $(RM) $@+ $@ + $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ $(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \ - $(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $< + $(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $< && \ mv $@+ $@ %.1 %.5 %.7 : %.xml - $(RM) $@ + $(QUIET_XMLTO)$(RM) $@ && \ xmlto -m $(MANPAGE_XSL) man $< %.xml : %.txt - $(RM) $@+ $@ + $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ $(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \ - $(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $< + $(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $< && \ mv $@+ $@ user-manual.xml: user-manual.txt user-manual.conf - $(ASCIIDOC) -b docbook -d book $< + $(QUIET_ASCIIDOC)$(ASCIIDOC) -b docbook -d book $< technical/api-index.txt: technical/api-index-skel.txt \ technical/api-index.sh $(patsubst %,%.txt,$(API_DOCS)) - cd technical && sh ./api-index.sh + $(QUIET_GEN)cd technical && sh ./api-index.sh $(patsubst %,%.html,$(API_DOCS) technical/api-index): %.html : %.txt - $(ASCIIDOC) -b xhtml11 -f asciidoc.conf \ + $(QUIET_ASCIIDOC)$(ASCIIDOC) -b xhtml11 -f asciidoc.conf \ $(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) $*.txt XSLT = docbook.xsl XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css user-manual.html: user-manual.xml - xsltproc $(XSLTOPTS) -o $@ $(XSLT) $< + $(QUIET_XSLTPROC)xsltproc $(XSLTOPTS) -o $@ $(XSLT) $< git.info: user-manual.texi - $(MAKEINFO) --no-split -o $@ user-manual.texi + $(QUIET_MAKEINFO)$(MAKEINFO) --no-split -o $@ user-manual.texi user-manual.texi: user-manual.xml - $(RM) $@+ $@ + $(QUIET_DB2TEXI)$(RM) $@+ $@ && \ $(DOCBOOK2X_TEXI) user-manual.xml --encoding=UTF-8 --to-stdout | \ - $(PERL_PATH) fix-texi.perl >$@+ + $(PERL_PATH) fix-texi.perl >$@+ && \ mv $@+ $@ user-manual.pdf: user-manual.xml - $(RM) $@+ $@ - $(DBLATEX) -o $@+ -p /etc/asciidoc/dblatex/asciidoc-dblatex.xsl -s /etc/asciidoc/dblatex/asciidoc-dblatex.sty $< + $(QUIET_DBLATEX)$(RM) $@+ $@ && \ + $(DBLATEX) -o $@+ -p /etc/asciidoc/dblatex/asciidoc-dblatex.xsl -s /etc/asciidoc/dblatex/asciidoc-dblatex.sty $< && \ mv $@+ $@ gitman.texi: $(MAN_XML) cat-texi.perl - $(RM) $@+ $@ + $(QUIET_DB2TEXI)$(RM) $@+ $@ && \ ($(foreach xml,$(MAN_XML),$(DOCBOOK2X_TEXI) --encoding=UTF-8 \ - --to-stdout $(xml);)) | $(PERL_PATH) cat-texi.perl $@ >$@+ + --to-stdout $(xml) &&) true) | $(PERL_PATH) cat-texi.perl $@ >$@+ && \ mv $@+ $@ gitman.info: gitman.texi - $(MAKEINFO) --no-split --no-validate $*.texi + $(QUIET_MAKEINFO)$(MAKEINFO) --no-split --no-validate $*.texi $(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml - $(RM) $@+ $@ - $(DOCBOOK2X_TEXI) --to-stdout $*.xml >$@+ + $(QUIET_DB2TEXI)$(RM) $@+ $@ && \ + $(DOCBOOK2X_TEXI) --to-stdout $*.xml >$@+ && \ mv $@+ $@ howto-index.txt: howto-index.sh $(wildcard howto/*.txt) - $(RM) $@+ $@ - sh ./howto-index.sh $(wildcard howto/*.txt) >$@+ + $(QUIET_GEN)$(RM) $@+ $@ && \ + sh ./howto-index.sh $(wildcard howto/*.txt) >$@+ && \ mv $@+ $@ $(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt - $(ASCIIDOC) -b xhtml11 $*.txt + $(QUIET_ASCIIDOC)$(ASCIIDOC) -b xhtml11 $*.txt WEBDOC_DEST = /pub/software/scm/git/docs $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt - $(RM) $@+ $@ - sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+ + $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ + sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+ && \ mv $@+ $@ install-webdoc : html From c6a5ad21e57ce38a0add04a2708ccf02ed17af39 Mon Sep 17 00:00:00 2001 From: Chris Johnsen <chris_johnsen@pobox.com> Date: Fri, 27 Mar 2009 01:49:39 -0500 Subject: [PATCH 299/654] Documentation/Makefile: break up texi pipeline Most shells define the exit value of a pipeline as the exit value of the last process. For each texi rule, run the DOCBOOK2X_TEXI tool and the "fixup" script in their own non-pipeline commands so that make will notice an error exit code. Signed-off-by: Chris Johnsen <chris_johnsen@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/Makefile | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Documentation/Makefile b/Documentation/Makefile index 3e1d175ee6..d145372393 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -178,7 +178,7 @@ cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT) clean: $(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7 - $(RM) *.texi *.texi+ git.info gitman.info + $(RM) *.texi *.texi+ *.texi++ git.info gitman.info $(RM) howto-index.txt howto/*.html doc.dep $(RM) technical/api-*.html technical/api-index.txt $(RM) $(cmds_txt) *.made @@ -221,8 +221,9 @@ git.info: user-manual.texi user-manual.texi: user-manual.xml $(QUIET_DB2TEXI)$(RM) $@+ $@ && \ - $(DOCBOOK2X_TEXI) user-manual.xml --encoding=UTF-8 --to-stdout | \ - $(PERL_PATH) fix-texi.perl >$@+ && \ + $(DOCBOOK2X_TEXI) user-manual.xml --encoding=UTF-8 --to-stdout >$@++ && \ + $(PERL_PATH) fix-texi.perl <$@++ >$@+ && \ + rm $@++ && \ mv $@+ $@ user-manual.pdf: user-manual.xml @@ -233,7 +234,9 @@ user-manual.pdf: user-manual.xml gitman.texi: $(MAN_XML) cat-texi.perl $(QUIET_DB2TEXI)$(RM) $@+ $@ && \ ($(foreach xml,$(MAN_XML),$(DOCBOOK2X_TEXI) --encoding=UTF-8 \ - --to-stdout $(xml) &&) true) | $(PERL_PATH) cat-texi.perl $@ >$@+ && \ + --to-stdout $(xml) &&) true) > $@++ && \ + $(PERL_PATH) cat-texi.perl $@ <$@++ >$@+ && \ + rm $@++ && \ mv $@+ $@ gitman.info: gitman.texi From c30e9485238bb8e9daa4cbba5deb1f79c8da7dde Mon Sep 17 00:00:00 2001 From: Chris Johnsen <chris_johnsen@pobox.com> Date: Fri, 27 Mar 2009 01:43:58 -0500 Subject: [PATCH 300/654] Documentation: move callouts.xsl to manpage-{base,normal}.xsl Each of manpage-base.xsl and manpage-normal.xsl gets a copy of the contents of callouts.xsl and the original is removed. The Makefile is adjusted to refer to manpage-normal.xsl instead of callouts.xsl. manpage-base.xsl will be later made into a common base for -normal and -1.72. Testing done with asciidoc 8.3.1 and docbook-xsl 1.74.0. Signed-off-by: Chris Johnsen <chris_johnsen@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/Makefile | 2 +- .../{callouts.xsl => manpage-base.xsl} | 0 Documentation/manpage-normal.xsl | 30 +++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) rename Documentation/{callouts.xsl => manpage-base.xsl} (100%) create mode 100644 Documentation/manpage-normal.xsl diff --git a/Documentation/Makefile b/Documentation/Makefile index 144ec32f12..e1562e351c 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -41,7 +41,7 @@ man7dir=$(mandir)/man7 ASCIIDOC=asciidoc ASCIIDOC_EXTRA = -MANPAGE_XSL = callouts.xsl +MANPAGE_XSL = manpage-normal.xsl INSTALL?=install RM ?= rm -f DOC_REF = origin/man diff --git a/Documentation/callouts.xsl b/Documentation/manpage-base.xsl similarity index 100% rename from Documentation/callouts.xsl rename to Documentation/manpage-base.xsl diff --git a/Documentation/manpage-normal.xsl b/Documentation/manpage-normal.xsl new file mode 100644 index 0000000000..6a361a2136 --- /dev/null +++ b/Documentation/manpage-normal.xsl @@ -0,0 +1,30 @@ +<!-- callout.xsl: converts asciidoc callouts to man page format --> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> +<xsl:template match="co"> + <xsl:value-of select="concat('\fB(',substring-after(@id,'-'),')\fR')"/> +</xsl:template> +<xsl:template match="calloutlist"> + <xsl:text>.sp </xsl:text> + <xsl:apply-templates/> + <xsl:text> </xsl:text> +</xsl:template> +<xsl:template match="callout"> + <xsl:value-of select="concat('\fB',substring-after(@arearefs,'-'),'. \fR')"/> + <xsl:apply-templates/> + <xsl:text>.br </xsl:text> +</xsl:template> + +<!-- sorry, this is not about callouts, but attempts to work around + spurious .sp at the tail of the line docbook stylesheets seem to add --> +<xsl:template match="simpara"> + <xsl:variable name="content"> + <xsl:apply-templates/> + </xsl:variable> + <xsl:value-of select="normalize-space($content)"/> + <xsl:if test="not(ancestor::authorblurb) and + not(ancestor::personblurb)"> + <xsl:text> </xsl:text> + </xsl:if> +</xsl:template> + +</xsl:stylesheet> From ae8d09b8fa138aeb8ec3e20819360241dfb9f0b8 Mon Sep 17 00:00:00 2001 From: Chris Johnsen <chris_johnsen@pobox.com> Date: Fri, 27 Mar 2009 01:43:59 -0500 Subject: [PATCH 301/654] Documentation: use parametrized manpage-base.xsl with manpage-{1.72,normal}.xsl Parametrize the backslash and dot characters that are used to generate roff control sequences in manpage-base.xsl. Testing done with asciidoc 8.3.1 and docbook-xsl 1.74.0. Signed-off-by: Chris Johnsen <chris_johnsen@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/manpage-1.72.xsl | 29 +++++++++++------------- Documentation/manpage-base.xsl | 39 ++++++++++++++++---------------- Documentation/manpage-normal.xsl | 30 +++++++++++------------- 3 files changed, 46 insertions(+), 52 deletions(-) diff --git a/Documentation/manpage-1.72.xsl b/Documentation/manpage-1.72.xsl index 4065a3a27a..e24d26cd00 100644 --- a/Documentation/manpage-1.72.xsl +++ b/Documentation/manpage-1.72.xsl @@ -1,21 +1,18 @@ -<!-- Based on callouts.xsl. Fixes man page callouts for DocBook 1.72 XSL --> -<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> +<!-- manpage-1.72.xsl: + special settings for manpages rendered from asciidoc+docbook + handles peculiarities in docbook-xsl 1.72.0 --> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version="1.0"> +<xsl:import href="manpage-base.xsl"/> + +<!-- these are the special values for the roff control characters + needed for docbook-xsl 1.72.0 --> +<xsl:param name="git.docbook.backslash">▓</xsl:param> +<xsl:param name="git.docbook.dot" >⌂</xsl:param> + +<!-- these params silence some output from xmlto --> <xsl:param name="man.output.quietly" select="1"/> <xsl:param name="refentry.meta.get.quietly" select="1"/> -<xsl:template match="co"> - <xsl:value-of select="concat('▓fB(',substring-after(@id,'-'),')▓fR')"/> -</xsl:template> -<xsl:template match="calloutlist"> - <xsl:text>⌂sp </xsl:text> - <xsl:apply-templates/> - <xsl:text> </xsl:text> -</xsl:template> -<xsl:template match="callout"> - <xsl:value-of select="concat('▓fB',substring-after(@arearefs,'-'),'. ▓fR')"/> - <xsl:apply-templates/> - <xsl:text>⌂br </xsl:text> -</xsl:template> - </xsl:stylesheet> diff --git a/Documentation/manpage-base.xsl b/Documentation/manpage-base.xsl index 6a361a2136..6d3eb1912a 100644 --- a/Documentation/manpage-base.xsl +++ b/Documentation/manpage-base.xsl @@ -1,30 +1,31 @@ -<!-- callout.xsl: converts asciidoc callouts to man page format --> -<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> +<!-- manpage-base.xsl: + special formatting for manpages rendered from asciidoc+docbook --> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version="1.0"> + +<!-- convert asciidoc callouts to man page format; + git.docbook.backslash and git.docbook.dot params + must be supplied by another XSL file or other means --> <xsl:template match="co"> - <xsl:value-of select="concat('\fB(',substring-after(@id,'-'),')\fR')"/> + <xsl:value-of select="concat( + $git.docbook.backslash,'fB(', + substring-after(@id,'-'),')', + $git.docbook.backslash,'fR')"/> </xsl:template> <xsl:template match="calloutlist"> - <xsl:text>.sp </xsl:text> + <xsl:value-of select="$git.docbook.dot"/> + <xsl:text>sp </xsl:text> <xsl:apply-templates/> <xsl:text> </xsl:text> </xsl:template> <xsl:template match="callout"> - <xsl:value-of select="concat('\fB',substring-after(@arearefs,'-'),'. \fR')"/> + <xsl:value-of select="concat( + $git.docbook.backslash,'fB', + substring-after(@arearefs,'-'), + '. ',$git.docbook.backslash,'fR')"/> <xsl:apply-templates/> - <xsl:text>.br </xsl:text> -</xsl:template> - -<!-- sorry, this is not about callouts, but attempts to work around - spurious .sp at the tail of the line docbook stylesheets seem to add --> -<xsl:template match="simpara"> - <xsl:variable name="content"> - <xsl:apply-templates/> - </xsl:variable> - <xsl:value-of select="normalize-space($content)"/> - <xsl:if test="not(ancestor::authorblurb) and - not(ancestor::personblurb)"> - <xsl:text> </xsl:text> - </xsl:if> + <xsl:value-of select="$git.docbook.dot"/> + <xsl:text>br </xsl:text> </xsl:template> </xsl:stylesheet> diff --git a/Documentation/manpage-normal.xsl b/Documentation/manpage-normal.xsl index 6a361a2136..e36472f5ad 100644 --- a/Documentation/manpage-normal.xsl +++ b/Documentation/manpage-normal.xsl @@ -1,21 +1,17 @@ -<!-- callout.xsl: converts asciidoc callouts to man page format --> -<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> -<xsl:template match="co"> - <xsl:value-of select="concat('\fB(',substring-after(@id,'-'),')\fR')"/> -</xsl:template> -<xsl:template match="calloutlist"> - <xsl:text>.sp </xsl:text> - <xsl:apply-templates/> - <xsl:text> </xsl:text> -</xsl:template> -<xsl:template match="callout"> - <xsl:value-of select="concat('\fB',substring-after(@arearefs,'-'),'. \fR')"/> - <xsl:apply-templates/> - <xsl:text>.br </xsl:text> -</xsl:template> +<!-- manpage-normal.xsl: + special settings for manpages rendered from asciidoc+docbook + handles anything we want to keep away from docbook-xsl 1.72.0 --> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version="1.0"> -<!-- sorry, this is not about callouts, but attempts to work around - spurious .sp at the tail of the line docbook stylesheets seem to add --> +<xsl:import href="manpage-base.xsl"/> + +<!-- these are the normal values for the roff control characters --> +<xsl:param name="git.docbook.backslash">\</xsl:param> +<xsl:param name="git.docbook.dot" >.</xsl:param> + +<!-- attempt to work around spurious .sp at the tail of the line + that docbook stylesheets seem to add --> <xsl:template match="simpara"> <xsl:variable name="content"> <xsl:apply-templates/> From 8fa2b45f3a70a1622c8fc5d35af148da5cab80d1 Mon Sep 17 00:00:00 2001 From: Chris Johnsen <chris_johnsen@pobox.com> Date: Fri, 27 Mar 2009 01:44:00 -0500 Subject: [PATCH 302/654] Documentation: rename docbook-xsl-172 attribute to git-asciidoc-no-roff It seems that the ability to use raw roff codes in asciidoc.conf was eliminated by docbook-xsl 1.72.0 _and later_. Unlike the 1.72.0-specific XSLT problem, this behavior was not reverted in later releases. This patch aims to make it clear that the affected asciidoc attribute (flag) can be reasonably used with docbook-xsl versions other than 1.72.0. Also, document which make variables should be set for various versions of asciidoc and docbook-xsl. Testing done with asciidoc 8.3.1 and docbook-xsl 1.74.0. Signed-off-by: Chris Johnsen <chris_johnsen@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/Makefile | 29 ++++++++++++++++++++++++++++- Documentation/asciidoc.conf | 8 ++++---- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/Documentation/Makefile b/Documentation/Makefile index e1562e351c..d71760b807 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -59,12 +59,39 @@ endif -include ../config.mak.autogen -include ../config.mak +# +# For asciidoc ... +# -7.1.2, no extra settings are needed. +# 8.0-, set ASCIIDOC8. +# + +# +# For docbook-xsl ... +# -1.68.1, set ASCIIDOC_NO_ROFF? (based on changelog from 1.73.0) +# 1.69.0-1.71.1, no extra settings are needed? +# 1.72.0, set DOCBOOK_XSL_172. +# 1.73.0-, set ASCIIDOC_NO_ROFF +# + +# +# If you had been using DOCBOOK_XSL_172 in an attempt to get rid +# of 'the ".ft C" problem' in your generated manpages, and you +# instead ended up with weird characters around callouts, try +# using ASCIIDOC_NO_ROFF instead (it works fine with ASCIIDOC8). +# + ifdef ASCIIDOC8 ASCIIDOC_EXTRA += -a asciidoc7compatible endif ifdef DOCBOOK_XSL_172 -ASCIIDOC_EXTRA += -a docbook-xsl-172 +ASCIIDOC_EXTRA += -a git-asciidoc-no-roff MANPAGE_XSL = manpage-1.72.xsl +else + ifdef ASCIIDOC_NO_ROFF + # docbook-xsl after 1.72 needs the regular XSL, but will not + # pass-thru raw roff codes from asciidoc.conf, so turn them off. + ASCIIDOC_EXTRA += -a git-asciidoc-no-roff + endif endif # diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf index 1e735df3bb..ce1b1755ae 100644 --- a/Documentation/asciidoc.conf +++ b/Documentation/asciidoc.conf @@ -27,7 +27,7 @@ ifdef::backend-docbook[] endif::backend-docbook[] ifdef::backend-docbook[] -ifndef::docbook-xsl-172[] +ifndef::git-asciidoc-no-roff[] # "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this. # v1.72 breaks with this because it replaces dots not in roff requests. [listingblock] @@ -42,9 +42,9 @@ ifdef::doctype-manpage[] endif::doctype-manpage[] </literallayout> {title#}</example> -endif::docbook-xsl-172[] +endif::git-asciidoc-no-roff[] -ifdef::docbook-xsl-172[] +ifdef::git-asciidoc-no-roff[] ifdef::doctype-manpage[] # The following two small workarounds insert a simple paragraph after screen [listingblock] @@ -62,7 +62,7 @@ ifdef::doctype-manpage[] </literallayout><simpara></simpara> {title#}</para></formalpara> endif::doctype-manpage[] -endif::docbook-xsl-172[] +endif::git-asciidoc-no-roff[] endif::backend-docbook[] ifdef::doctype-manpage[] From 9d8d13a8c52c55ad4695b659cbffa61e4c3a3774 Mon Sep 17 00:00:00 2001 From: Chris Johnsen <chris_johnsen@pobox.com> Date: Fri, 27 Mar 2009 01:44:01 -0500 Subject: [PATCH 303/654] Documentation: move quieting params into manpage-base.xsl Move a couple of XSL parameters that act to silence informational/warning messages generated when running xmlto from manpage-1.72.xsl to manpage-base.xsl. Since unused parameters are silently ignored, there is no problem if some version of docbook-xsl does not know about these parameters. The only problem might be if a version of docbook-xsl uses the parameters for alternate functionality. Since both parameters have fairly specific names such a situation is unlikely. Testing done with asciidoc 8.3.1 and docbook-xsl 1.74.0. Signed-off-by: Chris Johnsen <chris_johnsen@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/manpage-1.72.xsl | 4 ---- Documentation/manpage-base.xsl | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/manpage-1.72.xsl b/Documentation/manpage-1.72.xsl index e24d26cd00..b4d315cb8c 100644 --- a/Documentation/manpage-1.72.xsl +++ b/Documentation/manpage-1.72.xsl @@ -11,8 +11,4 @@ <xsl:param name="git.docbook.backslash">▓</xsl:param> <xsl:param name="git.docbook.dot" >⌂</xsl:param> -<!-- these params silence some output from xmlto --> -<xsl:param name="man.output.quietly" select="1"/> -<xsl:param name="refentry.meta.get.quietly" select="1"/> - </xsl:stylesheet> diff --git a/Documentation/manpage-base.xsl b/Documentation/manpage-base.xsl index 6d3eb1912a..a264fa6160 100644 --- a/Documentation/manpage-base.xsl +++ b/Documentation/manpage-base.xsl @@ -3,6 +3,10 @@ <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> +<!-- these params silence some output from xmlto --> +<xsl:param name="man.output.quietly" select="1"/> +<xsl:param name="refentry.meta.get.quietly" select="1"/> + <!-- convert asciidoc callouts to man page format; git.docbook.backslash and git.docbook.dot params must be supplied by another XSL file or other means --> From 34c800b8fcbd85c276cb102b3e60d170aa9e55e0 Mon Sep 17 00:00:00 2001 From: Chris Johnsen <chris_johnsen@pobox.com> Date: Fri, 27 Mar 2009 01:44:02 -0500 Subject: [PATCH 304/654] Documentation: move "spurious .sp" code into manpage-base.xsl The "spurious .sp" code should be independent of docbook-xsl versions. Testing done with asciidoc 8.3.1 and docbook-xsl 1.74.0. Signed-off-by: Chris Johnsen <chris_johnsen@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/manpage-base.xsl | 13 +++++++++++++ Documentation/manpage-normal.xsl | 13 ------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Documentation/manpage-base.xsl b/Documentation/manpage-base.xsl index a264fa6160..16e2e40976 100644 --- a/Documentation/manpage-base.xsl +++ b/Documentation/manpage-base.xsl @@ -32,4 +32,17 @@ <xsl:text>br </xsl:text> </xsl:template> +<!-- attempt to work around spurious .sp at the tail of the line + that docbook stylesheets seem to add --> +<xsl:template match="simpara"> + <xsl:variable name="content"> + <xsl:apply-templates/> + </xsl:variable> + <xsl:value-of select="normalize-space($content)"/> + <xsl:if test="not(ancestor::authorblurb) and + not(ancestor::personblurb)"> + <xsl:text> </xsl:text> + </xsl:if> +</xsl:template> + </xsl:stylesheet> diff --git a/Documentation/manpage-normal.xsl b/Documentation/manpage-normal.xsl index e36472f5ad..a48f5b11f3 100644 --- a/Documentation/manpage-normal.xsl +++ b/Documentation/manpage-normal.xsl @@ -10,17 +10,4 @@ <xsl:param name="git.docbook.backslash">\</xsl:param> <xsl:param name="git.docbook.dot" >.</xsl:param> -<!-- attempt to work around spurious .sp at the tail of the line - that docbook stylesheets seem to add --> -<xsl:template match="simpara"> - <xsl:variable name="content"> - <xsl:apply-templates/> - </xsl:variable> - <xsl:value-of select="normalize-space($content)"/> - <xsl:if test="not(ancestor::authorblurb) and - not(ancestor::personblurb)"> - <xsl:text> </xsl:text> - </xsl:if> -</xsl:template> - </xsl:stylesheet> From dad3211503e2760a0e704b3c617849ba298a76e7 Mon Sep 17 00:00:00 2001 From: Chris Johnsen <chris_johnsen@pobox.com> Date: Fri, 27 Mar 2009 01:44:03 -0500 Subject: [PATCH 305/654] Documentation: asciidoc.conf: always use <literallayout> for [blocktext] Make the docbook-xsl-no-raw-roff variant match the no-docbook-xsl-no-raw-roff variant in terms of which XML tag is used to wrap listing block text (delimited with lines of dashes). e920b56 (Tweak asciidoc output to work with broken docbook-xsl, 2006-03-05) says docbook-xsl 1.68 needs <literallayout>. This <screen> usages was in the old, 1.72-only section. But since it is now the "roff-less" section, it probably makes sense to make it symmetric with the "roff-ful" section. Testing done with asciidoc 8.3.1 and docbook-xsl 1.74.0. Signed-off-by: Chris Johnsen <chris_johnsen@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/asciidoc.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf index ce1b1755ae..9963f2da81 100644 --- a/Documentation/asciidoc.conf +++ b/Documentation/asciidoc.conf @@ -49,9 +49,9 @@ ifdef::doctype-manpage[] # The following two small workarounds insert a simple paragraph after screen [listingblock] <example><title>{title}</title> -<screen> +<literallayout> | -</screen><simpara></simpara> +</literallayout><simpara></simpara> {title#}</example> [verseblock] From 0c04f5273579da4b8308c125b1eb4b8f888bffab Mon Sep 17 00:00:00 2001 From: Chris Johnsen <chris_johnsen@pobox.com> Date: Fri, 27 Mar 2009 01:44:04 -0500 Subject: [PATCH 306/654] Documentation: asciidoc.conf: fix verse block with block titles No files use the variant of block-title with verse-block, but such a case would have generated broken docbook XML (<simpara> is not allowed inside <para>). This fixes the potential deviation from valid docbook XML. Testing done with asciidoc 8.3.1 and docbook-xsl 1.74.0. Signed-off-by: Chris Johnsen <chris_johnsen@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/asciidoc.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf index 9963f2da81..dc76e7f073 100644 --- a/Documentation/asciidoc.conf +++ b/Documentation/asciidoc.conf @@ -59,8 +59,9 @@ ifdef::doctype-manpage[] {title%}<literallayout{id? id="{id}"}> {title#}<literallayout> | -</literallayout><simpara></simpara> +</literallayout> {title#}</para></formalpara> +{title%}<simpara></simpara> endif::doctype-manpage[] endif::git-asciidoc-no-roff[] endif::backend-docbook[] From 5121a6d99368906292dfdf7fe0047fb89c4c1969 Mon Sep 17 00:00:00 2001 From: Chris Johnsen <chris_johnsen@pobox.com> Date: Fri, 27 Mar 2009 01:44:05 -0500 Subject: [PATCH 307/654] Documentation: option to render literal text as bold for manpages This allows manpages viewed on a tty to render inline literal text in a manner that is distinct from the surrounding text. The initial implementation (pre-mailing-list) of this patch included a conditional variant of the XSLT code in manpage-base.xsl and use xmlto's --stringparam option to optionally enable the functionality. It turns out that --stringparam is broken in all versions of xmlto except for the pre-release, SVN version. Since xmlto is a shell script the patch to fix it is simple enough, but I instead opted to use xmlto's "module" functionality. Testing done with asciidoc 8.3.1 and docbook-xsl 1.74.0. Signed-off-by: Chris Johnsen <chris_johnsen@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/Makefile | 6 +++++- Documentation/manpage-bold-literal.xsl | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 Documentation/manpage-bold-literal.xsl diff --git a/Documentation/Makefile b/Documentation/Makefile index d71760b807..1c94531874 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -42,6 +42,7 @@ man7dir=$(mandir)/man7 ASCIIDOC=asciidoc ASCIIDOC_EXTRA = MANPAGE_XSL = manpage-normal.xsl +XMLTO_EXTRA = INSTALL?=install RM ?= rm -f DOC_REF = origin/man @@ -93,6 +94,9 @@ else ASCIIDOC_EXTRA += -a git-asciidoc-no-roff endif endif +ifdef MAN_BOLD_LITERAL +XMLTO_EXTRA += -m manpage-bold-literal.xsl +endif # # Please note that there is a minor bug in asciidoc. @@ -192,7 +196,7 @@ $(MAN_HTML): %.html : %.txt %.1 %.5 %.7 : %.xml $(RM) $@ - xmlto -m $(MANPAGE_XSL) man $< + xmlto -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $< %.xml : %.txt $(RM) $@+ $@ diff --git a/Documentation/manpage-bold-literal.xsl b/Documentation/manpage-bold-literal.xsl new file mode 100644 index 0000000000..608eb5df62 --- /dev/null +++ b/Documentation/manpage-bold-literal.xsl @@ -0,0 +1,17 @@ +<!-- manpage-bold-literal.xsl: + special formatting for manpages rendered from asciidoc+docbook --> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version="1.0"> + +<!-- render literal text as bold (instead of plain or monospace); + this makes literal text easier to distinguish in manpages + viewed on a tty --> +<xsl:template match="literal"> + <xsl:value-of select="$git.docbook.backslash"/> + <xsl:text>fB</xsl:text> + <xsl:apply-templates/> + <xsl:value-of select="$git.docbook.backslash"/> + <xsl:text>fR</xsl:text> +</xsl:template> + +</xsl:stylesheet> From 57dac0bfe43a68d55e16def58b8ed305e0676d3f Mon Sep 17 00:00:00 2001 From: Michael J Gruber <git@drmicha.warpmail.net> Date: Thu, 26 Mar 2009 21:53:24 +0100 Subject: [PATCH 308/654] Test for local branches being followed with --track According to the documentation, it is perfectly okay to follow local branches using the --track option. Introduce a test which checks whether they behave the same. Currently one test fails. Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t6040-tracking-info.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh index ba9060190d..2a2b6b63d5 100755 --- a/t/t6040-tracking-info.sh +++ b/t/t6040-tracking-info.sh @@ -29,7 +29,9 @@ test_expect_success setup ' git checkout -b b4 origin && advance e && advance f - ) + ) && + git checkout -b follower --track master && + advance g ' script='s/^..\(b.\)[ 0-9a-f]*\[\([^]]*\)\].*/\1 \2/p' @@ -56,6 +58,12 @@ test_expect_success 'checkout' ' grep "have 1 and 1 different" actual ' +test_expect_failure 'checkout with local tracked branch' ' + git checkout master && + git checkout follower >actual + grep "is ahead of" actual +' + test_expect_success 'status' ' ( cd test && From b09b868f7fee689483d00bea3d52c0f14a80386c Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Fri, 27 Mar 2009 01:13:01 +0100 Subject: [PATCH 309/654] log-tree: fix patch filename computation in "git format-patch" When using "git format-patch", "get_patch_filename" in "log-tree.c" calls "strbuf_splice" that could die with the following message: "`pos + len' is too far after the end of the buffer" if you have: buf->len < start_len + FORMAT_PATCH_NAME_MAX but: buf->len + suffix_len > start_len + FORMAT_PATCH_NAME_MAX This patch tries to get rid of that bug. [jc: w/ simplified logic] Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- log-tree.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/log-tree.c b/log-tree.c index 56a3488592..5bd29e6994 100644 --- a/log-tree.c +++ b/log-tree.c @@ -187,17 +187,12 @@ void get_patch_filename(struct commit *commit, int nr, const char *suffix, strbuf_addf(buf, commit ? "%04d-" : "%d", nr); if (commit) { + int max_len = start_len + FORMAT_PATCH_NAME_MAX - suffix_len; + format_commit_message(commit, "%f", buf, DATE_NORMAL); - /* - * Replace characters at the end with the suffix if the - * filename is too long - */ - if (buf->len + suffix_len > FORMAT_PATCH_NAME_MAX + start_len) - strbuf_splice(buf, - start_len + FORMAT_PATCH_NAME_MAX - suffix_len, - suffix_len, suffix, suffix_len); - else - strbuf_addstr(buf, suffix); + if (max_len < buf->len) + strbuf_setlen(buf, max_len); + strbuf_addstr(buf, suffix); } } From 3f7d99282d336824b789a5ccb2523a5d84f9be2e Mon Sep 17 00:00:00 2001 From: Michele Ballabio <barra_cuda@katamail.com> Date: Wed, 18 Mar 2009 19:05:56 +0100 Subject: [PATCH 310/654] rebase: fix typo (force_rebas -> force-rebas) Signed-off-by: Michele Ballabio <barra_cuda@katamail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-rebase.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-rebase.sh b/git-rebase.sh index 0ade699228..b83fd3f970 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -319,7 +319,7 @@ do --root) rebase_root=t ;; - -f|--f|--fo|--for|--forc|force|--force-r|--force-re|--force-reb|--force-reba|--force_rebas|--force-rebase) + -f|--f|--fo|--for|--forc|force|--force-r|--force-re|--force-reb|--force-reba|--force-rebas|--force-rebase) force_rebase=t ;; -*) From d7d9c2d04962b5aec34ec891d82dd74262306c56 Mon Sep 17 00:00:00 2001 From: Michael Hendricks <michael@ndrix.org> Date: Thu, 26 Mar 2009 10:51:05 -0600 Subject: [PATCH 311/654] format-patch: add arbitrary email headers format-patch supports the format.headers configuration for adding arbitrary email headers to the patches it outputs. This patch adds support for an --add-header argument which makes the same feature available from the command line. This is useful when the content of custom email headers must change from branch to branch. This patch has been sponsored by Grant Street Group Signed-off-by: Michael Hendricks <michael@ndrix.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-format-patch.txt | 5 +++++ builtin-log.c | 2 ++ t/t4014-format-patch.sh | 15 +++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index c2eb5fab4c..51fd716902 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -161,6 +161,11 @@ if that is not set. Add a "Cc:" header to the email headers. This is in addition to any configured headers, and may be used multiple times. +--add-header=<header>:: + Add an arbitrary header to the email headers. This is in addition + to any configured headers, and may be used multiple times. + For example, --add-header="Organization: git-foo" + --cover-letter:: In addition to the patches, generate a cover letter file containing the shortlog and the overall diffstat. You can diff --git a/builtin-log.c b/builtin-log.c index c7a5772594..27bc0dce23 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -918,6 +918,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) cover_letter = 1; else if (!strcmp(argv[i], "--no-binary")) no_binary_diff = 1; + else if (!prefixcmp(argv[i], "--add-header=")) + add_header(argv[i] + 13); else argv[j++] = argv[i]; } diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index f187d15e32..11061ddd5b 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -128,6 +128,21 @@ test_expect_success 'additional command line cc' ' grep "^ *S. E. Cipient <scipient@example.com>$" patch5 ' +test_expect_success 'command line headers' ' + + git config --unset-all format.headers && + git format-patch --add-header="Cc: R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^$/q" >patch6 && + grep "^Cc: R. E. Cipient <rcipient@example.com>$" patch6 +' + +test_expect_success 'configuration headers and command line headers' ' + + git config --replace-all format.headers "Cc: R. E. Cipient <rcipient@example.com>" && + git format-patch --add-header="Cc: S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^$/q" >patch7 && + grep "^Cc: R. E. Cipient <rcipient@example.com>,$" patch7 && + grep "^ *S. E. Cipient <scipient@example.com>$" patch7 +' + test_expect_success 'multiple files' ' rm -rf patches/ && From a1b1ae0571f6b57117678aeaa1939d97c992a254 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Sat, 28 Mar 2009 00:55:52 -0700 Subject: [PATCH 312/654] Update draft release notes to 1.6.3 Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/RelNotes-1.6.3.txt | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/Documentation/RelNotes-1.6.3.txt b/Documentation/RelNotes-1.6.3.txt index 0d8260a842..f0a2e41c71 100644 --- a/Documentation/RelNotes-1.6.3.txt +++ b/Documentation/RelNotes-1.6.3.txt @@ -22,12 +22,12 @@ branch pointed at by its HEAD, gets a large warning. You can choose what should happen upon such a push by setting the configuration variable receive.denyDeleteCurrent in the receiving repository. -In a future release, the default of "git push" without further -arguments might be changed. Currently, it will push all matching -refspecs to the current remote. A configuration variable push.default -has been introduced to select the default behaviour. To ease the -transition, a big warning is issued if this is not configured and a -git push without arguments is attempted. +When the user does not tell "git push" what to push, it has always +pushed matching refs. For some people it is unexpected, and a new +configuration variable push.default has been introduced to allow +changing a different default behaviour. To advertise the new feature, +a big warning is issued if this is not configured and a git push without +arguments is attempted. Updates since v1.6.2 @@ -46,6 +46,9 @@ Updates since v1.6.2 repositories. It may not be useful in practice; meant primarily for testing. +* http transport learned to prompt and use password when fetching from or + pushing to http://user@host.xz/ URL. + * (msysgit) progress output that is sent over the sideband protocol can be handled appropriately in Windows console. @@ -99,6 +102,8 @@ Updates since v1.6.2 * Test scripts can be run under valgrind. +* Test scripts can be run with installed git. + * Makefile learned 'coverage' option to run the test suites with coverage tracking enabled. @@ -111,11 +116,20 @@ release, unless otherwise noted. Here are fixes that this release has, but have not been backported to v1.6.2.X series. +* "git-blame -S" did not quite work near the commits that were given + on the command line correctly (jc/maint-1.6.0-blame-s). + +* The initial checkout did not read the attributes from the .gitattribute + file that is being checked out. + +* git-diff feeds files in work-tree representation to external diff and + textconv (js/maint-diff-temp-smudge). + * git-gc spent excessive amount of time to decide if an object appears in a locally existing pack (if needed, backport by merging 69e020a). --- exec >/var/tmp/1 -O=v1.6.2.1-213-g7d4e3a7 +O=v1.6.2.1-399-gaa72a14 echo O=$(git describe master) git shortlog --no-merges $O..master ^maint From 4f821012c3feb7c0a36be3849e971fbeff4fbc3b Mon Sep 17 00:00:00 2001 From: Eric Wong <normalperson@yhbt.net> Date: Sat, 28 Mar 2009 22:10:08 -0700 Subject: [PATCH 313/654] git-svn: fix ls-tree usage with dash-prefixed paths To find the blob object name given a tree and pathname, we were incorrectly calling "git ls-tree" with a "--" argument followed by the pathname of the file we wanted to get. git ls-tree <TREE> -- --dashed/path/name.c Unlike many command-line interfaces, the "--" alone does not symbolize the end of non-option arguments on the command-line. ls-tree interprets the "--" as a prefix to match against, thus the entire contents of the --dashed/* hierarchy would be returned because the "--" matches "--dashed" and every path under it. Thanks to Anton Gyllenberg for pointing me toward the Twisted repository as a real-world example of this case. Signed-off-by: Eric Wong <normalperson@yhbt.net> --- git-svn.perl | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/git-svn.perl b/git-svn.perl index 8be6be00c6..f21cfb462d 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -3387,15 +3387,18 @@ sub delete_entry { return undef if ($gpath eq ''); # remove entire directories. - if (command('ls-tree', $self->{c}, '--', $gpath) =~ /^040000 tree/) { + my ($tree) = (command('ls-tree', '-z', $self->{c}, "./$gpath") + =~ /\A040000 tree ([a-f\d]{40})\t\Q$gpath\E\0/); + if ($tree) { my ($ls, $ctx) = command_output_pipe(qw/ls-tree -r --name-only -z/, - $self->{c}, '--', $gpath); + $tree); local $/ = "\0"; while (<$ls>) { chomp; - $self->{gii}->remove($_); - print "\tD\t$_\n" unless $::_q; + my $rmpath = "$gpath/$_"; + $self->{gii}->remove($rmpath); + print "\tD\t$rmpath\n" unless $::_q; } print "\tD\t$gpath/\n" unless $::_q; command_close_pipe($ls, $ctx); @@ -3414,8 +3417,8 @@ sub open_file { goto out if is_path_ignored($path); my $gpath = $self->git_path($path); - ($mode, $blob) = (command('ls-tree', $self->{c}, '--', $gpath) - =~ /^(\d{6}) blob ([a-f\d]{40})\t/); + ($mode, $blob) = (command('ls-tree', '-z', $self->{c}, "./$gpath") + =~ /\A(\d{6}) blob ([a-f\d]{40})\t\Q$gpath\E\0/); unless (defined $mode && defined $blob) { die "$path was not found in commit $self->{c} (r$rev)\n"; } From 18d5cf908fe89c780872acc8a9f11d061e4556b6 Mon Sep 17 00:00:00 2001 From: Simon Arlott <simon@fire.lp0.eu> Date: Sun, 29 Mar 2009 20:34:50 +0100 Subject: [PATCH 314/654] git-svn: don't output git commits in quiet mode Ideally only errors should be output in this mode so fetch can be run from cron and normally produce no output. Without this change it would output a single line on each git commit, e.g. r1909 = 32ef87860662526d4a62f903949ed21e0341079e (u2_10_12_branch) Signed-off-by: Simon Arlott <simon@fire.lp0.eu> Acked-by: Eric Wong <normalperson@yhbt.net> --- git-svn.perl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/git-svn.perl b/git-svn.perl index f21cfb462d..e5c3dfe5d2 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -2331,13 +2331,13 @@ sub do_git_commit { $self->{last_rev} = $log_entry->{revision}; $self->{last_commit} = $commit; - print "r$log_entry->{revision}"; + print "r$log_entry->{revision}" unless $::_q; if (defined $log_entry->{svm_revision}) { - print " (\@$log_entry->{svm_revision})"; + print " (\@$log_entry->{svm_revision})" unless $::_q; $self->rev_map_set($log_entry->{svm_revision}, $commit, 0, $self->svm_uuid); } - print " = $commit ($self->{ref_id})\n"; + print " = $commit ($self->{ref_id})\n" unless $::_q; if (--$_gc_nr == 0) { $_gc_nr = $_gc_period; gc(); From 41a5c70f2caf5c22859574f0503afbdb3728a89c Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund <kusmabite@gmail.com> Date: Mon, 23 Mar 2009 12:53:06 +0000 Subject: [PATCH 315/654] test-suite: adding a test for fast-export with tag variants Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t9301-fast-export.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/t/t9301-fast-export.sh b/t/t9301-fast-export.sh index 86c376088c..2e31f67465 100755 --- a/t/t9301-fast-export.sh +++ b/t/t9301-fast-export.sh @@ -259,4 +259,20 @@ test_expect_success 'cope with tagger-less tags' ' ' +test_expect_success 'set-up a few more tags for tag export tests' ' + git checkout -f master && + HEAD_TREE=`git show -s --pretty=raw HEAD | grep tree | sed "s/tree //"` && + git tag tree_tag -m "tagging a tree" $HEAD_TREE && + git tag -a tree_tag-obj -m "tagging a tree" $HEAD_TREE && + git tag tag-obj_tag -m "tagging a tag" tree_tag-obj && + git tag -a tag-obj_tag-obj -m "tagging a tag" tree_tag-obj +' + +# NEEDSWORK: not just check return status, but validate the output +# two tests commented out due to crash and thus unreliable return code +test_expect_failure 'tree_tag' 'git fast-export tree_tag' +test_expect_failure 'tree_tag-obj' 'git fast-export tree_tag-obj' +test_expect_failure 'tag-obj_tag' 'git fast-export tag-obj_tag' +test_expect_failure 'tag-obj_tag-obj' 'git fast-export tag-obj_tag-obj' + test_done From 2d07f6d4b728d19d115b89123224268718f34efd Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund <kusmabite@gmail.com> Date: Mon, 23 Mar 2009 12:53:07 +0000 Subject: [PATCH 316/654] builtin-fast-export.c: turn error into warning fast-import doesn't have a syntax to support tree-objects (and some other object-types), so fast-export shouldn't handle them. However, aborting the operation is a bit drastic. This patch turns the error into a warning instead. Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-fast-export.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/builtin-fast-export.c b/builtin-fast-export.c index fdf4ae9ebd..8a6cf5e649 100644 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -378,8 +378,10 @@ static void get_tags_and_duplicates(struct object_array *pending, } break; default: - die ("Unexpected object of type %s", - typename(e->item->type)); + warning("%s: Unexpected object of type %s, skipping.", + e->name, + typename(e->item->type)); + continue; } if (commit->util) /* more than one name for the same object */ From c0582c53bcf4e83bba70e1ad23abbad31f96ebc8 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund <kusmabite@gmail.com> Date: Mon, 23 Mar 2009 12:53:08 +0000 Subject: [PATCH 317/654] builtin-fast-export.c: fix crash on tagged trees If a tag object points to a tree (or another unhandled type), the commit- pointer is left uninitialized and later dereferenced. This patch adds a default case to the switch that issues a warning and skips the object. Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-fast-export.c | 4 ++++ t/t9301-fast-export.sh | 5 ++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/builtin-fast-export.c b/builtin-fast-export.c index 8a6cf5e649..1ec459f057 100644 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -375,6 +375,10 @@ static void get_tags_and_duplicates(struct object_array *pending, case OBJ_BLOB: handle_object(tag->object.sha1); continue; + default: + warning("Tag points to object of unexpected type %s, skipping.", + typename(tag->object.type)); + continue; } break; default: diff --git a/t/t9301-fast-export.sh b/t/t9301-fast-export.sh index 2e31f67465..b1f75ceea4 100755 --- a/t/t9301-fast-export.sh +++ b/t/t9301-fast-export.sh @@ -269,9 +269,8 @@ test_expect_success 'set-up a few more tags for tag export tests' ' ' # NEEDSWORK: not just check return status, but validate the output -# two tests commented out due to crash and thus unreliable return code -test_expect_failure 'tree_tag' 'git fast-export tree_tag' -test_expect_failure 'tree_tag-obj' 'git fast-export tree_tag-obj' +test_expect_success 'tree_tag' 'git fast-export tree_tag' +test_expect_success 'tree_tag-obj' 'git fast-export tree_tag-obj' test_expect_failure 'tag-obj_tag' 'git fast-export tag-obj_tag' test_expect_failure 'tag-obj_tag-obj' 'git fast-export tag-obj_tag-obj' From 1982467d9229e3c92157f2a41363365dcb866e86 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund <kusmabite@gmail.com> Date: Mon, 23 Mar 2009 12:53:09 +0000 Subject: [PATCH 318/654] builtin-fast-export.c: handle nested tags When tags that points to tags are passed to fast-export, an error is given, saying "Tag [TAGNAME] points nowhere?". This fix calls parse_object() on the object before referencing it's tag, to ensure the tag-info is fully initialized. In addition, it inserts a comment to point out where nested tags are handled. This is consistent with the comment for signed tags. Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-fast-export.c | 5 ++++- t/t9301-fast-export.sh | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/builtin-fast-export.c b/builtin-fast-export.c index 1ec459f057..f171ee4a2b 100644 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -362,7 +362,10 @@ static void get_tags_and_duplicates(struct object_array *pending, break; case OBJ_TAG: tag = (struct tag *)e->item; + + /* handle nested tags */ while (tag && tag->object.type == OBJ_TAG) { + parse_object(tag->object.sha1); string_list_append(full_name, extra_refs)->util = tag; tag = (struct tag *)tag->tagged; } @@ -375,7 +378,7 @@ static void get_tags_and_duplicates(struct object_array *pending, case OBJ_BLOB: handle_object(tag->object.sha1); continue; - default: + default: /* OBJ_TAG (nested tags) is already handled */ warning("Tag points to object of unexpected type %s, skipping.", typename(tag->object.type)); continue; diff --git a/t/t9301-fast-export.sh b/t/t9301-fast-export.sh index b1f75ceea4..4a87f36258 100755 --- a/t/t9301-fast-export.sh +++ b/t/t9301-fast-export.sh @@ -271,7 +271,7 @@ test_expect_success 'set-up a few more tags for tag export tests' ' # NEEDSWORK: not just check return status, but validate the output test_expect_success 'tree_tag' 'git fast-export tree_tag' test_expect_success 'tree_tag-obj' 'git fast-export tree_tag-obj' -test_expect_failure 'tag-obj_tag' 'git fast-export tag-obj_tag' -test_expect_failure 'tag-obj_tag-obj' 'git fast-export tag-obj_tag-obj' +test_expect_success 'tag-obj_tag' 'git fast-export tag-obj_tag' +test_expect_success 'tag-obj_tag-obj' 'git fast-export tag-obj_tag-obj' test_done From 6e1825186bd052fc1f77b7c8c9a31fbb9a67d90c Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Sat, 28 Mar 2009 21:39:10 -0400 Subject: [PATCH 319/654] send-email: refactor and ensure prompting doesn't loop forever Several places in send-email prompt for input, and will do so forever when the input is EOF. This is poor behavior when send-email is run unattended (say from cron). This patch refactors the prompting to an ask() function which takes a prompt, an optional default, and an optional regex to validate the input. The function returns on EOF, or if a default is provided and the user simply types return, or if the input passes the validating regex (which accepts all input by default). The ask() function gives up after 10 tries in case of invalid input. There are four callers of the function: 1) "Who should the emails appear to be from?" which provides a default sender. Previously the user would have to type ctrl-d to accept the default. Now the user can just hit return, or type ctrl-d. 2) "Who should the emails be sent to?". Previously this prompt passed a second argument ("") to $term->readline() which was ignored. I believe the intent was to allow the user to just hit return. Now the user can do so, or type ctrl-d. 3) "Message-ID to be used as In-Reply-To for the first email?". Previously this prompt passed a second argument (effectively undef) to $term->readline() which was ignored. I believe the intent was the same as for (2), to allow the user to just hit return. Now the user can do so, or type ctrl-d. 4) "Send this email?". Previously this prompt would loop forever until it got a valid reply. Now it stops prompting on EOF or a valid reply. In the case where confirm = "inform", it now defaults to "y" on EOF or the user hitting return, otherwise an invalid reply causes send-email to terminate. A followup patch adds tests for the new functionality. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-send-email.perl | 66 +++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/git-send-email.perl b/git-send-email.perl index 546d2ebc0c..5916c86b68 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -606,32 +606,40 @@ EOT do_edit(@files); } +sub ask { + my ($prompt, %arg) = @_; + my $valid_re = $arg{valid_re} || ""; # "" matches anything + my $default = $arg{default}; + my $resp; + my $i = 0; + while ($i++ < 10) { + $resp = $term->readline($prompt); + if (!defined $resp) { # EOF + print "\n"; + return defined $default ? $default : undef; + } + if ($resp eq '' and defined $default) { + return $default; + } + if ($resp =~ /$valid_re/) { + return $resp; + } + } + return undef; +} + my $prompting = 0; if (!defined $sender) { $sender = $repoauthor || $repocommitter || ''; - - while (1) { - $_ = $term->readline("Who should the emails appear to be from? [$sender] "); - last if defined $_; - print "\n"; - } - - $sender = $_ if ($_); + $sender = ask("Who should the emails appear to be from? [$sender] ", + default => $sender); print "Emails will be sent from: ", $sender, "\n"; $prompting++; } if (!@to) { - - - while (1) { - $_ = $term->readline("Who should the emails be sent to? ", ""); - last if defined $_; - print "\n"; - } - - my $to = $_; - push @to, parse_address_line($to); + my $to = ask("Who should the emails be sent to? "); + push @to, parse_address_line($to) if defined $to; # sanitized/validated later $prompting++; } @@ -651,13 +659,8 @@ sub expand_aliases { @bcclist = expand_aliases(@bcclist); if ($thread && !defined $initial_reply_to && $prompting) { - while (1) { - $_= $term->readline("Message-ID to be used as In-Reply-To for the first email? ", $initial_reply_to); - last if defined $_; - print "\n"; - } - - $initial_reply_to = $_; + $initial_reply_to = ask( + "Message-ID to be used as In-Reply-To for the first email? "); } if (defined $initial_reply_to) { $initial_reply_to =~ s/^\s*<?//; @@ -839,8 +842,10 @@ X-Mailer: git-send-email $gitversion if ($needs_confirm && !$dry_run) { print "\n$header\n"; + my $ask_default; if ($needs_confirm eq "inform") { $confirm_unconfigured = 0; # squelch this message for the rest of this run + $ask_default = "y"; # assume yes on EOF since user hasn't explicitly asked for confirmation print " The Cc list above has been expanded by additional\n"; print " addresses found in the patch commit message. By default\n"; print " send-email prompts before sending whenever this occurs.\n"; @@ -851,13 +856,10 @@ X-Mailer: git-send-email $gitversion print " To retain the current behavior, but squelch this message,\n"; print " run 'git config --global sendemail.confirm auto'.\n\n"; } - while (1) { - chomp ($_ = $term->readline( - "Send this email? ([y]es|[n]o|[q]uit|[a]ll): " - )); - last if /^(?:yes|y|no|n|quit|q|all|a)/i; - print "\n"; - } + $_ = ask("Send this email? ([y]es|[n]o|[q]uit|[a]ll): ", + valid_re => qr/^(?:yes|y|no|n|quit|q|all|a)/i, + default => $ask_default); + die "Send this email reply required" unless defined $_; if (/^n/i) { return; } elsif (/^q/i) { From c18f75a1e96ff0f028edf94effd10cf56d892f22 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Sat, 28 Mar 2009 21:39:11 -0400 Subject: [PATCH 320/654] send-email: add tests for refactored prompting Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t9001-send-email.sh | 52 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index e426c96fb7..b4de98c1f2 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -421,8 +421,8 @@ test_confirm () { --from="Example <nobody@example.com>" \ --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ - $@ \ - $patches | grep "Send this email" + $@ $patches > stdout && + grep "Send this email" stdout } test_expect_success '--confirm=always' ' @@ -444,8 +444,10 @@ test_expect_success '--confirm=compose' ' test_expect_success 'confirm by default (due to cc)' ' CONFIRM=$(git config --get sendemail.confirm) && git config --unset sendemail.confirm && - test_confirm && - git config sendemail.confirm $CONFIRM + test_confirm + ret="$?" + git config sendemail.confirm ${CONFIRM:-never} + test $ret = "0" ' test_expect_success 'confirm by default (due to --compose)' ' @@ -457,6 +459,48 @@ test_expect_success 'confirm by default (due to --compose)' ' test $ret = "0" ' +test_expect_success 'confirm detects EOF (inform assumes y)' ' + CONFIRM=$(git config --get sendemail.confirm) && + git config --unset sendemail.confirm && + GIT_SEND_EMAIL_NOTTY=1 \ + git send-email \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches < /dev/null + ret="$?" + git config sendemail.confirm ${CONFIRM:-never} + test $ret = "0" +' + +test_expect_success 'confirm detects EOF (auto causes failure)' ' + CONFIRM=$(git config --get sendemail.confirm) && + git config sendemail.confirm auto && + GIT_SEND_EMAIL_NOTTY=1 \ + test_must_fail git send-email \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches < /dev/null + ret="$?" + git config sendemail.confirm ${CONFIRM:-never} + test $ret = "0" +' + +test_expect_success 'confirm doesnt loop forever' ' + CONFIRM=$(git config --get sendemail.confirm) && + git config sendemail.confirm auto && + yes "bogus" | GIT_SEND_EMAIL_NOTTY=1 \ + test_must_fail git send-email \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches + ret="$?" + git config sendemail.confirm ${CONFIRM:-never} + test $ret = "0" +' + test_expect_success '--compose adds MIME for utf8 body' ' clean_fake_sendmail && (echo "#!$SHELL_PATH" && From ebbc088e13e1bf0dbf8eb08b00519602c176f864 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sun, 29 Mar 2009 11:44:44 +0200 Subject: [PATCH 321/654] quote: implement "sq_dequote_many" to unwrap many args in one string The sq_dequote() function does not allow parsing a string with more than one single-quoted parameter easily; use its code to implement a new API sq_dequote_step() to allow the caller iterate through such a string to parse them one-by-one. The original sq_dequote() becomes a thin wrapper around it. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- quote.c | 18 ++++++++++++++++-- quote.h | 8 ++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/quote.c b/quote.c index 6a520855d6..ea49c7a99f 100644 --- a/quote.c +++ b/quote.c @@ -72,7 +72,7 @@ void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen) } } -char *sq_dequote(char *arg) +char *sq_dequote_step(char *arg, char **next) { char *dst = arg; char *src = arg; @@ -92,6 +92,8 @@ char *sq_dequote(char *arg) switch (*++src) { case '\0': *dst = 0; + if (next) + *next = NULL; return arg; case '\\': c = *++src; @@ -101,11 +103,23 @@ char *sq_dequote(char *arg) } /* Fallthrough */ default: - return NULL; + if (!next || !isspace(*src)) + return NULL; + do { + c = *++src; + } while (isspace(c)); + *dst = 0; + *next = src; + return arg; } } } +char *sq_dequote(char *arg) +{ + return sq_dequote_step(arg, NULL); +} + /* 1 means: quote as octal * 0 means: quote as octal if (quote_path_fully) * -1 means: never quote diff --git a/quote.h b/quote.h index c5eea6f18e..2315105fa3 100644 --- a/quote.h +++ b/quote.h @@ -39,6 +39,14 @@ extern void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen); */ extern char *sq_dequote(char *); +/* + * Same as the above, but can be used to unwrap many arguments in the + * same string separated by space. "next" is changed to point to the + * next argument that should be passed as first parameter. When there + * is no more argument to be dequoted, "next" is updated to point to NULL. + */ +extern char *sq_dequote_step(char *arg, char **next); + extern int unquote_c_style(struct strbuf *, const char *quoted, const char **endp); extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq); extern void quote_two_c_style(struct strbuf *, const char *, const char *, int); From eaa759b9141f125d7e55a4b08b60497845d3c52e Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sun, 29 Mar 2009 11:44:52 +0200 Subject: [PATCH 322/654] quote: add "sq_dequote_to_argv" to put unwrapped args in an argv array This new function unwraps the space separated shell quoted elements in its first argument and places them in the argv array passed as its second argument. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- quote.c | 17 +++++++++++++++++ quote.h | 1 + 2 files changed, 18 insertions(+) diff --git a/quote.c b/quote.c index ea49c7a99f..7a49fcf696 100644 --- a/quote.c +++ b/quote.c @@ -120,6 +120,23 @@ char *sq_dequote(char *arg) return sq_dequote_step(arg, NULL); } +int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc) +{ + char *next = arg; + + if (!*arg) + return 0; + do { + char *dequoted = sq_dequote_step(next, &next); + if (!dequoted) + return -1; + ALLOC_GROW(*argv, *nr + 1, *alloc); + (*argv)[(*nr)++] = dequoted; + } while (next); + + return 0; +} + /* 1 means: quote as octal * 0 means: quote as octal if (quote_path_fully) * -1 means: never quote diff --git a/quote.h b/quote.h index 2315105fa3..66730f2bff 100644 --- a/quote.h +++ b/quote.h @@ -46,6 +46,7 @@ extern char *sq_dequote(char *); * is no more argument to be dequoted, "next" is updated to point to NULL. */ extern char *sq_dequote_step(char *arg, char **next); +extern int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc); extern int unquote_c_style(struct strbuf *, const char *quoted, const char **endp); extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq); From 2a8177b63d39503b182248b04ffcc75e3495754c Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Mon, 30 Mar 2009 05:07:15 +0200 Subject: [PATCH 323/654] refs: add "for_each_ref_in" function to refactor "for_each_*_ref" functions The "for_each_{tag,branch,remote,replace,}_ref" functions are redefined in terms of "for_each_ref_in" so that we can lose the hardcoded length of prefix strings from the code. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> --- refs.c | 11 ++++++++--- refs.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/refs.c b/refs.c index aeef257ee3..2d198a1add 100644 --- a/refs.c +++ b/refs.c @@ -647,19 +647,24 @@ int for_each_ref(each_ref_fn fn, void *cb_data) return do_for_each_ref("refs/", fn, 0, 0, cb_data); } +int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data) +{ + return do_for_each_ref(prefix, fn, strlen(prefix), 0, cb_data); +} + int for_each_tag_ref(each_ref_fn fn, void *cb_data) { - return do_for_each_ref("refs/tags/", fn, 10, 0, cb_data); + return for_each_ref_in("refs/tags/", fn, cb_data); } int for_each_branch_ref(each_ref_fn fn, void *cb_data) { - return do_for_each_ref("refs/heads/", fn, 11, 0, cb_data); + return for_each_ref_in("refs/heads/", fn, cb_data); } int for_each_remote_ref(each_ref_fn fn, void *cb_data) { - return do_for_each_ref("refs/remotes/", fn, 13, 0, cb_data); + return for_each_ref_in("refs/remotes/", fn, cb_data); } int for_each_rawref(each_ref_fn fn, void *cb_data) diff --git a/refs.h b/refs.h index 29bdcecd4e..abb125754d 100644 --- a/refs.h +++ b/refs.h @@ -20,6 +20,7 @@ struct ref_lock { typedef int each_ref_fn(const char *refname, const unsigned char *sha1, int flags, void *cb_data); extern int head_ref(each_ref_fn, void *); extern int for_each_ref(each_ref_fn, void *); +extern int for_each_ref_in(const char *, each_ref_fn, void *); extern int for_each_tag_ref(each_ref_fn, void *); extern int for_each_branch_ref(each_ref_fn, void *); extern int for_each_remote_ref(each_ref_fn, void *); From ff62d732d826efcf271cd6c50a41f613af97aff6 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Thu, 26 Mar 2009 05:55:17 +0100 Subject: [PATCH 324/654] rev-list: make "bisect_list" variable local to "cmd_rev_list" The "bisect_list" variable was static for no reason as it is only used in the "cmd_rev_list" function. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-rev-list.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 40d5fcb6b0..28fe2dc30b 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -52,7 +52,6 @@ static const char rev_list_usage[] = static struct rev_info revs; -static int bisect_list; static int show_timestamp; static int hdr_termination; static const char *header_prefix; @@ -618,6 +617,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) struct commit_list *list; int i; int read_from_stdin = 0; + int bisect_list = 0; int bisect_show_vars = 0; int bisect_find_all = 0; int quiet = 0; From a2ad79ced25e1b76fabec079549f521e8071ddd1 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Thu, 26 Mar 2009 05:55:24 +0100 Subject: [PATCH 325/654] rev-list: move bisect related code into its own file This patch creates new "bisect.c" and "bisect.h" files and move bisect related code into these files. While at it, we also remove some include directives that are not needed any more from the beginning of "builtin-rev-list.c". Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 1 + bisect.c | 388 +++++++++++++++++++++++++++++++++++++++++++++ bisect.h | 8 + builtin-rev-list.c | 388 +-------------------------------------------- 4 files changed, 398 insertions(+), 387 deletions(-) create mode 100644 bisect.c create mode 100644 bisect.h diff --git a/Makefile b/Makefile index 320c89786c..9fa2928357 100644 --- a/Makefile +++ b/Makefile @@ -420,6 +420,7 @@ LIB_OBJS += archive-tar.o LIB_OBJS += archive-zip.o LIB_OBJS += attr.o LIB_OBJS += base85.o +LIB_OBJS += bisect.o LIB_OBJS += blob.o LIB_OBJS += branch.o LIB_OBJS += bundle.o diff --git a/bisect.c b/bisect.c new file mode 100644 index 0000000000..27def7dacf --- /dev/null +++ b/bisect.c @@ -0,0 +1,388 @@ +#include "cache.h" +#include "commit.h" +#include "diff.h" +#include "revision.h" +#include "bisect.h" + +/* bits #0-15 in revision.h */ + +#define COUNTED (1u<<16) + +/* + * This is a truly stupid algorithm, but it's only + * used for bisection, and we just don't care enough. + * + * We care just barely enough to avoid recursing for + * non-merge entries. + */ +static int count_distance(struct commit_list *entry) +{ + int nr = 0; + + while (entry) { + struct commit *commit = entry->item; + struct commit_list *p; + + if (commit->object.flags & (UNINTERESTING | COUNTED)) + break; + if (!(commit->object.flags & TREESAME)) + nr++; + commit->object.flags |= COUNTED; + p = commit->parents; + entry = p; + if (p) { + p = p->next; + while (p) { + nr += count_distance(p); + p = p->next; + } + } + } + + return nr; +} + +static void clear_distance(struct commit_list *list) +{ + while (list) { + struct commit *commit = list->item; + commit->object.flags &= ~COUNTED; + list = list->next; + } +} + +#define DEBUG_BISECT 0 + +static inline int weight(struct commit_list *elem) +{ + return *((int*)(elem->item->util)); +} + +static inline void weight_set(struct commit_list *elem, int weight) +{ + *((int*)(elem->item->util)) = weight; +} + +static int count_interesting_parents(struct commit *commit) +{ + struct commit_list *p; + int count; + + for (count = 0, p = commit->parents; p; p = p->next) { + if (p->item->object.flags & UNINTERESTING) + continue; + count++; + } + return count; +} + +static inline int halfway(struct commit_list *p, int nr) +{ + /* + * Don't short-cut something we are not going to return! + */ + if (p->item->object.flags & TREESAME) + return 0; + if (DEBUG_BISECT) + return 0; + /* + * 2 and 3 are halfway of 5. + * 3 is halfway of 6 but 2 and 4 are not. + */ + switch (2 * weight(p) - nr) { + case -1: case 0: case 1: + return 1; + default: + return 0; + } +} + +#if !DEBUG_BISECT +#define show_list(a,b,c,d) do { ; } while (0) +#else +static void show_list(const char *debug, int counted, int nr, + struct commit_list *list) +{ + struct commit_list *p; + + fprintf(stderr, "%s (%d/%d)\n", debug, counted, nr); + + for (p = list; p; p = p->next) { + struct commit_list *pp; + struct commit *commit = p->item; + unsigned flags = commit->object.flags; + enum object_type type; + unsigned long size; + char *buf = read_sha1_file(commit->object.sha1, &type, &size); + char *ep, *sp; + + fprintf(stderr, "%c%c%c ", + (flags & TREESAME) ? ' ' : 'T', + (flags & UNINTERESTING) ? 'U' : ' ', + (flags & COUNTED) ? 'C' : ' '); + if (commit->util) + fprintf(stderr, "%3d", weight(p)); + else + fprintf(stderr, "---"); + fprintf(stderr, " %.*s", 8, sha1_to_hex(commit->object.sha1)); + for (pp = commit->parents; pp; pp = pp->next) + fprintf(stderr, " %.*s", 8, + sha1_to_hex(pp->item->object.sha1)); + + sp = strstr(buf, "\n\n"); + if (sp) { + sp += 2; + for (ep = sp; *ep && *ep != '\n'; ep++) + ; + fprintf(stderr, " %.*s", (int)(ep - sp), sp); + } + fprintf(stderr, "\n"); + } +} +#endif /* DEBUG_BISECT */ + +static struct commit_list *best_bisection(struct commit_list *list, int nr) +{ + struct commit_list *p, *best; + int best_distance = -1; + + best = list; + for (p = list; p; p = p->next) { + int distance; + unsigned flags = p->item->object.flags; + + if (flags & TREESAME) + continue; + distance = weight(p); + if (nr - distance < distance) + distance = nr - distance; + if (distance > best_distance) { + best = p; + best_distance = distance; + } + } + + return best; +} + +struct commit_dist { + struct commit *commit; + int distance; +}; + +static int compare_commit_dist(const void *a_, const void *b_) +{ + struct commit_dist *a, *b; + + a = (struct commit_dist *)a_; + b = (struct commit_dist *)b_; + if (a->distance != b->distance) + return b->distance - a->distance; /* desc sort */ + return hashcmp(a->commit->object.sha1, b->commit->object.sha1); +} + +static struct commit_list *best_bisection_sorted(struct commit_list *list, int nr) +{ + struct commit_list *p; + struct commit_dist *array = xcalloc(nr, sizeof(*array)); + int cnt, i; + + for (p = list, cnt = 0; p; p = p->next) { + int distance; + unsigned flags = p->item->object.flags; + + if (flags & TREESAME) + continue; + distance = weight(p); + if (nr - distance < distance) + distance = nr - distance; + array[cnt].commit = p->item; + array[cnt].distance = distance; + cnt++; + } + qsort(array, cnt, sizeof(*array), compare_commit_dist); + for (p = list, i = 0; i < cnt; i++) { + struct name_decoration *r = xmalloc(sizeof(*r) + 100); + struct object *obj = &(array[i].commit->object); + + sprintf(r->name, "dist=%d", array[i].distance); + r->next = add_decoration(&name_decoration, obj, r); + p->item = array[i].commit; + p = p->next; + } + if (p) + p->next = NULL; + free(array); + return list; +} + +/* + * zero or positive weight is the number of interesting commits it can + * reach, including itself. Especially, weight = 0 means it does not + * reach any tree-changing commits (e.g. just above uninteresting one + * but traversal is with pathspec). + * + * weight = -1 means it has one parent and its distance is yet to + * be computed. + * + * weight = -2 means it has more than one parent and its distance is + * unknown. After running count_distance() first, they will get zero + * or positive distance. + */ +static struct commit_list *do_find_bisection(struct commit_list *list, + int nr, int *weights, + int find_all) +{ + int n, counted; + struct commit_list *p; + + counted = 0; + + for (n = 0, p = list; p; p = p->next) { + struct commit *commit = p->item; + unsigned flags = commit->object.flags; + + p->item->util = &weights[n++]; + switch (count_interesting_parents(commit)) { + case 0: + if (!(flags & TREESAME)) { + weight_set(p, 1); + counted++; + show_list("bisection 2 count one", + counted, nr, list); + } + /* + * otherwise, it is known not to reach any + * tree-changing commit and gets weight 0. + */ + break; + case 1: + weight_set(p, -1); + break; + default: + weight_set(p, -2); + break; + } + } + + show_list("bisection 2 initialize", counted, nr, list); + + /* + * If you have only one parent in the resulting set + * then you can reach one commit more than that parent + * can reach. So we do not have to run the expensive + * count_distance() for single strand of pearls. + * + * However, if you have more than one parents, you cannot + * just add their distance and one for yourself, since + * they usually reach the same ancestor and you would + * end up counting them twice that way. + * + * So we will first count distance of merges the usual + * way, and then fill the blanks using cheaper algorithm. + */ + for (p = list; p; p = p->next) { + if (p->item->object.flags & UNINTERESTING) + continue; + if (weight(p) != -2) + continue; + weight_set(p, count_distance(p)); + clear_distance(list); + + /* Does it happen to be at exactly half-way? */ + if (!find_all && halfway(p, nr)) + return p; + counted++; + } + + show_list("bisection 2 count_distance", counted, nr, list); + + while (counted < nr) { + for (p = list; p; p = p->next) { + struct commit_list *q; + unsigned flags = p->item->object.flags; + + if (0 <= weight(p)) + continue; + for (q = p->item->parents; q; q = q->next) { + if (q->item->object.flags & UNINTERESTING) + continue; + if (0 <= weight(q)) + break; + } + if (!q) + continue; + + /* + * weight for p is unknown but q is known. + * add one for p itself if p is to be counted, + * otherwise inherit it from q directly. + */ + if (!(flags & TREESAME)) { + weight_set(p, weight(q)+1); + counted++; + show_list("bisection 2 count one", + counted, nr, list); + } + else + weight_set(p, weight(q)); + + /* Does it happen to be at exactly half-way? */ + if (!find_all && halfway(p, nr)) + return p; + } + } + + show_list("bisection 2 counted all", counted, nr, list); + + if (!find_all) + return best_bisection(list, nr); + else + return best_bisection_sorted(list, nr); +} + +struct commit_list *find_bisection(struct commit_list *list, + int *reaches, int *all, + int find_all) +{ + int nr, on_list; + struct commit_list *p, *best, *next, *last; + int *weights; + + show_list("bisection 2 entry", 0, 0, list); + + /* + * Count the number of total and tree-changing items on the + * list, while reversing the list. + */ + for (nr = on_list = 0, last = NULL, p = list; + p; + p = next) { + unsigned flags = p->item->object.flags; + + next = p->next; + if (flags & UNINTERESTING) + continue; + p->next = last; + last = p; + if (!(flags & TREESAME)) + nr++; + on_list++; + } + list = last; + show_list("bisection 2 sorted", 0, nr, list); + + *all = nr; + weights = xcalloc(on_list, sizeof(*weights)); + + /* Do the real work of finding bisection commit. */ + best = do_find_bisection(list, nr, weights, find_all); + if (best) { + if (!find_all) + best->next = NULL; + *reaches = weight(best); + } + free(weights); + return best; +} + diff --git a/bisect.h b/bisect.h new file mode 100644 index 0000000000..60b2fe1cdc --- /dev/null +++ b/bisect.h @@ -0,0 +1,8 @@ +#ifndef BISECT_H +#define BISECT_H + +extern struct commit_list *find_bisection(struct commit_list *list, + int *reaches, int *all, + int find_all); + +#endif diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 28fe2dc30b..b1e8200d2b 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -1,20 +1,12 @@ #include "cache.h" -#include "refs.h" -#include "tag.h" #include "commit.h" -#include "tree.h" -#include "blob.h" -#include "tree-walk.h" #include "diff.h" #include "revision.h" #include "list-objects.h" #include "builtin.h" #include "log-tree.h" #include "graph.h" - -/* bits #0-15 in revision.h */ - -#define COUNTED (1u<<16) +#include "bisect.h" static const char rev_list_usage[] = "git rev-list [OPTION] <commit-id>... [ -- paths... ]\n" @@ -195,384 +187,6 @@ static void show_edge(struct commit *commit) printf("-%s\n", sha1_to_hex(commit->object.sha1)); } -/* - * This is a truly stupid algorithm, but it's only - * used for bisection, and we just don't care enough. - * - * We care just barely enough to avoid recursing for - * non-merge entries. - */ -static int count_distance(struct commit_list *entry) -{ - int nr = 0; - - while (entry) { - struct commit *commit = entry->item; - struct commit_list *p; - - if (commit->object.flags & (UNINTERESTING | COUNTED)) - break; - if (!(commit->object.flags & TREESAME)) - nr++; - commit->object.flags |= COUNTED; - p = commit->parents; - entry = p; - if (p) { - p = p->next; - while (p) { - nr += count_distance(p); - p = p->next; - } - } - } - - return nr; -} - -static void clear_distance(struct commit_list *list) -{ - while (list) { - struct commit *commit = list->item; - commit->object.flags &= ~COUNTED; - list = list->next; - } -} - -#define DEBUG_BISECT 0 - -static inline int weight(struct commit_list *elem) -{ - return *((int*)(elem->item->util)); -} - -static inline void weight_set(struct commit_list *elem, int weight) -{ - *((int*)(elem->item->util)) = weight; -} - -static int count_interesting_parents(struct commit *commit) -{ - struct commit_list *p; - int count; - - for (count = 0, p = commit->parents; p; p = p->next) { - if (p->item->object.flags & UNINTERESTING) - continue; - count++; - } - return count; -} - -static inline int halfway(struct commit_list *p, int nr) -{ - /* - * Don't short-cut something we are not going to return! - */ - if (p->item->object.flags & TREESAME) - return 0; - if (DEBUG_BISECT) - return 0; - /* - * 2 and 3 are halfway of 5. - * 3 is halfway of 6 but 2 and 4 are not. - */ - switch (2 * weight(p) - nr) { - case -1: case 0: case 1: - return 1; - default: - return 0; - } -} - -#if !DEBUG_BISECT -#define show_list(a,b,c,d) do { ; } while (0) -#else -static void show_list(const char *debug, int counted, int nr, - struct commit_list *list) -{ - struct commit_list *p; - - fprintf(stderr, "%s (%d/%d)\n", debug, counted, nr); - - for (p = list; p; p = p->next) { - struct commit_list *pp; - struct commit *commit = p->item; - unsigned flags = commit->object.flags; - enum object_type type; - unsigned long size; - char *buf = read_sha1_file(commit->object.sha1, &type, &size); - char *ep, *sp; - - fprintf(stderr, "%c%c%c ", - (flags & TREESAME) ? ' ' : 'T', - (flags & UNINTERESTING) ? 'U' : ' ', - (flags & COUNTED) ? 'C' : ' '); - if (commit->util) - fprintf(stderr, "%3d", weight(p)); - else - fprintf(stderr, "---"); - fprintf(stderr, " %.*s", 8, sha1_to_hex(commit->object.sha1)); - for (pp = commit->parents; pp; pp = pp->next) - fprintf(stderr, " %.*s", 8, - sha1_to_hex(pp->item->object.sha1)); - - sp = strstr(buf, "\n\n"); - if (sp) { - sp += 2; - for (ep = sp; *ep && *ep != '\n'; ep++) - ; - fprintf(stderr, " %.*s", (int)(ep - sp), sp); - } - fprintf(stderr, "\n"); - } -} -#endif /* DEBUG_BISECT */ - -static struct commit_list *best_bisection(struct commit_list *list, int nr) -{ - struct commit_list *p, *best; - int best_distance = -1; - - best = list; - for (p = list; p; p = p->next) { - int distance; - unsigned flags = p->item->object.flags; - - if (flags & TREESAME) - continue; - distance = weight(p); - if (nr - distance < distance) - distance = nr - distance; - if (distance > best_distance) { - best = p; - best_distance = distance; - } - } - - return best; -} - -struct commit_dist { - struct commit *commit; - int distance; -}; - -static int compare_commit_dist(const void *a_, const void *b_) -{ - struct commit_dist *a, *b; - - a = (struct commit_dist *)a_; - b = (struct commit_dist *)b_; - if (a->distance != b->distance) - return b->distance - a->distance; /* desc sort */ - return hashcmp(a->commit->object.sha1, b->commit->object.sha1); -} - -static struct commit_list *best_bisection_sorted(struct commit_list *list, int nr) -{ - struct commit_list *p; - struct commit_dist *array = xcalloc(nr, sizeof(*array)); - int cnt, i; - - for (p = list, cnt = 0; p; p = p->next) { - int distance; - unsigned flags = p->item->object.flags; - - if (flags & TREESAME) - continue; - distance = weight(p); - if (nr - distance < distance) - distance = nr - distance; - array[cnt].commit = p->item; - array[cnt].distance = distance; - cnt++; - } - qsort(array, cnt, sizeof(*array), compare_commit_dist); - for (p = list, i = 0; i < cnt; i++) { - struct name_decoration *r = xmalloc(sizeof(*r) + 100); - struct object *obj = &(array[i].commit->object); - - sprintf(r->name, "dist=%d", array[i].distance); - r->next = add_decoration(&name_decoration, obj, r); - p->item = array[i].commit; - p = p->next; - } - if (p) - p->next = NULL; - free(array); - return list; -} - -/* - * zero or positive weight is the number of interesting commits it can - * reach, including itself. Especially, weight = 0 means it does not - * reach any tree-changing commits (e.g. just above uninteresting one - * but traversal is with pathspec). - * - * weight = -1 means it has one parent and its distance is yet to - * be computed. - * - * weight = -2 means it has more than one parent and its distance is - * unknown. After running count_distance() first, they will get zero - * or positive distance. - */ -static struct commit_list *do_find_bisection(struct commit_list *list, - int nr, int *weights, - int find_all) -{ - int n, counted; - struct commit_list *p; - - counted = 0; - - for (n = 0, p = list; p; p = p->next) { - struct commit *commit = p->item; - unsigned flags = commit->object.flags; - - p->item->util = &weights[n++]; - switch (count_interesting_parents(commit)) { - case 0: - if (!(flags & TREESAME)) { - weight_set(p, 1); - counted++; - show_list("bisection 2 count one", - counted, nr, list); - } - /* - * otherwise, it is known not to reach any - * tree-changing commit and gets weight 0. - */ - break; - case 1: - weight_set(p, -1); - break; - default: - weight_set(p, -2); - break; - } - } - - show_list("bisection 2 initialize", counted, nr, list); - - /* - * If you have only one parent in the resulting set - * then you can reach one commit more than that parent - * can reach. So we do not have to run the expensive - * count_distance() for single strand of pearls. - * - * However, if you have more than one parents, you cannot - * just add their distance and one for yourself, since - * they usually reach the same ancestor and you would - * end up counting them twice that way. - * - * So we will first count distance of merges the usual - * way, and then fill the blanks using cheaper algorithm. - */ - for (p = list; p; p = p->next) { - if (p->item->object.flags & UNINTERESTING) - continue; - if (weight(p) != -2) - continue; - weight_set(p, count_distance(p)); - clear_distance(list); - - /* Does it happen to be at exactly half-way? */ - if (!find_all && halfway(p, nr)) - return p; - counted++; - } - - show_list("bisection 2 count_distance", counted, nr, list); - - while (counted < nr) { - for (p = list; p; p = p->next) { - struct commit_list *q; - unsigned flags = p->item->object.flags; - - if (0 <= weight(p)) - continue; - for (q = p->item->parents; q; q = q->next) { - if (q->item->object.flags & UNINTERESTING) - continue; - if (0 <= weight(q)) - break; - } - if (!q) - continue; - - /* - * weight for p is unknown but q is known. - * add one for p itself if p is to be counted, - * otherwise inherit it from q directly. - */ - if (!(flags & TREESAME)) { - weight_set(p, weight(q)+1); - counted++; - show_list("bisection 2 count one", - counted, nr, list); - } - else - weight_set(p, weight(q)); - - /* Does it happen to be at exactly half-way? */ - if (!find_all && halfway(p, nr)) - return p; - } - } - - show_list("bisection 2 counted all", counted, nr, list); - - if (!find_all) - return best_bisection(list, nr); - else - return best_bisection_sorted(list, nr); -} - -static struct commit_list *find_bisection(struct commit_list *list, - int *reaches, int *all, - int find_all) -{ - int nr, on_list; - struct commit_list *p, *best, *next, *last; - int *weights; - - show_list("bisection 2 entry", 0, 0, list); - - /* - * Count the number of total and tree-changing items on the - * list, while reversing the list. - */ - for (nr = on_list = 0, last = NULL, p = list; - p; - p = next) { - unsigned flags = p->item->object.flags; - - next = p->next; - if (flags & UNINTERESTING) - continue; - p->next = last; - last = p; - if (!(flags & TREESAME)) - nr++; - on_list++; - } - list = last; - show_list("bisection 2 sorted", 0, nr, list); - - *all = nr; - weights = xcalloc(on_list, sizeof(*weights)); - - /* Do the real work of finding bisection commit. */ - best = do_find_bisection(list, nr, weights, find_all); - if (best) { - if (!find_all) - best->next = NULL; - *reaches = weight(best); - } - free(weights); - return best; -} - static inline int log2i(int n) { int log2 = 0; From 9996983c9c35353f352ef7c1abd9b3d2fbb21114 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Thu, 26 Mar 2009 05:55:30 +0100 Subject: [PATCH 326/654] rev-list: move code to show bisect vars into its own function This is a straightforward clean up to make "cmd_rev_list" function smaller. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-rev-list.c | 83 +++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/builtin-rev-list.c b/builtin-rev-list.c index b1e8200d2b..74d22b4658 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -226,6 +226,49 @@ static int estimate_bisect_steps(int all) return (e < 3 * x) ? n : n - 1; } +static int show_bisect_vars(int reaches, int all, int bisect_find_all) +{ + int cnt; + char hex[41]; + + if (!revs.commits) + return 1; + + /* + * revs.commits can reach "reaches" commits among + * "all" commits. If it is good, then there are + * (all-reaches) commits left to be bisected. + * On the other hand, if it is bad, then the set + * to bisect is "reaches". + * A bisect set of size N has (N-1) commits further + * to test, as we already know one bad one. + */ + cnt = all - reaches; + if (cnt < reaches) + cnt = reaches; + strcpy(hex, sha1_to_hex(revs.commits->item->object.sha1)); + + if (bisect_find_all) { + traverse_commit_list(&revs, show_commit, show_object); + printf("------\n"); + } + + printf("bisect_rev=%s\n" + "bisect_nr=%d\n" + "bisect_good=%d\n" + "bisect_bad=%d\n" + "bisect_all=%d\n" + "bisect_steps=%d\n", + hex, + cnt - 1, + all - reaches - 1, + reaches - 1, + all, + estimate_bisect_steps(all)); + + return 0; +} + int cmd_rev_list(int argc, const char **argv, const char *prefix) { struct commit_list *list; @@ -313,44 +356,8 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) revs.commits = find_bisection(revs.commits, &reaches, &all, bisect_find_all); - if (bisect_show_vars) { - int cnt; - char hex[41]; - if (!revs.commits) - return 1; - /* - * revs.commits can reach "reaches" commits among - * "all" commits. If it is good, then there are - * (all-reaches) commits left to be bisected. - * On the other hand, if it is bad, then the set - * to bisect is "reaches". - * A bisect set of size N has (N-1) commits further - * to test, as we already know one bad one. - */ - cnt = all - reaches; - if (cnt < reaches) - cnt = reaches; - strcpy(hex, sha1_to_hex(revs.commits->item->object.sha1)); - - if (bisect_find_all) { - traverse_commit_list(&revs, show_commit, show_object); - printf("------\n"); - } - - printf("bisect_rev=%s\n" - "bisect_nr=%d\n" - "bisect_good=%d\n" - "bisect_bad=%d\n" - "bisect_all=%d\n" - "bisect_steps=%d\n", - hex, - cnt - 1, - all - reaches - 1, - reaches - 1, - all, - estimate_bisect_steps(all)); - return 0; - } + if (bisect_show_vars) + return show_bisect_vars(reaches, all, bisect_find_all); } traverse_commit_list(&revs, From 6a17fad73369173ca71d3adf0d4335a0c8137cb9 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Thu, 26 Mar 2009 05:55:35 +0100 Subject: [PATCH 327/654] rev-list: make "show_bisect_vars" non static and declare it in "bisect.h" as we will use this function later. While at it, rename its last argument "show_all" instead of "bisect_find_all". Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.h | 2 ++ builtin-rev-list.c | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/bisect.h b/bisect.h index 60b2fe1cdc..860a15c9b8 100644 --- a/bisect.h +++ b/bisect.h @@ -5,4 +5,6 @@ extern struct commit_list *find_bisection(struct commit_list *list, int *reaches, int *all, int find_all); +extern int show_bisect_vars(int reaches, int all, int show_all); + #endif diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 74d22b4658..c700c34be5 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -226,7 +226,7 @@ static int estimate_bisect_steps(int all) return (e < 3 * x) ? n : n - 1; } -static int show_bisect_vars(int reaches, int all, int bisect_find_all) +int show_bisect_vars(int reaches, int all, int show_all) { int cnt; char hex[41]; @@ -246,9 +246,10 @@ static int show_bisect_vars(int reaches, int all, int bisect_find_all) cnt = all - reaches; if (cnt < reaches) cnt = reaches; + strcpy(hex, sha1_to_hex(revs.commits->item->object.sha1)); - if (bisect_find_all) { + if (show_all) { traverse_commit_list(&revs, show_commit, show_object); printf("------\n"); } From 7428d754e2dec9e82253d1e02b4df20fab3f3384 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Thu, 26 Mar 2009 05:55:41 +0100 Subject: [PATCH 328/654] rev-list: pass "revs" to "show_bisect_vars" instead of using static "revs" data Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.h | 3 ++- builtin-rev-list.c | 13 +++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/bisect.h b/bisect.h index 860a15c9b8..31c99fe5f4 100644 --- a/bisect.h +++ b/bisect.h @@ -5,6 +5,7 @@ extern struct commit_list *find_bisection(struct commit_list *list, int *reaches, int *all, int find_all); -extern int show_bisect_vars(int reaches, int all, int show_all); +extern int show_bisect_vars(struct rev_info *revs, int reaches, int all, + int show_all); #endif diff --git a/builtin-rev-list.c b/builtin-rev-list.c index c700c34be5..cdb0f9d913 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -226,16 +226,16 @@ static int estimate_bisect_steps(int all) return (e < 3 * x) ? n : n - 1; } -int show_bisect_vars(int reaches, int all, int show_all) +int show_bisect_vars(struct rev_info *revs, int reaches, int all, int show_all) { int cnt; char hex[41]; - if (!revs.commits) + if (!revs->commits) return 1; /* - * revs.commits can reach "reaches" commits among + * revs->commits can reach "reaches" commits among * "all" commits. If it is good, then there are * (all-reaches) commits left to be bisected. * On the other hand, if it is bad, then the set @@ -247,10 +247,10 @@ int show_bisect_vars(int reaches, int all, int show_all) if (cnt < reaches) cnt = reaches; - strcpy(hex, sha1_to_hex(revs.commits->item->object.sha1)); + strcpy(hex, sha1_to_hex(revs->commits->item->object.sha1)); if (show_all) { - traverse_commit_list(&revs, show_commit, show_object); + traverse_commit_list(revs, show_commit, show_object); printf("------\n"); } @@ -358,7 +358,8 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) revs.commits = find_bisection(revs.commits, &reaches, &all, bisect_find_all); if (bisect_show_vars) - return show_bisect_vars(reaches, all, bisect_find_all); + return show_bisect_vars(&revs, reaches, all, + bisect_find_all); } traverse_commit_list(&revs, From bf516ecaac4d7fca840f55e2534066227aa639be Mon Sep 17 00:00:00 2001 From: Markus Heidelberg <markus.heidelberg@web.de> Date: Sun, 29 Mar 2009 15:29:23 +0100 Subject: [PATCH 329/654] git-gui: fix deleting from the context menu with empty selection An "Application Error" was raised when trying to delete text from the commit message field when no text was selected. Signed-off-by: Markus Heidelberg <markus.heidelberg@web.de> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui.sh b/git-gui.sh index 2f1f305019..b3aa7325f0 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -2944,7 +2944,7 @@ $ctxm add command \ -command {tk_textPaste $ui_comm} $ctxm add command \ -label [mc Delete] \ - -command {$ui_comm delete sel.first sel.last} + -command {catch {$ui_comm delete sel.first sel.last}} $ctxm add separator $ctxm add command \ -label [mc "Select All"] \ From 76d3cc50b518d1c28d802ad2917063d8a5d34419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santi=20B=C3=A9jar?= <santi@agolina.net> Date: Mon, 30 Mar 2009 12:11:40 +0200 Subject: [PATCH 330/654] Documentation: enhance branch.<name>.{remote,merge} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The documentation for branch.*.merge is very dense, so add a simple explanation on top of it. And branch.*.remote also affects 'git push'. Signed-off-by: Santi Béjar <santi@agolina.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 750675530c..a6fc8da0bf 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -473,10 +473,14 @@ branch.autosetuprebase:: This option defaults to never. branch.<name>.remote:: - When in branch <name>, it tells 'git-fetch' which remote to fetch. - If this option is not given, 'git-fetch' defaults to remote "origin". + When in branch <name>, it tells 'git-fetch' and 'git-push' which + remote to fetch from/push to. It defaults to `origin` if no remote is + configured. `origin` is also used if you are not on any branch. branch.<name>.merge:: + Defines, together with branch.<name>.remote, the upstream branch + for the given branch. It tells 'git-fetch'/'git-pull' which + branch to merge from. When in branch <name>, it tells 'git-fetch' the default refspec to be marked for merging in FETCH_HEAD. The value is handled like the remote part of a refspec, and must match a From 01eadafccbeae485503f5373dc60cc5a04877c3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santi=20B=C3=A9jar?= <santi@agolina.net> Date: Mon, 30 Mar 2009 12:11:41 +0200 Subject: [PATCH 331/654] Documentation: push.default applies to all remotes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit push.default is not only for the current remote but setting the default behaviour for all remotes. Signed-off-by: Santi Béjar <santi@agolina.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index a6fc8da0bf..ad22cb875e 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1202,19 +1202,14 @@ push.default:: Defines the action git push should take if no refspec is given on the command line, no refspec is configured in the remote, and no refspec is implied by any of the options given on the command - line. -+ -The term `current remote` means the remote configured for the current -branch, or `origin` if no remote is configured. `origin` is also used -if you are not on any branch. Possible values are: + line. Possible values are: + * `nothing` do not push anything. -* `matching` push all matching branches to the current remote. +* `matching` push all matching branches. All branches having the same name in both ends are considered to be - matching. This is the current default value. + matching. This is the default. * `tracking` push the current branch to the branch it is tracking. -* `current` push the current branch to a branch of the same name on the - current remote. +* `current` push the current branch to a branch of the same name. rebase.stat:: Whether to show a diffstat of what changed upstream since the last From 49750f30767b3eb4683e8d2f4d742354dd5d03d3 Mon Sep 17 00:00:00 2001 From: Simon Arlott <simon@fire.lp0.eu> Date: Mon, 30 Mar 2009 19:31:41 +0100 Subject: [PATCH 332/654] git-svn: add a double quiet option to hide git commits People may expect/prefer -q to still show git commits, so this change allows a second -q to hide them. Signed-off-by: Michael Poole <mdpoole@troilus.org> Signed-off-by: Simon Arlott <simon@fire.lp0.eu> Acked-by: Eric Wong <normalperson@yhbt.net> --- Documentation/git-svn.txt | 3 ++- git-svn.perl | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index cda3389331..8163a19843 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -385,7 +385,8 @@ config key: svn.authorsfile -q:: --quiet:: - Make 'git-svn' less verbose. + Make 'git-svn' less verbose. Specify a second time to make it + even less verbose. --repack[=<n>]:: --repack-flags=<flags>:: diff --git a/git-svn.perl b/git-svn.perl index e5c3dfe5d2..d9197989d2 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -68,6 +68,7 @@ my ($_stdin, $_help, $_edit, $_prefix, $_no_checkout, $_url, $_verbose, $_git_format, $_commit_url, $_tag); $Git::SVN::_follow_parent = 1; +$_q ||= 0; my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username, 'config-dir=s' => \$Git::SVN::Ra::config_dir, 'no-auth-cache' => \$Git::SVN::Prompt::_no_auth_cache, @@ -80,7 +81,7 @@ my %fc_opts = ( 'follow-parent|follow!' => \$Git::SVN::_follow_parent, 'useSvnsyncProps' => \$Git::SVN::_use_svnsync_props, 'log-window-size=i' => \$Git::SVN::Ra::_log_window_size, 'no-checkout' => \$_no_checkout, - 'quiet|q' => \$_q, + 'quiet|q+' => \$_q, 'repack-flags|repack-args|repack-opts=s' => \$Git::SVN::_repack_flags, 'use-log-author' => \$Git::SVN::_use_log_author, @@ -2331,13 +2332,13 @@ sub do_git_commit { $self->{last_rev} = $log_entry->{revision}; $self->{last_commit} = $commit; - print "r$log_entry->{revision}" unless $::_q; + print "r$log_entry->{revision}" unless $::_q > 1; if (defined $log_entry->{svm_revision}) { - print " (\@$log_entry->{svm_revision})" unless $::_q; + print " (\@$log_entry->{svm_revision})" unless $::_q > 1; $self->rev_map_set($log_entry->{svm_revision}, $commit, 0, $self->svm_uuid); } - print " = $commit ($self->{ref_id})\n" unless $::_q; + print " = $commit ($self->{ref_id})\n" unless $::_q > 1; if (--$_gc_nr == 0) { $_gc_nr = $_gc_period; gc(); From e161acd11da05add6575a6931f4ff38a5685dd7d Mon Sep 17 00:00:00 2001 From: Ali Gholami Rudi <ali@rudi.ir> Date: Wed, 1 Apr 2009 12:34:44 +0430 Subject: [PATCH 333/654] builtin-clone.c: make junk_pid static junk_pid is used only in builtin-clone.c. Signed-off-by: Ali Gholami Rudi <ali@rudi.ir> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-clone.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-clone.c b/builtin-clone.c index 0031b5f51c..736c72c236 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -270,7 +270,7 @@ static const struct ref *clone_local(const char *src_repo, static const char *junk_work_tree; static const char *junk_git_dir; -pid_t junk_pid; +static pid_t junk_pid; static void remove_junk(void) { From 50b5f420fe94399e3da867a0ff0585bc5d3fe86f Mon Sep 17 00:00:00 2001 From: Ali Gholami Rudi <ali@rudi.ir> Date: Wed, 1 Apr 2009 15:52:25 +0430 Subject: [PATCH 334/654] builtin-clone.c: no need to strdup for setenv The setenv function makes a copy, itself. Signed-off-by: Ali Gholami Rudi <ali@rudi.ir> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-clone.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-clone.c b/builtin-clone.c index 736c72c236..880373f279 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -406,7 +406,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) atexit(remove_junk); sigchain_push_common(remove_junk_on_signal); - setenv(CONFIG_ENVIRONMENT, xstrdup(mkpath("%s/config", git_dir)), 1); + setenv(CONFIG_ENVIRONMENT, mkpath("%s/config", git_dir), 1); if (safe_create_leading_directories_const(git_dir) < 0) die("could not create leading directories of '%s'", git_dir); From 2346431e476ab9f095f0dd2921f63fa071039bb8 Mon Sep 17 00:00:00 2001 From: Chris Johnsen <chris_johnsen@pobox.com> Date: Wed, 1 Apr 2009 03:50:34 -0500 Subject: [PATCH 335/654] Documentation: use "spurious .sp" XSLT if DOCBOOK_SUPPRESS_SP is set With this change, the "spurious .sp" suppression XSLT code is disabled by default. It can be enabled by defining DOCBOOK_SUPPRESS_SP. The "spurious .sp" XSLT fragment was used to work around a bug first released in docbook-xsl 1.69.1. Modern versions of docbook-xsl are negatively affected by the code (some empty lines are omitted from manpage output; see <http://article.gmane.org/gmane.comp.version-control.git/115302>). The key revisions in the docbook SVN repo seem to be 5144 (before docbook-xsl 1.69.1) and 6359 (before docbook-xsl 1.71.1). Testing done with asciidoc 8.3.1 and docbook-xsl 1.74.0. Signed-off-by: Chris Johnsen <chris_johnsen@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/Makefile | 7 ++++++- Documentation/RelNotes-1.6.3.txt | 5 +++++ Documentation/manpage-base.xsl | 13 ------------- Documentation/manpage-suppress-sp.xsl | 21 +++++++++++++++++++++ 4 files changed, 32 insertions(+), 14 deletions(-) create mode 100644 Documentation/manpage-suppress-sp.xsl diff --git a/Documentation/Makefile b/Documentation/Makefile index dae3174667..dba97dc21d 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -69,7 +69,9 @@ endif # # For docbook-xsl ... # -1.68.1, set ASCIIDOC_NO_ROFF? (based on changelog from 1.73.0) -# 1.69.0-1.71.1, no extra settings are needed? +# 1.69.0, no extra settings are needed? +# 1.69.1-1.71.0, set DOCBOOK_SUPPRESS_SP? +# 1.71.1, no extra settings are needed? # 1.72.0, set DOCBOOK_XSL_172. # 1.73.0-, set ASCIIDOC_NO_ROFF # @@ -97,6 +99,9 @@ endif ifdef MAN_BOLD_LITERAL XMLTO_EXTRA += -m manpage-bold-literal.xsl endif +ifdef DOCBOOK_SUPPRESS_SP +XMLTO_EXTRA += -m manpage-suppress-sp.xsl +endif # # Please note that there is a minor bug in asciidoc. diff --git a/Documentation/RelNotes-1.6.3.txt b/Documentation/RelNotes-1.6.3.txt index 0d8260a842..95405907b8 100644 --- a/Documentation/RelNotes-1.6.3.txt +++ b/Documentation/RelNotes-1.6.3.txt @@ -102,6 +102,11 @@ Updates since v1.6.2 * Makefile learned 'coverage' option to run the test suites with coverage tracking enabled. +* Building the manpages with docbook-xsl between 1.69.1 and 1.71.1 now + requires setting DOCBOOK_SUPPRESS_SP to work around a docbook-xsl bug. + This workaround used to be enabled by default, but causes problems + with newer versions of docbook-xsl. + Fixes since v1.6.2 ------------------ diff --git a/Documentation/manpage-base.xsl b/Documentation/manpage-base.xsl index 16e2e40976..a264fa6160 100644 --- a/Documentation/manpage-base.xsl +++ b/Documentation/manpage-base.xsl @@ -32,17 +32,4 @@ <xsl:text>br </xsl:text> </xsl:template> -<!-- attempt to work around spurious .sp at the tail of the line - that docbook stylesheets seem to add --> -<xsl:template match="simpara"> - <xsl:variable name="content"> - <xsl:apply-templates/> - </xsl:variable> - <xsl:value-of select="normalize-space($content)"/> - <xsl:if test="not(ancestor::authorblurb) and - not(ancestor::personblurb)"> - <xsl:text> </xsl:text> - </xsl:if> -</xsl:template> - </xsl:stylesheet> diff --git a/Documentation/manpage-suppress-sp.xsl b/Documentation/manpage-suppress-sp.xsl new file mode 100644 index 0000000000..a63c7632a8 --- /dev/null +++ b/Documentation/manpage-suppress-sp.xsl @@ -0,0 +1,21 @@ +<!-- manpage-suppress-sp.xsl: + special settings for manpages rendered from asciidoc+docbook + handles erroneous, inline .sp in manpage output of some + versions of docbook-xsl --> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version="1.0"> + +<!-- attempt to work around spurious .sp at the tail of the line + that some versions of docbook stylesheets seem to add --> +<xsl:template match="simpara"> + <xsl:variable name="content"> + <xsl:apply-templates/> + </xsl:variable> + <xsl:value-of select="normalize-space($content)"/> + <xsl:if test="not(ancestor::authorblurb) and + not(ancestor::personblurb)"> + <xsl:text> </xsl:text> + </xsl:if> +</xsl:template> + +</xsl:stylesheet> From 871d21d42e0f782b7cb111beec8c252e9aa627ff Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Tue, 31 Mar 2009 16:24:38 -0700 Subject: [PATCH 336/654] format_sanitized_subject: Don't trim past initial length of strbuf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the subject line is '...' the strbuf will be accessed before the first dot is added; potentially changing the strbuf passed into the function or accessing sb->buf[-1] if it was originally empty. Reported-by: René Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- pretty.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pretty.c b/pretty.c index c57cef47c9..a0ef356558 100644 --- a/pretty.c +++ b/pretty.c @@ -502,6 +502,7 @@ static int istitlechar(char c) static void format_sanitized_subject(struct strbuf *sb, const char *msg) { size_t trimlen; + size_t start_len = sb->len; int space = 2; for (; *msg && *msg != '\n'; msg++) { @@ -519,8 +520,9 @@ static void format_sanitized_subject(struct strbuf *sb, const char *msg) /* trim any trailing '.' or '-' characters */ trimlen = 0; - while (sb->buf[sb->len - 1 - trimlen] == '.' - || sb->buf[sb->len - 1 - trimlen] == '-') + while (sb->len - trimlen > start_len && + (sb->buf[sb->len - 1 - trimlen] == '.' + || sb->buf[sb->len - 1 - trimlen] == '-')) trimlen++; strbuf_remove(sb, sb->len - trimlen, trimlen); } From 5906f54e474c6e8aabb0f6b955d446b509cde06e Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Tue, 31 Mar 2009 12:22:11 -0400 Subject: [PATCH 337/654] send-email: don't attempt to prompt if tty is closed Attempting to prompt when the tty is closed (typically when running from cron) is pointless and emits a warning. This patch causes ask() to return early, squelching the warning. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-send-email.perl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-send-email.perl b/git-send-email.perl index 5916c86b68..d790660bcf 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -612,6 +612,9 @@ sub ask { my $default = $arg{default}; my $resp; my $i = 0; + return defined $default ? $default : undef + unless defined $term->IN and defined fileno($term->IN) and + defined $term->OUT and defined fileno($term->OUT); while ($i++ < 10) { $resp = $term->readline($prompt); if (!defined $resp) { # EOF From dc1460aa8de64f62b4612b6d2546ed7b88050de2 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Tue, 31 Mar 2009 12:22:12 -0400 Subject: [PATCH 338/654] send-email: ask_default should apply to all emails, not just the first Commit 6e18251 made the "Send this email?" prompt assume yes if confirm = "inform" when it was unable to get a valid response. However, the "yes" assumption only worked correctly for the first email. This commit fixes the issue and confirms the fix by modifying the existing test for the prompt to send multiple emails. Reported by Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-send-email.perl | 3 +-- t/t9001-send-email.sh | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/git-send-email.perl b/git-send-email.perl index d790660bcf..fc153f9459 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -687,7 +687,7 @@ if ($compose && $compose > 0) { # Variables we set as part of the loop over files our ($message_id, %mail, $subject, $reply_to, $references, $message, - $needs_confirm, $message_num); + $needs_confirm, $message_num, $ask_default); sub extract_valid_address { my $address = shift; @@ -845,7 +845,6 @@ X-Mailer: git-send-email $gitversion if ($needs_confirm && !$dry_run) { print "\n$header\n"; - my $ask_default; if ($needs_confirm eq "inform") { $confirm_unconfigured = 0; # squelch this message for the rest of this run $ask_default = "y"; # assume yes on EOF since user hasn't explicitly asked for confirmation diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index b4de98c1f2..195ff8b27b 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -462,12 +462,14 @@ test_expect_success 'confirm by default (due to --compose)' ' test_expect_success 'confirm detects EOF (inform assumes y)' ' CONFIRM=$(git config --get sendemail.confirm) && git config --unset sendemail.confirm && + rm -fr outdir && + git format-patch -2 -o outdir && GIT_SEND_EMAIL_NOTTY=1 \ git send-email \ --from="Example <nobody@example.com>" \ --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ - $patches < /dev/null + outdir/*.patch < /dev/null ret="$?" git config sendemail.confirm ${CONFIRM:-never} test $ret = "0" From 666e07e69703c3930a60fbb1a74ed9923d293f16 Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@linux-foundation.org> Date: Tue, 31 Mar 2009 09:45:22 -0700 Subject: [PATCH 339/654] Clean up reflog unreachability pruning decision This clarifies the pruning rules for unreachable commits by having a separate helpder function for the unreachability decision. It's preparation for actual bigger changes to come to speed up the decision when the reachability calculations become a bottleneck. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-reflog.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/builtin-reflog.c b/builtin-reflog.c index d95f515f2e..a07960ff5e 100644 --- a/builtin-reflog.c +++ b/builtin-reflog.c @@ -209,6 +209,31 @@ static int keep_entry(struct commit **it, unsigned char *sha1) return 1; } +static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsigned char *sha1) +{ + /* + * We may or may not have the commit yet - if not, look it + * up using the supplied sha1. + */ + if (!commit) { + if (is_null_sha1(sha1)) + return 0; + + commit = lookup_commit_reference_gently(sha1, 1); + + /* Not a commit -- keep it */ + if (!commit) + return 0; + } + + /* Reachable from the current ref? Don't prune. */ + if (in_merge_bases(commit, &cb->ref_commit, 1)) + return 0; + + /* We can't reach it - prune it. */ + return 1; +} + static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1, const char *email, unsigned long timestamp, int tz, const char *message, void *cb_data) @@ -230,12 +255,7 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1, if (timestamp < cb->cmd->expire_unreachable) { if (!cb->ref_commit) goto prune; - if (!old && !is_null_sha1(osha1)) - old = lookup_commit_reference_gently(osha1, 1); - if (!new && !is_null_sha1(nsha1)) - new = lookup_commit_reference_gently(nsha1, 1); - if ((old && !in_merge_bases(old, &cb->ref_commit, 1)) || - (new && !in_merge_bases(new, &cb->ref_commit, 1))) + if (unreachable(cb, old, osha1) || unreachable(cb, new, nsha1)) goto prune; } From 494fbfe87ade4658cb5c3a061a5be5d6f6496607 Mon Sep 17 00:00:00 2001 From: Junio Hamano <gitster@pobox.com> Date: Mon, 30 Mar 2009 21:34:14 -0700 Subject: [PATCH 340/654] Speed up reflog pruning of unreachable commits Instead of doing the (potentially very expensive) "in_merge_base()" check for each commit that might be pruned if it is unreachable, do a preparatory reachability graph of the commit space, so that the common case of being reachable can be tested directly. [ Cleaned up a bit and tweaked to actually work. - Linus ] Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-reflog.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/builtin-reflog.c b/builtin-reflog.c index a07960ff5e..249ad2a311 100644 --- a/builtin-reflog.c +++ b/builtin-reflog.c @@ -52,6 +52,7 @@ struct collect_reflog_cb { #define INCOMPLETE (1u<<10) #define STUDYING (1u<<11) +#define REACHABLE (1u<<12) static int tree_is_complete(const unsigned char *sha1) { @@ -227,6 +228,8 @@ static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsig } /* Reachable from the current ref? Don't prune. */ + if (commit->object.flags & REACHABLE) + return 0; if (in_merge_bases(commit, &cb->ref_commit, 1)) return 0; @@ -234,6 +237,43 @@ static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsig return 1; } +static void mark_reachable(struct commit *commit, unsigned long expire_limit) +{ + /* + * We need to compute if commit on either side of an reflog + * entry is reachable from the tip of the ref for all entries. + * Mark commits that are reachable from the tip down to the + * time threashold first; we know a commit marked thusly is + * reachable from the tip without running in_merge_bases() + * at all. + */ + struct commit_list *pending = NULL; + + commit_list_insert(commit, &pending); + while (pending) { + struct commit_list *entry = pending; + struct commit_list *parent; + pending = entry->next; + commit = entry->item; + free(entry); + if (commit->object.flags & REACHABLE) + continue; + if (parse_commit(commit)) + continue; + commit->object.flags |= REACHABLE; + if (commit->date < expire_limit) + continue; + parent = commit->parents; + while (parent) { + commit = parent->item; + parent = parent->next; + if (commit->object.flags & REACHABLE) + continue; + commit_list_insert(commit, &pending); + } + } +} + static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1, const char *email, unsigned long timestamp, int tz, const char *message, void *cb_data) @@ -308,7 +348,11 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused, cb.ref_commit = lookup_commit_reference_gently(sha1, 1); cb.ref = ref; cb.cmd = cmd; + if (cb.ref_commit) + mark_reachable(cb.ref_commit, cmd->expire_total); for_each_reflog_ent(ref, expire_reflog_ent, &cb); + if (cb.ref_commit) + clear_commit_marks(cb.ref_commit, REACHABLE); finish: if (cb.newlog) { if (fclose(cb.newlog)) { From 75fd877e150ecca74f9749bfd6bfa9a6b425ab57 Mon Sep 17 00:00:00 2001 From: Heiko Voigt <hvoigt@hvoigt.net> Date: Wed, 1 Apr 2009 22:24:28 +0200 Subject: [PATCH 341/654] Cleanup warning about known issues in cvsimport documentation Not all statements were complete sentences. Signed-off-by: Heiko Voigt <hvoigt@hvoigt.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-cvsimport.txt | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt index e1fd047bb5..d7bab13f6c 100644 --- a/Documentation/git-cvsimport.txt +++ b/Documentation/git-cvsimport.txt @@ -173,24 +173,26 @@ ISSUES Problems related to timestamps: * If timestamps of commits in the cvs repository are not stable enough - to be used for ordering commits + to be used for ordering commits changes may show up in the wrong + order. * If any files were ever "cvs import"ed more than once (e.g., import of - more than one vendor release) + more than one vendor release) the HEAD contains the wrong content. * If the timestamp order of different files cross the revision order - within the commit matching time window + within the commit matching time window the order of commits may be + wrong. Problems related to branches: - * Branches on which no commits have been made are not imported + * Branches on which no commits have been made are not imported. * All files from the branching point are added to a branch even if - never added in cvs - * files added to the source branch *after* a daughter branch was - created: If previously no commit was made on the daugther branch they - will erroneously be added to the daughter branch in git + never added in cvs. + * This applies to files added to the source branch *after* a daughter + branch was created: if previously no commit was made on the daughter + branch they will erroneously be added to the daughter branch in git. Problems related to tags: -* Multiple tags on the same revision are not imported +* Multiple tags on the same revision are not imported. If you suspect that any of these issues may apply to the repository you want to import consider using these alternative tools which proved to be From 5e6e2b487e76066d03b4f5809dc6b44b1234519a Mon Sep 17 00:00:00 2001 From: Michael J Gruber <git@drmicha.warpmail.net> Date: Wed, 1 Apr 2009 23:42:49 +0200 Subject: [PATCH 342/654] Make local branches behave like remote branches when --tracked This makes sure that local branches, when followed using --track, behave the same as remote ones (e.g. differences being reported by git status and git checkout). This fixes 1 known failure. The fix is done within branch_get(): The first natural candidate, namely remote_find_tracking(), does not have all the necessary info because in general there is no remote struct for '.', and we don't want one because it would show up in other places as well. branch_get(), on the other hand, has access to merge_names[] (in addition to merge[]) and therefore can set up the followed branch easily. Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- remote.c | 7 +++++-- t/t6040-tracking-info.sh | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/remote.c b/remote.c index e5d6b100d7..30d7fdec83 100644 --- a/remote.c +++ b/remote.c @@ -1170,8 +1170,9 @@ struct branch *branch_get(const char *name) for (i = 0; i < ret->merge_nr; i++) { ret->merge[i] = xcalloc(1, sizeof(**ret->merge)); ret->merge[i]->src = xstrdup(ret->merge_name[i]); - remote_find_tracking(ret->remote, - ret->merge[i]); + if (remote_find_tracking(ret->remote, ret->merge[i]) + && !strcmp(ret->remote_name, ".")) + ret->merge[i]->dst = xstrdup(ret->merge_name[i]); } } } @@ -1450,6 +1451,8 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb) base = branch->merge[0]->dst; if (!prefixcmp(base, "refs/remotes/")) { base += strlen("refs/remotes/"); + } else if (!prefixcmp(base, "refs/heads/")) { + base += strlen("refs/heads/"); } if (!num_theirs) strbuf_addf(sb, "Your branch is ahead of '%s' " diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh index 2a2b6b63d5..3d6db4d386 100755 --- a/t/t6040-tracking-info.sh +++ b/t/t6040-tracking-info.sh @@ -58,7 +58,7 @@ test_expect_success 'checkout' ' grep "have 1 and 1 different" actual ' -test_expect_failure 'checkout with local tracked branch' ' +test_expect_success 'checkout with local tracked branch' ' git checkout master && git checkout follower >actual grep "is ahead of" actual From 5288dd58356e53d61e2b3804fc7d8d23c3a46ab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= <B.Steinbrink@gmx.de> Date: Tue, 31 Mar 2009 17:30:39 +0200 Subject: [PATCH 343/654] Mailmap: Allow empty email addresses to be mapped MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While it makes no sense to map some email address to an empty one, doing things the other way around can be useful. For example when using filter-branch with an env-filter that employs a mailmap to fix up an import that created such broken commits with empty email addresses. Signed-off-by: Björn Steinbrink <B.Steinbrink@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- mailmap.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mailmap.c b/mailmap.c index f12bb45a3f..654c6295cb 100644 --- a/mailmap.c +++ b/mailmap.c @@ -90,7 +90,8 @@ static void add_mapping(struct string_list *map, old_name, old_email, new_name, new_email); } -static char *parse_name_and_email(char *buffer, char **name, char **email) +static char *parse_name_and_email(char *buffer, char **name, + char **email, int allow_empty_email) { char *left, *right, *nstart, *nend; *name = *email = 0; @@ -99,7 +100,7 @@ static char *parse_name_and_email(char *buffer, char **name, char **email) return NULL; if ((right = strchr(left+1, '>')) == NULL) return NULL; - if (left+1 == right) + if (!allow_empty_email && (left+1 == right)) return NULL; /* remove whitespace from beginning and end of name */ @@ -150,8 +151,8 @@ static int read_single_mailmap(struct string_list *map, const char *filename, ch } continue; } - if ((name2 = parse_name_and_email(buffer, &name1, &email1)) != NULL) - parse_name_and_email(name2, &name2, &email2); + if ((name2 = parse_name_and_email(buffer, &name1, &email1, 0)) != NULL) + parse_name_and_email(name2, &name2, &email2, 1); if (email1) add_mapping(map, name1, email1, name2, email2); From 0e5e69a355b7bdd1af6ca33ac7ee35299bda368e Mon Sep 17 00:00:00 2001 From: "Wesley J. Landaker" <wjl@icecavern.net> Date: Wed, 1 Apr 2009 16:05:01 -0600 Subject: [PATCH 344/654] Documentation: git-svn: fix trunk/fetch svn-remote key typo Fix the git-svn documentation svn-remote example section talking about tags and branches by using the proper key "fetch" instead of "trunk". Using "trunk" actually might be nice, but it doesn't currently work. The fetch line for the trunk was also reordered to be at the top of the list, since most people think about the trunk/tags/branches trio in that logical order. Signed-off-by: Wesley J. Landaker <wjl@icecavern.net> Acked-by: Eric Wong <normalperson@yhbt.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-svn.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index 8163a19843..b7b1af813d 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -673,9 +673,9 @@ listed below are allowed: ------------------------------------------------------------------------ [svn-remote "project-a"] url = http://server.org/svn + fetch = trunk/project-a:refs/remotes/project-a/trunk branches = branches/*/project-a:refs/remotes/project-a/branches/* tags = tags/*/project-a:refs/remotes/project-a/tags/* - trunk = trunk/project-a:refs/remotes/project-a/trunk ------------------------------------------------------------------------ Keep in mind that the '*' (asterisk) wildcard of the local ref From 3b3637c3f1d752e6e6d559f30cc53bbec18537ef Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Tue, 31 Mar 2009 12:22:13 -0400 Subject: [PATCH 345/654] send-email: correct two tests which were going interactive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit c18f75a (send-email: add tests for refactored prompting, 2009-03-28) added two tests which went interactive under the dash shell. This patch corrects the issue, reported by Björn Steinbrink. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t9001-send-email.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 195ff8b27b..84238f7197 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -478,7 +478,8 @@ test_expect_success 'confirm detects EOF (inform assumes y)' ' test_expect_success 'confirm detects EOF (auto causes failure)' ' CONFIRM=$(git config --get sendemail.confirm) && git config sendemail.confirm auto && - GIT_SEND_EMAIL_NOTTY=1 \ + GIT_SEND_EMAIL_NOTTY=1 && + export GIT_SEND_EMAIL_NOTTY && test_must_fail git send-email \ --from="Example <nobody@example.com>" \ --to=nobody@example.com \ @@ -492,8 +493,9 @@ test_expect_success 'confirm detects EOF (auto causes failure)' ' test_expect_success 'confirm doesnt loop forever' ' CONFIRM=$(git config --get sendemail.confirm) && git config sendemail.confirm auto && - yes "bogus" | GIT_SEND_EMAIL_NOTTY=1 \ - test_must_fail git send-email \ + GIT_SEND_EMAIL_NOTTY=1 && + export GIT_SEND_EMAIL_NOTTY && + yes "bogus" | test_must_fail git send-email \ --from="Example <nobody@example.com>" \ --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ From a61c0ffa4474ad6dcec18a5454630371106710f4 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Tue, 31 Mar 2009 12:22:14 -0400 Subject: [PATCH 346/654] send-email: ensure quoted addresses are rfc2047 encoded sanitize_address assumes that quoted addresses (e.g., "first last" <first.last@example.com) do not need rfc2047 encoding, but this is not always the case. For example, various places in send-email extract addresses using parse_address_line. parse_address_line returns the addresses already quoted (e.g., "first last" <first.last@example.com), but not rfc2047 encoded. This patch makes sanitize_address stricter about what needs rfc2047 encoding and adds a test demonstrating where I noticed the problem. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-send-email.perl | 3 ++- t/t9001-send-email.sh | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index fc153f9459..6bbdfec849 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -776,12 +776,13 @@ sub sanitize_address } # if recipient_name is already quoted, do nothing - if ($recipient_name =~ /^(".*"|=\?utf-8\?q\?.*\?=)$/) { + if ($recipient_name =~ /^("[[:ascii:]]*"|=\?utf-8\?q\?.*\?=)$/) { return $recipient; } # rfc2047 is needed if a non-ascii char is included if ($recipient_name =~ /[^[:ascii:]]/) { + $recipient_name =~ s/^"(.*)"$/$1/; $recipient_name = quote_rfc2047($recipient_name); } diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 84238f7197..192b97b2d6 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -505,6 +505,19 @@ test_expect_success 'confirm doesnt loop forever' ' test $ret = "0" ' +test_expect_success 'utf8 Cc is rfc2047 encoded' ' + clean_fake_sendmail && + rm -fr outdir && + git format-patch -1 -o outdir --cc="àéìöú <utf8@example.com>" && + git send-email \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + outdir/*.patch && + grep "^Cc:" msgtxt1 | + grep "=?utf-8?q?=C3=A0=C3=A9=C3=AC=C3=B6=C3=BA?= <utf8@example.com>" +' + test_expect_success '--compose adds MIME for utf8 body' ' clean_fake_sendmail && (echo "#!$SHELL_PATH" && From 3944ba0cb0ef5119dc9d1708c572855fca88fc43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st> Date: Wed, 1 Apr 2009 19:48:24 +0300 Subject: [PATCH 347/654] Allow curl to rewind the read buffers When using multi-pass authentication methods, the curl library may need to rewind the read buffers (depending on how much already has been fed to the server) used for providing data to HTTP PUT, POST or PROPFIND, and in order to allow the library to do so, we need to tell it how by providing either an ioctl callback or a seek callback. This patch adds an ioctl callback, which should be usable on older curl versions (since 7.12.3) than the seek callback (introduced in curl 7.18.0). Some HTTP servers (such as Apache) give an 401 error reply immediately after receiving the headers (so no data has been read from the read buffers, and thus no rewinding is needed), but other servers (such as Lighttpd) only replies after the whole request has been sent and all data has been read from the read buffers, making rewinding necessary. Signed-off-by: Martin Storsjo <martin@martin.st> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- http-push.c | 24 ++++++++++++++++++++++++ http.c | 19 +++++++++++++++++++ http.h | 7 +++++++ 3 files changed, 50 insertions(+) diff --git a/http-push.c b/http-push.c index 6ce5a1d550..7dc0dd4ec7 100644 --- a/http-push.c +++ b/http-push.c @@ -567,6 +567,10 @@ static void start_put(struct transfer_request *request) curl_easy_setopt(slot->curl, CURLOPT_INFILE, &request->buffer); curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, request->buffer.buf.len); curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer); +#ifndef NO_CURL_IOCTL + curl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer); + curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &request->buffer); +#endif curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null); curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT); curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1); @@ -1267,6 +1271,10 @@ static struct remote_lock *lock_remote(const char *path, long timeout) curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer); curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len); curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer); +#ifndef NO_CURL_IOCTL + curl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer); + curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer); +#endif curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer); curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); curl_easy_setopt(slot->curl, CURLOPT_URL, url); @@ -1508,6 +1516,10 @@ static void remote_ls(const char *path, int flags, curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer); curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len); curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer); +#ifndef NO_CURL_IOCTL + curl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer); + curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer); +#endif curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer); curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); curl_easy_setopt(slot->curl, CURLOPT_URL, url); @@ -1584,6 +1596,10 @@ static int locking_available(void) curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer); curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len); curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer); +#ifndef NO_CURL_IOCTL + curl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer); + curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer); +#endif curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer); curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); curl_easy_setopt(slot->curl, CURLOPT_URL, repo->url); @@ -1766,6 +1782,10 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock) curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer); curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len); curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer); +#ifndef NO_CURL_IOCTL + curl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer); + curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer); +#endif curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null); curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT); curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers); @@ -1910,6 +1930,10 @@ static void update_remote_info_refs(struct remote_lock *lock) curl_easy_setopt(slot->curl, CURLOPT_INFILE, &buffer); curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, buffer.buf.len); curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer); +#ifndef NO_CURL_IOCTL + curl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer); + curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &buffer); +#endif curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null); curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT); curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers); diff --git a/http.c b/http.c index 2fc55d671e..2e3d6493ef 100644 --- a/http.c +++ b/http.c @@ -44,6 +44,25 @@ size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, void *buffer_) return size; } +#ifndef NO_CURL_IOCTL +curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp) +{ + struct buffer *buffer = clientp; + + switch (cmd) { + case CURLIOCMD_NOP: + return CURLIOE_OK; + + case CURLIOCMD_RESTARTREAD: + buffer->posn = 0; + return CURLIOE_OK; + + default: + return CURLIOE_UNKNOWNCMD; + } +} +#endif + size_t fwrite_buffer(const void *ptr, size_t eltsize, size_t nmemb, void *buffer_) { size_t size = eltsize * nmemb; diff --git a/http.h b/http.h index 905b4629a4..26abebed1f 100644 --- a/http.h +++ b/http.h @@ -37,6 +37,10 @@ #define CURLE_HTTP_RETURNED_ERROR CURLE_HTTP_NOT_FOUND #endif +#if LIBCURL_VERSION_NUM < 0x070c03 +#define NO_CURL_IOCTL +#endif + struct slot_results { CURLcode curl_result; @@ -67,6 +71,9 @@ struct buffer extern size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, void *strbuf); extern size_t fwrite_buffer(const void *ptr, size_t eltsize, size_t nmemb, void *strbuf); extern size_t fwrite_null(const void *ptr, size_t eltsize, size_t nmemb, void *strbuf); +#ifndef NO_CURL_IOCTL +extern curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp); +#endif /* Slot lifecycle functions */ extern struct active_request_slot *get_active_slot(void); From e96f3689ecd95997a2a474c2b7f21b0a67f138b1 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Thu, 2 Apr 2009 13:42:24 -0700 Subject: [PATCH 348/654] Update draft release notes to 1.6.3 Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/RelNotes-1.6.3.txt | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Documentation/RelNotes-1.6.3.txt b/Documentation/RelNotes-1.6.3.txt index bcbd7c5a21..db6956205d 100644 --- a/Documentation/RelNotes-1.6.3.txt +++ b/Documentation/RelNotes-1.6.3.txt @@ -62,6 +62,10 @@ Updates since v1.6.2 with the 'edit' action in git-add -i/-p, you can abort the editor to tell git not to apply it. +* The number of commits shown in "you are ahead/behind your upstream" + messages given by "git checkout" and "git status" used to count merge + commits; now it doesn't. + * git-archive learned --output=<file> option. * git-bisect shows not just the number of remaining commits whose goodness @@ -77,11 +81,17 @@ Updates since v1.6.2 * git-clone runs post-checkout hook when run without --no-checkout. +* git-fast-export choked when seeing a tag that does not point at commit. + * git-format-patch can be told to use attachment with a new configuration, format.attach. * git-format-patch can be told to produce deep or shallow message threads. +* git-format-patch learned format.headers configuration to add extra + header fields to the output. This behaviour is similar to the existing + --add-header=<header> option of the command. + * git-grep learned to highlight the found substrings in color. * git-imap-send learned to work around Thunderbird's inability to easily @@ -95,6 +105,11 @@ Updates since v1.6.2 * Output from git-remote command has been vastly improved. +* git-repack (invoked from git-gc) did not work as nicely as it should in + a repository that borrows objects from neighbours via alternates + mechanism especially when some packs are marked with the ".keep" flag + to prevent them from being repacked. + * git-send-email learned --confirm option to review the Cc: list before sending the messages out. @@ -110,7 +125,9 @@ Updates since v1.6.2 * Building the manpages with docbook-xsl between 1.69.1 and 1.71.1 now requires setting DOCBOOK_SUPPRESS_SP to work around a docbook-xsl bug. This workaround used to be enabled by default, but causes problems - with newer versions of docbook-xsl. + with newer versions of docbook-xsl. In addition, there are a few more + knobs you can tweak to work around issues with various versions of the + docbook-xsl package. See comments in Documentation/Makefile for details. Fixes since v1.6.2 ------------------ @@ -129,6 +146,6 @@ v1.6.2.X series. --- exec >/var/tmp/1 -O=v1.6.2.1-399-gaa72a14 +O=v1.6.2.2-403-g8130949 echo O=$(git describe master) git shortlog --no-merges $O..master ^maint From 0da43a685aa061f55ed19ea30e1d6220020059a6 Mon Sep 17 00:00:00 2001 From: Jay Soffian <jaysoffian@gmail.com> Date: Sat, 4 Apr 2009 23:23:21 -0400 Subject: [PATCH 349/654] send-email: fix nasty bug in ask() function Commit 6e18251 (send-email: refactor and ensure prompting doesn't loop forever) introduced an ask function, which unfortunately had a nasty bug. This caused it not to accept anything but the default reply to the "Who should the emails appear to be from?" prompt, and nothing but ctrl-d to the "Who should the emails be sent to?" and "Message-ID to be used as In-Reply-To for the first email?" prompts. This commit corrects the issues and adds a test to confirm the fix. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-send-email.perl | 4 ++-- t/t9001-send-email.sh | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/git-send-email.perl b/git-send-email.perl index 6bbdfec849..172b53c2d5 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -608,7 +608,7 @@ EOT sub ask { my ($prompt, %arg) = @_; - my $valid_re = $arg{valid_re} || ""; # "" matches anything + my $valid_re = $arg{valid_re}; my $default = $arg{default}; my $resp; my $i = 0; @@ -624,7 +624,7 @@ sub ask { if ($resp eq '' and defined $default) { return $default; } - if ($resp =~ /$valid_re/) { + if (!defined $valid_re or $resp =~ /$valid_re/) { return $resp; } } diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 192b97b2d6..3c90c4fc1c 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -130,6 +130,19 @@ test_expect_success 'Show all headers' ' test_cmp expected-show-all-headers actual-show-all-headers ' +test_expect_success 'Prompting works' ' + clean_fake_sendmail && + (echo "Example <from@example.com>" + echo "to@example.com" + echo "" + ) | GIT_SEND_EMAIL_NOTTY=1 git send-email \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches \ + 2>errors && + grep "^From: Example <from@example.com>$" msgtxt1 && + grep "^To: to@example.com$" msgtxt1 +' + z8=zzzzzzzz z64=$z8$z8$z8$z8$z8$z8$z8$z8 z512=$z64$z64$z64$z64$z64$z64$z64$z64 From 96beef8c2efaab06f703991ed7802b8cef4c00e3 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sat, 4 Apr 2009 22:59:26 +0200 Subject: [PATCH 350/654] sha1-lookup: add new "sha1_pos" function to efficiently lookup sha1 This function has been copied from the "patch_pos" function in "patch-ids.c" but an additional parameter has been added. The new parameter is a function pointer, that is used to access the sha1 of an element in the table. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- sha1-lookup.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++ sha1-lookup.h | 7 ++++ 2 files changed, 108 insertions(+) diff --git a/sha1-lookup.c b/sha1-lookup.c index da357479cf..055dd87dc1 100644 --- a/sha1-lookup.c +++ b/sha1-lookup.c @@ -1,6 +1,107 @@ #include "cache.h" #include "sha1-lookup.h" +static uint32_t take2(const unsigned char *sha1) +{ + return ((sha1[0] << 8) | sha1[1]); +} + +/* + * Conventional binary search loop looks like this: + * + * do { + * int mi = (lo + hi) / 2; + * int cmp = "entry pointed at by mi" minus "target"; + * if (!cmp) + * return (mi is the wanted one) + * if (cmp > 0) + * hi = mi; "mi is larger than target" + * else + * lo = mi+1; "mi is smaller than target" + * } while (lo < hi); + * + * The invariants are: + * + * - When entering the loop, lo points at a slot that is never + * above the target (it could be at the target), hi points at a + * slot that is guaranteed to be above the target (it can never + * be at the target). + * + * - We find a point 'mi' between lo and hi (mi could be the same + * as lo, but never can be the same as hi), and check if it hits + * the target. There are three cases: + * + * - if it is a hit, we are happy. + * + * - if it is strictly higher than the target, we update hi with + * it. + * + * - if it is strictly lower than the target, we update lo to be + * one slot after it, because we allow lo to be at the target. + * + * When choosing 'mi', we do not have to take the "middle" but + * anywhere in between lo and hi, as long as lo <= mi < hi is + * satisfied. When we somehow know that the distance between the + * target and lo is much shorter than the target and hi, we could + * pick mi that is much closer to lo than the midway. + */ +/* + * The table should contain "nr" elements. + * The sha1 of element i (between 0 and nr - 1) should be returned + * by "fn(i, table)". + */ +int sha1_pos(const unsigned char *sha1, void *table, size_t nr, + sha1_access_fn fn) +{ + size_t hi = nr; + size_t lo = 0; + size_t mi = 0; + + if (!nr) + return -1; + + if (nr != 1) { + size_t lov, hiv, miv, ofs; + + for (ofs = 0; ofs < 18; ofs += 2) { + lov = take2(fn(0, table) + ofs); + hiv = take2(fn(nr - 1, table) + ofs); + miv = take2(sha1 + ofs); + if (miv < lov) + return -1; + if (hiv < miv) + return -1 - nr; + if (lov != hiv) { + /* + * At this point miv could be equal + * to hiv (but sha1 could still be higher); + * the invariant of (mi < hi) should be + * kept. + */ + mi = (nr - 1) * (miv - lov) / (hiv - lov); + if (lo <= mi && mi < hi) + break; + die("oops"); + } + } + if (18 <= ofs) + die("cannot happen -- lo and hi are identical"); + } + + do { + int cmp; + cmp = hashcmp(fn(mi, table), sha1); + if (!cmp) + return mi; + if (cmp > 0) + hi = mi; + else + lo = mi + 1; + mi = (hi + lo) / 2; + } while (lo < hi); + return -lo-1; +} + /* * Conventional binary search loop looks like this: * diff --git a/sha1-lookup.h b/sha1-lookup.h index 3249a81b3d..20af285681 100644 --- a/sha1-lookup.h +++ b/sha1-lookup.h @@ -1,6 +1,13 @@ #ifndef SHA1_LOOKUP_H #define SHA1_LOOKUP_H +typedef const unsigned char *sha1_access_fn(size_t index, void *table); + +extern int sha1_pos(const unsigned char *sha1, + void *table, + size_t nr, + sha1_access_fn fn); + extern int sha1_entry_pos(const void *table, size_t elem_size, size_t key_offset, From 5289bae17f24805cc8507129e21d794b0b56264c Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sat, 4 Apr 2009 22:59:31 +0200 Subject: [PATCH 351/654] patch-ids: use the new generic "sha1_pos" function to lookup sha1 instead of the specific one from which the new one has been copied. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- patch-ids.c | 93 +++-------------------------------------------------- 1 file changed, 5 insertions(+), 88 deletions(-) diff --git a/patch-ids.c b/patch-ids.c index 3be5d3165e..5717257051 100644 --- a/patch-ids.c +++ b/patch-ids.c @@ -1,6 +1,7 @@ #include "cache.h" #include "diff.h" #include "commit.h" +#include "sha1-lookup.h" #include "patch-ids.h" static int commit_patch_id(struct commit *commit, struct diff_options *options, @@ -15,99 +16,15 @@ static int commit_patch_id(struct commit *commit, struct diff_options *options, return diff_flush_patch_id(options, sha1); } -static uint32_t take2(const unsigned char *id) +static const unsigned char *patch_id_access(size_t index, void *table) { - return ((id[0] << 8) | id[1]); + struct patch_id **id_table = table; + return id_table[index]->patch_id; } -/* - * Conventional binary search loop looks like this: - * - * do { - * int mi = (lo + hi) / 2; - * int cmp = "entry pointed at by mi" minus "target"; - * if (!cmp) - * return (mi is the wanted one) - * if (cmp > 0) - * hi = mi; "mi is larger than target" - * else - * lo = mi+1; "mi is smaller than target" - * } while (lo < hi); - * - * The invariants are: - * - * - When entering the loop, lo points at a slot that is never - * above the target (it could be at the target), hi points at a - * slot that is guaranteed to be above the target (it can never - * be at the target). - * - * - We find a point 'mi' between lo and hi (mi could be the same - * as lo, but never can be the same as hi), and check if it hits - * the target. There are three cases: - * - * - if it is a hit, we are happy. - * - * - if it is strictly higher than the target, we update hi with - * it. - * - * - if it is strictly lower than the target, we update lo to be - * one slot after it, because we allow lo to be at the target. - * - * When choosing 'mi', we do not have to take the "middle" but - * anywhere in between lo and hi, as long as lo <= mi < hi is - * satisfied. When we somehow know that the distance between the - * target and lo is much shorter than the target and hi, we could - * pick mi that is much closer to lo than the midway. - */ static int patch_pos(struct patch_id **table, int nr, const unsigned char *id) { - int hi = nr; - int lo = 0; - int mi = 0; - - if (!nr) - return -1; - - if (nr != 1) { - unsigned lov, hiv, miv, ofs; - - for (ofs = 0; ofs < 18; ofs += 2) { - lov = take2(table[0]->patch_id + ofs); - hiv = take2(table[nr-1]->patch_id + ofs); - miv = take2(id + ofs); - if (miv < lov) - return -1; - if (hiv < miv) - return -1 - nr; - if (lov != hiv) { - /* - * At this point miv could be equal - * to hiv (but id could still be higher); - * the invariant of (mi < hi) should be - * kept. - */ - mi = (nr-1) * (miv - lov) / (hiv - lov); - if (lo <= mi && mi < hi) - break; - die("oops"); - } - } - if (18 <= ofs) - die("cannot happen -- lo and hi are identical"); - } - - do { - int cmp; - cmp = hashcmp(table[mi]->patch_id, id); - if (!cmp) - return mi; - if (cmp > 0) - hi = mi; - else - lo = mi + 1; - mi = (hi + lo) / 2; - } while (lo < hi); - return -lo-1; + return sha1_pos(id, table, nr, patch_id_access); } #define BUCKET_SIZE 190 /* 190 * 21 = 3990, with slop close enough to 4K */ From 89a56bfbd3fd855cb0c2a381520e6255de41a55e Mon Sep 17 00:00:00 2001 From: Markus Heidelberg <markus.heidelberg@web.de> Date: Sun, 5 Apr 2009 04:15:16 +0200 Subject: [PATCH 352/654] add --html-path to get the location of installed HTML docs This can be used in GUIs to open installed HTML documentation in the browser. Signed-off-by: Markus Heidelberg <markus.heidelberg@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git.txt | 6 +++++- Makefile | 1 + contrib/completion/git-completion.bash | 1 + git.c | 5 ++++- perl/Git.pm | 12 +++++++++++- 5 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Documentation/git.txt b/Documentation/git.txt index 7513c57c6a..2ce5e6b451 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -9,7 +9,7 @@ git - the stupid content tracker SYNOPSIS -------- [verse] -'git' [--version] [--exec-path[=GIT_EXEC_PATH]] +'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path] [-p|--paginate|--no-pager] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS] @@ -178,6 +178,10 @@ help ...`. environment variable. If no path is given, 'git' will print the current setting and then exit. +--html-path:: + Print the path to wherever your git HTML documentation is installed + and exit. + -p:: --paginate:: Pipe all output into 'less' (or if set, $PAGER). diff --git a/Makefile b/Makefile index 7867eaccdb..bcf7cbb3fb 100644 --- a/Makefile +++ b/Makefile @@ -1191,6 +1191,7 @@ strip: $(PROGRAMS) git$X git.o: git.c common-cmds.h GIT-CFLAGS $(QUIET_CC)$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \ + '-DGIT_HTML_PATH="$(htmldir_SQ)"' \ $(ALL_CFLAGS) -c $(filter %.c,$^) git$X: git.o $(BUILTIN_OBJS) $(GITLIBS) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index e72ce2428d..fdc5a24b27 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1870,6 +1870,7 @@ _git () --bare --version --exec-path + --html-path --work-tree= --help " diff --git a/git.c b/git.c index c2b181ed78..ff72e22bec 100644 --- a/git.c +++ b/git.c @@ -5,7 +5,7 @@ #include "run-command.h" const char git_usage_string[] = - "git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate|--no-pager] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]"; + "git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path] [-p|--paginate|--no-pager] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]"; const char git_more_info_string[] = "See 'git help COMMAND' for more information on a specific command."; @@ -75,6 +75,9 @@ static int handle_options(const char*** argv, int* argc, int* envchanged) puts(git_exec_path()); exit(0); } + } else if (!strcmp(cmd, "--html-path")) { + puts(system_path(GIT_HTML_PATH)); + exit(0); } else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) { use_pager = 1; } else if (!strcmp(cmd, "--no-pager")) { diff --git a/perl/Git.pm b/perl/Git.pm index 7d7f2b1d36..291ff5b53c 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -56,7 +56,7 @@ require Exporter; @EXPORT_OK = qw(command command_oneline command_noisy command_output_pipe command_input_pipe command_close_pipe command_bidi_pipe command_close_bidi_pipe - version exec_path hash_object git_cmd_try + version exec_path html_path hash_object git_cmd_try remote_refs temp_acquire temp_release temp_reset temp_path); @@ -492,6 +492,16 @@ C<git --exec-path>). Useful mostly only internally. sub exec_path { command_oneline('--exec-path') } +=item html_path () + +Return path to the Git html documentation (the same as +C<git --html-path>). Useful mostly only internally. + +=cut + +sub html_path { command_oneline('--html-path') } + + =item repo_path () Return path to the git repository. Must be called on a repository instance. From f3a186ffade15f793ea17713a10e10ec4f26ff11 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sat, 4 Apr 2009 22:02:26 +0200 Subject: [PATCH 353/654] bisect: improve error message when branch checkout fails In "git-bisect.sh" the "git checkout" command is only used to change the current branch, but it is used like this: git checkout "$branch" which will output the following misleading error message when it fails: error: pathspec 'foo' did not match any file(s) known to git. This patch change the way we use "git checkout" like this: git checkout "$branch" -- so that we will get the following error message: fatal: invalid reference: foo which is better. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-bisect.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/git-bisect.sh b/git-bisect.sh index e313bdea70..df0ae63b4e 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -77,7 +77,7 @@ bisect_start() { then # Reset to the rev from where we started. start_head=$(cat "$GIT_DIR/BISECT_START") - git checkout "$start_head" || exit + git checkout "$start_head" -- || exit else # Get rev from where we start. case "$head" in @@ -370,7 +370,7 @@ bisect_checkout() { _msg="$2" echo "Bisecting: $_msg" mark_expected_rev "$_rev" - git checkout -q "$_rev" || exit + git checkout -q "$_rev" -- || exit git show-branch "$_rev" } @@ -549,7 +549,7 @@ bisect_reset() { *) usage ;; esac - git checkout "$branch" && bisect_clean_state + git checkout "$branch" -- && bisect_clean_state } bisect_clean_state() { From 5dba35912474770d0df45ed801d78c4c9ed5e949 Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Fri, 3 Apr 2009 15:31:10 -0400 Subject: [PATCH 354/654] tests: remove exit after test_done call test_done always exits, so this line is never executed. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/lib-git-svn.sh | 4 ---- t/lib-httpd.sh | 3 --- t/t4004-diff-rename-symlink.sh | 1 - t/t4011-diff-symlink.sh | 1 - t/t4023-diff-rename-typechange.sh | 1 - t/t4114-apply-typechange.sh | 1 - t/t4115-apply-symlink.sh | 1 - t/t4122-apply-symlink-inside.sh | 1 - t/t5503-tagfollow.sh | 1 - t/t5522-pull-symlink.sh | 1 - t/t5540-http-push.sh | 1 - t/t7005-editor.sh | 1 - t/t9200-git-cvsexportcommit.sh | 1 - t/t9400-git-cvsserver-server.sh | 2 -- t/t9401-git-cvsserver-crlf.sh | 2 -- t/t9500-gitweb-standalone-no-errors.sh | 1 - t/t9600-cvsimport.sh | 3 --- 17 files changed, 26 deletions(-) diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh index de384e6ac3..cdd7ccdd2a 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -7,7 +7,6 @@ if test -n "$NO_SVN_TESTS" then say 'skipping git svn tests, NO_SVN_TESTS defined' test_done - exit fi GIT_DIR=$PWD/.git @@ -19,7 +18,6 @@ if test $? -ne 1 then say 'skipping git svn tests, svn not found' test_done - exit fi svnrepo=$PWD/svnrepo @@ -43,7 +41,6 @@ then fi say "$err" test_done - exit fi rawsvnrepo="$svnrepo" @@ -144,7 +141,6 @@ require_svnserve () { then say 'skipping svnserve test. (set $SVNSERVE_PORT to enable)' test_done - exit fi } diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh index 589aaf8214..cde659d14a 100644 --- a/t/lib-httpd.sh +++ b/t/lib-httpd.sh @@ -8,7 +8,6 @@ then say "skipping test, network testing disabled by default" say "(define GIT_TEST_HTTPD to enable)" test_done - exit fi HTTPD_PARA="" @@ -36,7 +35,6 @@ if ! test -x "$LIB_HTTPD_PATH" then say "skipping test, no web server found at '$LIB_HTTPD_PATH'" test_done - exit fi HTTPD_VERSION=`$LIB_HTTPD_PATH -v | \ @@ -50,7 +48,6 @@ then then say "skipping test, at least Apache version 2 is required" test_done - exit fi LIB_HTTPD_MODULE_PATH="$DEFAULT_HTTPD_MODULE_PATH" diff --git a/t/t4004-diff-rename-symlink.sh b/t/t4004-diff-rename-symlink.sh index 3db74443f8..a4da1196a9 100755 --- a/t/t4004-diff-rename-symlink.sh +++ b/t/t4004-diff-rename-symlink.sh @@ -16,7 +16,6 @@ if ! test_have_prereq SYMLINKS then say 'Symbolic links not supported, skipping tests.' test_done - exit fi test_expect_success \ diff --git a/t/t4011-diff-symlink.sh b/t/t4011-diff-symlink.sh index 3a81309967..d7e327cc5b 100755 --- a/t/t4011-diff-symlink.sh +++ b/t/t4011-diff-symlink.sh @@ -13,7 +13,6 @@ if ! test_have_prereq SYMLINKS then say 'Symbolic links not supported, skipping tests.' test_done - exit fi cat > expected << EOF diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh index 5099862eba..9bdf6596d8 100755 --- a/t/t4023-diff-rename-typechange.sh +++ b/t/t4023-diff-rename-typechange.sh @@ -8,7 +8,6 @@ if ! test_have_prereq SYMLINKS then say 'Symbolic links not supported, skipping tests.' test_done - exit fi test_expect_success setup ' diff --git a/t/t4114-apply-typechange.sh b/t/t4114-apply-typechange.sh index 7dc35dea38..99ec13dd53 100755 --- a/t/t4114-apply-typechange.sh +++ b/t/t4114-apply-typechange.sh @@ -13,7 +13,6 @@ if ! test_have_prereq SYMLINKS then say 'Symbolic links not supported, skipping tests.' test_done - exit fi test_expect_success 'setup repository and commits' ' diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh index 1a3aea34ce..b852e58980 100755 --- a/t/t4115-apply-symlink.sh +++ b/t/t4115-apply-symlink.sh @@ -13,7 +13,6 @@ if ! test_have_prereq SYMLINKS then say 'Symbolic links not supported, skipping tests.' test_done - exit fi test_expect_success setup ' diff --git a/t/t4122-apply-symlink-inside.sh b/t/t4122-apply-symlink-inside.sh index 8aad20bfcc..0d3c1d5dd5 100755 --- a/t/t4122-apply-symlink-inside.sh +++ b/t/t4122-apply-symlink-inside.sh @@ -7,7 +7,6 @@ if ! test_have_prereq SYMLINKS then say 'Symbolic links not supported, skipping tests.' test_done - exit fi lecho () { diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh index e75ccbcaeb..d5db75d826 100755 --- a/t/t5503-tagfollow.sh +++ b/t/t5503-tagfollow.sh @@ -8,7 +8,6 @@ case $(uname -s) in *MINGW*) say "GIT_DEBUG_SEND_PACK not supported - skipping tests" test_done - exit esac # End state of the repository: diff --git a/t/t5522-pull-symlink.sh b/t/t5522-pull-symlink.sh index d887eb6c1a..86bbd7d024 100755 --- a/t/t5522-pull-symlink.sh +++ b/t/t5522-pull-symlink.sh @@ -8,7 +8,6 @@ if ! test_have_prereq SYMLINKS then say 'Symbolic links not supported, skipping tests.' test_done - exit fi # The scenario we are building: diff --git a/t/t5540-http-push.sh b/t/t5540-http-push.sh index c46592f03d..5fe479e1c2 100755 --- a/t/t5540-http-push.sh +++ b/t/t5540-http-push.sh @@ -17,7 +17,6 @@ if git http-push > /dev/null 2>&1 || [ $? -eq 128 ] then say "skipping test, USE_CURL_MULTI is not defined" test_done - exit fi . "$TEST_DIRECTORY"/lib-httpd.sh diff --git a/t/t7005-editor.sh b/t/t7005-editor.sh index e83bc8fd89..b647957d75 100755 --- a/t/t7005-editor.sh +++ b/t/t7005-editor.sh @@ -92,7 +92,6 @@ if ! echo 'echo space > "$1"' > "e space.sh" then say "Skipping; FS does not support spaces in filenames" test_done - exit fi test_expect_success 'editor with a space' ' diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index 995f60771a..36656923ac 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -11,7 +11,6 @@ if test $? -ne 1 then say 'skipping git cvsexportcommit tests, cvs not found' test_done - exit fi CVSROOT=$(pwd)/cvsroot diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index 466240cd41..39185db6c9 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -15,12 +15,10 @@ if test $? -ne 1 then say 'skipping git-cvsserver tests, cvs not found' test_done - exit fi perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || { say 'skipping git-cvsserver tests, Perl SQLite interface unavailable' test_done - exit } unset GIT_DIR GIT_CONFIG diff --git a/t/t9401-git-cvsserver-crlf.sh b/t/t9401-git-cvsserver-crlf.sh index 8882230134..12e0e50822 100755 --- a/t/t9401-git-cvsserver-crlf.sh +++ b/t/t9401-git-cvsserver-crlf.sh @@ -51,12 +51,10 @@ if test $? -ne 1 then say 'skipping git-cvsserver tests, cvs not found' test_done - exit fi perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || { say 'skipping git-cvsserver tests, Perl SQLite interface unavailable' test_done - exit } unset GIT_DIR GIT_CONFIG diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 9ec5030a91..0bd332c493 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -68,7 +68,6 @@ gitweb_run () { perl -MEncode -e 'decode_utf8("", Encode::FB_CROAK)' >/dev/null 2>&1 || { say 'skipping gitweb tests, perl version is too old' test_done - exit } gitweb_init diff --git a/t/t9600-cvsimport.sh b/t/t9600-cvsimport.sh index d2379e7f62..33eb51938d 100755 --- a/t/t9600-cvsimport.sh +++ b/t/t9600-cvsimport.sh @@ -14,7 +14,6 @@ if ! type cvs >/dev/null 2>&1 then say 'skipping cvsimport tests, cvs not found' test_done - exit fi cvsps_version=`cvsps -h 2>&1 | sed -ne 's/cvsps version //p'` @@ -24,12 +23,10 @@ case "$cvsps_version" in '') say 'skipping cvsimport tests, cvsps not found' test_done - exit ;; *) say 'skipping cvsimport tests, unsupported cvsps version' test_done - exit ;; esac From 951886481668b97485640a1b24fc73fccff0d629 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Thu, 26 Mar 2009 05:55:49 +0100 Subject: [PATCH 355/654] rev-list: call new "filter_skip" function This patch implements a new "filter_skip" function in C in "bisect.c" that will later replace the existing implementation in shell in "git-bisect.sh". An array is used to store the skipped commits. But the array is not yet fed anything. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++ bisect.h | 6 ++++- builtin-rev-list.c | 30 ++++++++++++++++++---- 3 files changed, 93 insertions(+), 6 deletions(-) diff --git a/bisect.c b/bisect.c index 27def7dacf..9178a7a8e2 100644 --- a/bisect.c +++ b/bisect.c @@ -4,6 +4,9 @@ #include "revision.h" #include "bisect.h" +static unsigned char (*skipped_sha1)[20]; +static int skipped_sha1_nr; + /* bits #0-15 in revision.h */ #define COUNTED (1u<<16) @@ -386,3 +389,63 @@ struct commit_list *find_bisection(struct commit_list *list, return best; } +static int skipcmp(const void *a, const void *b) +{ + return hashcmp(a, b); +} + +static void prepare_skipped(void) +{ + qsort(skipped_sha1, skipped_sha1_nr, sizeof(*skipped_sha1), skipcmp); +} + +static int lookup_skipped(unsigned char *sha1) +{ + int lo, hi; + lo = 0; + hi = skipped_sha1_nr; + while (lo < hi) { + int mi = (lo + hi) / 2; + int cmp = hashcmp(sha1, skipped_sha1[mi]); + if (!cmp) + return mi; + if (cmp < 0) + hi = mi; + else + lo = mi + 1; + } + return -lo - 1; +} + +struct commit_list *filter_skipped(struct commit_list *list, + struct commit_list **tried, + int show_all) +{ + struct commit_list *filtered = NULL, **f = &filtered; + + *tried = NULL; + + if (!skipped_sha1_nr) + return list; + + prepare_skipped(); + + while (list) { + struct commit_list *next = list->next; + list->next = NULL; + if (0 <= lookup_skipped(list->item->object.sha1)) { + /* Move current to tried list */ + *tried = list; + tried = &list->next; + } else { + if (!show_all) + return list; + /* Move current to filtered list */ + *f = list; + f = &list->next; + } + list = next; + } + + return filtered; +} diff --git a/bisect.h b/bisect.h index 31c99fe5f4..2489630da0 100644 --- a/bisect.h +++ b/bisect.h @@ -5,7 +5,11 @@ extern struct commit_list *find_bisection(struct commit_list *list, int *reaches, int *all, int find_all); +extern struct commit_list *filter_skipped(struct commit_list *list, + struct commit_list **tried, + int show_all); + extern int show_bisect_vars(struct rev_info *revs, int reaches, int all, - int show_all); + int show_all, int show_tried); #endif diff --git a/builtin-rev-list.c b/builtin-rev-list.c index cdb0f9d913..925d64356c 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -226,14 +226,28 @@ static int estimate_bisect_steps(int all) return (e < 3 * x) ? n : n - 1; } -int show_bisect_vars(struct rev_info *revs, int reaches, int all, int show_all) +static void show_tried_revs(struct commit_list *tried) +{ + printf("bisect_tried='"); + for (;tried; tried = tried->next) { + char *format = tried->next ? "%s|" : "%s"; + printf(format, sha1_to_hex(tried->item->object.sha1)); + } + printf("'\n"); +} + +int show_bisect_vars(struct rev_info *revs, int reaches, int all, + int show_all, int show_tried) { int cnt; - char hex[41]; + char hex[41] = ""; + struct commit_list *tried; - if (!revs->commits) + if (!revs->commits && !show_tried) return 1; + revs->commits = filter_skipped(revs->commits, &tried, show_all); + /* * revs->commits can reach "reaches" commits among * "all" commits. If it is good, then there are @@ -247,13 +261,16 @@ int show_bisect_vars(struct rev_info *revs, int reaches, int all, int show_all) if (cnt < reaches) cnt = reaches; - strcpy(hex, sha1_to_hex(revs->commits->item->object.sha1)); + if (revs->commits) + strcpy(hex, sha1_to_hex(revs->commits->item->object.sha1)); if (show_all) { traverse_commit_list(revs, show_commit, show_object); printf("------\n"); } + if (show_tried) + show_tried_revs(tried); printf("bisect_rev=%s\n" "bisect_nr=%d\n" "bisect_good=%d\n" @@ -278,6 +295,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) int bisect_list = 0; int bisect_show_vars = 0; int bisect_find_all = 0; + int bisect_show_all = 0; int quiet = 0; git_config(git_default_config, NULL); @@ -305,6 +323,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) if (!strcmp(arg, "--bisect-all")) { bisect_list = 1; bisect_find_all = 1; + bisect_show_all = 1; revs.show_decorations = 1; continue; } @@ -357,9 +376,10 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) revs.commits = find_bisection(revs.commits, &reaches, &all, bisect_find_all); + if (bisect_show_vars) return show_bisect_vars(&revs, reaches, all, - bisect_find_all); + bisect_show_all, 0); } traverse_commit_list(&revs, From 4eb5b64631d281f3789b052efac53f4c1ec2c1b6 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sat, 4 Apr 2009 22:59:36 +0200 Subject: [PATCH 356/654] bisect: use the new generic "sha1_pos" function to lookup sha1 instead of the specific one that was simpler but less efficient. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/bisect.c b/bisect.c index 9178a7a8e2..47120c1cd8 100644 --- a/bisect.c +++ b/bisect.c @@ -2,6 +2,7 @@ #include "commit.h" #include "diff.h" #include "revision.h" +#include "sha1-lookup.h" #include "bisect.h" static unsigned char (*skipped_sha1)[20]; @@ -399,22 +400,16 @@ static void prepare_skipped(void) qsort(skipped_sha1, skipped_sha1_nr, sizeof(*skipped_sha1), skipcmp); } +static const unsigned char *skipped_sha1_access(size_t index, void *table) +{ + unsigned char (*skipped)[20] = table; + return skipped[index]; +} + static int lookup_skipped(unsigned char *sha1) { - int lo, hi; - lo = 0; - hi = skipped_sha1_nr; - while (lo < hi) { - int mi = (lo + hi) / 2; - int cmp = hashcmp(sha1, skipped_sha1[mi]); - if (!cmp) - return mi; - if (cmp < 0) - hi = mi; - else - lo = mi + 1; - } - return -lo - 1; + return sha1_pos(sha1, skipped_sha1, skipped_sha1_nr, + skipped_sha1_access); } struct commit_list *filter_skipped(struct commit_list *list, From 1bf072e3661eeef8d9721079a332e804b5678c7e Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Thu, 26 Mar 2009 05:55:54 +0100 Subject: [PATCH 357/654] bisect--helper: implement "git bisect--helper" This patch implements a new "git bisect--helper" builtin plumbing command that will be used to migrate "git-bisect.sh" to C. We start by implementing only the "--next-vars" option that will read bisect refs from "refs/bisect/", and then compute the next bisect step, and output shell variables ready to be eval'ed by the shell. At this step, "git bisect--helper" ignores the paths that may have been put in "$GIT_DIR/BISECT_NAMES". This will be fixed in a later patch. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 1 + bisect.c | 68 ++++++++++++++++++++++++++++++++++++++++ bisect.h | 7 +++++ builtin-bisect--helper.c | 27 ++++++++++++++++ builtin.h | 1 + git.c | 1 + 6 files changed, 105 insertions(+) create mode 100644 builtin-bisect--helper.c diff --git a/Makefile b/Makefile index 42cabe8162..a2bfad43bc 100644 --- a/Makefile +++ b/Makefile @@ -533,6 +533,7 @@ BUILTIN_OBJS += builtin-add.o BUILTIN_OBJS += builtin-annotate.o BUILTIN_OBJS += builtin-apply.o BUILTIN_OBJS += builtin-archive.o +BUILTIN_OBJS += builtin-bisect--helper.o BUILTIN_OBJS += builtin-blame.o BUILTIN_OBJS += builtin-branch.o BUILTIN_OBJS += builtin-bundle.o diff --git a/bisect.c b/bisect.c index 47120c1cd8..94ec011786 100644 --- a/bisect.c +++ b/bisect.c @@ -2,11 +2,18 @@ #include "commit.h" #include "diff.h" #include "revision.h" +#include "refs.h" +#include "list-objects.h" #include "sha1-lookup.h" #include "bisect.h" static unsigned char (*skipped_sha1)[20]; static int skipped_sha1_nr; +static int skipped_sha1_alloc; + +static const char **rev_argv; +static int rev_argv_nr; +static int rev_argv_alloc; /* bits #0-15 in revision.h */ @@ -390,6 +397,33 @@ struct commit_list *find_bisection(struct commit_list *list, return best; } +static int register_ref(const char *refname, const unsigned char *sha1, + int flags, void *cb_data) +{ + if (!strcmp(refname, "bad")) { + ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); + rev_argv[rev_argv_nr++] = xstrdup(sha1_to_hex(sha1)); + } else if (!prefixcmp(refname, "good-")) { + const char *hex = sha1_to_hex(sha1); + char *good = xmalloc(strlen(hex) + 2); + *good = '^'; + memcpy(good + 1, hex, strlen(hex) + 1); + ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); + rev_argv[rev_argv_nr++] = good; + } else if (!prefixcmp(refname, "skip-")) { + ALLOC_GROW(skipped_sha1, skipped_sha1_nr + 1, + skipped_sha1_alloc); + hashcpy(skipped_sha1[skipped_sha1_nr++], sha1); + } + + return 0; +} + +static int read_bisect_refs(void) +{ + return for_each_ref_in("refs/bisect/", register_ref, NULL); +} + static int skipcmp(const void *a, const void *b) { return hashcmp(a, b); @@ -444,3 +478,37 @@ struct commit_list *filter_skipped(struct commit_list *list, return filtered; } + +int bisect_next_vars(const char *prefix) +{ + struct rev_info revs; + int reaches = 0, all = 0; + + init_revisions(&revs, prefix); + revs.abbrev = 0; + revs.commit_format = CMIT_FMT_UNSPECIFIED; + + /* argv[0] will be ignored by setup_revisions */ + ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); + rev_argv[rev_argv_nr++] = xstrdup("bisect_rev_setup"); + + if (read_bisect_refs()) + die("reading bisect refs failed"); + + ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); + rev_argv[rev_argv_nr++] = xstrdup("--"); + + setup_revisions(rev_argv_nr, rev_argv, &revs, NULL); + + revs.limited = 1; + + if (prepare_revision_walk(&revs)) + die("revision walk setup failed"); + if (revs.tree_objects) + mark_edges_uninteresting(revs.commits, &revs, NULL); + + revs.commits = find_bisection(revs.commits, &reaches, &all, + !!skipped_sha1_nr); + + return show_bisect_vars(&revs, reaches, all, 0, 1); +} diff --git a/bisect.h b/bisect.h index 2489630da0..05eea175f7 100644 --- a/bisect.h +++ b/bisect.h @@ -9,7 +9,14 @@ extern struct commit_list *filter_skipped(struct commit_list *list, struct commit_list **tried, int show_all); +/* + * The "show_all" parameter should be 0 if this function is called + * from outside "builtin-rev-list.c" as otherwise it would use + * static "revs" from this file. + */ extern int show_bisect_vars(struct rev_info *revs, int reaches, int all, int show_all, int show_tried); +extern int bisect_next_vars(const char *prefix); + #endif diff --git a/builtin-bisect--helper.c b/builtin-bisect--helper.c new file mode 100644 index 0000000000..8fe778766a --- /dev/null +++ b/builtin-bisect--helper.c @@ -0,0 +1,27 @@ +#include "builtin.h" +#include "cache.h" +#include "parse-options.h" +#include "bisect.h" + +static const char * const git_bisect_helper_usage[] = { + "git bisect--helper --next-vars", + NULL +}; + +int cmd_bisect__helper(int argc, const char **argv, const char *prefix) +{ + int next_vars = 0; + struct option options[] = { + OPT_BOOLEAN(0, "next-vars", &next_vars, + "output next bisect step variables"), + OPT_END() + }; + + argc = parse_options(argc, argv, options, git_bisect_helper_usage, 0); + + if (!next_vars) + usage_with_options(git_bisect_helper_usage, options); + + /* next-vars */ + return bisect_next_vars(prefix); +} diff --git a/builtin.h b/builtin.h index 1495cf6a20..425ff8e89b 100644 --- a/builtin.h +++ b/builtin.h @@ -25,6 +25,7 @@ extern int cmd_add(int argc, const char **argv, const char *prefix); extern int cmd_annotate(int argc, const char **argv, const char *prefix); extern int cmd_apply(int argc, const char **argv, const char *prefix); extern int cmd_archive(int argc, const char **argv, const char *prefix); +extern int cmd_bisect__helper(int argc, const char **argv, const char *prefix); extern int cmd_blame(int argc, const char **argv, const char *prefix); extern int cmd_branch(int argc, const char **argv, const char *prefix); extern int cmd_bundle(int argc, const char **argv, const char *prefix); diff --git a/git.c b/git.c index c2b181ed78..a553926b68 100644 --- a/git.c +++ b/git.c @@ -271,6 +271,7 @@ static void handle_internal_command(int argc, const char **argv) { "annotate", cmd_annotate, RUN_SETUP }, { "apply", cmd_apply }, { "archive", cmd_archive }, + { "bisect--helper", cmd_bisect__helper, RUN_SETUP | NEED_WORK_TREE }, { "blame", cmd_blame, RUN_SETUP }, { "branch", cmd_branch, RUN_SETUP }, { "bundle", cmd_bundle }, From 3b437b0dabfdff12d5dd78b9bb55a0be4e2da51c Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Thu, 26 Mar 2009 05:55:59 +0100 Subject: [PATCH 358/654] bisect: implement "read_bisect_paths" to read paths in "$GIT_DIR/BISECT_NAMES" This is needed because "git bisect--helper" must read bisect paths in "$GIT_DIR/BISECT_NAMES", so that a bisection can be performed only on commits that touches paths in this file. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/bisect.c b/bisect.c index 94ec011786..3279fb12b2 100644 --- a/bisect.c +++ b/bisect.c @@ -4,6 +4,7 @@ #include "revision.h" #include "refs.h" #include "list-objects.h" +#include "quote.h" #include "sha1-lookup.h" #include "bisect.h" @@ -424,6 +425,32 @@ static int read_bisect_refs(void) return for_each_ref_in("refs/bisect/", register_ref, NULL); } +void read_bisect_paths(void) +{ + struct strbuf str = STRBUF_INIT; + const char *filename = git_path("BISECT_NAMES"); + FILE *fp = fopen(filename, "r"); + + if (!fp) + die("Could not open file '%s': %s", filename, strerror(errno)); + + while (strbuf_getline(&str, fp, '\n') != EOF) { + char *quoted; + int res; + + strbuf_trim(&str); + quoted = strbuf_detach(&str, NULL); + res = sq_dequote_to_argv(quoted, &rev_argv, + &rev_argv_nr, &rev_argv_alloc); + if (res) + die("Badly quoted content in file '%s': %s", + filename, quoted); + } + + strbuf_release(&str); + fclose(fp); +} + static int skipcmp(const void *a, const void *b) { return hashcmp(a, b); @@ -479,14 +506,11 @@ struct commit_list *filter_skipped(struct commit_list *list, return filtered; } -int bisect_next_vars(const char *prefix) +static void bisect_rev_setup(struct rev_info *revs, const char *prefix) { - struct rev_info revs; - int reaches = 0, all = 0; - - init_revisions(&revs, prefix); - revs.abbrev = 0; - revs.commit_format = CMIT_FMT_UNSPECIFIED; + init_revisions(revs, prefix); + revs->abbrev = 0; + revs->commit_format = CMIT_FMT_UNSPECIFIED; /* argv[0] will be ignored by setup_revisions */ ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); @@ -498,9 +522,22 @@ int bisect_next_vars(const char *prefix) ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); rev_argv[rev_argv_nr++] = xstrdup("--"); - setup_revisions(rev_argv_nr, rev_argv, &revs, NULL); + read_bisect_paths(); - revs.limited = 1; + ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); + rev_argv[rev_argv_nr++] = NULL; + + setup_revisions(rev_argv_nr, rev_argv, revs, NULL); + + revs->limited = 1; +} + +int bisect_next_vars(const char *prefix) +{ + struct rev_info revs; + int reaches = 0, all = 0; + + bisect_rev_setup(&revs, prefix); if (prepare_revision_walk(&revs)) die("revision walk setup failed"); From 23b5f18b50c15155f79618522b5721b880eceb65 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Thu, 26 Mar 2009 05:56:02 +0100 Subject: [PATCH 359/654] bisect: use "bisect--helper" and remove "filter_skipped" function Use the new "git bisect--helper" builtin. It should be faster and safer instead of the old "filter_skipped" shell function. And it is a first step to move more shell code to C. As the output is a little bit different we have to change the code that interpret the results. But these changes improve code clarity. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-bisect.sh | 89 +++++++-------------------------------------------- 1 file changed, 12 insertions(+), 77 deletions(-) diff --git a/git-bisect.sh b/git-bisect.sh index e313bdea70..0f7590dfc2 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -279,76 +279,13 @@ bisect_auto_next() { bisect_next_check && bisect_next || : } -filter_skipped() { +eval_and_string_together() { _eval="$1" - _skip="$2" - if [ -z "$_skip" ]; then - eval "$_eval" | { - while read line - do - echo "$line &&" - done - echo ':' - } - return - fi - - # Let's parse the output of: - # "git rev-list --bisect-vars --bisect-all ..." eval "$_eval" | { - VARS= FOUND= TRIED= - while read hash line + while read line do - case "$VARS,$FOUND,$TRIED,$hash" in - 1,*,*,*) - # "bisect_foo=bar" read from rev-list output. - echo "$hash &&" - ;; - ,*,*,---*) - # Separator - ;; - ,,,bisect_rev*) - # We had nothing to search. - echo "bisect_rev= &&" - VARS=1 - ;; - ,,*,bisect_rev*) - # We did not find a good bisect rev. - # This should happen only if the "bad" - # commit is also a "skip" commit. - echo "bisect_rev='$TRIED' &&" - VARS=1 - ;; - ,,*,*) - # We are searching. - TRIED="${TRIED:+$TRIED|}$hash" - case "$_skip" in - *$hash*) ;; - *) - echo "bisect_rev=$hash &&" - echo "bisect_tried='$TRIED' &&" - FOUND=1 - ;; - esac - ;; - ,1,*,bisect_rev*) - # We have already found a rev to be tested. - VARS=1 - ;; - ,1,*,*) - ;; - *) - # Unexpected input - echo "die 'filter_skipped error'" - die "filter_skipped error " \ - "VARS: '$VARS' " \ - "FOUND: '$FOUND' " \ - "TRIED: '$TRIED' " \ - "hash: '$hash' " \ - "line: '$line'" - ;; - esac + echo "$line &&" done echo ':' } @@ -356,10 +293,12 @@ filter_skipped() { exit_if_skipped_commits () { _tried=$1 - if expr "$_tried" : ".*[|].*" > /dev/null ; then + _bad=$2 + if test -n "$_tried" ; then echo "There are only 'skip'ped commit left to test." echo "The first bad commit could be any of:" echo "$_tried" | tr '[|]' '[\012]' + test -n "$_bad" && echo "$_bad" echo "We cannot bisect more!" exit 2 fi @@ -490,28 +429,24 @@ bisect_next() { test "$?" -eq "1" && return # Get bisection information - BISECT_OPT='' - test -n "$skip" && BISECT_OPT='--bisect-all' - eval="git rev-list --bisect-vars $BISECT_OPT $good $bad --" && - eval="$eval $(cat "$GIT_DIR/BISECT_NAMES")" && - eval=$(filter_skipped "$eval" "$skip") && + eval="git bisect--helper --next-vars" && + eval=$(eval_and_string_together "$eval") && eval "$eval" || exit if [ -z "$bisect_rev" ]; then + # We should exit here only if the "bad" + # commit is also a "skip" commit (see above). + exit_if_skipped_commits "$bisect_tried" echo "$bad was both good and bad" exit 1 fi if [ "$bisect_rev" = "$bad" ]; then - exit_if_skipped_commits "$bisect_tried" + exit_if_skipped_commits "$bisect_tried" "$bad" echo "$bisect_rev is first bad commit" git diff-tree --pretty $bisect_rev exit 0 fi - # We should exit here only if the "bad" - # commit is also a "skip" commit (see above). - exit_if_skipped_commits "$bisect_rev" - bisect_checkout "$bisect_rev" "$bisect_nr revisions left to test after this (roughly $bisect_steps steps)" } From b74d7efb108c9d3fd2d057b0c452583552a0577a Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sun, 29 Mar 2009 11:45:01 +0200 Subject: [PATCH 360/654] t6030: test bisecting with paths This patch adds some tests to check that "git bisect" works fine when passing paths to "git bisect start" to reduce the number of bisection steps. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t6030-bisect-porcelain.sh | 60 +++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh index 052a6c90f5..54b7ea6505 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -506,6 +506,66 @@ test_expect_success 'optimized merge base checks' ' unset GIT_TRACE ' +# This creates another side branch called "parallel" with some files +# in some directories, to test bisecting with paths. +# +# We should have the following: +# +# P1-P2-P3-P4-P5-P6-P7 +# / / / +# H1-H2-H3-H4-H5-H6-H7 +# \ \ \ +# S5-A \ +# \ \ +# S6-S7----B +# +test_expect_success '"parallel" side branch creation' ' + git bisect reset && + git checkout -b parallel $HASH1 && + mkdir dir1 dir2 && + add_line_into_file "1(para): line 1 on parallel branch" dir1/file1 && + PARA_HASH1=$(git rev-parse --verify HEAD) && + add_line_into_file "2(para): line 2 on parallel branch" dir2/file2 && + PARA_HASH2=$(git rev-parse --verify HEAD) && + add_line_into_file "3(para): line 3 on parallel branch" dir2/file3 && + PARA_HASH3=$(git rev-parse --verify HEAD) + git merge -m "merge HASH4 and PARA_HASH3" "$HASH4" && + PARA_HASH4=$(git rev-parse --verify HEAD) + add_line_into_file "5(para): add line on parallel branch" dir1/file1 && + PARA_HASH5=$(git rev-parse --verify HEAD) + add_line_into_file "6(para): add line on parallel branch" dir2/file2 && + PARA_HASH6=$(git rev-parse --verify HEAD) + git merge -m "merge HASH7 and PARA_HASH6" "$HASH7" && + PARA_HASH7=$(git rev-parse --verify HEAD) +' + +test_expect_success 'restricting bisection on one dir' ' + git bisect reset && + git bisect start HEAD $HASH1 -- dir1 && + para1=$(git rev-parse --verify HEAD) && + test "$para1" = "$PARA_HASH1" && + git bisect bad > my_bisect_log.txt && + grep "$PARA_HASH1 is first bad commit" my_bisect_log.txt +' + +test_expect_success 'restricting bisection on one dir and a file' ' + git bisect reset && + git bisect start HEAD $HASH1 -- dir1 hello && + para4=$(git rev-parse --verify HEAD) && + test "$para4" = "$PARA_HASH4" && + git bisect bad && + hash3=$(git rev-parse --verify HEAD) && + test "$hash3" = "$HASH3" && + git bisect good && + hash4=$(git rev-parse --verify HEAD) && + test "$hash4" = "$HASH4" && + git bisect good && + para1=$(git rev-parse --verify HEAD) && + test "$para1" = "$PARA_HASH1" && + git bisect good > my_bisect_log.txt && + grep "$PARA_HASH4 is first bad commit" my_bisect_log.txt +' + # # test_done From 37c4c38d7356bf256d0297fdbac78ef8b6807fac Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sun, 29 Mar 2009 11:55:43 +0200 Subject: [PATCH 361/654] rev-list: pass "int flags" as last argument of "show_bisect_vars" Instead of "int show_all, int show_tried" we now only pass "int flags", because we will add one more flag in a later patch. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 2 +- bisect.h | 8 ++++++-- builtin-rev-list.c | 13 ++++++------- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/bisect.c b/bisect.c index 3279fb12b2..285bf146c1 100644 --- a/bisect.c +++ b/bisect.c @@ -547,5 +547,5 @@ int bisect_next_vars(const char *prefix) revs.commits = find_bisection(revs.commits, &reaches, &all, !!skipped_sha1_nr); - return show_bisect_vars(&revs, reaches, all, 0, 1); + return show_bisect_vars(&revs, reaches, all, BISECT_SHOW_TRIED); } diff --git a/bisect.h b/bisect.h index 05eea175f7..b9aa88482e 100644 --- a/bisect.h +++ b/bisect.h @@ -9,13 +9,17 @@ extern struct commit_list *filter_skipped(struct commit_list *list, struct commit_list **tried, int show_all); +/* show_bisect_vars flags */ +#define BISECT_SHOW_ALL (1<<0) +#define BISECT_SHOW_TRIED (1<<1) + /* - * The "show_all" parameter should be 0 if this function is called + * The flag BISECT_SHOW_ALL should not be set if this function is called * from outside "builtin-rev-list.c" as otherwise it would use * static "revs" from this file. */ extern int show_bisect_vars(struct rev_info *revs, int reaches, int all, - int show_all, int show_tried); + int flags); extern int bisect_next_vars(const char *prefix); diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 925d64356c..69dca631d9 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -236,17 +236,16 @@ static void show_tried_revs(struct commit_list *tried) printf("'\n"); } -int show_bisect_vars(struct rev_info *revs, int reaches, int all, - int show_all, int show_tried) +int show_bisect_vars(struct rev_info *revs, int reaches, int all, int flags) { int cnt; char hex[41] = ""; struct commit_list *tried; - if (!revs->commits && !show_tried) + if (!revs->commits && !(flags & BISECT_SHOW_TRIED)) return 1; - revs->commits = filter_skipped(revs->commits, &tried, show_all); + revs->commits = filter_skipped(revs->commits, &tried, flags & BISECT_SHOW_ALL); /* * revs->commits can reach "reaches" commits among @@ -264,12 +263,12 @@ int show_bisect_vars(struct rev_info *revs, int reaches, int all, if (revs->commits) strcpy(hex, sha1_to_hex(revs->commits->item->object.sha1)); - if (show_all) { + if (flags & BISECT_SHOW_ALL) { traverse_commit_list(revs, show_commit, show_object); printf("------\n"); } - if (show_tried) + if (flags & BISECT_SHOW_TRIED) show_tried_revs(tried); printf("bisect_rev=%s\n" "bisect_nr=%d\n" @@ -379,7 +378,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) if (bisect_show_vars) return show_bisect_vars(&revs, reaches, all, - bisect_show_all, 0); + bisect_show_all ? BISECT_SHOW_ALL : 0); } traverse_commit_list(&revs, From e89aa6d2f546b2d4f2d88c15ce7e343751d6922f Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Mon, 30 Mar 2009 06:59:59 +0200 Subject: [PATCH 362/654] bisect--helper: string output variables together with "&&" When doing: eval "git bisect--helper --next-vars" | { while read line do echo "$line &&" done echo ':' } the result code comes from the last "echo ':'", not from running "git bisect--helper --next-vars". This patch gets rid of the need to string together the line from the output of "git bisect--helper" with "&&" in the calling script by making "git bisect--helper --next-vars" return output variables already in that format. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 3 ++- bisect.h | 1 + builtin-rev-list.c | 29 +++++++++++++++++++---------- git-bisect.sh | 15 +-------------- 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/bisect.c b/bisect.c index 285bf146c1..69f8860ca1 100644 --- a/bisect.c +++ b/bisect.c @@ -547,5 +547,6 @@ int bisect_next_vars(const char *prefix) revs.commits = find_bisection(revs.commits, &reaches, &all, !!skipped_sha1_nr); - return show_bisect_vars(&revs, reaches, all, BISECT_SHOW_TRIED); + return show_bisect_vars(&revs, reaches, all, + BISECT_SHOW_TRIED | BISECT_SHOW_STRINGED); } diff --git a/bisect.h b/bisect.h index b9aa88482e..f5d106735c 100644 --- a/bisect.h +++ b/bisect.h @@ -12,6 +12,7 @@ extern struct commit_list *filter_skipped(struct commit_list *list, /* show_bisect_vars flags */ #define BISECT_SHOW_ALL (1<<0) #define BISECT_SHOW_TRIED (1<<1) +#define BISECT_SHOW_STRINGED (1<<2) /* * The flag BISECT_SHOW_ALL should not be set if this function is called diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 69dca631d9..eb341477ca 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -226,20 +226,20 @@ static int estimate_bisect_steps(int all) return (e < 3 * x) ? n : n - 1; } -static void show_tried_revs(struct commit_list *tried) +static void show_tried_revs(struct commit_list *tried, int stringed) { printf("bisect_tried='"); for (;tried; tried = tried->next) { char *format = tried->next ? "%s|" : "%s"; printf(format, sha1_to_hex(tried->item->object.sha1)); } - printf("'\n"); + printf(stringed ? "' &&\n" : "'\n"); } int show_bisect_vars(struct rev_info *revs, int reaches, int all, int flags) { int cnt; - char hex[41] = ""; + char hex[41] = "", *format; struct commit_list *tried; if (!revs->commits && !(flags & BISECT_SHOW_TRIED)) @@ -269,13 +269,22 @@ int show_bisect_vars(struct rev_info *revs, int reaches, int all, int flags) } if (flags & BISECT_SHOW_TRIED) - show_tried_revs(tried); - printf("bisect_rev=%s\n" - "bisect_nr=%d\n" - "bisect_good=%d\n" - "bisect_bad=%d\n" - "bisect_all=%d\n" - "bisect_steps=%d\n", + show_tried_revs(tried, flags & BISECT_SHOW_STRINGED); + format = (flags & BISECT_SHOW_STRINGED) ? + "bisect_rev=%s &&\n" + "bisect_nr=%d &&\n" + "bisect_good=%d &&\n" + "bisect_bad=%d &&\n" + "bisect_all=%d &&\n" + "bisect_steps=%d\n" + : + "bisect_rev=%s\n" + "bisect_nr=%d\n" + "bisect_good=%d\n" + "bisect_bad=%d\n" + "bisect_all=%d\n" + "bisect_steps=%d\n"; + printf(format, hex, cnt - 1, all - reaches - 1, diff --git a/git-bisect.sh b/git-bisect.sh index 0f7590dfc2..5074dda451 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -279,18 +279,6 @@ bisect_auto_next() { bisect_next_check && bisect_next || : } -eval_and_string_together() { - _eval="$1" - - eval "$_eval" | { - while read line - do - echo "$line &&" - done - echo ':' - } -} - exit_if_skipped_commits () { _tried=$1 _bad=$2 @@ -429,8 +417,7 @@ bisect_next() { test "$?" -eq "1" && return # Get bisection information - eval="git bisect--helper --next-vars" && - eval=$(eval_and_string_together "$eval") && + eval=$(eval "git bisect--helper --next-vars") && eval "$eval" || exit if [ -z "$bisect_rev" ]; then From b92c5f228a9c07fe339c8fd5406069602b6452f6 Mon Sep 17 00:00:00 2001 From: Finn Arne Gangstad <finnag@pvv.org> Date: Fri, 3 Apr 2009 11:02:37 +0200 Subject: [PATCH 363/654] builtin-remote.c: Split out prune_remote as a separate function. prune_remote will be used in update(), so this function was split out to avoid code duplication. Signed-off-by: Finn Arne Gangstad <finnag@pvv.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-remote.c | 62 ++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/builtin-remote.c b/builtin-remote.c index 9ef846f6a4..c53966fd8d 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -26,6 +26,7 @@ static const char * const builtin_remote_usage[] = { static int verbose; static int show_all(void); +static int prune_remote(const char *remote, int dry_run); static inline int postfixcmp(const char *string, const char *postfix) { @@ -1128,46 +1129,49 @@ static int prune(int argc, const char **argv) OPT__DRY_RUN(&dry_run), OPT_END() }; - struct ref_states states; - const char *dangling_msg; argc = parse_options(argc, argv, options, builtin_remote_usage, 0); if (argc < 1) usage_with_options(builtin_remote_usage, options); - dangling_msg = (dry_run - ? " %s will become dangling!\n" - : " %s has become dangling!\n"); + for (; argc; argc--, argv++) + result |= prune_remote(*argv, dry_run); + + return result; +} + +static int prune_remote(const char *remote, int dry_run) +{ + int result = 0, i; + struct ref_states states; + const char *dangling_msg = dry_run + ? " %s will become dangling!\n" + : " %s has become dangling!\n"; memset(&states, 0, sizeof(states)); - for (; argc; argc--, argv++) { - int i; + get_remote_ref_states(remote, &states, GET_REF_STATES); - get_remote_ref_states(*argv, &states, GET_REF_STATES); - - if (states.stale.nr) { - printf("Pruning %s\n", *argv); - printf("URL: %s\n", - states.remote->url_nr - ? states.remote->url[0] - : "(no URL)"); - } - - for (i = 0; i < states.stale.nr; i++) { - const char *refname = states.stale.items[i].util; - - if (!dry_run) - result |= delete_ref(refname, NULL, 0); - - printf(" * [%s] %s\n", dry_run ? "would prune" : "pruned", - abbrev_ref(refname, "refs/remotes/")); - warn_dangling_symref(dangling_msg, refname); - } - - free_remote_ref_states(&states); + if (states.stale.nr) { + printf("Pruning %s\n", remote); + printf("URL: %s\n", + states.remote->url_nr + ? states.remote->url[0] + : "(no URL)"); } + for (i = 0; i < states.stale.nr; i++) { + const char *refname = states.stale.items[i].util; + + if (!dry_run) + result |= delete_ref(refname, NULL, 0); + + printf(" * [%s] %s\n", dry_run ? "would prune" : "pruned", + abbrev_ref(refname, "refs/remotes/")); + warn_dangling_symref(dangling_msg, refname); + } + + free_remote_ref_states(&states); return result; } From efa54803cb1dc15923799f94abf82cb0433c2b9b Mon Sep 17 00:00:00 2001 From: Finn Arne Gangstad <finnag@pvv.org> Date: Fri, 3 Apr 2009 11:03:44 +0200 Subject: [PATCH 364/654] git remote update: New option --prune With the --prune (or -p) option, git remote update will also prune all the remotes that it fetches. Previously, you had to do a manual git remote prune <remote> for each of the remotes you wanted to prune, and this could be tedious with many remotes. A single command will now update a set of remotes, and remove all stale branches: git remote update -p [group] Signed-off-by: Finn Arne Gangstad <finnag@pvv.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-remote.txt | 4 +++- builtin-remote.c | 20 ++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt index c9c0e6f932..0b6e67dbca 100644 --- a/Documentation/git-remote.txt +++ b/Documentation/git-remote.txt @@ -16,7 +16,7 @@ SYNOPSIS 'git remote set-head' <name> [-a | -d | <branch>] 'git remote show' [-n] <name> 'git remote prune' [-n | --dry-run] <name> -'git remote update' [group] +'git remote update' [-p | --prune] [group] DESCRIPTION ----------- @@ -125,6 +125,8 @@ the configuration parameter remotes.default will get used; if remotes.default is not defined, all remotes which do not have the configuration parameter remote.<name>.skipDefaultUpdate set to true will be updated. (See linkgit:git-config[1]). ++ +With `--prune` option, prune all the remotes that are updated. DISCUSSION diff --git a/builtin-remote.c b/builtin-remote.c index c53966fd8d..3146eb467d 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -15,7 +15,7 @@ static const char * const builtin_remote_usage[] = { "git remote set-head <name> [-a | -d | <branch>]", "git remote show [-n] <name>", "git remote prune [-n | --dry-run] <name>", - "git remote [-v | --verbose] update [group]", + "git remote [-v | --verbose] update [-p | --prune] [group]", NULL }; @@ -1208,10 +1208,18 @@ static int get_remote_group(const char *key, const char *value, void *cb) static int update(int argc, const char **argv) { - int i, result = 0; + int i, result = 0, prune = 0; struct string_list list = { NULL, 0, 0, 0 }; static const char *default_argv[] = { NULL, "default", NULL }; + struct option options[] = { + OPT_GROUP("update specific options"), + OPT_BOOLEAN('p', "prune", &prune, + "prune remotes after fecthing"), + OPT_END() + }; + argc = parse_options(argc, argv, options, builtin_remote_usage, + PARSE_OPT_KEEP_ARGV0); if (argc < 2) { argc = 2; argv = default_argv; @@ -1226,8 +1234,12 @@ static int update(int argc, const char **argv) if (!result && !list.nr && argc == 2 && !strcmp(argv[1], "default")) result = for_each_remote(get_one_remote_for_update, &list); - for (i = 0; i < list.nr; i++) - result |= fetch_remote(list.items[i].string); + for (i = 0; i < list.nr; i++) { + int err = fetch_remote(list.items[i].string); + result |= err; + if (!err && prune) + result |= prune_remote(list.items[i].string, 0); + } /* all names were strdup()ed or strndup()ed */ list.strdup_strings = 1; From 43acdf243ee8a8fa876bdd6659026fe5ed2d4c24 Mon Sep 17 00:00:00 2001 From: Todd Zullinger <tmz@pobox.com> Date: Sun, 5 Apr 2009 12:33:38 -0400 Subject: [PATCH 365/654] bash completion: Update 'git am' options This adds --committer-date-is-author-date, --ignore-date, and --no-utf8 options. The --binary option is removed, as it was made a no-op by cb3a160. The option list is also sorted alphabetically. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index e72ce2428d..d3d8203171 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -646,7 +646,8 @@ _git_am () ;; --*) __gitcomp " - --signoff --utf8 --binary --3way --interactive + --3way --committer-date-is-author-date --ignore-date + --interactive --keep --no-utf8 --signoff --utf8 --whitespace= " return From 3eb5682b0b1c16c1b9232f04aff13bd189573b4d Mon Sep 17 00:00:00 2001 From: Markus Heidelberg <markus.heidelberg@web.de> Date: Sun, 5 Apr 2009 03:48:21 +0200 Subject: [PATCH 366/654] git-gui: use `git --html-path` to get the location of installed HTML docs Previously a hardcoded path $GIT_EXEC_PATH/../Documentation/ was used to search for the documentation, when the user has asked for it via menu "Help -> Online Documentation". This didn't work for the default directory structure. To find the path reliably, use the new git command line option, which returns the correct path. If the output of `git --html-path` is empty because git is not found or the option is not yet supported in the installed git, the documentation from kernel.org is launched. There is no additional guessing of the right location of the installed docs. Signed-off-by: Markus Heidelberg <markus.heidelberg@web.de> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- git-gui.sh | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/git-gui.sh b/git-gui.sh index b3aa7325f0..259251ba19 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -122,6 +122,7 @@ unset oguimsg set _appname {Git Gui} set _gitdir {} set _gitexec {} +set _githtmldir {} set _reponame {} set _iscygwin {} set _search_path {} @@ -168,6 +169,28 @@ proc gitexec {args} { return [eval [list file join $_gitexec] $args] } +proc githtmldir {args} { + global _githtmldir + if {$_githtmldir eq {}} { + if {[catch {set _githtmldir [git --html-path]}]} { + # Git not installed or option not yet supported + return {} + } + if {[is_Cygwin]} { + set _githtmldir [exec cygpath \ + --windows \ + --absolute \ + $_githtmldir] + } else { + set _githtmldir [file normalize $_githtmldir] + } + } + if {$args eq {}} { + return $_githtmldir + } + return [eval [list file join $_githtmldir] $args] +} + proc reponame {} { return $::_reponame } @@ -2591,11 +2614,13 @@ if {![is_MacOSX]} { } -set doc_path [file dirname [gitexec]] -set doc_path [file join $doc_path Documentation index.html] +set doc_path [githtmldir] +if {$doc_path ne {}} { + set doc_path [file join $doc_path index.html] -if {[is_Cygwin]} { - set doc_path [exec cygpath --mixed $doc_path] + if {[is_Cygwin]} { + set doc_path [exec cygpath --mixed $doc_path] + } } if {[file isfile $doc_path]} { From f0d4eec99f2367bad77ec46680d7b07d4472d230 Mon Sep 17 00:00:00 2001 From: Jens Lehmann <Jens.Lehmann@web.de> Date: Mon, 30 Mar 2009 20:35:57 +0200 Subject: [PATCH 367/654] git-gui: When calling post-commit hook wrong variable was cleared. Before calling the post-commit hook, the variable "pc_err" is cleared while later only "pch_error" is used. "pch_error$cmt_id" only appeared in "upvar"-Statements (which were changed to "global") and was removed. Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- lib/commit.tcl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/commit.tcl b/lib/commit.tcl index 17aba914af..7f459cd564 100644 --- a/lib/commit.tcl +++ b/lib/commit.tcl @@ -407,8 +407,8 @@ A rescan will be automatically started now. # set fd_ph [githook_read post-commit] if {$fd_ph ne {}} { - upvar #0 pch_error$cmt_id pc_err - set pc_err {} + global pch_error + set pch_error {} fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} fileevent $fd_ph readable \ [list commit_postcommit_wait $fd_ph $cmt_id] @@ -470,7 +470,7 @@ A rescan will be automatically started now. } proc commit_postcommit_wait {fd_ph cmt_id} { - upvar #0 pch_error$cmt_id pch_error + global pch_error append pch_error [read $fd_ph] fconfigure $fd_ph -blocking 1 From c9498339a40566c736a85238c29fd45d63510abe Mon Sep 17 00:00:00 2001 From: Jens Lehmann <Jens.Lehmann@web.de> Date: Mon, 30 Mar 2009 21:46:17 +0200 Subject: [PATCH 368/654] git-gui: run post-checkout hook on checkout git-gui is using "git-read-tree -u" for checkout which doesn't invoke the post-checkout hook as a plain git-checkout would. So git-gui must call the hook itself. Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- lib/checkout_op.tcl | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/lib/checkout_op.tcl b/lib/checkout_op.tcl index caca88831b..9e7412c446 100644 --- a/lib/checkout_op.tcl +++ b/lib/checkout_op.tcl @@ -9,6 +9,7 @@ field w_cons {}; # embedded console window object field new_expr ; # expression the user saw/thinks this is field new_hash ; # commit SHA-1 we are switching to field new_ref ; # ref we are updating/creating +field old_hash ; # commit SHA-1 that was checked out when we started field parent_w .; # window that started us field merge_type none; # type of merge to apply to existing branch @@ -280,11 +281,11 @@ method _start_checkout {} { # -- Our in memory state should match the repository. # - repository_state curType curHEAD curMERGE_HEAD + repository_state curType old_hash curMERGE_HEAD if {[string match amend* $commit_type] && $curType eq {normal} - && $curHEAD eq $HEAD} { - } elseif {$commit_type ne $curType || $HEAD ne $curHEAD} { + && $old_hash eq $HEAD} { + } elseif {$commit_type ne $curType || $HEAD ne $old_hash} { info_popup [mc "Last scanned state does not match repository state. Another Git program has modified this repository since the last scan. A rescan must be performed before the current branch can be changed. @@ -297,7 +298,7 @@ The rescan will be automatically started now. return } - if {$curHEAD eq $new_hash} { + if {$old_hash eq $new_hash} { _after_readtree $this } elseif {[is_config_true gui.trustmtime]} { _readtree $this @@ -453,13 +454,47 @@ method _after_readtree {} { If you wanted to be on a branch, create one now starting from 'This Detached Checkout'."] } + # -- Run the post-checkout hook. + # + set fd_ph [githook_read post-checkout $old_hash $new_hash 1] + if {$fd_ph ne {}} { + global pch_error + set pch_error {} + fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} + fileevent $fd_ph readable [cb _postcheckout_wait $fd_ph] + } else { + _update_repo_state $this + } +} + +method _postcheckout_wait {fd_ph} { + global pch_error + + append pch_error [read $fd_ph] + fconfigure $fd_ph -blocking 1 + if {[eof $fd_ph]} { + if {[catch {close $fd_ph}]} { + hook_failed_popup post-checkout $pch_error 0 + } + unset pch_error + _update_repo_state $this + return + } + fconfigure $fd_ph -blocking 0 +} + +method _update_repo_state {} { # -- Update our repository state. If we were previously in # amend mode we need to toss the current buffer and do a # full rescan to update our file lists. If we weren't in # amend mode our file lists are accurate and we can avoid # the rescan. # + global selected_commit_type commit_type HEAD MERGE_HEAD PARENT + global ui_comm + unlock_index + set name [_name $this] set selected_commit_type new if {[string match amend* $commit_type]} { $ui_comm delete 0.0 end From 454efb47b6199f70ec7992ea4bf459f193a43bb7 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg <markus.heidelberg@web.de> Date: Wed, 1 Apr 2009 01:55:36 +0200 Subject: [PATCH 369/654] git-gui (Win): make "Explore Working Copy" more robust Starting the Explorer from the git-gui menu "Explore Working Copy" didn't work, when git-gui was started via Windows Explorer shell extension (Git GUI Here) from a directory within the project. The Explorer raised an error message like this: Path "C:/somedir/worktree" is not available or not a directory It worked when started from the project directory itself, because then the path argument for the Explorer was just '.' (current directory) without any problematic forward slashes. To make it work, convert the path given as argument to explorer.exe to its native format with backslashes. Signed-off-by: Markus Heidelberg <markus.heidelberg@web.de> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui.sh b/git-gui.sh index 259251ba19..e4a9230ea0 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -1947,7 +1947,7 @@ proc do_explore {} { # freedesktop.org-conforming system is our best shot set explorer "xdg-open" } - eval exec $explorer [file dirname [gitdir]] & + eval exec $explorer [list [file nativename [file dirname [gitdir]]]] & } set is_quitting 0 From b01d4326040ec6b9d98baba32091c9458fc809d4 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg <markus.heidelberg@web.de> Date: Wed, 1 Apr 2009 01:55:39 +0200 Subject: [PATCH 370/654] git-gui (Win): make starting via "Git GUI Here" on .git/ possible This works around git-gui's error message Cannot use funny .git directory: . when started from the .git/ directory, which is useful in repositories without any directories for the right click. Now git-gui can be started via Windows Explorer shell extension (Git GUI Here) from the .git/ directory. Signed-off-by: Markus Heidelberg <markus.heidelberg@web.de> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- windows/git-gui.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/windows/git-gui.sh b/windows/git-gui.sh index 53c3a94686..66bbb2f8fa 100644 --- a/windows/git-gui.sh +++ b/windows/git-gui.sh @@ -3,7 +3,12 @@ exec wish "$0" -- "$@" if { $argc >=2 && [lindex $argv 0] == "--working-dir" } { - cd [lindex $argv 1] + set workdir [lindex $argv 1] + cd $workdir + if {[lindex [file split $workdir] end] eq {.git}} { + # Workaround for Explorer right click "Git GUI Here" on .git/ + cd .. + } set argv [lrange $argv 2 end] incr argc -2 } From 1d1876e9300c56f399ea2976c5831674cd9818b1 Mon Sep 17 00:00:00 2001 From: Heiko Voigt <hvoigt@hvoigt.net> Date: Wed, 1 Apr 2009 19:51:54 +0200 Subject: [PATCH 371/654] Add configuration variable for sign-off to format-patch If you regularly create patches which require a Signed-off: line you may want to make it your default to add that line. It also helps you not to forget to add the -s/--signoff switch. Signed-off-by: Heiko Voigt <hvoigt@hvoigt.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 7 +++++++ Documentation/git-format-patch.txt | 1 + builtin-log.c | 23 ++++++++++++++++------- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index ad22cb875e..27cb7f1408 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -715,6 +715,13 @@ format.thread:: A true boolean value is the same as `shallow`, and a false value disables threading. +format.signoff:: + A boolean value which lets you enable the `-s/--signoff` option of + format-patch by default. *Note:* Adding the Signed-off-by: line to a + patch should be a conscious act and means that you certify you have + the rights to submit this work under the same open source license. + Please see the 'SubmittingPatches' document for further discussion. + gc.aggressiveWindow:: The window size parameter used in the delta compression algorithm used by 'git-gc --aggressive'. This defaults diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index db3bdb5657..eb2fbcff1a 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -205,6 +205,7 @@ more than one. numbered = auto cc = <email> attach [ = mime-boundary-string ] + signoff = true ------------ diff --git a/builtin-log.c b/builtin-log.c index 27bc0dce23..eb2c0541b5 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -465,6 +465,7 @@ static void add_header(const char *value) #define THREAD_SHALLOW 1 #define THREAD_DEEP 2 static int thread = 0; +static int do_signoff = 0; static int git_format_config(const char *var, const char *value, void *cb) { @@ -514,6 +515,10 @@ static int git_format_config(const char *var, const char *value, void *cb) thread = git_config_bool(var, value) && THREAD_SHALLOW; return 0; } + if (!strcmp(var, "format.signoff")) { + do_signoff = git_config_bool(var, value); + return 0; + } return git_log_config(var, value, cb); } @@ -865,13 +870,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) } else if (!strcmp(argv[i], "--signoff") || !strcmp(argv[i], "-s")) { - const char *committer; - const char *endpos; - committer = git_committer_info(IDENT_ERROR_ON_NO_NAME); - endpos = strchr(committer, '>'); - if (!endpos) - die("bogus committer info %s", committer); - add_signoff = xmemdupz(committer, endpos - committer + 1); + do_signoff = 1; } else if (!strcmp(argv[i], "--attach")) { rev.mime_boundary = git_version_string; @@ -925,6 +924,16 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) } argc = j; + if (do_signoff) { + const char *committer; + const char *endpos; + committer = git_committer_info(IDENT_ERROR_ON_NO_NAME); + endpos = strchr(committer, '>'); + if (!endpos) + die("bogus committer info %s", committer); + add_signoff = xmemdupz(committer, endpos - committer + 1); + } + for (i = 0; i < extra_hdr_nr; i++) { strbuf_addstr(&buf, extra_hdr[i]); strbuf_addch(&buf, '\n'); From 5c9c990341bad6b4087c2dd99d28a6cb910749df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santi=20B=C3=A9jar?= <santi@agolina.net> Date: Mon, 30 Mar 2009 12:11:42 +0200 Subject: [PATCH 372/654] Documentation: branch.*.merge can also affect 'git-push' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Santi Béjar <santi@agolina.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 27cb7f1408..3afd124749 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -480,7 +480,7 @@ branch.<name>.remote:: branch.<name>.merge:: Defines, together with branch.<name>.remote, the upstream branch for the given branch. It tells 'git-fetch'/'git-pull' which - branch to merge from. + branch to merge and can also affect 'git-push' (see push.default). When in branch <name>, it tells 'git-fetch' the default refspec to be marked for merging in FETCH_HEAD. The value is handled like the remote part of a refspec, and must match a From 6127c0864798111d3524da2bea6188b0048d9fcf Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Sat, 4 Apr 2009 12:38:23 +0300 Subject: [PATCH 373/654] user-manual: remove some git-foo usage Also, use `git foo` when it make sense. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/user-manual.txt | 148 +++++++++++++++++----------------- 1 file changed, 74 insertions(+), 74 deletions(-) diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt index e33b29b1dd..1bc4b7037a 100644 --- a/Documentation/user-manual.txt +++ b/Documentation/user-manual.txt @@ -188,7 +188,7 @@ As you can see, a commit shows who made the latest change, what they did, and why. Every commit has a 40-hexdigit id, sometimes called the "object name" or the -"SHA1 id", shown on the first line of the "git-show" output. You can usually +"SHA1 id", shown on the first line of the "git show" output. You can usually refer to a commit by a shorter name, such as a tag or a branch name, but this longer name can also be useful. Most importantly, it is a globally unique name for this commit: so if you tell somebody else the object name (for @@ -307,7 +307,7 @@ ref: refs/heads/master Examining an old version without creating a new branch ------------------------------------------------------ -The git-checkout command normally expects a branch head, but will also +The `git checkout` command normally expects a branch head, but will also accept an arbitrary commit; for example, you can check out the commit referenced by a tag: @@ -400,7 +400,7 @@ references with the same shorthand name, see the "SPECIFYING REVISIONS" section of linkgit:git-rev-parse[1]. [[Updating-a-repository-With-git-fetch]] -Updating a repository with git-fetch +Updating a repository with git fetch ------------------------------------ Eventually the developer cloned from will do additional work in her @@ -427,7 +427,7 @@ $ git fetch linux-nfs ------------------------------------------------- New remote-tracking branches will be stored under the shorthand name -that you gave "git-remote add", in this case linux-nfs: +that you gave "git remote add", in this case linux-nfs: ------------------------------------------------- $ git branch -r @@ -516,7 +516,7 @@ $ git bisect reset to return you to the branch you were on before. -Note that the version which git-bisect checks out for you at each +Note that the version which `git bisect` checks out for you at each point is just a suggestion, and you're free to try a different version if you think it would be a good idea. For example, occasionally you may land on a commit that broke something unrelated; @@ -592,11 +592,11 @@ In addition to HEAD, there are several other special names for commits: Merges (to be discussed later), as well as operations such as -git-reset, which change the currently checked-out commit, generally +`git reset`, which change the currently checked-out commit, generally set ORIG_HEAD to the value HEAD had before the current operation. -The git-fetch operation always stores the head of the last fetched -branch in FETCH_HEAD. For example, if you run git fetch without +The `git fetch` operation always stores the head of the last fetched +branch in FETCH_HEAD. For example, if you run `git fetch` without specifying a local branch as the target of the operation ------------------------------------------------- @@ -1073,9 +1073,9 @@ $ git diff shows the difference between the working tree and the index file. -Note that "git-add" always adds just the current contents of a file +Note that "git add" always adds just the current contents of a file to the index; further changes to the same file will be ignored unless -you run git-add on the file again. +you run `git add` on the file again. When you're ready, just run @@ -1136,7 +1136,7 @@ Ignoring files A project will often generate files that you do 'not' want to track with git. This typically includes files generated by a build process or temporary backup files made by your editor. Of course, 'not' tracking files with git -is just a matter of 'not' calling `git-add` on them. But it quickly becomes +is just a matter of 'not' calling `git add` on them. But it quickly becomes annoying to have these untracked files lying around; e.g. they make `git add .` practically useless, and they keep showing up in the output of `git status`. @@ -1349,7 +1349,7 @@ $ git add file.txt ------------------------------------------------- the different stages of that file will be "collapsed", after which -git-diff will (by default) no longer show diffs for that file. +`git diff` will (by default) no longer show diffs for that file. [[undoing-a-merge]] Undoing a merge @@ -1446,7 +1446,7 @@ Fixing a mistake by rewriting history If the problematic commit is the most recent commit, and you have not yet made that commit public, then you may just -<<undoing-a-merge,destroy it using git-reset>>. +<<undoing-a-merge,destroy it using `git reset`>>. Alternatively, you can edit the working directory and update the index to fix your @@ -1474,7 +1474,7 @@ Checking out an old version of a file In the process of undoing a previous bad change, you may find it useful to check out an older version of a particular file using -linkgit:git-checkout[1]. We've used git-checkout before to switch +linkgit:git-checkout[1]. We've used `git checkout` before to switch branches, but it has quite different behavior if it is given a path name: the command @@ -1542,7 +1542,7 @@ $ git gc ------------------------------------------------- to recompress the archive. This can be very time-consuming, so -you may prefer to run git-gc when you are not doing other work. +you may prefer to run `git gc` when you are not doing other work. [[ensuring-reliability]] @@ -1634,7 +1634,7 @@ In some situations the reflog may not be able to save you. For example, suppose you delete a branch, then realize you need the history it contained. The reflog is also deleted; however, if you have not yet pruned the repository, then you may still be able to find the lost -commits in the dangling objects that git-fsck reports. See +commits in the dangling objects that `git fsck` reports. See <<dangling-objects>> for the details. ------------------------------------------------- @@ -1676,7 +1676,7 @@ Sharing development with others =============================== [[getting-updates-With-git-pull]] -Getting updates with git-pull +Getting updates with git pull ----------------------------- After you clone a repository and make a few changes of your own, you @@ -1722,7 +1722,7 @@ repository that you pulled from. <<fast-forwards,fast forward>>; instead, your branch will just be updated to point to the latest commit from the upstream branch.) -The git-pull command can also be given "." as the "remote" repository, +The `git pull` command can also be given "." as the "remote" repository, in which case it just merges in a branch from the current repository; so the commands @@ -1795,7 +1795,7 @@ Public git repositories Another way to submit changes to a project is to tell the maintainer of that project to pull the changes from your repository using linkgit:git-pull[1]. In the section "<<getting-updates-With-git-pull, -Getting updates with git-pull>>" we described this as a way to get +Getting updates with `git pull`>>" we described this as a way to get updates from the "main" repository, but it works just as well in the other direction. @@ -1847,7 +1847,7 @@ Setting up a public repository ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Assume your personal repository is in the directory ~/proj. We -first create a new clone of the repository and tell git-daemon that it +first create a new clone of the repository and tell `git daemon` that it is meant to be public: ------------------------------------------------- @@ -1878,10 +1878,10 @@ repository>>", below. Otherwise, all you need to do is start linkgit:git-daemon[1]; it will listen on port 9418. By default, it will allow access to any directory that looks like a git directory and contains the magic file -git-daemon-export-ok. Passing some directory paths as git-daemon +git-daemon-export-ok. Passing some directory paths as `git daemon` arguments will further restrict the exports to those paths. -You can also run git-daemon as an inetd service; see the +You can also run `git daemon` as an inetd service; see the linkgit:git-daemon[1] man page for details. (See especially the examples section.) @@ -1942,7 +1942,7 @@ or just $ git push ssh://yourserver.com/~you/proj.git master ------------------------------------------------- -As with git-fetch, git-push will complain if this does not result in a +As with `git fetch`, `git push` will complain if this does not result in a <<fast-forwards,fast forward>>; see the following section for details on handling this case. @@ -1952,7 +1952,7 @@ repository that has a checked-out working tree, but the working tree will not be updated by the push. This may lead to unexpected results if the branch you push to is the currently checked-out branch! -As with git-fetch, you may also set up configuration options to +As with `git fetch`, you may also set up configuration options to save typing; so, for example, after ------------------------------------------------- @@ -1988,13 +1988,13 @@ error: failed to push to 'ssh://yourserver.com/~you/proj.git' This can happen, for example, if you: - - use `git-reset --hard` to remove already-published commits, or - - use `git-commit --amend` to replace already-published commits + - use `git reset --hard` to remove already-published commits, or + - use `git commit --amend` to replace already-published commits (as in <<fixing-a-mistake-by-rewriting-history>>), or - - use `git-rebase` to rebase any already-published commits (as + - use `git rebase` to rebase any already-published commits (as in <<using-git-rebase>>). -You may force git-push to perform the update anyway by preceding the +You may force `git push` to perform the update anyway by preceding the branch name with a plus sign: ------------------------------------------------- @@ -2036,7 +2036,7 @@ advantages over the central shared repository: - Git's ability to quickly import and merge patches allows a single maintainer to process incoming changes even at very - high rates. And when that becomes too much, git-pull provides + high rates. And when that becomes too much, `git pull` provides an easy way for that maintainer to delegate this job to other maintainers while still allowing optional review of incoming changes. @@ -2404,7 +2404,7 @@ use them, and then explain some of the problems that can arise because you are rewriting history. [[using-git-rebase]] -Keeping a patch series up to date using git-rebase +Keeping a patch series up to date using git rebase -------------------------------------------------- Suppose that you create a branch "mywork" on a remote-tracking branch @@ -2468,9 +2468,9 @@ patches to the new mywork. The result will look like: ................................................ In the process, it may discover conflicts. In that case it will stop -and allow you to fix the conflicts; after fixing conflicts, use "git-add" +and allow you to fix the conflicts; after fixing conflicts, use `git add` to update the index with those contents, and then, instead of -running git-commit, just run +running `git commit`, just run ------------------------------------------------- $ git rebase --continue @@ -2508,7 +2508,7 @@ with $ git tag bad mywork~5 ------------------------------------------------- -(Either gitk or git-log may be useful for finding the commit.) +(Either gitk or `git log` may be useful for finding the commit.) Then check out that commit, edit it, and rebase the rest of the series on top of it (note that we could check out the commit on a temporary @@ -2549,12 +2549,12 @@ $ gitk origin..mywork & and browse through the list of patches in the mywork branch using gitk, applying them (possibly in a different order) to mywork-new using -cherry-pick, and possibly modifying them as you go using `commit --amend`. +cherry-pick, and possibly modifying them as you go using `git commit --amend`. The linkgit:git-gui[1] command may also help as it allows you to individually select diff hunks for inclusion in the index (by right-clicking on the diff hunk and choosing "Stage Hunk for Commit"). -Another technique is to use git-format-patch to create a series of +Another technique is to use `git format-patch` to create a series of patches, then reset the state to before the patches: ------------------------------------------------- @@ -2662,7 +2662,7 @@ you know is that D is bad, that Z is good, and that linkgit:git-bisect[1] identifies C as the culprit, how will you figure out that the problem is due to this change in semantics? -When the result of a git-bisect is a non-merge commit, you should +When the result of a `git bisect` is a non-merge commit, you should normally be able to discover the problem by examining just that commit. Developers can make this easy by breaking their changes into small self-contained commits. That won't help in the case above, however, @@ -2725,7 +2725,7 @@ master branch. In more detail: git fetch and fast-forwards --------------------------- -In the previous example, when updating an existing branch, "git-fetch" +In the previous example, when updating an existing branch, "git fetch" checks to make sure that the most recent commit on the remote branch is a descendant of the most recent commit on your copy of the branch before updating your copy of the branch to point at the new @@ -2751,7 +2751,7 @@ resulting in a situation like: o--o--o <-- new head of the branch ................................................ -In this case, "git-fetch" will fail, and print out a warning. +In this case, "git fetch" will fail, and print out a warning. In that case, you can still force git to update to the new head, as described in the following section. However, note that in the @@ -2760,7 +2760,7 @@ unless you've already created a reference of your own pointing to them. [[forcing-fetch]] -Forcing git-fetch to do non-fast-forward updates +Forcing git fetch to do non-fast-forward updates ------------------------------------------------ If git fetch fails because the new head of a branch is not a @@ -3131,7 +3131,7 @@ $ git prune to remove any of the "loose" objects that are now contained in the pack. This will also remove any unreferenced objects (which may be -created when, for example, you use "git-reset" to remove a commit). +created when, for example, you use "git reset" to remove a commit). You can verify that the loose objects are gone by looking at the .git/objects directory or by running @@ -3160,7 +3160,7 @@ branch still exists, as does everything it pointed to. The branch pointer itself just doesn't, since you replaced it with another one. There are also other situations that cause dangling objects. For -example, a "dangling blob" may arise because you did a "git-add" of a +example, a "dangling blob" may arise because you did a "git add" of a file, but then, before you actually committed it and made it part of the bigger picture, you changed something else in that file and committed that *updated* thing--the old state that you added originally ends up @@ -3210,7 +3210,7 @@ Usually, dangling blobs and trees aren't very interesting. They're almost always the result of either being a half-way mergebase (the blob will often even have the conflict markers from a merge in it, if you have had conflicting merges that you fixed up by hand), or simply -because you interrupted a "git-fetch" with ^C or something like that, +because you interrupted a "git fetch" with ^C or something like that, leaving _some_ of the new objects in the object database, but just dangling and useless. @@ -3225,9 +3225,9 @@ and they'll be gone. But you should only run "git prune" on a quiescent repository--it's kind of like doing a filesystem fsck recovery: you don't want to do that while the filesystem is mounted. -(The same is true of "git-fsck" itself, btw, but since -git-fsck never actually *changes* the repository, it just reports -on what it found, git-fsck itself is never "dangerous" to run. +(The same is true of "git fsck" itself, btw, but since +`git fsck` never actually *changes* the repository, it just reports +on what it found, `git fsck` itself is never 'dangerous' to run. Running it while somebody is actually changing the repository can cause confusing and scary messages, but it won't actually do anything bad. In contrast, running "git prune" while somebody is actively changing the @@ -3489,14 +3489,14 @@ done NOTE: Do not use local URLs here if you plan to publish your superproject! -See what files `git-submodule` created: +See what files `git submodule` created: ------------------------------------------------- $ ls -a . .. .git .gitmodules a b c d ------------------------------------------------- -The `git-submodule add <repo> <path>` command does a couple of things: +The `git submodule add <repo> <path>` command does a couple of things: - It clones the submodule from <repo> to the given <path> under the current directory and by default checks out the master branch. @@ -3542,7 +3542,7 @@ init` to add the submodule repository URLs to `.git/config`: $ git submodule init ------------------------------------------------- -Now use `git-submodule update` to clone the repositories and check out the +Now use `git submodule update` to clone the repositories and check out the commits specified in the superproject: ------------------------------------------------- @@ -3552,8 +3552,8 @@ $ ls -a . .. .git a.txt ------------------------------------------------- -One major difference between `git-submodule update` and `git-submodule add` is -that `git-submodule update` checks out a specific commit, rather than the tip +One major difference between `git submodule update` and `git submodule add` is +that `git submodule update` checks out a specific commit, rather than the tip of a branch. It's like checking out a tag: the head is detached, so you're not working on a branch. @@ -3769,7 +3769,7 @@ You update your working directory from the index by "checking out" files. This is not a very common operation, since normally you'd just keep your files updated, and rather than write to your working directory, you'd tell the index files about the changes in your -working directory (i.e. `git-update-index`). +working directory (i.e. `git update-index`). However, if you decide to jump to a new version, or check out somebody else's version, or just restore a previous tree, you'd populate your @@ -3782,7 +3782,7 @@ $ git checkout-index filename or, if you want to check out all of the index, use `-a`. -NOTE! git-checkout-index normally refuses to overwrite old files, so +NOTE! `git checkout-index` normally refuses to overwrite old files, so if you have an old version of the tree already checked out, you will need to use the "-f" flag ('before' the "-a" flag or the filename) to 'force' the checkout. @@ -3820,7 +3820,7 @@ $ git commit-tree <tree> -p <parent> [-p <parent2> ..] and then giving the reason for the commit on stdin (either through redirection from a pipe or file, or by just typing it at the tty). -git-commit-tree will return the name of the object that represents +`git commit-tree` will return the name of the object that represents that commit, and you should save it away for later use. Normally, you'd commit a new `HEAD` state, and while git doesn't care where you save the note about that state, in practice we tend to just write the @@ -3889,7 +3889,7 @@ $ git cat-file blob|tree|commit|tag <objectname> to show its contents. NOTE! Trees have binary content, and as a result there is a special helper for showing that content, called -`git-ls-tree`, which turns the binary content into a more easily +`git ls-tree`, which turns the binary content into a more easily readable form. It's especially instructive to look at "commit" objects, since those @@ -3984,7 +3984,7 @@ came from: stage 1 corresponds to `$orig` tree, stage 2 `HEAD` tree, and stage3 `$target` tree. Earlier we said that trivial merges are done inside -`git-read-tree -m`. For example, if the file did not change +`git read-tree -m`. For example, if the file did not change from `$orig` to `HEAD` nor `$target`, or if the file changed from `$orig` to `HEAD` and `$orig` to `$target` the same way, obviously the final outcome is what is in `HEAD`. What the @@ -4011,20 +4011,20 @@ $ mv -f hello.c~2 hello.c $ git update-index hello.c ------------------------------------------------- -When a path is in the "unmerged" state, running `git-update-index` for +When a path is in the "unmerged" state, running `git update-index` for that path tells git to mark the path resolved. The above is the description of a git merge at the lowest level, to help you understand what conceptually happens under the hood. -In practice, nobody, not even git itself, runs `git-cat-file` three times -for this. There is a `git-merge-index` program that extracts the +In practice, nobody, not even git itself, runs `git cat-file` three times +for this. There is a `git merge-index` program that extracts the stages to temporary files and calls a "merge" script on it: ------------------------------------------------- $ git merge-index git-merge-one-file hello.c ------------------------------------------------- -and that is what higher level `git-merge -s resolve` is implemented with. +and that is what higher level `git merge -s resolve` is implemented with. [[hacking-git]] Hacking git @@ -4061,7 +4061,7 @@ size> {plus} <byte\0> {plus} <binary object data>. The structured objects can further have their structure and connectivity to other objects verified. This is generally done with -the `git-fsck` program, which generates a full dependency graph +the `git fsck` program, which generates a full dependency graph of all objects, and verifies their internal consistency (in addition to just verifying their superficial consistency through the hash). @@ -4120,7 +4120,7 @@ functions like `get_sha1_basic()` or the likes. This is just to get you into the groove for the most libified part of Git: the revision walker. -Basically, the initial version of `git-log` was a shell script: +Basically, the initial version of `git log` was a shell script: ---------------------------------------------------------------- $ git-rev-list --pretty $(git-rev-parse --default HEAD "$@") | \ @@ -4129,20 +4129,20 @@ $ git-rev-list --pretty $(git-rev-parse --default HEAD "$@") | \ What does this mean? -`git-rev-list` is the original version of the revision walker, which +`git rev-list` is the original version of the revision walker, which _always_ printed a list of revisions to stdout. It is still functional, and needs to, since most new Git programs start out as scripts using -`git-rev-list`. +`git rev-list`. -`git-rev-parse` is not as important any more; it was only used to filter out +`git rev-parse` is not as important any more; it was only used to filter out options that were relevant for the different plumbing commands that were called by the script. -Most of what `git-rev-list` did is contained in `revision.c` and +Most of what `git rev-list` did is contained in `revision.c` and `revision.h`. It wraps the options in a struct named `rev_info`, which controls how and what revisions are walked, and more. -The original job of `git-rev-parse` is now taken by the function +The original job of `git rev-parse` is now taken by the function `setup_revisions()`, which parses the revisions and the common command line options for the revision walker. This information is stored in the struct `rev_info` for later consumption. You can do your own command line option @@ -4155,7 +4155,7 @@ just have a look at the first implementation of `cmd_log()`; call `git show v1.3.0{tilde}155^2{tilde}4` and scroll down to that function (note that you no longer need to call `setup_pager()` directly). -Nowadays, `git-log` is a builtin, which means that it is _contained_ in the +Nowadays, `git log` is a builtin, which means that it is _contained_ in the command `git`. The source side of a builtin is - a function called `cmd_<bla>`, typically defined in `builtin-<bla>.c`, @@ -4171,7 +4171,7 @@ since they share quite a bit of code. In that case, the commands which are _not_ named like the `.c` file in which they live have to be listed in `BUILT_INS` in the `Makefile`. -`git-log` looks more complicated in C than it does in the original script, +`git log` looks more complicated in C than it does in the original script, but that allows for a much greater flexibility and performance. Here again it is a good point to take a pause. @@ -4182,9 +4182,9 @@ the organization of Git (after you know the basic concepts). So, think about something which you are interested in, say, "how can I access a blob just knowing the object name of it?". The first step is to find a Git command with which you can do it. In this example, it is either -`git-show` or `git-cat-file`. +`git show` or `git cat-file`. -For the sake of clarity, let's stay with `git-cat-file`, because it +For the sake of clarity, let's stay with `git cat-file`, because it - is plumbing, and @@ -4198,7 +4198,7 @@ it does. ------------------------------------------------------------------ git_config(git_default_config); if (argc != 3) - usage("git-cat-file [-t|-s|-e|-p|<type>] <sha1>"); + usage("git cat-file [-t|-s|-e|-p|<type>] <sha1>"); if (get_sha1(argv[2], sha1)) die("Not a valid object name %s", argv[2]); ------------------------------------------------------------------ @@ -4243,10 +4243,10 @@ To find out how the result can be used, just read on in `cmd_cat_file()`: ----------------------------------- Sometimes, you do not know where to look for a feature. In many such cases, -it helps to search through the output of `git log`, and then `git-show` the +it helps to search through the output of `git log`, and then `git show` the corresponding commit. -Example: If you know that there was some test case for `git-bundle`, but +Example: If you know that there was some test case for `git bundle`, but do not remember where it was (yes, you _could_ `git grep bundle t/`, but that does not illustrate the point!): @@ -4530,7 +4530,7 @@ The basic requirements: - Whenever possible, section headings should clearly describe the task they explain how to do, in language that requires no more knowledge than necessary: for example, "importing patches into a project" rather - than "the git-am command" + than "the `git am` command" Think about how to create a clear chapter dependency graph that will allow people to get to important topics without necessarily reading From a3df1e464e110776120e37f467cc0ad3b957a80e Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Sat, 4 Apr 2009 12:38:24 +0300 Subject: [PATCH 374/654] docbook: change css style A handful of random personal preference: - Force sans-serif for the text. - Quote code sample literal inside a single-quote pair. - Show emphasis in blue-green italics. - Do not use itarlics for term definition, but show them in navy. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/docbook-xsl.css | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Documentation/docbook-xsl.css b/Documentation/docbook-xsl.css index b878b385c6..e11c8f053a 100644 --- a/Documentation/docbook-xsl.css +++ b/Documentation/docbook-xsl.css @@ -16,6 +16,7 @@ body blockquote { html body { margin: 1em 5% 1em 5%; line-height: 1.2; + font-family: sans-serif; } body div { @@ -128,6 +129,15 @@ body pre { tt.literal, code.literal { color: navy; + font-family: sans-serif; +} + +code.literal:before { content: "'"; } +code.literal:after { content: "'"; } + +em { + font-style: italic; + color: #064; } div.literallayout p { @@ -137,7 +147,6 @@ div.literallayout p { div.literallayout { font-family: monospace; -# margin: 0.5em 10% 0.5em 1em; margin: 0em; color: navy; border: 1px solid silver; @@ -187,7 +196,8 @@ dt { } dt span.term { - font-style: italic; + font-style: normal; + color: navy; } div.variablelist dd p { From a6e5ef7d9cc34199fb6618e1fbb57f3615d002f6 Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Sat, 4 Apr 2009 12:38:27 +0300 Subject: [PATCH 375/654] user-manual: the name of the hash function is SHA-1, not sha1 Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/user-manual.txt | 50 +++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt index 1bc4b7037a..dbbeb7e7c7 100644 --- a/Documentation/user-manual.txt +++ b/Documentation/user-manual.txt @@ -188,7 +188,7 @@ As you can see, a commit shows who made the latest change, what they did, and why. Every commit has a 40-hexdigit id, sometimes called the "object name" or the -"SHA1 id", shown on the first line of the "git show" output. You can usually +"SHA-1 id", shown on the first line of the "git show" output. You can usually refer to a commit by a shorter name, such as a tag or a branch name, but this longer name can also be useful. Most importantly, it is a globally unique name for this commit: so if you tell somebody else the object name (for @@ -320,7 +320,7 @@ If you want to create a new branch from this checkout, you may do so HEAD is now at 427abfa... Linux v2.6.17 ------------------------------------------------ -The HEAD then refers to the SHA1 of the commit instead of to a branch, +The HEAD then refers to the SHA-1 of the commit instead of to a branch, and git branch shows that you are no longer on a branch: ------------------------------------------------ @@ -739,7 +739,7 @@ $ git log --pretty=oneline origin..mybranch | wc -l ------------------------------------------------- Alternatively, you may often see this sort of thing done with the -lower-level command linkgit:git-rev-list[1], which just lists the SHA1's +lower-level command linkgit:git-rev-list[1], which just lists the SHA-1's of all the given commits: ------------------------------------------------- @@ -2865,8 +2865,8 @@ The Object Database We already saw in <<understanding-commits>> that all commits are stored under a 40-digit "object name". In fact, all the information needed to represent the history of a project is stored in objects with such names. -In each case the name is calculated by taking the SHA1 hash of the -contents of the object. The SHA1 hash is a cryptographic hash function. +In each case the name is calculated by taking the SHA-1 hash of the +contents of the object. The SHA-1 hash is a cryptographic hash function. What that means to us is that it is impossible to find two different objects with the same name. This has a number of advantages; among others: @@ -2877,10 +2877,10 @@ others: same content stored in two repositories will always be stored under the same name. - Git can detect errors when it reads an object, by checking that the - object's name is still the SHA1 hash of its contents. + object's name is still the SHA-1 hash of its contents. (See <<object-details>> for the details of the object formatting and -SHA1 calculation.) +SHA-1 calculation.) There are four different types of objects: "blob", "tree", "commit", and "tag". @@ -2926,9 +2926,9 @@ committer Junio C Hamano <gitster@pobox.com> 1187591163 -0700 As you can see, a commit is defined by: -- a tree: The SHA1 name of a tree object (as defined below), representing +- a tree: The SHA-1 name of a tree object (as defined below), representing the contents of a directory at a certain point in time. -- parent(s): The SHA1 name of some number of commits which represent the +- parent(s): The SHA-1 name of some number of commits which represent the immediately previous step(s) in the history of the project. The example above has one parent; merge commits may have more than one. A commit with no parents is called a "root" commit, and @@ -2977,13 +2977,13 @@ $ git ls-tree fb3a8bdd0ce ------------------------------------------------ As you can see, a tree object contains a list of entries, each with a -mode, object type, SHA1 name, and name, sorted by name. It represents +mode, object type, SHA-1 name, and name, sorted by name. It represents the contents of a single directory tree. The object type may be a blob, representing the contents of a file, or another tree, representing the contents of a subdirectory. Since trees -and blobs, like all other objects, are named by the SHA1 hash of their -contents, two trees have the same SHA1 name if and only if their +and blobs, like all other objects, are named by the SHA-1 hash of their +contents, two trees have the same SHA-1 name if and only if their contents (including, recursively, the contents of all subdirectories) are identical. This allows git to quickly determine the differences between two related tree objects, since it can ignore any entries with @@ -3029,15 +3029,15 @@ currently checked out. Trust ~~~~~ -If you receive the SHA1 name of a blob from one source, and its contents +If you receive the SHA-1 name of a blob from one source, and its contents from another (possibly untrusted) source, you can still trust that those -contents are correct as long as the SHA1 name agrees. This is because -the SHA1 is designed so that it is infeasible to find different contents +contents are correct as long as the SHA-1 name agrees. This is because +the SHA-1 is designed so that it is infeasible to find different contents that produce the same hash. -Similarly, you need only trust the SHA1 name of a top-level tree object +Similarly, you need only trust the SHA-1 name of a top-level tree object to trust the contents of the entire directory that it refers to, and if -you receive the SHA1 name of a commit from a trusted source, then you +you receive the SHA-1 name of a commit from a trusted source, then you can easily verify the entire history of commits reachable through parents of that commit, and all of those contents of the trees referred to by those commits. @@ -3049,7 +3049,7 @@ that you trust that commit, and the immutability of the history of commits tells others that they can trust the whole history. In other words, you can easily validate a whole archive by just -sending out a single email that tells the people the name (SHA1 hash) +sending out a single email that tells the people the name (SHA-1 hash) of the top commit, and digitally sign that email using something like GPG/PGP. @@ -3090,7 +3090,7 @@ How git stores objects efficiently: pack files ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Newly created objects are initially created in a file named after the -object's SHA1 hash (stored in .git/objects). +object's SHA-1 hash (stored in .git/objects). Unfortunately this system becomes inefficient once a project has a lot of objects. Try this on an old project: @@ -3297,7 +3297,7 @@ $ git hash-object -w somedirectory/myfile ------------------------------------------------ which will create and store a blob object with the contents of -somedirectory/myfile, and output the sha1 of that object. if you're +somedirectory/myfile, and output the SHA-1 of that object. if you're extremely lucky it might be 4b9458b3786228369c63936db65827de3cc06200, in which case you've guessed right, and the corruption is fixed! @@ -3359,7 +3359,7 @@ The index ----------- The index is a binary file (generally kept in .git/index) containing a -sorted list of path names, each with permissions and the SHA1 of a blob +sorted list of path names, each with permissions and the SHA-1 of a blob object; linkgit:git-ls-files[1] can show you the contents of the index: ------------------------------------------------- @@ -3754,7 +3754,7 @@ unsaved state that you might want to restore later!) your current index. Normal operation is just ------------------------------------------------- -$ git read-tree <sha1 of tree> +$ git read-tree <SHA-1 of tree> ------------------------------------------------- and your index file will now be equivalent to the tree that you saved @@ -3978,7 +3978,7 @@ $ git ls-files --unmerged ------------------------------------------------ Each line of the `git ls-files --unmerged` output begins with -the blob mode bits, blob SHA1, 'stage number', and the +the blob mode bits, blob SHA-1, 'stage number', and the filename. The 'stage number' is git's way to say which tree it came from: stage 1 corresponds to `$orig` tree, stage 2 `HEAD` tree, and stage3 `$target` tree. @@ -4045,12 +4045,12 @@ objects). There are currently four different object types: "blob", Regardless of object type, all objects share the following characteristics: they are all deflated with zlib, and have a header that not only specifies their type, but also provides size information -about the data in the object. It's worth noting that the SHA1 hash +about the data in the object. It's worth noting that the SHA-1 hash that is used to name the object is the hash of the original data plus this header, so `sha1sum` 'file' does not match the object name for 'file'. (Historical note: in the dawn of the age of git the hash -was the sha1 of the 'compressed' object.) +was the SHA-1 of the 'compressed' object.) As a result, the general consistency of an object can always be tested independently of the contents or the type of the object: all objects can From 1a7b1f6b9c9a129236c66c392877e8697825470f Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Mon, 6 Apr 2009 00:48:49 -0700 Subject: [PATCH 376/654] sha1-lookup: fix up the assertion message Signed-off-by: Junio C Hamano <gitster@pobox.com> --- sha1-lookup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sha1-lookup.c b/sha1-lookup.c index 055dd87dc1..c4dc55d1f5 100644 --- a/sha1-lookup.c +++ b/sha1-lookup.c @@ -81,7 +81,7 @@ int sha1_pos(const unsigned char *sha1, void *table, size_t nr, mi = (nr - 1) * (miv - lov) / (hiv - lov); if (lo <= mi && mi < hi) break; - die("oops"); + die("BUG: assertion failed in binary search"); } } if (18 <= ofs) From bed5d42163ec2e2ddde3b1d78d303a4fb39bc0d0 Mon Sep 17 00:00:00 2001 From: Finn Arne Gangstad <finnag@pvv.org> Date: Mon, 6 Apr 2009 15:41:00 +0200 Subject: [PATCH 377/654] git remote update: Report error for non-existing groups Previosly, git remote update <non-existing-group> would just silently fail and do nothing. Now it will report an error saying that the group does not exist. Signed-off-by: Finn Arne Gangstad <finnag@pvv.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-remote.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/builtin-remote.c b/builtin-remote.c index 3146eb467d..51df99ba93 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -1188,16 +1188,18 @@ struct remote_group { struct string_list *list; } remote_group; -static int get_remote_group(const char *key, const char *value, void *cb) +static int get_remote_group(const char *key, const char *value, void *num_hits) { if (!prefixcmp(key, "remotes.") && !strcmp(key + 8, remote_group.name)) { /* split list by white space */ int space = strcspn(value, " \t\n"); while (*value) { - if (space > 1) + if (space > 1) { string_list_append(xstrndup(value, space), remote_group.list); + ++*((int *)num_hits); + } value += space + (value[space] != '\0'); space = strcspn(value, " \t\n"); } @@ -1227,8 +1229,11 @@ static int update(int argc, const char **argv) remote_group.list = &list; for (i = 1; i < argc; i++) { + int groups_found = 0; remote_group.name = argv[i]; - result = git_config(get_remote_group, NULL); + result = git_config(get_remote_group, &groups_found); + if (!groups_found && (i != 1 || strcmp(argv[1], "default"))) + die("No such remote group: '%s'", argv[i]); } if (!result && !list.nr && argc == 2 && !strcmp(argv[1], "default")) From 9a23ba3375e2afa8045a433a3debce99c373beb2 Mon Sep 17 00:00:00 2001 From: Finn Arne Gangstad <finnag@pvv.org> Date: Mon, 6 Apr 2009 15:41:01 +0200 Subject: [PATCH 378/654] remote: New function remote_is_configured() Previously, there was no easy way to check for the existence of a configured remote. remote_get for example would always create the remote "on demand". This new function returns 1 if the remote is configured, 0 otherwise. Signed-off-by: Finn Arne Gangstad <finnag@pvv.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- remote.c | 11 +++++++++++ remote.h | 1 + 2 files changed, 12 insertions(+) diff --git a/remote.c b/remote.c index 2b037f11b2..b36fd70978 100644 --- a/remote.c +++ b/remote.c @@ -667,6 +667,17 @@ struct remote *remote_get(const char *name) return ret; } +int remote_is_configured(const char *name) +{ + int i; + read_config(); + + for (i = 0; i < remotes_nr; i++) + if (!strcmp(name, remotes[i]->name)) + return 1; + return 0; +} + int for_each_remote(each_remote_fn fn, void *priv) { int i, result = 0; diff --git a/remote.h b/remote.h index de3d21b662..99706a89bc 100644 --- a/remote.h +++ b/remote.h @@ -45,6 +45,7 @@ struct remote { }; struct remote *remote_get(const char *name); +int remote_is_configured(const char *name); typedef int each_remote_fn(struct remote *remote, void *priv); int for_each_remote(each_remote_fn fn, void *priv); From b344e1614b15dfde0ab4dfc175bed1aac39bc264 Mon Sep 17 00:00:00 2001 From: Finn Arne Gangstad <finnag@pvv.org> Date: Mon, 6 Apr 2009 15:41:02 +0200 Subject: [PATCH 379/654] git remote update: Fallback to remote if group does not exist Previously, git remote update <remote> would fail unless there was a remote group configured with the same name as the remote. git remote update will now fall back to using the remote if no matching group can be found. This enables "git remote update -p <remote>..." to fetch and prune one or more remotes, for example. Signed-off-by: Finn Arne Gangstad <finnag@pvv.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-remote.txt | 2 +- builtin-remote.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt index 0b6e67dbca..9e2b4eaa38 100644 --- a/Documentation/git-remote.txt +++ b/Documentation/git-remote.txt @@ -16,7 +16,7 @@ SYNOPSIS 'git remote set-head' <name> [-a | -d | <branch>] 'git remote show' [-n] <name> 'git remote prune' [-n | --dry-run] <name> -'git remote update' [-p | --prune] [group] +'git remote update' [-p | --prune] [group | remote]... DESCRIPTION ----------- diff --git a/builtin-remote.c b/builtin-remote.c index 51df99ba93..ca7c639ad3 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -1232,8 +1232,14 @@ static int update(int argc, const char **argv) int groups_found = 0; remote_group.name = argv[i]; result = git_config(get_remote_group, &groups_found); - if (!groups_found && (i != 1 || strcmp(argv[1], "default"))) - die("No such remote group: '%s'", argv[i]); + if (!groups_found && (i != 1 || strcmp(argv[1], "default"))) { + struct remote *remote; + if (!remote_is_configured(argv[i])) + die("No such remote or remote group: %s", + argv[i]); + remote = remote_get(argv[i]); + string_list_append(remote->name, remote_group.list); + } } if (!result && !list.nr && argc == 2 && !strcmp(argv[1], "default")) From e892dc713e6b0881320d4c65bff7a49d44752bda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santi=20B=C3=A9jar?= <santi@agolina.net> Date: Tue, 7 Apr 2009 01:24:30 +0200 Subject: [PATCH 380/654] Documentation: Introduce "upstream branch" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Santi Béjar <santi@agolina.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 2 +- Documentation/glossary-content.txt | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index ad22cb875e..77d3a8e31c 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1208,7 +1208,7 @@ push.default:: * `matching` push all matching branches. All branches having the same name in both ends are considered to be matching. This is the default. -* `tracking` push the current branch to the branch it is tracking. +* `tracking` push the current branch to its upstream branch. * `current` push the current branch to a branch of the same name. rebase.stat:: diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt index 4fc1cf1184..572374f7a6 100644 --- a/Documentation/glossary-content.txt +++ b/Documentation/glossary-content.txt @@ -449,6 +449,12 @@ This commit is referred to as a "merge commit", or sometimes just a An <<def_object,object>> which is not <<def_reachable,reachable>> from a <<def_branch,branch>>, <<def_tag,tag>>, or any other reference. +[[def_upstream_branch]]upstream branch:: + The default <<def_branch,branch>> that is merged into the branch in + question (or the branch in question is rebased onto). It is configured + via branch.<name>.remote and branch.<name>.merge. If the upstream branch + of 'A' is 'origin/B' sometimes we say "'A' is tracking 'origin/B'". + [[def_working_tree]]working tree:: The tree of actual checked out files. The working tree is normally equal to the <<def_HEAD,HEAD>> plus any local changes From 3d4ecc0e23b2b2f555e7d33b5623fd4e67cc2ac7 Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Tue, 7 Apr 2009 03:05:01 -0400 Subject: [PATCH 381/654] for-each-ref: refactor get_short_ref function This function took a "refinfo" object which is unnecessarily restrictive; it only ever looked at the refname field. This patch refactors it to take just the ref name as a string. While we're touching the relevant lines, let's give it consistent memory semantics. Previously, some code paths would return an allocated string and some would return the original string; now it will always return a malloc'd string. This doesn't actually fix a bug or a leak, because for-each-ref doesn't clean up its memory, but it makes the function a lot less surprising for reuse (which will happen in a later patch). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-for-each-ref.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index 5cbb4b081d..4aaf75c779 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -569,7 +569,7 @@ static void gen_scanf_fmt(char *scanf_fmt, const char *rule) /* * Shorten the refname to an non-ambiguous form */ -static char *get_short_ref(struct refinfo *ref) +static char *get_short_ref(const char *ref) { int i; static char **scanf_fmts; @@ -598,17 +598,17 @@ static char *get_short_ref(struct refinfo *ref) /* bail out if there are no rules */ if (!nr_rules) - return ref->refname; + return xstrdup(ref); - /* buffer for scanf result, at most ref->refname must fit */ - short_name = xstrdup(ref->refname); + /* buffer for scanf result, at most ref must fit */ + short_name = xstrdup(ref); /* skip first rule, it will always match */ for (i = nr_rules - 1; i > 0 ; --i) { int j; int short_name_len; - if (1 != sscanf(ref->refname, scanf_fmts[i], short_name)) + if (1 != sscanf(ref, scanf_fmts[i], short_name)) continue; short_name_len = strlen(short_name); @@ -642,7 +642,7 @@ static char *get_short_ref(struct refinfo *ref) } free(short_name); - return ref->refname; + return xstrdup(ref); } @@ -684,7 +684,7 @@ static void populate_value(struct refinfo *ref) if (formatp) { formatp++; if (!strcmp(formatp, "short")) - refname = get_short_ref(ref); + refname = get_short_ref(ref->refname); else die("unknown refname format %s", formatp); From 4c0fe0af68fdfc2d328992b8cadc953159f0ea30 Mon Sep 17 00:00:00 2001 From: Matthieu Moy <Matthieu.Moy@imag.fr> Date: Tue, 7 Apr 2009 19:24:32 +0200 Subject: [PATCH 382/654] git-send-email.txt: clarify which options take an argument. Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-send-email.txt | 34 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index 10dfd667b2..0b1f183ce8 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -39,13 +39,13 @@ OPTIONS Composing ~~~~~~~~~ ---bcc:: +--bcc=<address>:: Specify a "Bcc:" value for each email. Default is the value of 'sendemail.bcc'. + The --bcc option must be repeated for each user you want on the bcc list. ---cc:: +--cc=<address>:: Specify a starting "Cc:" value for each email. Default is the value of 'sendemail.cc'. + @@ -68,24 +68,24 @@ and In-Reply-To headers will be used unless they are removed. + Missing From or In-Reply-To headers will be prompted for. ---from:: +--from=<address>:: Specify the sender of the emails. This will default to the value GIT_COMMITTER_IDENT, as returned by "git var -l". The user will still be prompted to confirm this entry. ---in-reply-to:: +--in-reply-to=<identifier>:: Specify the contents of the first In-Reply-To header. Subsequent emails will refer to the previous email instead of this if --chain-reply-to is set (the default) Only necessary if --compose is also set. If --compose is not set, this will be prompted for. ---subject:: +--subject=<string>:: Specify the initial subject of the email thread. Only necessary if --compose is also set. If --compose is not set, this will be prompted for. ---to:: +--to=<address>:: Specify the primary recipient of the emails generated. Generally, this will be the upstream maintainer of the project involved. Default is the value of the 'sendemail.to' configuration value; if that is unspecified, @@ -97,7 +97,7 @@ The --to option must be repeated for each user you want on the to list. Sending ~~~~~~~ ---envelope-sender:: +--envelope-sender=<address>:: Specify the envelope sender used to send the emails. This is useful if your default address is not the address that is subscribed to a list. If you use the sendmail binary, you must have @@ -105,12 +105,12 @@ Sending the 'sendemail.envelopesender' configuration variable; if that is unspecified, choosing the envelope sender is left to your MTA. ---smtp-encryption:: +--smtp-encryption=<encryption>:: Specify the encryption to use, either 'ssl' or 'tls'. Any other value reverts to plain SMTP. Default is the value of 'sendemail.smtpencryption'. ---smtp-pass:: +--smtp-pass[=<password>]:: Password for SMTP-AUTH. The argument is optional: If no argument is specified, then the empty string is used as the password. Default is the value of 'sendemail.smtppass', @@ -122,7 +122,7 @@ or on the command line. If a username has been specified (with specified (with '--smtp-pass' or 'sendemail.smtppass'), then the user is prompted for a password while the input is masked for privacy. ---smtp-server:: +--smtp-server=<host>:: If set, specifies the outgoing SMTP server to use (e.g. `smtp.example.com` or a raw IP address). Alternatively it can specify a full pathname of a sendmail-like program instead; @@ -132,7 +132,7 @@ user is prompted for a password while the input is masked for privacy. `/usr/lib/sendmail` if such program is available, or `localhost` otherwise. ---smtp-server-port:: +--smtp-server-port=<port>:: Specifies a port different from the default port (SMTP servers typically listen to smtp port 25 and ssmtp port 465). This can be set with 'sendemail.smtpserverport'. @@ -140,7 +140,7 @@ user is prompted for a password while the input is masked for privacy. --smtp-ssl:: Legacy alias for '--smtp-encryption ssl'. ---smtp-user:: +--smtp-user=<user>:: Username for SMTP-AUTH. Default is the value of 'sendemail.smtpuser'; if a username is not specified (with '--smtp-user' or 'sendemail.smtpuser'), then authentication is not attempted. @@ -149,13 +149,13 @@ user is prompted for a password while the input is masked for privacy. Automating ~~~~~~~~~~ ---cc-cmd:: +--cc-cmd=<command>:: Specify a command to execute once per patch file which should generate patch file specific "Cc:" entries. Output of this command must be single email address per line. Default is the value of 'sendemail.cccmd' configuration value. ---[no-]chain-reply-to:: +--[no-]chain-reply-to=<identifier>:: If this is set, each email will be sent as a reply to the previous email sent. If disabled with "--no-chain-reply-to", all emails after the first will be sent as replies to the first email sent. When using @@ -163,7 +163,7 @@ Automating entire patch series. Default is the value of the 'sendemail.chainreplyto' configuration value; if that is unspecified, default to --chain-reply-to. ---identity:: +--identity=<identity>:: A configuration identity. When given, causes values in the 'sendemail.<identity>' subsection to take precedence over values in the 'sendemail' section. The default identity is @@ -174,7 +174,7 @@ Automating cc list. Default is the value of 'sendemail.signedoffbycc' configuration value; if that is unspecified, default to --signed-off-by-cc. ---suppress-cc:: +--suppress-cc=<category>:: Specify an additional category of recipients to suppress the auto-cc of: + @@ -211,7 +211,7 @@ specified, as well as 'body' if --no-signed-off-cc is specified. Administering ~~~~~~~~~~~~~ ---confirm:: +--confirm=<mode>:: Confirm just before sending: + -- From 982962ce24c7d614d94f40de54cfcfdf71dcb0d2 Mon Sep 17 00:00:00 2001 From: Matthieu Moy <Matthieu.Moy@imag.fr> Date: Tue, 7 Apr 2009 19:24:33 +0200 Subject: [PATCH 383/654] git-rev-list.txt: make ascii markup uniform with other pages. Other pages use --option=<argument>, not --option='argument', do the same here. Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/rev-list-options.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index 7dd237c2f6..11eec941df 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -140,38 +140,38 @@ limiting may be applied. -- -n 'number':: ---max-count='number':: +--max-count=<number>:: Limit the number of commits output. ---skip='number':: +--skip=<number>:: Skip 'number' commits before starting to show the commit output. ---since='date':: ---after='date':: +--since=<date>:: +--after=<date>:: Show commits more recent than a specific date. ---until='date':: ---before='date':: +--until=<date>:: +--before=<date>:: Show commits older than a specific date. ifdef::git-rev-list[] ---max-age='timestamp':: ---min-age='timestamp':: +--max-age=<timestamp>:: +--min-age=<timestamp>:: Limit the commits output to specified time range. endif::git-rev-list[] ---author='pattern':: ---committer='pattern':: +--author=<pattern>:: +--committer=<pattern>:: Limit the commits output to ones with author/committer header lines that match the specified pattern (regular expression). ---grep='pattern':: +--grep=<pattern>:: Limit the commits output to ones with log message that matches the specified pattern (regular expression). From 11c211fa06fc396e8ee8132ef83e2f2763ff6976 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Mon, 6 Apr 2009 21:28:36 +0200 Subject: [PATCH 384/654] list-objects: add "void *data" parameter to show functions The goal of this patch is to get rid of the "static struct rev_info revs" static variable in "builtin-rev-list.c". To do that, we need to pass the revs to the "show_commit" function in "builtin-rev-list.c" and this in turn means that the "traverse_commit_list" function in "list-objects.c" must be passed functions pointers to functions with 2 parameters instead of one. So we have to change all the callers and all the functions passed to "traverse_commit_list". Anyway this makes the code more clean and more generic, so it should be a good thing in the long run. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-pack-objects.c | 6 ++-- builtin-rev-list.c | 68 ++++++++++++++++++++++-------------------- list-objects.c | 9 +++--- list-objects.h | 6 ++-- upload-pack.c | 6 ++-- 5 files changed, 49 insertions(+), 46 deletions(-) diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 9fc3b35547..82536359d6 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -1901,13 +1901,13 @@ static void read_object_list_from_stdin(void) #define OBJECT_ADDED (1u<<20) -static void show_commit(struct commit *commit) +static void show_commit(struct commit *commit, void *data) { add_object_entry(commit->object.sha1, OBJ_COMMIT, NULL, 0); commit->object.flags |= OBJECT_ADDED; } -static void show_object(struct object_array_entry *p) +static void show_object(struct object_array_entry *p, void *data) { add_preferred_base_object(p->name); add_object_entry(p->item->sha1, p->item->type, p->name, 0); @@ -2071,7 +2071,7 @@ static void get_object_list(int ac, const char **av) if (prepare_revision_walk(&revs)) die("revision walk setup failed"); mark_edges_uninteresting(revs.commits, &revs, show_edge); - traverse_commit_list(&revs, show_commit, show_object); + traverse_commit_list(&revs, show_commit, show_object, NULL); if (keep_unreachable) add_objects_in_unpacked_packs(&revs); diff --git a/builtin-rev-list.c b/builtin-rev-list.c index eb341477ca..cd6f6b8fbb 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -42,72 +42,72 @@ static const char rev_list_usage[] = " --bisect-all" ; -static struct rev_info revs; - static int show_timestamp; static int hdr_termination; static const char *header_prefix; -static void finish_commit(struct commit *commit); -static void show_commit(struct commit *commit) +static void finish_commit(struct commit *commit, void *data); +static void show_commit(struct commit *commit, void *data) { - graph_show_commit(revs.graph); + struct rev_info *revs = data; + + graph_show_commit(revs->graph); if (show_timestamp) printf("%lu ", commit->date); if (header_prefix) fputs(header_prefix, stdout); - if (!revs.graph) { + if (!revs->graph) { if (commit->object.flags & BOUNDARY) putchar('-'); else if (commit->object.flags & UNINTERESTING) putchar('^'); - else if (revs.left_right) { + else if (revs->left_right) { if (commit->object.flags & SYMMETRIC_LEFT) putchar('<'); else putchar('>'); } } - if (revs.abbrev_commit && revs.abbrev) - fputs(find_unique_abbrev(commit->object.sha1, revs.abbrev), + if (revs->abbrev_commit && revs->abbrev) + fputs(find_unique_abbrev(commit->object.sha1, revs->abbrev), stdout); else fputs(sha1_to_hex(commit->object.sha1), stdout); - if (revs.print_parents) { + if (revs->print_parents) { struct commit_list *parents = commit->parents; while (parents) { printf(" %s", sha1_to_hex(parents->item->object.sha1)); parents = parents->next; } } - if (revs.children.name) { + if (revs->children.name) { struct commit_list *children; - children = lookup_decoration(&revs.children, &commit->object); + children = lookup_decoration(&revs->children, &commit->object); while (children) { printf(" %s", sha1_to_hex(children->item->object.sha1)); children = children->next; } } - show_decorations(&revs, commit); - if (revs.commit_format == CMIT_FMT_ONELINE) + show_decorations(revs, commit); + if (revs->commit_format == CMIT_FMT_ONELINE) putchar(' '); else putchar('\n'); - if (revs.verbose_header && commit->buffer) { + if (revs->verbose_header && commit->buffer) { struct strbuf buf = STRBUF_INIT; - pretty_print_commit(revs.commit_format, commit, - &buf, revs.abbrev, NULL, NULL, - revs.date_mode, 0); - if (revs.graph) { + pretty_print_commit(revs->commit_format, commit, + &buf, revs->abbrev, NULL, NULL, + revs->date_mode, 0); + if (revs->graph) { if (buf.len) { - if (revs.commit_format != CMIT_FMT_ONELINE) - graph_show_oneline(revs.graph); + if (revs->commit_format != CMIT_FMT_ONELINE) + graph_show_oneline(revs->graph); - graph_show_commit_msg(revs.graph, &buf); + graph_show_commit_msg(revs->graph, &buf); /* * Add a newline after the commit message. @@ -125,7 +125,7 @@ static void show_commit(struct commit *commit) * format doesn't explicitly end in a newline.) */ if (buf.len && buf.buf[buf.len - 1] == '\n') - graph_show_padding(revs.graph); + graph_show_padding(revs->graph); putchar('\n'); } else { /* @@ -133,7 +133,7 @@ static void show_commit(struct commit *commit) * the rest of the graph output for this * commit. */ - if (graph_show_remainder(revs.graph)) + if (graph_show_remainder(revs->graph)) putchar('\n'); } } else { @@ -142,14 +142,14 @@ static void show_commit(struct commit *commit) } strbuf_release(&buf); } else { - if (graph_show_remainder(revs.graph)) + if (graph_show_remainder(revs->graph)) putchar('\n'); } maybe_flush_or_die(stdout, "stdout"); - finish_commit(commit); + finish_commit(commit, data); } -static void finish_commit(struct commit *commit) +static void finish_commit(struct commit *commit, void *data) { if (commit->parents) { free_commit_list(commit->parents); @@ -159,20 +159,20 @@ static void finish_commit(struct commit *commit) commit->buffer = NULL; } -static void finish_object(struct object_array_entry *p) +static void finish_object(struct object_array_entry *p, void *data) { if (p->item->type == OBJ_BLOB && !has_sha1_file(p->item->sha1)) die("missing blob object '%s'", sha1_to_hex(p->item->sha1)); } -static void show_object(struct object_array_entry *p) +static void show_object(struct object_array_entry *p, void *data) { /* An object with name "foo\n0000000..." can be used to * confuse downstream "git pack-objects" very badly. */ const char *ep = strchr(p->name, '\n'); - finish_object(p); + finish_object(p, data); if (ep) { printf("%s %.*s\n", sha1_to_hex(p->item->sha1), (int) (ep - p->name), @@ -264,7 +264,7 @@ int show_bisect_vars(struct rev_info *revs, int reaches, int all, int flags) strcpy(hex, sha1_to_hex(revs->commits->item->object.sha1)); if (flags & BISECT_SHOW_ALL) { - traverse_commit_list(revs, show_commit, show_object); + traverse_commit_list(revs, show_commit, show_object, revs); printf("------\n"); } @@ -297,6 +297,7 @@ int show_bisect_vars(struct rev_info *revs, int reaches, int all, int flags) int cmd_rev_list(int argc, const char **argv, const char *prefix) { + struct rev_info revs; struct commit_list *list; int i; int read_from_stdin = 0; @@ -391,8 +392,9 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) } traverse_commit_list(&revs, - quiet ? finish_commit : show_commit, - quiet ? finish_object : show_object); + quiet ? finish_commit : show_commit, + quiet ? finish_object : show_object, + &revs); return 0; } diff --git a/list-objects.c b/list-objects.c index c8b8375e49..208a4cb002 100644 --- a/list-objects.c +++ b/list-objects.c @@ -137,8 +137,9 @@ void mark_edges_uninteresting(struct commit_list *list, } void traverse_commit_list(struct rev_info *revs, - void (*show_commit)(struct commit *), - void (*show_object)(struct object_array_entry *)) + show_commit_fn show_commit, + show_object_fn show_object, + void *data) { int i; struct commit *commit; @@ -146,7 +147,7 @@ void traverse_commit_list(struct rev_info *revs, while ((commit = get_revision(revs)) != NULL) { process_tree(revs, commit->tree, &objects, NULL, ""); - show_commit(commit); + show_commit(commit, data); } for (i = 0; i < revs->pending.nr; i++) { struct object_array_entry *pending = revs->pending.objects + i; @@ -173,7 +174,7 @@ void traverse_commit_list(struct rev_info *revs, sha1_to_hex(obj->sha1), name); } for (i = 0; i < objects.nr; i++) - show_object(&objects.objects[i]); + show_object(&objects.objects[i], data); free(objects.objects); if (revs->pending.nr) { free(revs->pending.objects); diff --git a/list-objects.h b/list-objects.h index 0f41391ecc..47fae2e468 100644 --- a/list-objects.h +++ b/list-objects.h @@ -1,11 +1,11 @@ #ifndef LIST_OBJECTS_H #define LIST_OBJECTS_H -typedef void (*show_commit_fn)(struct commit *); -typedef void (*show_object_fn)(struct object_array_entry *); +typedef void (*show_commit_fn)(struct commit *, void *); +typedef void (*show_object_fn)(struct object_array_entry *, void *); typedef void (*show_edge_fn)(struct commit *); -void traverse_commit_list(struct rev_info *revs, show_commit_fn, show_object_fn); +void traverse_commit_list(struct rev_info *, show_commit_fn, show_object_fn, void *); void mark_edges_uninteresting(struct commit_list *, struct rev_info *, show_edge_fn); diff --git a/upload-pack.c b/upload-pack.c index a49d872447..495c99f80a 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -66,7 +66,7 @@ static ssize_t send_client_data(int fd, const char *data, ssize_t sz) } static FILE *pack_pipe = NULL; -static void show_commit(struct commit *commit) +static void show_commit(struct commit *commit, void *data) { if (commit->object.flags & BOUNDARY) fputc('-', pack_pipe); @@ -78,7 +78,7 @@ static void show_commit(struct commit *commit) commit->buffer = NULL; } -static void show_object(struct object_array_entry *p) +static void show_object(struct object_array_entry *p, void *data) { /* An object with name "foo\n0000000..." can be used to * confuse downstream git-pack-objects very badly. @@ -134,7 +134,7 @@ static int do_rev_list(int fd, void *create_full_pack) if (prepare_revision_walk(&revs)) die("revision walk setup failed"); mark_edges_uninteresting(revs.commits, &revs, show_edge); - traverse_commit_list(&revs, show_commit, show_object); + traverse_commit_list(&revs, show_commit, show_object, NULL); fflush(pack_pipe); fclose(pack_pipe); return 0; From d797257eb280b67dd1f7153a66b03453c0fb927a Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Mon, 6 Apr 2009 22:28:00 +0200 Subject: [PATCH 385/654] rev-list: remove last static vars used in "show_commit" This patch removes the last static variables that were used in the "show_commit" function. To do that, we create a new "rev_list_info" struct that we will pass in the "void *data" argument to "show_commit". This means that we have to change the first argument to "show_bisect_vars" too. While at it, we also remove a "struct commit_list *list" variable in "cmd_rev_list" that is not really needed. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 6 +++++- bisect.h | 14 ++++++++------ builtin-rev-list.c | 42 +++++++++++++++++++++--------------------- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/bisect.c b/bisect.c index 69f8860ca1..4d2a150df2 100644 --- a/bisect.c +++ b/bisect.c @@ -535,8 +535,12 @@ static void bisect_rev_setup(struct rev_info *revs, const char *prefix) int bisect_next_vars(const char *prefix) { struct rev_info revs; + struct rev_list_info info; int reaches = 0, all = 0; + memset(&info, 0, sizeof(info)); + info.revs = &revs; + bisect_rev_setup(&revs, prefix); if (prepare_revision_walk(&revs)) @@ -547,6 +551,6 @@ int bisect_next_vars(const char *prefix) revs.commits = find_bisection(revs.commits, &reaches, &all, !!skipped_sha1_nr); - return show_bisect_vars(&revs, reaches, all, + return show_bisect_vars(&info, reaches, all, BISECT_SHOW_TRIED | BISECT_SHOW_STRINGED); } diff --git a/bisect.h b/bisect.h index f5d106735c..b1c334d349 100644 --- a/bisect.h +++ b/bisect.h @@ -14,12 +14,14 @@ extern struct commit_list *filter_skipped(struct commit_list *list, #define BISECT_SHOW_TRIED (1<<1) #define BISECT_SHOW_STRINGED (1<<2) -/* - * The flag BISECT_SHOW_ALL should not be set if this function is called - * from outside "builtin-rev-list.c" as otherwise it would use - * static "revs" from this file. - */ -extern int show_bisect_vars(struct rev_info *revs, int reaches, int all, +struct rev_list_info { + struct rev_info *revs; + int show_timestamp; + int hdr_termination; + const char *header_prefix; +}; + +extern int show_bisect_vars(struct rev_list_info *info, int reaches, int all, int flags); extern int bisect_next_vars(const char *prefix); diff --git a/builtin-rev-list.c b/builtin-rev-list.c index cd6f6b8fbb..244b73eaeb 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -42,21 +42,18 @@ static const char rev_list_usage[] = " --bisect-all" ; -static int show_timestamp; -static int hdr_termination; -static const char *header_prefix; - static void finish_commit(struct commit *commit, void *data); static void show_commit(struct commit *commit, void *data) { - struct rev_info *revs = data; + struct rev_list_info *info = data; + struct rev_info *revs = info->revs; graph_show_commit(revs->graph); - if (show_timestamp) + if (info->show_timestamp) printf("%lu ", commit->date); - if (header_prefix) - fputs(header_prefix, stdout); + if (info->header_prefix) + fputs(info->header_prefix, stdout); if (!revs->graph) { if (commit->object.flags & BOUNDARY) @@ -138,7 +135,7 @@ static void show_commit(struct commit *commit, void *data) } } else { if (buf.len) - printf("%s%c", buf.buf, hdr_termination); + printf("%s%c", buf.buf, info->hdr_termination); } strbuf_release(&buf); } else { @@ -236,11 +233,13 @@ static void show_tried_revs(struct commit_list *tried, int stringed) printf(stringed ? "' &&\n" : "'\n"); } -int show_bisect_vars(struct rev_info *revs, int reaches, int all, int flags) +int show_bisect_vars(struct rev_list_info *info, int reaches, int all, + int flags) { int cnt; char hex[41] = "", *format; struct commit_list *tried; + struct rev_info *revs = info->revs; if (!revs->commits && !(flags & BISECT_SHOW_TRIED)) return 1; @@ -264,7 +263,7 @@ int show_bisect_vars(struct rev_info *revs, int reaches, int all, int flags) strcpy(hex, sha1_to_hex(revs->commits->item->object.sha1)); if (flags & BISECT_SHOW_ALL) { - traverse_commit_list(revs, show_commit, show_object, revs); + traverse_commit_list(revs, show_commit, show_object, info); printf("------\n"); } @@ -298,7 +297,7 @@ int show_bisect_vars(struct rev_info *revs, int reaches, int all, int flags) int cmd_rev_list(int argc, const char **argv, const char *prefix) { struct rev_info revs; - struct commit_list *list; + struct rev_list_info info; int i; int read_from_stdin = 0; int bisect_list = 0; @@ -313,6 +312,9 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) revs.commit_format = CMIT_FMT_UNSPECIFIED; argc = setup_revisions(argc, argv, &revs, NULL); + memset(&info, 0, sizeof(info)); + info.revs = &revs; + quiet = DIFF_OPT_TST(&revs.diffopt, QUIET); for (i = 1 ; i < argc; i++) { const char *arg = argv[i]; @@ -322,7 +324,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) continue; } if (!strcmp(arg, "--timestamp")) { - show_timestamp = 1; + info.show_timestamp = 1; continue; } if (!strcmp(arg, "--bisect")) { @@ -352,19 +354,17 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) } if (revs.commit_format != CMIT_FMT_UNSPECIFIED) { /* The command line has a --pretty */ - hdr_termination = '\n'; + info.hdr_termination = '\n'; if (revs.commit_format == CMIT_FMT_ONELINE) - header_prefix = ""; + info.header_prefix = ""; else - header_prefix = "commit "; + info.header_prefix = "commit "; } else if (revs.verbose_header) /* Only --header was specified */ revs.commit_format = CMIT_FMT_RAW; - list = revs.commits; - - if ((!list && + if ((!revs.commits && (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) && !revs.pending.nr)) || revs.diff) @@ -387,14 +387,14 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) bisect_find_all); if (bisect_show_vars) - return show_bisect_vars(&revs, reaches, all, + return show_bisect_vars(&info, reaches, all, bisect_show_all ? BISECT_SHOW_ALL : 0); } traverse_commit_list(&revs, quiet ? finish_commit : show_commit, quiet ? finish_object : show_object, - &revs); + &info); return 0; } From 13858e5770dd218e5318819d3273c916b46cf8e5 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Tue, 7 Apr 2009 05:08:42 +0200 Subject: [PATCH 386/654] rev-list: add "int bisect_show_flags" in "struct rev_list_info" This is a cleanup patch to make it easier to use the "show_bisect_vars" function and take advantage of the rev_list_info struct. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 4 ++-- bisect.h | 6 +++--- builtin-rev-list.c | 11 ++++------- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/bisect.c b/bisect.c index 4d2a150df2..58f7e6f773 100644 --- a/bisect.c +++ b/bisect.c @@ -540,6 +540,7 @@ int bisect_next_vars(const char *prefix) memset(&info, 0, sizeof(info)); info.revs = &revs; + info.bisect_show_flags = BISECT_SHOW_TRIED | BISECT_SHOW_STRINGED; bisect_rev_setup(&revs, prefix); @@ -551,6 +552,5 @@ int bisect_next_vars(const char *prefix) revs.commits = find_bisection(revs.commits, &reaches, &all, !!skipped_sha1_nr); - return show_bisect_vars(&info, reaches, all, - BISECT_SHOW_TRIED | BISECT_SHOW_STRINGED); + return show_bisect_vars(&info, reaches, all); } diff --git a/bisect.h b/bisect.h index b1c334d349..fdba913877 100644 --- a/bisect.h +++ b/bisect.h @@ -9,20 +9,20 @@ extern struct commit_list *filter_skipped(struct commit_list *list, struct commit_list **tried, int show_all); -/* show_bisect_vars flags */ +/* bisect_show_flags flags in struct rev_list_info */ #define BISECT_SHOW_ALL (1<<0) #define BISECT_SHOW_TRIED (1<<1) #define BISECT_SHOW_STRINGED (1<<2) struct rev_list_info { struct rev_info *revs; + int bisect_show_flags; int show_timestamp; int hdr_termination; const char *header_prefix; }; -extern int show_bisect_vars(struct rev_list_info *info, int reaches, int all, - int flags); +extern int show_bisect_vars(struct rev_list_info *info, int reaches, int all); extern int bisect_next_vars(const char *prefix); diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 244b73eaeb..193993cf44 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -233,10 +233,9 @@ static void show_tried_revs(struct commit_list *tried, int stringed) printf(stringed ? "' &&\n" : "'\n"); } -int show_bisect_vars(struct rev_list_info *info, int reaches, int all, - int flags) +int show_bisect_vars(struct rev_list_info *info, int reaches, int all) { - int cnt; + int cnt, flags = info->bisect_show_flags; char hex[41] = "", *format; struct commit_list *tried; struct rev_info *revs = info->revs; @@ -303,7 +302,6 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) int bisect_list = 0; int bisect_show_vars = 0; int bisect_find_all = 0; - int bisect_show_all = 0; int quiet = 0; git_config(git_default_config, NULL); @@ -334,7 +332,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) if (!strcmp(arg, "--bisect-all")) { bisect_list = 1; bisect_find_all = 1; - bisect_show_all = 1; + info.bisect_show_flags = BISECT_SHOW_ALL; revs.show_decorations = 1; continue; } @@ -387,8 +385,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) bisect_find_all); if (bisect_show_vars) - return show_bisect_vars(&info, reaches, all, - bisect_show_all ? BISECT_SHOW_ALL : 0); + return show_bisect_vars(&info, reaches, all); } traverse_commit_list(&revs, From da81688cc5639c9c482a89a4b732737f7aa0d61d Mon Sep 17 00:00:00 2001 From: Markus Heidelberg <markus.heidelberg@web.de> Date: Mon, 6 Apr 2009 01:31:16 -0700 Subject: [PATCH 387/654] doc/merge-config: list ecmerge as a built-in merge tool Signed-off-by: Markus Heidelberg <markus.heidelberg@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/merge-config.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 1ff08ff2cc..9c44af8e4a 100644 --- a/Documentation/merge-config.txt +++ b/Documentation/merge-config.txt @@ -22,7 +22,8 @@ merge.stat:: merge.tool:: Controls which merge resolution program is used by linkgit:git-mergetool[1]. Valid built-in values are: "kdiff3", - "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and + "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", + "ecmerge" and "opendiff". Any other value is treated is custom merge tool and there must be a corresponding mergetool.<tool>.cmd option. From bad42732008cb0c1e77046d716e4446b1545d4d0 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg <markus.heidelberg@web.de> Date: Mon, 6 Apr 2009 01:31:17 -0700 Subject: [PATCH 388/654] git-mergetool/difftool: make (g)vimdiff workable under Windows Under Windows vimdiff and gvimdiff are not available as symbolic links, but as batch files vimdiff.bat and gvimdiff.bat. These files weren't found by 'type vimdiff' which led to the following error: The merge tool vimdiff is not available as 'vimdiff' Even if they were found, it wouldn't work to invoke these batch files from git-mergetool. To solve this, use vim and gvim (vim.exe and gvim.exe) and pass the -d command line switch over to them. Signed-off-by: Markus Heidelberg <markus.heidelberg@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/difftool/git-difftool-helper | 10 ++++++++-- git-mergetool.sh | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/contrib/difftool/git-difftool-helper b/contrib/difftool/git-difftool-helper index 9c0a13452a..e481913c91 100755 --- a/contrib/difftool/git-difftool-helper +++ b/contrib/difftool/git-difftool-helper @@ -86,11 +86,11 @@ launch_merge_tool () { ;; vimdiff) - "$merge_tool_path" -c "wincmd l" "$LOCAL" "$REMOTE" + "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$REMOTE" ;; gvimdiff) - "$merge_tool_path" -c "wincmd l" -f "$LOCAL" "$REMOTE" + "$merge_tool_path" -d -c "wincmd l" -f "$LOCAL" "$REMOTE" ;; xxdiff) @@ -160,6 +160,12 @@ init_merge_tool_path() { merge_tool_path=$(git config mergetool."$1".path) if test -z "$merge_tool_path"; then case "$1" in + vimdiff) + merge_tool_path=vim + ;; + gvimdiff) + merge_tool_path=gvim + ;; emerge) merge_tool_path=emacs ;; diff --git a/git-mergetool.sh b/git-mergetool.sh index 87fa88af55..6e611e94a4 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -214,12 +214,12 @@ merge_file () { ;; vimdiff) touch "$BACKUP" - "$merge_tool_path" -c "wincmd l" "$LOCAL" "$MERGED" "$REMOTE" + "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$MERGED" "$REMOTE" check_unchanged ;; gvimdiff) touch "$BACKUP" - "$merge_tool_path" -c "wincmd l" -f "$LOCAL" "$MERGED" "$REMOTE" + "$merge_tool_path" -d -c "wincmd l" -f "$LOCAL" "$MERGED" "$REMOTE" check_unchanged ;; xxdiff) @@ -359,6 +359,12 @@ init_merge_tool_path() { merge_tool_path=`git config mergetool.$1.path` if test -z "$merge_tool_path" ; then case "$1" in + vimdiff) + merge_tool_path=vim + ;; + gvimdiff) + merge_tool_path=gvim + ;; emerge) merge_tool_path=emacs ;; From b98c212a9fd97300a8cf39015b8d693f319fd71c Mon Sep 17 00:00:00 2001 From: Markus Heidelberg <markus.heidelberg@web.de> Date: Mon, 6 Apr 2009 01:31:18 -0700 Subject: [PATCH 389/654] git-mergetool: add new merge tool TortoiseMerge TortoiseMerge comes with TortoiseSVN or TortoiseGit for Windows. It can only be used as a merge tool with an existing base file. It cannot be used without a base nor as a diff tool. The documentation only mentions the slash '/' as command line option prefix, which refused to work, but the parser also accepts the dash '-' See http://code.google.com/p/msysgit/issues/detail?id=226 Signed-off-by: Markus Heidelberg <markus.heidelberg@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-mergetool.txt | 3 ++- Documentation/merge-config.txt | 2 +- git-mergetool.sh | 16 +++++++++++++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt index 5d3c632872..5edac4d267 100644 --- a/Documentation/git-mergetool.txt +++ b/Documentation/git-mergetool.txt @@ -26,7 +26,8 @@ OPTIONS --tool=<tool>:: Use the merge resolution program specified by <tool>. Valid merge tools are: - kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, and opendiff + kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, + tortoisemerge and opendiff + If a merge resolution program is not specified, 'git-mergetool' will use the configuration variable `merge.tool`. If the diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 9c44af8e4a..8c10f66702 100644 --- a/Documentation/merge-config.txt +++ b/Documentation/merge-config.txt @@ -23,7 +23,7 @@ merge.tool:: Controls which merge resolution program is used by linkgit:git-mergetool[1]. Valid built-in values are: "kdiff3", "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", - "ecmerge" and + "ecmerge", tortoisemerge and "opendiff". Any other value is treated is custom merge tool and there must be a corresponding mergetool.<tool>.cmd option. diff --git a/git-mergetool.sh b/git-mergetool.sh index 6e611e94a4..be9717a2f1 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -265,6 +265,16 @@ merge_file () { fi status=$? ;; + tortoisemerge) + if base_present ; then + touch "$BACKUP" + "$merge_tool_path" -base:"$BASE" -mine:"$LOCAL" -theirs:"$REMOTE" -merged:"$MERGED" + check_unchanged + else + echo "TortoiseMerge cannot be used without a base" 1>&2 + status=1 + fi + ;; *) if test -n "$merge_tool_cmd"; then if test "$merge_tool_trust_exit_code" = "false"; then @@ -345,7 +355,7 @@ valid_custom_tool() valid_tool() { case "$1" in - kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge) + kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge | tortoisemerge) ;; # happy *) if ! valid_custom_tool "$1"; then @@ -404,9 +414,9 @@ fi if test -z "$merge_tool" ; then if test -n "$DISPLAY"; then if test -n "$GNOME_DESKTOP_SESSION_ID" ; then - merge_tool_candidates="meld kdiff3 tkdiff xxdiff gvimdiff" + merge_tool_candidates="meld kdiff3 tkdiff xxdiff tortoisemerge gvimdiff" else - merge_tool_candidates="kdiff3 tkdiff xxdiff meld gvimdiff" + merge_tool_candidates="kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff" fi fi if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then From 76ca653842057766773776bffc6a415b39d5a147 Mon Sep 17 00:00:00 2001 From: David Aguilar <davvid@gmail.com> Date: Mon, 6 Apr 2009 01:31:19 -0700 Subject: [PATCH 390/654] difftool: remove merge options for opendiff, tkdiff, kdiff3 and xxdiff We shouldn't try to merge files when using difftool, so remove any merge-specific options. Signed-off-by: David Aguilar <davvid@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/difftool/git-difftool-helper | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/contrib/difftool/git-difftool-helper b/contrib/difftool/git-difftool-helper index e481913c91..ef684b6f68 100755 --- a/contrib/difftool/git-difftool-helper +++ b/contrib/difftool/git-difftool-helper @@ -69,7 +69,7 @@ launch_merge_tool () { "$merge_tool_path" --auto \ --L1 "$basename (A)" \ --L2 "$basename (B)" \ - -o "$MERGED" "$LOCAL" "$REMOTE" \ + "$LOCAL" "$REMOTE" \ > /dev/null 2>&1 ;; @@ -78,7 +78,7 @@ launch_merge_tool () { ;; tkdiff) - "$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE" + "$merge_tool_path" "$LOCAL" "$REMOTE" ;; meld) @@ -95,17 +95,13 @@ launch_merge_tool () { xxdiff) "$merge_tool_path" \ - -X \ - -R 'Accel.SaveAsMerged: "Ctrl-S"' \ -R 'Accel.Search: "Ctrl+F"' \ -R 'Accel.SearchForward: "Ctrl-G"' \ - --merged-file "$MERGED" \ "$LOCAL" "$REMOTE" ;; opendiff) - "$merge_tool_path" "$LOCAL" "$REMOTE" \ - -merge "$MERGED" | cat + "$merge_tool_path" "$LOCAL" "$REMOTE" | cat ;; ecmerge) From 2e8af7e42b15d4f2d573329ea2593a19f45f18d3 Mon Sep 17 00:00:00 2001 From: David Aguilar <davvid@gmail.com> Date: Mon, 6 Apr 2009 01:31:20 -0700 Subject: [PATCH 391/654] difftool: remove the backup file feature Most users find the backup file feature annoying and there's no need for it since diff is supposed to be a read-only operation. Signed-off-by: David Aguilar <davvid@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/difftool/git-difftool-helper | 34 +--------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/contrib/difftool/git-difftool-helper b/contrib/difftool/git-difftool-helper index ef684b6f68..e74a2747b6 100755 --- a/contrib/difftool/git-difftool-helper +++ b/contrib/difftool/git-difftool-helper @@ -9,31 +9,7 @@ # Set GIT_DIFFTOOL_NO_PROMPT to bypass the per-file prompt. should_prompt () { - ! test -n "$GIT_DIFFTOOL_NO_PROMPT" -} - -# Should we keep the backup .orig file? -keep_backup_mode="$(git config --bool merge.keepBackup || echo true)" -keep_backup () { - test "$keep_backup_mode" = "true" -} - -# This function manages the backup .orig file. -# A backup $MERGED.orig file is created if changes are detected. -cleanup_temp_files () { - if test -n "$MERGED"; then - if keep_backup && test "$MERGED" -nt "$BACKUP"; then - test -f "$BACKUP" && mv -- "$BACKUP" "$MERGED.orig" - else - rm -f -- "$BACKUP" - fi - fi -} - -# This is called when users Ctrl-C out of git-difftool-helper -sigint_handler () { - cleanup_temp_files - exit 1 + test -z "$GIT_DIFFTOOL_NO_PROMPT" } # This function prepares temporary files and launches the appropriate @@ -47,12 +23,6 @@ launch_merge_tool () { LOCAL="$2" REMOTE="$3" BASE="$1" - ext="$$$(expr "$MERGED" : '.*\(\.[^/]*\)$')" - BACKUP="$MERGED.BACKUP.$ext" - - # Create and ensure that we clean up $BACKUP - test -f "$MERGED" && cp -- "$MERGED" "$BACKUP" - trap sigint_handler INT # $LOCAL and $REMOTE are temporary files so prompt # the user with the real $MERGED name before launching $merge_tool. @@ -120,8 +90,6 @@ launch_merge_tool () { fi ;; esac - - cleanup_temp_files } # Verifies that (difftool|mergetool).<tool>.cmd exists From 46ae156d6c8c48d521e4d858ed84d93259cfc61f Mon Sep 17 00:00:00 2001 From: David Aguilar <davvid@gmail.com> Date: Mon, 6 Apr 2009 01:31:21 -0700 Subject: [PATCH 392/654] difftool: use perl built-ins when testing for msys I don't even know what $COMSPEC means so let's be safe and use the same perly $^O test add--interactive uses. While we're at it, make git-difftool match the prevalent git-perl style. Signed-off-by: David Aguilar <davvid@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/difftool/git-difftool | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/contrib/difftool/git-difftool b/contrib/difftool/git-difftool index 0deda3a0e4..207dd50f2c 100755 --- a/contrib/difftool/git-difftool +++ b/contrib/difftool/git-difftool @@ -33,7 +33,10 @@ sub setup_environment sub exe { my $exe = shift; - return defined $ENV{COMSPEC} ? "$exe.exe" : $exe; + if ($^O eq 'MSWin32' || $^O eq 'msys') { + return "$exe.exe"; + } + return $exe; } sub generate_command @@ -47,7 +50,7 @@ sub generate_command $skip_next = 0; next; } - if ($arg eq '-t' or $arg eq '--tool') { + if ($arg eq '-t' || $arg eq '--tool') { usage() if $#ARGV <= $idx; $ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1]; $skip_next = 1; From 8b7332221db8522fe23bf8cf25d058acea6b9142 Mon Sep 17 00:00:00 2001 From: David Aguilar <davvid@gmail.com> Date: Tue, 7 Apr 2009 01:21:19 -0700 Subject: [PATCH 393/654] difftool: add a -y shortcut for --no-prompt This is another consistency cleanup to make git-difftool's options match git-mergetool. Signed-off-by: David Aguilar <davvid@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/difftool/git-difftool | 6 +++--- contrib/difftool/git-difftool.txt | 36 ++++++++++++------------------- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/contrib/difftool/git-difftool b/contrib/difftool/git-difftool index 207dd50f2c..8c160e5bb4 100755 --- a/contrib/difftool/git-difftool +++ b/contrib/difftool/git-difftool @@ -18,7 +18,7 @@ my $DIR = abs_path(dirname($0)); sub usage { print << 'USAGE'; -usage: git difftool [--tool=<tool>] [--no-prompt] ["git diff" options] +usage: git difftool [--tool=<tool>] [-y|--no-prompt] ["git diff" options] USAGE exit 1; } @@ -60,11 +60,11 @@ sub generate_command $ENV{GIT_DIFF_TOOL} = substr($arg, 7); next; } - if ($arg eq '--no-prompt') { + if ($arg eq '-y' || $arg eq '--no-prompt') { $ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true'; next; } - if ($arg eq '-h' or $arg eq '--help') { + if ($arg eq '-h' || $arg eq '--help') { usage(); } push @command, $arg; diff --git a/contrib/difftool/git-difftool.txt b/contrib/difftool/git-difftool.txt index 2b7bc03ec3..a00e9431c5 100644 --- a/contrib/difftool/git-difftool.txt +++ b/contrib/difftool/git-difftool.txt @@ -3,35 +3,32 @@ git-difftool(1) NAME ---- -git-difftool - compare changes using common merge tools +git-difftool - Show changes using common diff tools SYNOPSIS -------- -'git difftool' [--tool=<tool>] [--no-prompt] ['git diff' options] +'git difftool' [--tool=<tool>] [-y|--no-prompt] [<'git diff' options>] DESCRIPTION ----------- 'git-difftool' is a git command that allows you to compare and edit files -between revisions using common merge tools. At its most basic level, -'git-difftool' does what 'git-mergetool' does but its use is for non-merge -situations such as when preparing commits or comparing changes against -the index. - -'git difftool' is a frontend to 'git diff' and accepts the same -arguments and options. - -See linkgit:git-diff[1] for the full list of supported options. +between revisions using common diff tools. 'git difftool' is a frontend +to 'git-diff' and accepts the same options and arguments. OPTIONS ------- +-y:: +--no-prompt:: + Do not prompt before launching a diff tool. + -t <tool>:: --tool=<tool>:: - Use the merge resolution program specified by <tool>. + Use the diff tool specified by <tool>. Valid merge tools are: kdiff3, kompare, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, and opendiff + -If a merge resolution program is not specified, 'git-difftool' +If a diff tool is not specified, 'git-difftool' will use the configuration variable `diff.tool`. If the configuration variable `diff.tool` is not set, 'git-difftool' will pick a suitable default. @@ -42,7 +39,7 @@ can configure the absolute path to kdiff3 by setting `difftool.kdiff3.path`. Otherwise, 'git-difftool' assumes the tool is available in PATH. + -Instead of running one of the known merge tool programs, +Instead of running one of the known diff tools, 'git-difftool' can be customized to run an alternative program by specifying the command line to invoke in a configuration variable `difftool.<tool>.cmd`. @@ -56,8 +53,7 @@ is set to the name of the temporary file containing the contents of the diff post-image. `$BASE` is provided for compatibility with custom merge tool commands and has the same value as `$LOCAL`. ---no-prompt:: - Do not prompt before launching a diff tool. +See linkgit:git-diff[1] for the full list of supported options. CONFIG VARIABLES ---------------- @@ -65,21 +61,17 @@ CONFIG VARIABLES difftool equivalents have not been defined. diff.tool:: - The default merge tool to use. + The default diff tool to use. difftool.<tool>.path:: Override the path for the given tool. This is useful in case your tool is not in the PATH. difftool.<tool>.cmd:: - Specify the command to invoke the specified merge tool. + Specify the command to invoke the specified diff tool. + See the `--tool=<tool>` option above for more details. -merge.keepBackup:: - The original, unedited file content can be saved to a file with - a `.orig` extension. Defaults to `true` (i.e. keep the backup files). - SEE ALSO -------- linkgit:git-diff[1]:: From 1c0f3d224eff2ff8ca8442811edb5a6830adba1a Mon Sep 17 00:00:00 2001 From: Sebastian Pipping <sebastian@pipping.org> Date: Mon, 6 Apr 2009 01:31:23 -0700 Subject: [PATCH 394/654] difftool/mergetool: add diffuse as merge and diff tool This adds diffuse as a built-in merge tool. Signed-off-by: Sebastian Pipping <sebastian@pipping.org> Signed-off-by: David Aguilar <davvid@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-mergetool.txt | 2 +- Documentation/merge-config.txt | 2 +- contrib/completion/git-completion.bash | 3 ++- contrib/difftool/git-difftool-helper | 10 ++++++---- contrib/difftool/git-difftool.txt | 4 ++-- git-mergetool.sh | 4 ++-- 6 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt index 5edac4d267..ff9700d17a 100644 --- a/Documentation/git-mergetool.txt +++ b/Documentation/git-mergetool.txt @@ -27,7 +27,7 @@ OPTIONS Use the merge resolution program specified by <tool>. Valid merge tools are: kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, - tortoisemerge and opendiff + diffuse, tortoisemerge and opendiff + If a merge resolution program is not specified, 'git-mergetool' will use the configuration variable `merge.tool`. If the diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 8c10f66702..4832bc75e2 100644 --- a/Documentation/merge-config.txt +++ b/Documentation/merge-config.txt @@ -23,7 +23,7 @@ merge.tool:: Controls which merge resolution program is used by linkgit:git-mergetool[1]. Valid built-in values are: "kdiff3", "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", - "ecmerge", tortoisemerge and + "diffuse", "ecmerge", "tortoisemerge", and "opendiff". Any other value is treated is custom merge tool and there must be a corresponding mergetool.<tool>.cmd option. diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index d3d8203171..e099ed48ff 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1174,7 +1174,8 @@ _git_mergetool () --tool=*) __gitcomp " kdiff3 tkdiff meld xxdiff emerge - vimdiff gvimdiff ecmerge opendiff + vimdiff gvimdiff ecmerge diffuse + opendiff " "" "${cur##--tool=}" return ;; diff --git a/contrib/difftool/git-difftool-helper b/contrib/difftool/git-difftool-helper index e74a2747b6..4b0daec5a7 100755 --- a/contrib/difftool/git-difftool-helper +++ b/contrib/difftool/git-difftool-helper @@ -1,7 +1,5 @@ #!/bin/sh # git-difftool-helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher. -# It supports kdiff3, kompare, tkdiff, xxdiff, meld, opendiff, -# emerge, ecmerge, vimdiff, gvimdiff, and custom user-configurable tools. # This script is typically launched by using the 'git difftool' # convenience command. # @@ -55,6 +53,10 @@ launch_merge_tool () { "$merge_tool_path" "$LOCAL" "$REMOTE" ;; + diffuse) + "$merge_tool_path" "$LOCAL" "$REMOTE" | cat + ;; + vimdiff) "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$REMOTE" ;; @@ -164,9 +166,9 @@ if test -z "$merge_tool"; then if test -n "$DISPLAY"; then # If gnome then prefer meld, otherwise, prefer kdiff3 or kompare if test -n "$GNOME_DESKTOP_SESSION_ID" ; then - merge_tool_candidates="meld kdiff3 kompare tkdiff xxdiff gvimdiff" + merge_tool_candidates="meld kdiff3 kompare tkdiff xxdiff gvimdiff diffuse" else - merge_tool_candidates="kdiff3 kompare tkdiff xxdiff meld gvimdiff" + merge_tool_candidates="kdiff3 kompare tkdiff xxdiff meld gvimdiff diffuse" fi fi if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then diff --git a/contrib/difftool/git-difftool.txt b/contrib/difftool/git-difftool.txt index a00e9431c5..af68466ebc 100644 --- a/contrib/difftool/git-difftool.txt +++ b/contrib/difftool/git-difftool.txt @@ -25,8 +25,8 @@ OPTIONS --tool=<tool>:: Use the diff tool specified by <tool>. Valid merge tools are: - kdiff3, kompare, tkdiff, meld, xxdiff, emerge, - vimdiff, gvimdiff, ecmerge, and opendiff + kdiff3, kompare, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, + ecmerge, diffuse and opendiff + If a diff tool is not specified, 'git-difftool' will use the configuration variable `diff.tool`. If the diff --git a/git-mergetool.sh b/git-mergetool.sh index be9717a2f1..b4d2432f02 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -414,9 +414,9 @@ fi if test -z "$merge_tool" ; then if test -n "$DISPLAY"; then if test -n "$GNOME_DESKTOP_SESSION_ID" ; then - merge_tool_candidates="meld kdiff3 tkdiff xxdiff tortoisemerge gvimdiff" + merge_tool_candidates="meld kdiff3 tkdiff xxdiff tortoisemerge gvimdiff diffuse" else - merge_tool_candidates="kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff" + merge_tool_candidates="kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse" fi fi if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then From afcbc8e7ecb18a3ee542e808f02f5df7d56d5bdc Mon Sep 17 00:00:00 2001 From: David Aguilar <davvid@gmail.com> Date: Tue, 7 Apr 2009 01:21:20 -0700 Subject: [PATCH 395/654] difftool: move 'git-difftool' out of contrib This prepares 'git-difftool' and its documentation for mainstream use. 'git-difftool-helper' became 'git-difftool--helper' since users should not use it directly. 'git-difftool' was added to the list of commands as an ancillaryinterrogator. Signed-off-by: David Aguilar <davvid@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- .gitignore | 2 ++ Documentation/config.txt | 18 ++++++++++++++++++ .../git-difftool.txt | 0 Makefile | 2 ++ command-list.txt | 1 + ...-difftool-helper => git-difftool--helper.sh | 2 +- .../difftool/git-difftool => git-difftool.perl | 6 +++--- 7 files changed, 27 insertions(+), 4 deletions(-) rename {contrib/difftool => Documentation}/git-difftool.txt (100%) rename contrib/difftool/git-difftool-helper => git-difftool--helper.sh (98%) rename contrib/difftool/git-difftool => git-difftool.perl (92%) diff --git a/.gitignore b/.gitignore index 1c57d4c958..a36da9d981 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,8 @@ git-diff git-diff-files git-diff-index git-diff-tree +git-difftool +git-difftool--helper git-describe git-fast-export git-fast-import diff --git a/Documentation/config.txt b/Documentation/config.txt index 3afd124749..94ef1a62f9 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -667,6 +667,24 @@ diff.suppressBlankEmpty:: A boolean to inhibit the standard behavior of printing a space before each empty output line. Defaults to false. +diff.tool:: + Controls which diff tool is used. `diff.tool` overrides + `merge.tool` when used by linkgit:git-difftool[1] and has + the same valid values as `merge.tool` minus "tortoisemerge" + and plus "kompare". + +difftool.<tool>.path:: + Override the path for the given tool. This is useful in case + your tool is not in the PATH. + +difftool.<tool>.cmd:: + Specify the command to invoke the specified diff tool. + The specified command is evaluated in shell with the following + variables available: 'LOCAL' is set to the name of the temporary + file containing the contents of the diff pre-image and 'REMOTE' + is set to the name of the temporary file containing the contents + of the diff post-image. + diff.wordRegex:: A POSIX Extended Regular Expression used to determine what is a "word" when performing word-by-word difference calculations. Character diff --git a/contrib/difftool/git-difftool.txt b/Documentation/git-difftool.txt similarity index 100% rename from contrib/difftool/git-difftool.txt rename to Documentation/git-difftool.txt diff --git a/Makefile b/Makefile index 7867eaccdb..a80055f38d 100644 --- a/Makefile +++ b/Makefile @@ -277,6 +277,7 @@ TEST_PROGRAMS = SCRIPT_SH += git-am.sh SCRIPT_SH += git-bisect.sh +SCRIPT_SH += git-difftool--helper.sh SCRIPT_SH += git-filter-branch.sh SCRIPT_SH += git-lost-found.sh SCRIPT_SH += git-merge-octopus.sh @@ -296,6 +297,7 @@ SCRIPT_SH += git-submodule.sh SCRIPT_SH += git-web--browse.sh SCRIPT_PERL += git-add--interactive.perl +SCRIPT_PERL += git-difftool.perl SCRIPT_PERL += git-archimport.perl SCRIPT_PERL += git-cvsexportcommit.perl SCRIPT_PERL += git-cvsimport.perl diff --git a/command-list.txt b/command-list.txt index 3583a33ee9..fb03a2ebb5 100644 --- a/command-list.txt +++ b/command-list.txt @@ -33,6 +33,7 @@ git-diff mainporcelain common git-diff-files plumbinginterrogators git-diff-index plumbinginterrogators git-diff-tree plumbinginterrogators +git-difftool ancillaryinterrogators git-fast-export ancillarymanipulators git-fast-import ancillarymanipulators git-fetch mainporcelain common diff --git a/contrib/difftool/git-difftool-helper b/git-difftool--helper.sh similarity index 98% rename from contrib/difftool/git-difftool-helper rename to git-difftool--helper.sh index 4b0daec5a7..fc61416acb 100755 --- a/contrib/difftool/git-difftool-helper +++ b/git-difftool--helper.sh @@ -1,5 +1,5 @@ #!/bin/sh -# git-difftool-helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher. +# git-difftool--helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher. # This script is typically launched by using the 'git difftool' # convenience command. # diff --git a/contrib/difftool/git-difftool b/git-difftool.perl similarity index 92% rename from contrib/difftool/git-difftool rename to git-difftool.perl index 8c160e5bb4..8857ac8a4c 100755 --- a/contrib/difftool/git-difftool +++ b/git-difftool.perl @@ -2,9 +2,9 @@ # Copyright (c) 2009 David Aguilar # # This is a wrapper around the GIT_EXTERNAL_DIFF-compatible -# git-difftool-helper script. This script exports +# git-difftool--helper script. This script exports # GIT_EXTERNAL_DIFF and GIT_PAGER for use by git, and -# GIT_DIFFTOOL_NO_PROMPT and GIT_DIFF_TOOL for use by git-difftool-helper. +# GIT_DIFFTOOL_NO_PROMPT and GIT_DIFF_TOOL for use by git-difftool--helper. # Any arguments that are unknown to this script are forwarded to 'git diff'. use strict; @@ -27,7 +27,7 @@ sub setup_environment { $ENV{PATH} = "$DIR:$ENV{PATH}"; $ENV{GIT_PAGER} = ''; - $ENV{GIT_EXTERNAL_DIFF} = 'git-difftool-helper'; + $ENV{GIT_EXTERNAL_DIFF} = 'git-difftool--helper'; } sub exe From f92f2038a5192ac5fc1bb4f38c49906aa45b3f1e Mon Sep 17 00:00:00 2001 From: David Aguilar <davvid@gmail.com> Date: Tue, 7 Apr 2009 16:30:53 -0700 Subject: [PATCH 396/654] difftool: add various git-difftool tests t7800-difftool.sh tests the various command-line flags, git-config variables, and environment settings supported by git-difftool. Signed-off-by: David Aguilar <davvid@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t7800-difftool.sh | 147 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100755 t/t7800-difftool.sh diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh new file mode 100755 index 0000000000..2699226557 --- /dev/null +++ b/t/t7800-difftool.sh @@ -0,0 +1,147 @@ +#!/bin/sh +# +# Copyright (c) 2009 David Aguilar +# + +test_description='git-difftool + +Testing basic diff tool invocation +' + +. ./test-lib.sh + +remove_config_vars() +{ + # Unset all config variables used by git-difftool + git config --unset diff.tool + git config --unset difftool.test-tool.cmd + git config --unset merge.tool + git config --unset mergetool.test-tool.cmd + return 0 +} + +restore_test_defaults() +{ + # Restores the test defaults used by several tests + remove_config_vars + unset GIT_DIFF_TOOL + unset GIT_MERGE_TOOL + unset GIT_DIFFTOOL_NO_PROMPT + git config diff.tool test-tool && + git config difftool.test-tool.cmd 'cat $LOCAL' +} + +# Create a file on master and change it on branch +test_expect_success 'setup' ' + echo master >file && + git add file && + git commit -m "added file" && + + git checkout -b branch master && + echo branch >file && + git commit -a -m "branch changed file" && + git checkout master +' + +# Configure a custom difftool.<tool>.cmd and use it +test_expect_success 'custom commands' ' + restore_test_defaults && + git config difftool.test-tool.cmd "cat \$REMOTE" && + + diff=$(git difftool --no-prompt branch) && + test "$diff" = "master" && + + restore_test_defaults && + diff=$(git difftool --no-prompt branch) && + test "$diff" = "branch" +' + +# Ensures that git-difftool ignores bogus --tool values +test_expect_success 'difftool ignores bad --tool values' ' + diff=$(git difftool --no-prompt --tool=bogus-tool branch) + test "$?" = 1 && + test "$diff" = "" +' + +# Specify the diff tool using $GIT_DIFF_TOOL +test_expect_success 'GIT_DIFF_TOOL variable' ' + git config --unset diff.tool + GIT_DIFF_TOOL=test-tool && + export GIT_DIFF_TOOL && + + diff=$(git difftool --no-prompt branch) && + test "$diff" = "branch" && + + restore_test_defaults +' + +# Test the $GIT_*_TOOL variables and ensure +# that $GIT_DIFF_TOOL always wins unless --tool is specified +test_expect_success 'GIT_DIFF_TOOL overrides' ' + git config diff.tool bogus-tool && + git config merge.tool bogus-tool && + + GIT_MERGE_TOOL=test-tool && + export GIT_MERGE_TOOL && + diff=$(git difftool --no-prompt branch) && + test "$diff" = "branch" && + unset GIT_MERGE_TOOL && + + GIT_MERGE_TOOL=bogus-tool && + GIT_DIFF_TOOL=test-tool && + export GIT_MERGE_TOOL && + export GIT_DIFF_TOOL && + + diff=$(git difftool --no-prompt branch) && + test "$diff" = "branch" && + + GIT_DIFF_TOOL=bogus-tool && + export GIT_DIFF_TOOL && + + diff=$(git difftool --no-prompt --tool=test-tool branch) && + test "$diff" = "branch" && + + restore_test_defaults +' + +# Test that we don't have to pass --no-prompt to difftool +# when $GIT_DIFFTOOL_NO_PROMPT is true +test_expect_success 'GIT_DIFFTOOL_NO_PROMPT variable' ' + GIT_DIFFTOOL_NO_PROMPT=true && + export GIT_DIFFTOOL_NO_PROMPT && + + diff=$(git difftool branch) && + test "$diff" = "branch" && + + restore_test_defaults +' + +# git-difftool falls back to git-mergetool config variables +# so test that behavior here +test_expect_success 'difftool + mergetool config variables' ' + remove_config_vars + git config merge.tool test-tool && + git config mergetool.test-tool.cmd "cat \$LOCAL" && + + diff=$(git difftool --no-prompt branch) && + test "$diff" = "branch" && + + # set merge.tool to something bogus, diff.tool to test-tool + git config merge.tool bogus-tool && + git config diff.tool test-tool && + + diff=$(git difftool --no-prompt branch) && + test "$diff" = "branch" && + + restore_test_defaults +' + +test_expect_success 'difftool.<tool>.path' ' + git config difftool.tkdiff.path echo && + diff=$(git difftool --tool=tkdiff --no-prompt branch) && + git config --unset difftool.tkdiff.path && + lines=$(echo "$diff" | grep file | wc -l) && + test "$lines" -eq 1 +' + +test_done From a904392eaeee1629c0ac14dae8e579bb8497636a Mon Sep 17 00:00:00 2001 From: David Aguilar <davvid@gmail.com> Date: Tue, 7 Apr 2009 01:21:22 -0700 Subject: [PATCH 397/654] difftool: add support for a difftool.prompt config variable difftool now supports difftool.prompt so that users do not have to pass --no-prompt or hit enter each time a diff tool is launched. The --prompt flag overrides the configuration variable. Signed-off-by: David Aguilar <davvid@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 3 ++ Documentation/git-difftool.txt | 10 +++++- git-difftool--helper.sh | 10 ++++-- git-difftool.perl | 15 ++++++-- t/t7800-difftool.sh | 64 ++++++++++++++++++++++++++++++++++ 5 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 94ef1a62f9..d427dafb41 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -685,6 +685,9 @@ difftool.<tool>.cmd:: is set to the name of the temporary file containing the contents of the diff post-image. +difftool.prompt:: + Prompt before each invocation of the diff tool. + diff.wordRegex:: A POSIX Extended Regular Expression used to determine what is a "word" when performing word-by-word difference calculations. Character diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt index af68466ebc..15b247bab4 100644 --- a/Documentation/git-difftool.txt +++ b/Documentation/git-difftool.txt @@ -7,7 +7,7 @@ git-difftool - Show changes using common diff tools SYNOPSIS -------- -'git difftool' [--tool=<tool>] [-y|--no-prompt] [<'git diff' options>] +'git difftool' [--tool=<tool>] [-y|--no-prompt|--prompt] [<'git diff' options>] DESCRIPTION ----------- @@ -21,6 +21,11 @@ OPTIONS --no-prompt:: Do not prompt before launching a diff tool. +--prompt:: + Prompt before each invocation of the diff tool. + This is the default behaviour; the option is provided to + override any configuration settings. + -t <tool>:: --tool=<tool>:: Use the diff tool specified by <tool>. @@ -72,6 +77,9 @@ difftool.<tool>.cmd:: + See the `--tool=<tool>` option above for more details. +difftool.prompt:: + Prompt before each invocation of the diff tool. + SEE ALSO -------- linkgit:git-diff[1]:: diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh index fc61416acb..f3c27d86ad 100755 --- a/git-difftool--helper.sh +++ b/git-difftool--helper.sh @@ -5,9 +5,15 @@ # # Copyright (c) 2009 David Aguilar -# Set GIT_DIFFTOOL_NO_PROMPT to bypass the per-file prompt. +# difftool.prompt controls the default prompt/no-prompt behavior +# and is overridden with $GIT_DIFFTOOL*_PROMPT. should_prompt () { - test -z "$GIT_DIFFTOOL_NO_PROMPT" + prompt=$(git config --bool difftool.prompt || echo true) + if test "$prompt" = true; then + test -z "$GIT_DIFFTOOL_NO_PROMPT" + else + test -n "$GIT_DIFFTOOL_PROMPT" + fi } # This function prepares temporary files and launches the appropriate diff --git a/git-difftool.perl b/git-difftool.perl index 8857ac8a4c..948ff7f6fd 100755 --- a/git-difftool.perl +++ b/git-difftool.perl @@ -2,9 +2,12 @@ # Copyright (c) 2009 David Aguilar # # This is a wrapper around the GIT_EXTERNAL_DIFF-compatible -# git-difftool--helper script. This script exports -# GIT_EXTERNAL_DIFF and GIT_PAGER for use by git, and -# GIT_DIFFTOOL_NO_PROMPT and GIT_DIFF_TOOL for use by git-difftool--helper. +# git-difftool--helper script. +# +# This script exports GIT_EXTERNAL_DIFF and GIT_PAGER for use by git. +# GIT_DIFFTOOL_NO_PROMPT, GIT_DIFFTOOL_PROMPT, and GIT_DIFF_TOOL +# are exported for use by git-difftool--helper. +# # Any arguments that are unknown to this script are forwarded to 'git diff'. use strict; @@ -62,6 +65,12 @@ sub generate_command } if ($arg eq '-y' || $arg eq '--no-prompt') { $ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true'; + delete $ENV{GIT_DIFFTOOL_PROMPT}; + next; + } + if ($arg eq '--prompt') { + $ENV{GIT_DIFFTOOL_PROMPT} = 'true'; + delete $ENV{GIT_DIFFTOOL_NO_PROMPT}; next; } if ($arg eq '-h' || $arg eq '--help') { diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index 2699226557..2586f864a0 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -15,6 +15,7 @@ remove_config_vars() # Unset all config variables used by git-difftool git config --unset diff.tool git config --unset difftool.test-tool.cmd + git config --unset difftool.prompt git config --unset merge.tool git config --unset mergetool.test-tool.cmd return 0 @@ -26,11 +27,18 @@ restore_test_defaults() remove_config_vars unset GIT_DIFF_TOOL unset GIT_MERGE_TOOL + unset GIT_DIFFTOOL_PROMPT unset GIT_DIFFTOOL_NO_PROMPT git config diff.tool test-tool && git config difftool.test-tool.cmd 'cat $LOCAL' } +prompt_given() +{ + prompt="$1" + test "$prompt" = "Hit return to launch 'test-tool': branch" +} + # Create a file on master and change it on branch test_expect_success 'setup' ' echo master >file && @@ -116,6 +124,62 @@ test_expect_success 'GIT_DIFFTOOL_NO_PROMPT variable' ' restore_test_defaults ' +# git-difftool supports the difftool.prompt variable. +# Test that GIT_DIFFTOOL_PROMPT can override difftool.prompt = false +test_expect_success 'GIT_DIFFTOOL_PROMPT variable' ' + git config difftool.prompt false && + GIT_DIFFTOOL_PROMPT=true && + export GIT_DIFFTOOL_PROMPT && + + prompt=$(echo | git difftool --prompt branch | tail -1) && + prompt_given "$prompt" && + + restore_test_defaults +' + +# Test that we don't have to pass --no-prompt when difftool.prompt is false +test_expect_success 'difftool.prompt config variable is false' ' + git config difftool.prompt false && + + diff=$(git difftool branch) && + test "$diff" = "branch" && + + restore_test_defaults +' + +# Test that the -y flag can override difftool.prompt = true +test_expect_success 'difftool.prompt can overridden with -y' ' + git config difftool.prompt true && + + diff=$(git difftool -y branch) && + test "$diff" = "branch" && + + restore_test_defaults +' + +# Test that the --prompt flag can override difftool.prompt = false +test_expect_success 'difftool.prompt can overridden with --prompt' ' + git config difftool.prompt false && + + prompt=$(echo | git difftool --prompt branch | tail -1) && + prompt_given "$prompt" && + + restore_test_defaults +' + +# Test that the last flag passed on the command-line wins +test_expect_success 'difftool last flag wins' ' + diff=$(git difftool --prompt --no-prompt branch) && + test "$diff" = "branch" && + + restore_test_defaults && + + prompt=$(echo | git difftool --no-prompt --prompt branch | tail -1) && + prompt_given "$prompt" && + + restore_test_defaults +' + # git-difftool falls back to git-mergetool config variables # so test that behavior here test_expect_success 'difftool + mergetool config variables' ' From e2dc2de917778a0601564e238c3cd61614f55e5f Mon Sep 17 00:00:00 2001 From: David Aguilar <davvid@gmail.com> Date: Mon, 6 Apr 2009 01:31:27 -0700 Subject: [PATCH 398/654] bash completion: add git-difftool This adds completion for difftool's --tool flag. The known diff tool names were also consolidated into a single variable. Signed-off-by: David Aguilar <davvid@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 27 +++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index e099ed48ff..069e19e82a 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -910,6 +910,26 @@ _git_diff () __git_complete_file } +__git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff + tkdiff vimdiff gvimdiff xxdiff +" + +_git_difftool () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + case "$cur" in + --tool=*) + __gitcomp "$__git_mergetools_common kompare" "" "${cur##--tool=}" + return + ;; + --*) + __gitcomp "--tool=" + return + ;; + esac + COMPREPLY=() +} + __git_fetch_options=" --quiet --verbose --append --upload-pack --force --keep --depth= --tags --no-tags @@ -1172,11 +1192,7 @@ _git_mergetool () local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --tool=*) - __gitcomp " - kdiff3 tkdiff meld xxdiff emerge - vimdiff gvimdiff ecmerge diffuse - opendiff - " "" "${cur##--tool=}" + __gitcomp "$__git_mergetools_common tortoisemerge" "" "${cur##--tool=}" return ;; --*) @@ -1901,6 +1917,7 @@ _git () config) _git_config ;; describe) _git_describe ;; diff) _git_diff ;; + difftool) _git_difftool ;; fetch) _git_fetch ;; format-patch) _git_format_patch ;; fsck) _git_fsck ;; From 9a62d72dfa833f98dd0730b3d5136f56d637a5c3 Mon Sep 17 00:00:00 2001 From: David Aguilar <davvid@gmail.com> Date: Mon, 6 Apr 2009 01:31:28 -0700 Subject: [PATCH 399/654] mergetool: use $( ... ) instead of `backticks` This makes mergetool consistent with Documentation/CodingGuidelines. Signed-off-by: David Aguilar <davvid@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-mergetool.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/git-mergetool.sh b/git-mergetool.sh index b4d2432f02..cceebb7210 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -137,7 +137,7 @@ checkout_staged_file () { merge_file () { MERGED="$1" - f=`git ls-files -u -- "$MERGED"` + f=$(git ls-files -u -- "$MERGED") if test -z "$f" ; then if test ! -f "$MERGED" ; then echo "$MERGED: file not found" @@ -156,9 +156,9 @@ merge_file () { mv -- "$MERGED" "$BACKUP" cp -- "$BACKUP" "$MERGED" - base_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}'` - local_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}'` - remote_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}'` + base_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}') + local_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}') + remote_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}') base_present && checkout_staged_file 1 "$MERGED" "$BASE" local_present && checkout_staged_file 2 "$MERGED" "$LOCAL" @@ -318,7 +318,7 @@ do -t|--tool*) case "$#,$1" in *,*=*) - merge_tool=`expr "z$1" : 'z-[^=]*=\(.*\)'` + merge_tool=$(expr "z$1" : 'z-[^=]*=\(.*\)') ;; 1,*) usage ;; @@ -366,7 +366,7 @@ valid_tool() { } init_merge_tool_path() { - merge_tool_path=`git config mergetool.$1.path` + merge_tool_path=$(git config mergetool.$1.path) if test -z "$merge_tool_path" ; then case "$1" in vimdiff) @@ -403,7 +403,7 @@ prompt_after_failed_merge() { } if test -z "$merge_tool"; then - merge_tool=`git config merge.tool` + merge_tool=$(git config merge.tool) if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then echo >&2 "git config option merge.tool set to unknown tool: $merge_tool" echo >&2 "Resetting to default..." @@ -463,7 +463,7 @@ last_status=0 rollup_status=0 if test $# -eq 0 ; then - files=`git ls-files -u | sed -e 's/^[^ ]* //' | sort -u` + files=$(git ls-files -u | sed -e 's/^[^ ]* //' | sort -u) if test -z "$files" ; then echo "No files need merging" exit 0 From 8db9a4b85d6b0d7424c8a19b77a5baa8529ab64c Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Tue, 7 Apr 2009 03:06:51 -0400 Subject: [PATCH 400/654] for-each-ref: refactor refname handling This code handles some special magic like *-deref and the :short formatting specifier. The next patch will add another field which outputs a ref and wants to use the same code. This patch splits the "which ref are we outputting" from the actual formatting. There should be no behavioral change. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-for-each-ref.c | 45 +++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index 4aaf75c779..653dca9a57 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -672,32 +672,37 @@ static void populate_value(struct refinfo *ref) const char *name = used_atom[i]; struct atom_value *v = &ref->value[i]; int deref = 0; + const char *refname; + const char *formatp; + if (*name == '*') { deref = 1; name++; } - if (!prefixcmp(name, "refname")) { - const char *formatp = strchr(name, ':'); - const char *refname = ref->refname; - /* look for "short" refname format */ - if (formatp) { - formatp++; - if (!strcmp(formatp, "short")) - refname = get_short_ref(ref->refname); - else - die("unknown refname format %s", - formatp); - } + if (!prefixcmp(name, "refname")) + refname = ref->refname; + else + continue; - if (!deref) - v->s = refname; - else { - int len = strlen(refname); - char *s = xmalloc(len + 4); - sprintf(s, "%s^{}", refname); - v->s = s; - } + formatp = strchr(name, ':'); + /* look for "short" refname format */ + if (formatp) { + formatp++; + if (!strcmp(formatp, "short")) + refname = get_short_ref(refname); + else + die("unknown %.*s format %s", + (int)(formatp - name), name, formatp); + } + + if (!deref) + v->s = refname; + else { + int len = strlen(refname); + char *s = xmalloc(len + 4); + sprintf(s, "%s^{}", refname); + v->s = s; } } From 8cae19d987b1bbd43258558f591e39d9d216dcb3 Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Tue, 7 Apr 2009 03:09:39 -0400 Subject: [PATCH 401/654] for-each-ref: add "upstream" format field The logic for determining the upstream ref of a branch is somewhat complex to perform in a shell script. This patch provides a plumbing mechanism for scripts to access the C logic used internally by git-status, git-branch, etc. For example: $ git for-each-ref \ --format='%(refname:short) %(upstream:short)' \ refs/heads/ master origin/master Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-for-each-ref.txt | 5 +++++ builtin-for-each-ref.c | 14 ++++++++++++++ t/t6300-for-each-ref.sh | 22 ++++++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index 5061d3e4e7..b362e9ed12 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -85,6 +85,11 @@ objectsize:: objectname:: The object name (aka SHA-1). +upstream:: + The name of a local ref which can be considered ``upstream'' + from the displayed ref. Respects `:short` in the same way as + `refname` above. + In addition to the above, for commit and tag objects, the header field names (`tree`, `parent`, `object`, `type`, and `tag`) can be used to specify the value in the header field. diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index 653dca9a57..8796352eb6 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -8,6 +8,7 @@ #include "blob.h" #include "quote.h" #include "parse-options.h" +#include "remote.h" /* Quoting styles */ #define QUOTE_NONE 0 @@ -66,6 +67,7 @@ static struct { { "subject" }, { "body" }, { "contents" }, + { "upstream" }, }; /* @@ -682,6 +684,18 @@ static void populate_value(struct refinfo *ref) if (!prefixcmp(name, "refname")) refname = ref->refname; + else if(!prefixcmp(name, "upstream")) { + struct branch *branch; + /* only local branches may have an upstream */ + if (prefixcmp(ref->refname, "refs/heads/")) + continue; + branch = branch_get(ref->refname + 11); + + if (!branch || !branch->merge || !branch->merge[0] || + !branch->merge[0]->dst) + continue; + refname = branch->merge[0]->dst; + } else continue; diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index 8bfae44a83..daf02d5c10 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -26,6 +26,13 @@ test_expect_success 'Create sample commit with known timestamp' ' git tag -a -m "Tagging at $datestamp" testtag ' +test_expect_success 'Create upstream config' ' + git update-ref refs/remotes/origin/master master && + git remote add origin nowhere && + git config branch.master.remote origin && + git config branch.master.merge refs/heads/master +' + test_atom() { case "$1" in head) ref=refs/heads/master ;; @@ -39,6 +46,7 @@ test_atom() { } test_atom head refname refs/heads/master +test_atom head upstream refs/remotes/origin/master test_atom head objecttype commit test_atom head objectsize 171 test_atom head objectname 67a36f10722846e891fbada1ba48ed035de75581 @@ -68,6 +76,7 @@ test_atom head contents 'Initial ' test_atom tag refname refs/tags/testtag +test_atom tag upstream '' test_atom tag objecttype tag test_atom tag objectsize 154 test_atom tag objectname 98b46b1d36e5b07909de1b3886224e3e81e87322 @@ -203,6 +212,7 @@ test_expect_success 'Check format "rfc2822" date fields output' ' cat >expected <<\EOF refs/heads/master +refs/remotes/origin/master refs/tags/testtag EOF @@ -214,6 +224,7 @@ test_expect_success 'Verify ascending sort' ' cat >expected <<\EOF refs/tags/testtag +refs/remotes/origin/master refs/heads/master EOF @@ -224,6 +235,7 @@ test_expect_success 'Verify descending sort' ' cat >expected <<\EOF 'refs/heads/master' +'refs/remotes/origin/master' 'refs/tags/testtag' EOF @@ -244,6 +256,7 @@ test_expect_success 'Quoting style: python' ' cat >expected <<\EOF "refs/heads/master" +"refs/remotes/origin/master" "refs/tags/testtag" EOF @@ -273,6 +286,15 @@ test_expect_success 'Check short refname format' ' test_cmp expected actual ' +cat >expected <<EOF +origin/master +EOF + +test_expect_success 'Check short upstream format' ' + git for-each-ref --format="%(upstream:short)" refs/heads >actual && + test_cmp expected actual +' + test_expect_success 'Check for invalid refname format' ' test_must_fail git for-each-ref --format="%(refname:INVALID)" ' From 7c2b3029df45a74d0ebd11afcc94259791cfb90d Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Tue, 7 Apr 2009 03:14:20 -0400 Subject: [PATCH 402/654] make get_short_ref a public function Often we want to shorten a full ref name to something "prettier" to show a user. For example, "refs/heads/master" is often shown simply as "master", or "refs/remotes/origin/master" is shown as "origin/master". Many places in the code use a very simple formula: skip common prefixes like refs/heads, refs/remotes, etc. This is codified in the prettify_ref function. for-each-ref has a more correct (but more expensive) approach: consider the ref lookup rules, and try shortening as much as possible while remaining unambiguous. This patch makes the latter strategy globally available as shorten_unambiguous_ref. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-for-each-ref.c | 105 +---------------------------------------- refs.c | 99 ++++++++++++++++++++++++++++++++++++++ refs.h | 1 + 3 files changed, 101 insertions(+), 104 deletions(-) diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index 8796352eb6..c8114c8afd 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -545,109 +545,6 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, v } } -/* - * generate a format suitable for scanf from a ref_rev_parse_rules - * rule, that is replace the "%.*s" spec with a "%s" spec - */ -static void gen_scanf_fmt(char *scanf_fmt, const char *rule) -{ - char *spec; - - spec = strstr(rule, "%.*s"); - if (!spec || strstr(spec + 4, "%.*s")) - die("invalid rule in ref_rev_parse_rules: %s", rule); - - /* copy all until spec */ - strncpy(scanf_fmt, rule, spec - rule); - scanf_fmt[spec - rule] = '\0'; - /* copy new spec */ - strcat(scanf_fmt, "%s"); - /* copy remaining rule */ - strcat(scanf_fmt, spec + 4); - - return; -} - -/* - * Shorten the refname to an non-ambiguous form - */ -static char *get_short_ref(const char *ref) -{ - int i; - static char **scanf_fmts; - static int nr_rules; - char *short_name; - - /* pre generate scanf formats from ref_rev_parse_rules[] */ - if (!nr_rules) { - size_t total_len = 0; - - /* the rule list is NULL terminated, count them first */ - for (; ref_rev_parse_rules[nr_rules]; nr_rules++) - /* no +1 because strlen("%s") < strlen("%.*s") */ - total_len += strlen(ref_rev_parse_rules[nr_rules]); - - scanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len); - - total_len = 0; - for (i = 0; i < nr_rules; i++) { - scanf_fmts[i] = (char *)&scanf_fmts[nr_rules] - + total_len; - gen_scanf_fmt(scanf_fmts[i], ref_rev_parse_rules[i]); - total_len += strlen(ref_rev_parse_rules[i]); - } - } - - /* bail out if there are no rules */ - if (!nr_rules) - return xstrdup(ref); - - /* buffer for scanf result, at most ref must fit */ - short_name = xstrdup(ref); - - /* skip first rule, it will always match */ - for (i = nr_rules - 1; i > 0 ; --i) { - int j; - int short_name_len; - - if (1 != sscanf(ref, scanf_fmts[i], short_name)) - continue; - - short_name_len = strlen(short_name); - - /* - * check if the short name resolves to a valid ref, - * but use only rules prior to the matched one - */ - for (j = 0; j < i; j++) { - const char *rule = ref_rev_parse_rules[j]; - unsigned char short_objectname[20]; - char refname[PATH_MAX]; - - /* - * the short name is ambiguous, if it resolves - * (with this previous rule) to a valid ref - * read_ref() returns 0 on success - */ - mksnpath(refname, sizeof(refname), - rule, short_name_len, short_name); - if (!read_ref(refname, short_objectname)) - break; - } - - /* - * short name is non-ambiguous if all previous rules - * haven't resolved to a valid ref - */ - if (j == i) - return short_name; - } - - free(short_name); - return xstrdup(ref); -} - - /* * Parse the object referred by ref, and grab needed value. */ @@ -704,7 +601,7 @@ static void populate_value(struct refinfo *ref) if (formatp) { formatp++; if (!strcmp(formatp, "short")) - refname = get_short_ref(refname); + refname = shorten_unambiguous_ref(refname); else die("unknown %.*s format %s", (int)(formatp - name), name, formatp); diff --git a/refs.c b/refs.c index 59c373fc6d..1e5e7b4ad9 100644 --- a/refs.c +++ b/refs.c @@ -1652,3 +1652,102 @@ struct ref *find_ref_by_name(const struct ref *list, const char *name) return (struct ref *)list; return NULL; } + +/* + * generate a format suitable for scanf from a ref_rev_parse_rules + * rule, that is replace the "%.*s" spec with a "%s" spec + */ +static void gen_scanf_fmt(char *scanf_fmt, const char *rule) +{ + char *spec; + + spec = strstr(rule, "%.*s"); + if (!spec || strstr(spec + 4, "%.*s")) + die("invalid rule in ref_rev_parse_rules: %s", rule); + + /* copy all until spec */ + strncpy(scanf_fmt, rule, spec - rule); + scanf_fmt[spec - rule] = '\0'; + /* copy new spec */ + strcat(scanf_fmt, "%s"); + /* copy remaining rule */ + strcat(scanf_fmt, spec + 4); + + return; +} + +char *shorten_unambiguous_ref(const char *ref) +{ + int i; + static char **scanf_fmts; + static int nr_rules; + char *short_name; + + /* pre generate scanf formats from ref_rev_parse_rules[] */ + if (!nr_rules) { + size_t total_len = 0; + + /* the rule list is NULL terminated, count them first */ + for (; ref_rev_parse_rules[nr_rules]; nr_rules++) + /* no +1 because strlen("%s") < strlen("%.*s") */ + total_len += strlen(ref_rev_parse_rules[nr_rules]); + + scanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len); + + total_len = 0; + for (i = 0; i < nr_rules; i++) { + scanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + + total_len; + gen_scanf_fmt(scanf_fmts[i], ref_rev_parse_rules[i]); + total_len += strlen(ref_rev_parse_rules[i]); + } + } + + /* bail out if there are no rules */ + if (!nr_rules) + return xstrdup(ref); + + /* buffer for scanf result, at most ref must fit */ + short_name = xstrdup(ref); + + /* skip first rule, it will always match */ + for (i = nr_rules - 1; i > 0 ; --i) { + int j; + int short_name_len; + + if (1 != sscanf(ref, scanf_fmts[i], short_name)) + continue; + + short_name_len = strlen(short_name); + + /* + * check if the short name resolves to a valid ref, + * but use only rules prior to the matched one + */ + for (j = 0; j < i; j++) { + const char *rule = ref_rev_parse_rules[j]; + unsigned char short_objectname[20]; + char refname[PATH_MAX]; + + /* + * the short name is ambiguous, if it resolves + * (with this previous rule) to a valid ref + * read_ref() returns 0 on success + */ + mksnpath(refname, sizeof(refname), + rule, short_name_len, short_name); + if (!read_ref(refname, short_objectname)) + break; + } + + /* + * short name is non-ambiguous if all previous rules + * haven't resolved to a valid ref + */ + if (j == i) + return short_name; + } + + free(short_name); + return xstrdup(ref); +} diff --git a/refs.h b/refs.h index 68c2d16d53..2d0f961c7c 100644 --- a/refs.h +++ b/refs.h @@ -80,6 +80,7 @@ extern int for_each_reflog(each_ref_fn, void *); extern int check_ref_format(const char *target); extern const char *prettify_ref(const struct ref *ref); +extern char *shorten_unambiguous_ref(const char *ref); /** rename ref, return 0 on success **/ extern int rename_ref(const char *oldref, const char *newref, const char *logmsg); From 2d8a7f0b30b4f9ef750ab763aabec117ffe4e749 Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Tue, 7 Apr 2009 03:16:56 -0400 Subject: [PATCH 403/654] branch: show upstream branch when double verbose This information is easily accessible when we are calculating the relationship. The only reason not to print it all the time is that it consumes a fair bit of screen space, and may not be of interest to the user. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-branch.txt | 4 +++- builtin-branch.c | 23 +++++++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index 31ba7f2ade..ba3dea6840 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -100,7 +100,9 @@ OPTIONS -v:: --verbose:: - Show sha1 and commit subject line for each head. + Show sha1 and commit subject line for each head, along with + relationship to upstream branch (if any). If given twice, print + the name of the upstream branch, as well. --abbrev=<length>:: Alter the sha1's minimum display length in the output listing. diff --git a/builtin-branch.c b/builtin-branch.c index ca81d725cb..3275821696 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -301,19 +301,30 @@ static int ref_cmp(const void *r1, const void *r2) return strcmp(c1->name, c2->name); } -static void fill_tracking_info(struct strbuf *stat, const char *branch_name) +static void fill_tracking_info(struct strbuf *stat, const char *branch_name, + int show_upstream_ref) { int ours, theirs; struct branch *branch = branch_get(branch_name); - if (!stat_tracking_info(branch, &ours, &theirs) || (!ours && !theirs)) + if (!stat_tracking_info(branch, &ours, &theirs)) { + if (branch && branch->merge && branch->merge[0]->dst && + show_upstream_ref) + strbuf_addf(stat, "[%s] ", + shorten_unambiguous_ref(branch->merge[0]->dst)); return; + } + + strbuf_addch(stat, '['); + if (show_upstream_ref) + strbuf_addf(stat, "%s: ", + shorten_unambiguous_ref(branch->merge[0]->dst)); if (!ours) - strbuf_addf(stat, "[behind %d] ", theirs); + strbuf_addf(stat, "behind %d] ", theirs); else if (!theirs) - strbuf_addf(stat, "[ahead %d] ", ours); + strbuf_addf(stat, "ahead %d] ", ours); else - strbuf_addf(stat, "[ahead %d, behind %d] ", ours, theirs); + strbuf_addf(stat, "ahead %d, behind %d] ", ours, theirs); } static int matches_merge_filter(struct commit *commit) @@ -379,7 +390,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, } if (item->kind == REF_LOCAL_BRANCH) - fill_tracking_info(&stat, item->name); + fill_tracking_info(&stat, item->name, verbose > 1); strbuf_addf(&out, " %s %s%s", find_unique_abbrev(item->commit->object.sha1, abbrev), From 21d0ba7ebb0c6b6c6ad844f8a40fff8dd4c0b105 Mon Sep 17 00:00:00 2001 From: David Aguilar <davvid@gmail.com> Date: Wed, 8 Apr 2009 00:17:20 -0700 Subject: [PATCH 404/654] difftool/mergetool: refactor commands to use git-mergetool--lib This consolidates the common functionality from git-mergetool and git-difftool--helper into a single git-mergetool--lib scriptlet. Signed-off-by: David Aguilar <davvid@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- .gitignore | 1 + Documentation/git-mergetool--lib.txt | 56 ++++ Makefile | 1 + git-difftool--helper.sh | 186 +------------ git-mergetool--lib.sh | 378 +++++++++++++++++++++++++++ git-mergetool.sh | 224 +--------------- 6 files changed, 458 insertions(+), 388 deletions(-) create mode 100644 Documentation/git-mergetool--lib.txt create mode 100644 git-mergetool--lib.sh diff --git a/.gitignore b/.gitignore index a36da9d981..757c7f0ad9 100644 --- a/.gitignore +++ b/.gitignore @@ -80,6 +80,7 @@ git-merge-recursive git-merge-resolve git-merge-subtree git-mergetool +git-mergetool--lib git-mktag git-mktree git-name-rev diff --git a/Documentation/git-mergetool--lib.txt b/Documentation/git-mergetool--lib.txt new file mode 100644 index 0000000000..3d57031d78 --- /dev/null +++ b/Documentation/git-mergetool--lib.txt @@ -0,0 +1,56 @@ +git-mergetool--lib(1) +===================== + +NAME +---- +git-mergetool--lib - Common git merge tool shell scriptlets + +SYNOPSIS +-------- +'. "$(git --exec-path)/git-mergetool--lib"' + +DESCRIPTION +----------- + +This is not a command the end user would want to run. Ever. +This documentation is meant for people who are studying the +Porcelain-ish scripts and/or are writing new ones. + +The 'git-mergetool--lib' scriptlet is designed to be sourced (using +`.`) by other shell scripts to set up functions for working +with git merge tools. + +Before sourcing it, your script should set up a few variables; +`TOOL_MODE` is used to define the operation mode for various +functions. 'diff' and 'merge' are valid values. + +FUNCTIONS +--------- +get_merge_tool:: + returns a merge tool + +get_merge_tool_cmd:: + returns the custom command for a merge tool. + +get_merge_tool_path:: + returns the custom path for a merge tool. + +run_merge_tool:: + launches a merge tool given the tool name and a true/false + flag to indicate whether a merge base is present. + '$merge_tool', '$merge_tool_path', and for custom commands, + '$merge_tool_cmd', must be defined prior to calling + run_merge_tool. Additionally, '$MERGED', '$LOCAL', '$REMOTE', + and '$BASE' must be defined for use by the merge tool. + +Author +------ +Written by David Aguilar <davvid@gmail.com> + +Documentation +-------------- +Documentation by David Aguilar and the git-list <git@vger.kernel.org>. + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Makefile b/Makefile index a80055f38d..3e56274d36 100644 --- a/Makefile +++ b/Makefile @@ -284,6 +284,7 @@ SCRIPT_SH += git-merge-octopus.sh SCRIPT_SH += git-merge-one-file.sh SCRIPT_SH += git-merge-resolve.sh SCRIPT_SH += git-mergetool.sh +SCRIPT_SH += git-mergetool--lib.sh SCRIPT_SH += git-parse-remote.sh SCRIPT_SH += git-pull.sh SCRIPT_SH += git-quiltimport.sh diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh index f3c27d86ad..b4500368c3 100755 --- a/git-difftool--helper.sh +++ b/git-difftool--helper.sh @@ -5,6 +5,10 @@ # # Copyright (c) 2009 David Aguilar +# Load common functions from git-mergetool--lib +TOOL_MODE=diff +. git-mergetool--lib + # difftool.prompt controls the default prompt/no-prompt behavior # and is overridden with $GIT_DIFFTOOL*_PROMPT. should_prompt () { @@ -16,8 +20,7 @@ should_prompt () { fi } -# This function prepares temporary files and launches the appropriate -# merge tool. +# Sets up shell variables and runs a merge tool launch_merge_tool () { # Merged is the filename as it appears in the work tree # Local is the contents of a/filename @@ -37,187 +40,16 @@ launch_merge_tool () { fi # Run the appropriate merge tool command - case "$merge_tool" in - kdiff3) - basename=$(basename "$MERGED") - "$merge_tool_path" --auto \ - --L1 "$basename (A)" \ - --L2 "$basename (B)" \ - "$LOCAL" "$REMOTE" \ - > /dev/null 2>&1 - ;; - - kompare) - "$merge_tool_path" "$LOCAL" "$REMOTE" - ;; - - tkdiff) - "$merge_tool_path" "$LOCAL" "$REMOTE" - ;; - - meld) - "$merge_tool_path" "$LOCAL" "$REMOTE" - ;; - - diffuse) - "$merge_tool_path" "$LOCAL" "$REMOTE" | cat - ;; - - vimdiff) - "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$REMOTE" - ;; - - gvimdiff) - "$merge_tool_path" -d -c "wincmd l" -f "$LOCAL" "$REMOTE" - ;; - - xxdiff) - "$merge_tool_path" \ - -R 'Accel.Search: "Ctrl+F"' \ - -R 'Accel.SearchForward: "Ctrl-G"' \ - "$LOCAL" "$REMOTE" - ;; - - opendiff) - "$merge_tool_path" "$LOCAL" "$REMOTE" | cat - ;; - - ecmerge) - "$merge_tool_path" "$LOCAL" "$REMOTE" \ - --default --mode=merge2 --to="$MERGED" - ;; - - emerge) - "$merge_tool_path" -f emerge-files-command \ - "$LOCAL" "$REMOTE" "$(basename "$MERGED")" - ;; - - *) - if test -n "$merge_tool_cmd"; then - ( eval $merge_tool_cmd ) - fi - ;; - esac -} - -# Verifies that (difftool|mergetool).<tool>.cmd exists -valid_custom_tool() { - merge_tool_cmd="$(git config difftool.$1.cmd)" - test -z "$merge_tool_cmd" && - merge_tool_cmd="$(git config mergetool.$1.cmd)" - test -n "$merge_tool_cmd" -} - -# Verifies that the chosen merge tool is properly setup. -# Built-in merge tools are always valid. -valid_tool() { - case "$1" in - kdiff3 | kompare | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge) - ;; # happy - *) - if ! valid_custom_tool "$1" - then - return 1 - fi - ;; - esac -} - -# Sets up the merge_tool_path variable. -# This handles the difftool.<tool>.path configuration. -# This also falls back to mergetool defaults. -init_merge_tool_path() { - merge_tool_path=$(git config difftool."$1".path) - test -z "$merge_tool_path" && - merge_tool_path=$(git config mergetool."$1".path) - if test -z "$merge_tool_path"; then - case "$1" in - vimdiff) - merge_tool_path=vim - ;; - gvimdiff) - merge_tool_path=gvim - ;; - emerge) - merge_tool_path=emacs - ;; - *) - merge_tool_path="$1" - ;; - esac - fi + run_merge_tool "$merge_tool" } # Allow GIT_DIFF_TOOL and GIT_MERGE_TOOL to provide default values test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL" test -n "$GIT_DIFF_TOOL" && merge_tool="$GIT_DIFF_TOOL" -# If merge tool was not specified then use the diff.tool -# configuration variable. If that's invalid then reset merge_tool. -# Fallback to merge.tool. -if test -z "$merge_tool"; then - merge_tool=$(git config diff.tool) - test -z "$merge_tool" && - merge_tool=$(git config merge.tool) - if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then - echo >&2 "git config option diff.tool set to unknown tool: $merge_tool" - echo >&2 "Resetting to default..." - unset merge_tool - fi -fi - -# Try to guess an appropriate merge tool if no tool has been set. -if test -z "$merge_tool"; then - # We have a $DISPLAY so try some common UNIX merge tools - if test -n "$DISPLAY"; then - # If gnome then prefer meld, otherwise, prefer kdiff3 or kompare - if test -n "$GNOME_DESKTOP_SESSION_ID" ; then - merge_tool_candidates="meld kdiff3 kompare tkdiff xxdiff gvimdiff diffuse" - else - merge_tool_candidates="kdiff3 kompare tkdiff xxdiff meld gvimdiff diffuse" - fi - fi - if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then - # $EDITOR is emacs so add emerge as a candidate - merge_tool_candidates="$merge_tool_candidates emerge opendiff vimdiff" - elif echo "${VISUAL:-$EDITOR}" | grep 'vim' > /dev/null 2>&1; then - # $EDITOR is vim so add vimdiff as a candidate - merge_tool_candidates="$merge_tool_candidates vimdiff opendiff emerge" - else - merge_tool_candidates="$merge_tool_candidates opendiff emerge vimdiff" - fi - echo "merge tool candidates: $merge_tool_candidates" - - # Loop over each candidate and stop when a valid merge tool is found. - for i in $merge_tool_candidates - do - init_merge_tool_path $i - if type "$merge_tool_path" > /dev/null 2>&1; then - merge_tool=$i - break - fi - done - - if test -z "$merge_tool" ; then - echo "No known merge resolution program available." - exit 1 - fi - -else - # A merge tool has been set, so verify that it's valid. - if ! valid_tool "$merge_tool"; then - echo >&2 "Unknown merge tool $merge_tool" - exit 1 - fi - - init_merge_tool_path "$merge_tool" - - if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then - echo "The merge tool $merge_tool is not available as '$merge_tool_path'" - exit 1 - fi -fi - +merge_tool=$(get_merge_tool "$merge_tool") || exit +merge_tool_cmd="$(get_merge_tool_cmd "$merge_tool")" +merge_tool_path="$(get_merge_tool_path "$merge_tool")" || exit # Launch the merge tool on each path provided by 'git diff' while test $# -gt 6 diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh new file mode 100644 index 0000000000..c5db24e45d --- /dev/null +++ b/git-mergetool--lib.sh @@ -0,0 +1,378 @@ +# git-mergetool--lib is a library for common merge tool functions +diff_mode() { + test "$TOOL_MODE" = diff +} + +merge_mode() { + test "$TOOL_MODE" = merge +} + +translate_merge_tool_path () { + if test -n "$2"; then + echo "$2" + else + case "$1" in + vimdiff) + path=vim + ;; + gvimdiff) + path=gvim + ;; + emerge) + path=emacs + ;; + *) + path="$1" + ;; + esac + echo "$path" + fi +} + +check_unchanged () { + if test "$MERGED" -nt "$BACKUP"; then + status=0 + else + while true; do + echo "$MERGED seems unchanged." + printf "Was the merge successful? [y/n] " + read answer < /dev/tty + case "$answer" in + y*|Y*) status=0; break ;; + n*|N*) status=1; break ;; + esac + done + fi +} + +valid_tool () { + case "$1" in + kdiff3 | tkdiff | xxdiff | meld | opendiff | \ + emerge | vimdiff | gvimdiff | ecmerge | diffuse) + ;; # happy + tortoisemerge) + if ! merge_mode; then + return 1 + fi + ;; + kompare) + if ! diff_mode; then + return 1 + fi + ;; + *) + if test -z "$(get_merge_tool_cmd "$1")"; then + return 1 + fi + ;; + esac +} + +get_merge_tool_cmd () { + diff_mode && + custom_cmd="$(git config difftool.$1.cmd)" + test -z "$custom_cmd" && + custom_cmd="$(git config mergetool.$1.cmd)" + test -n "$custom_cmd" && + echo "$custom_cmd" +} + +run_merge_tool () { + base_present="$2" + status=0 + + case "$1" in + kdiff3) + if merge_mode; then + if $base_present; then + ("$merge_tool_path" --auto \ + --L1 "$MERGED (Base)" \ + --L2 "$MERGED (Local)" \ + --L3 "$MERGED (Remote)" \ + -o "$MERGED" \ + "$BASE" "$LOCAL" "$REMOTE" \ + > /dev/null 2>&1) + else + ("$merge_tool_path" --auto \ + --L1 "$MERGED (Local)" \ + --L2 "$MERGED (Remote)" \ + -o "$MERGED" \ + "$LOCAL" "$REMOTE" \ + > /dev/null 2>&1) + fi + status=$? + else + ("$merge_tool_path" --auto \ + --L1 "$MERGED (A)" \ + --L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \ + > /dev/null 2>&1) + fi + ;; + kompare) + "$merge_tool_path" "$LOCAL" "$REMOTE" + ;; + tkdiff) + if merge_mode; then + if $base_present; then + "$merge_tool_path" -a "$BASE" \ + -o "$MERGED" "$LOCAL" "$REMOTE" + else + "$merge_tool_path" \ + -o "$MERGED" "$LOCAL" "$REMOTE" + fi + status=$? + else + "$merge_tool_path" "$LOCAL" "$REMOTE" + fi + ;; + meld) + if merge_mode; then + touch "$BACKUP" + "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE" + check_unchanged + else + "$merge_tool_path" "$LOCAL" "$REMOTE" + fi + ;; + diffuse) + if merge_mode; then + touch "$BACKUP" + if $base_present; then + "$merge_tool_path" \ + "$LOCAL" "$MERGED" "$REMOTE" \ + "$BASE" | cat + else + "$merge_tool_path" \ + "$LOCAL" "$MERGED" "$REMOTE" | cat + fi + check_unchanged + else + "$merge_tool_path" "$LOCAL" "$REMOTE" | cat + fi + ;; + vimdiff) + if merge_mode; then + touch "$BACKUP" + "$merge_tool_path" -d -c "wincmd l" \ + "$LOCAL" "$MERGED" "$REMOTE" + check_unchanged + else + "$merge_tool_path" -d -c "wincmd l" \ + "$LOCAL" "$REMOTE" + fi + ;; + gvimdiff) + if merge_mode; then + touch "$BACKUP" + "$merge_tool_path" -d -c "wincmd l" -f \ + "$LOCAL" "$MERGED" "$REMOTE" + check_unchanged + else + "$merge_tool_path" -d -c "wincmd l" -f \ + "$LOCAL" "$REMOTE" + fi + ;; + xxdiff) + if merge_mode; then + touch "$BACKUP" + if $base_present; then + "$merge_tool_path" -X --show-merged-pane \ + -R 'Accel.SaveAsMerged: "Ctrl-S"' \ + -R 'Accel.Search: "Ctrl+F"' \ + -R 'Accel.SearchForward: "Ctrl-G"' \ + --merged-file "$MERGED" \ + "$LOCAL" "$BASE" "$REMOTE" + else + "$merge_tool_path" -X $extra \ + -R 'Accel.SaveAsMerged: "Ctrl-S"' \ + -R 'Accel.Search: "Ctrl+F"' \ + -R 'Accel.SearchForward: "Ctrl-G"' \ + --merged-file "$MERGED" \ + "$LOCAL" "$REMOTE" + fi + check_unchanged + else + "$merge_tool_path" \ + -R 'Accel.Search: "Ctrl+F"' \ + -R 'Accel.SearchForward: "Ctrl-G"' \ + "$LOCAL" "$REMOTE" + fi + ;; + opendiff) + if merge_mode; then + touch "$BACKUP" + if $base_present; then + "$merge_tool_path" "$LOCAL" "$REMOTE" \ + -ancestor "$BASE" \ + -merge "$MERGED" | cat + else + "$merge_tool_path" "$LOCAL" "$REMOTE" \ + -merge "$MERGED" | cat + fi + check_unchanged + else + "$merge_tool_path" "$LOCAL" "$REMOTE" | cat + fi + ;; + ecmerge) + if merge_mode; then + touch "$BACKUP" + if $base_present; then + "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" \ + --default --mode=merge3 --to="$MERGED" + else + "$merge_tool_path" "$LOCAL" "$REMOTE" \ + --default --mode=merge2 --to="$MERGED" + fi + check_unchanged + else + "$merge_tool_path" "$LOCAL" "$REMOTE" \ + --default --mode=merge2 --to="$MERGED" + fi + ;; + emerge) + if merge_mode; then + if $base_present; then + "$merge_tool_path" \ + -f emerge-files-with-ancestor-command \ + "$LOCAL" "$REMOTE" "$BASE" \ + "$(basename "$MERGED")" + else + "$merge_tool_path" \ + -f emerge-files-command \ + "$LOCAL" "$REMOTE" \ + "$(basename "$MERGED")" + fi + status=$? + else + "$merge_tool_path" -f emerge-files-command \ + "$LOCAL" "$REMOTE" "$(basename "$MERGED")" + fi + ;; + tortoisemerge) + if $base_present; then + touch "$BACKUP" + "$merge_tool_path" \ + -base:"$BASE" -mine:"$LOCAL" \ + -theirs:"$REMOTE" -merged:"$MERGED" + check_unchanged + else + echo "TortoiseMerge cannot be used without a base" 1>&2 + status=1 + fi + ;; + *) + if test -z "$merge_tool_cmd"; then + if merge_mode; then + status=1 + fi + break + fi + if merge_mode; then + if test "$merge_tool_trust_exit_code" = "false"; then + touch "$BACKUP" + ( eval $merge_tool_cmd ) + check_unchanged + else + ( eval $merge_tool_cmd ) + status=$? + fi + else + ( eval $merge_tool_cmd ) + fi + ;; + esac + return $status +} + +guess_merge_tool () { + if merge_mode; then + tools="tortoisemerge" + else + tools="kompare" + fi + if test -n "$DISPLAY"; then + if test -n "$GNOME_DESKTOP_SESSION_ID" ; then + tools="meld opendiff kdiff3 tkdiff xxdiff $tools" + else + tools="opendiff kdiff3 tkdiff xxdiff meld $tools" + fi + tools="$tools gvimdiff diffuse ecmerge" + fi + if echo "${VISUAL:-$EDITOR}" | grep emacs > /dev/null 2>&1; then + # $EDITOR is emacs so add emerge as a candidate + tools="$tools emerge vimdiff" + elif echo "${VISUAL:-$EDITOR}" | grep vim > /dev/null 2>&1; then + # $EDITOR is vim so add vimdiff as a candidate + tools="$tools vimdiff emerge" + else + tools="$tools emerge vimdiff" + fi + echo >&2 "merge tool candidates: $tools" + + # Loop over each candidate and stop when a valid merge tool is found. + for i in $tools + do + merge_tool_path="$(translate_merge_tool_path "$i")" + if type "$merge_tool_path" > /dev/null 2>&1; then + merge_tool="$i" + break + fi + done + + if test -z "$merge_tool" ; then + echo >&2 "No known merge resolution program available." + return 1 + fi + echo "$merge_tool" +} + +get_configured_merge_tool () { + # Diff mode first tries diff.tool and falls back to merge.tool. + # Merge mode only checks merge.tool + if diff_mode; then + tool=$(git config diff.tool) + fi + if test -z "$tool"; then + tool=$(git config merge.tool) + fi + if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then + echo >&2 "git config option $TOOL_MODE.tool set to unknown tool: $merge_tool" + echo >&2 "Resetting to default..." + return 1 + fi + echo "$tool" +} + +get_merge_tool_path () { + # A merge tool has been set, so verify that it's valid. + if ! valid_tool "$merge_tool"; then + echo >&2 "Unknown merge tool $merge_tool" + exit 1 + fi + if diff_mode; then + merge_tool_path=$(git config difftool."$merge_tool".path) + fi + if test -z "$merge_tool_path"; then + merge_tool_path=$(git config mergetool."$merge_tool".path) + fi + merge_tool_path="$(translate_merge_tool_path "$merge_tool" "$merge_tool_path")" + if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then + echo >&2 "The $TOOL_MODE tool $merge_tool is not available as '$merge_tool_path'" + exit 1 + fi + echo "$merge_tool_path" +} + +get_merge_tool () { + merge_tool="$1" + # Check if a merge tool has been configured + if test -z "$merge_tool"; then + merge_tool=$(get_configured_merge_tool) + fi + # Try to guess an appropriate merge tool if no tool has been set. + if test -z "$merge_tool"; then + merge_tool=$(guess_merge_tool) || exit + fi + echo "$merge_tool" +} diff --git a/git-mergetool.sh b/git-mergetool.sh index cceebb7210..efa31a228e 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -11,7 +11,9 @@ USAGE='[--tool=tool] [-y|--no-prompt|--prompt] [file to merge] ...' SUBDIRECTORY_OK=Yes OPTIONS_SPEC= +TOOL_MODE=merge . git-sh-setup +. git-mergetool--lib require_work_tree # Returns true if the mode reflects a symlink @@ -110,22 +112,6 @@ resolve_deleted_merge () { done } -check_unchanged () { - if test "$MERGED" -nt "$BACKUP" ; then - status=0; - else - while true; do - echo "$MERGED seems unchanged." - printf "Was the merge successful? [y/n] " - read answer < /dev/tty - case "$answer" in - y*|Y*) status=0; break ;; - n*|N*) status=1; break ;; - esac - done - fi -} - checkout_staged_file () { tmpfile=$(expr "$(git checkout-index --temp --stage="$1" "$2")" : '\([^ ]*\) ') @@ -188,107 +174,11 @@ merge_file () { read ans fi - case "$merge_tool" in - kdiff3) - if base_present ; then - ("$merge_tool_path" --auto --L1 "$MERGED (Base)" --L2 "$MERGED (Local)" --L3 "$MERGED (Remote)" \ - -o "$MERGED" "$BASE" "$LOCAL" "$REMOTE" > /dev/null 2>&1) - else - ("$merge_tool_path" --auto --L1 "$MERGED (Local)" --L2 "$MERGED (Remote)" \ - -o "$MERGED" "$LOCAL" "$REMOTE" > /dev/null 2>&1) - fi - status=$? - ;; - tkdiff) - if base_present ; then - "$merge_tool_path" -a "$BASE" -o "$MERGED" "$LOCAL" "$REMOTE" - else - "$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE" - fi - status=$? - ;; - meld) - touch "$BACKUP" - "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE" - check_unchanged - ;; - vimdiff) - touch "$BACKUP" - "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$MERGED" "$REMOTE" - check_unchanged - ;; - gvimdiff) - touch "$BACKUP" - "$merge_tool_path" -d -c "wincmd l" -f "$LOCAL" "$MERGED" "$REMOTE" - check_unchanged - ;; - xxdiff) - touch "$BACKUP" - if base_present ; then - "$merge_tool_path" -X --show-merged-pane \ - -R 'Accel.SaveAsMerged: "Ctrl-S"' \ - -R 'Accel.Search: "Ctrl+F"' \ - -R 'Accel.SearchForward: "Ctrl-G"' \ - --merged-file "$MERGED" "$LOCAL" "$BASE" "$REMOTE" - else - "$merge_tool_path" -X --show-merged-pane \ - -R 'Accel.SaveAsMerged: "Ctrl-S"' \ - -R 'Accel.Search: "Ctrl+F"' \ - -R 'Accel.SearchForward: "Ctrl-G"' \ - --merged-file "$MERGED" "$LOCAL" "$REMOTE" - fi - check_unchanged - ;; - opendiff) - touch "$BACKUP" - if base_present; then - "$merge_tool_path" "$LOCAL" "$REMOTE" -ancestor "$BASE" -merge "$MERGED" | cat - else - "$merge_tool_path" "$LOCAL" "$REMOTE" -merge "$MERGED" | cat - fi - check_unchanged - ;; - ecmerge) - touch "$BACKUP" - if base_present; then - "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" --default --mode=merge3 --to="$MERGED" - else - "$merge_tool_path" "$LOCAL" "$REMOTE" --default --mode=merge2 --to="$MERGED" - fi - check_unchanged - ;; - emerge) - if base_present ; then - "$merge_tool_path" -f emerge-files-with-ancestor-command "$LOCAL" "$REMOTE" "$BASE" "$(basename "$MERGED")" - else - "$merge_tool_path" -f emerge-files-command "$LOCAL" "$REMOTE" "$(basename "$MERGED")" - fi - status=$? - ;; - tortoisemerge) - if base_present ; then - touch "$BACKUP" - "$merge_tool_path" -base:"$BASE" -mine:"$LOCAL" -theirs:"$REMOTE" -merged:"$MERGED" - check_unchanged - else - echo "TortoiseMerge cannot be used without a base" 1>&2 - status=1 - fi - ;; - *) - if test -n "$merge_tool_cmd"; then - if test "$merge_tool_trust_exit_code" = "false"; then - touch "$BACKUP" - ( eval $merge_tool_cmd ) - check_unchanged - else - ( eval $merge_tool_cmd ) - status=$? - fi - fi - ;; - esac - if test "$status" -ne 0; then + present=false + base_present && + present=true + + if ! run_merge_tool "$merge_tool" "$present"; then echo "merge of $MERGED failed" 1>&2 mv -- "$BACKUP" "$MERGED" @@ -347,44 +237,6 @@ do shift done -valid_custom_tool() -{ - merge_tool_cmd="$(git config mergetool.$1.cmd)" - test -n "$merge_tool_cmd" -} - -valid_tool() { - case "$1" in - kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge | tortoisemerge) - ;; # happy - *) - if ! valid_custom_tool "$1"; then - return 1 - fi - ;; - esac -} - -init_merge_tool_path() { - merge_tool_path=$(git config mergetool.$1.path) - if test -z "$merge_tool_path" ; then - case "$1" in - vimdiff) - merge_tool_path=vim - ;; - gvimdiff) - merge_tool_path=gvim - ;; - emerge) - merge_tool_path=emacs - ;; - *) - merge_tool_path=$1 - ;; - esac - fi -} - prompt_after_failed_merge() { while true; do printf "Continue merging other unresolved paths (y/n) ? " @@ -402,62 +254,12 @@ prompt_after_failed_merge() { done } -if test -z "$merge_tool"; then - merge_tool=$(git config merge.tool) - if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then - echo >&2 "git config option merge.tool set to unknown tool: $merge_tool" - echo >&2 "Resetting to default..." - unset merge_tool - fi -fi - -if test -z "$merge_tool" ; then - if test -n "$DISPLAY"; then - if test -n "$GNOME_DESKTOP_SESSION_ID" ; then - merge_tool_candidates="meld kdiff3 tkdiff xxdiff tortoisemerge gvimdiff diffuse" - else - merge_tool_candidates="kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse" - fi - fi - if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then - merge_tool_candidates="$merge_tool_candidates emerge opendiff vimdiff" - elif echo "${VISUAL:-$EDITOR}" | grep 'vim' > /dev/null 2>&1; then - merge_tool_candidates="$merge_tool_candidates vimdiff opendiff emerge" - else - merge_tool_candidates="$merge_tool_candidates opendiff emerge vimdiff" - fi - echo "merge tool candidates: $merge_tool_candidates" - for i in $merge_tool_candidates; do - init_merge_tool_path $i - if type "$merge_tool_path" > /dev/null 2>&1; then - merge_tool=$i - break - fi - done - if test -z "$merge_tool" ; then - echo "No known merge resolution program available." - exit 1 - fi -else - if ! valid_tool "$merge_tool"; then - echo >&2 "Unknown merge_tool $merge_tool" - exit 1 - fi - - init_merge_tool_path "$merge_tool" - - merge_keep_backup="$(git config --bool merge.keepBackup || echo true)" - merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)" - - if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then - echo "The merge tool $merge_tool is not available as '$merge_tool_path'" - exit 1 - fi - - if ! test -z "$merge_tool_cmd"; then - merge_tool_trust_exit_code="$(git config --bool mergetool.$merge_tool.trustExitCode || echo false)" - fi -fi +merge_tool=$(get_merge_tool "$merge_tool") || exit +merge_tool_cmd="$(get_merge_tool_cmd "$merge_tool")" +merge_tool_path="$(get_merge_tool_path "$merge_tool")" || exit +merge_keep_backup="$(git config --bool merge.keepBackup || echo true)" +merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)" +merge_tool_trust_exit_code="$(git config --bool mergetool."$merge_tool".trustExitCode || echo false)" last_status=0 rollup_status=0 From 8052e788b5e9ae2e2d06b5050fa73394ffe0993a Mon Sep 17 00:00:00 2001 From: Joerg Bornemann <joerg.bornemann@web.de> Date: Mon, 6 Apr 2009 21:59:28 +0200 Subject: [PATCH 405/654] git-gui: fix use of undeclared variable diff_empty_count Commit 584fa9cc introduced the global variable diff_empty_count, which is used in diff.tcl. This variable wasn't declared anywhere which resulted in an ugly error message box instead of the intended informative message. Signed-off-by: Joerg Bornemann <joerg.bornemann@web.de> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- git-gui.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/git-gui.sh b/git-gui.sh index b3aa7325f0..b70e1598dc 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -1108,6 +1108,7 @@ set current_diff_path {} set is_3way_diff 0 set is_conflict_diff 0 set selected_commit_type new +set diff_empty_count 0 set nullid "0000000000000000000000000000000000000000" set nullid2 "0000000000000000000000000000000000000001" From fb25092a88ba889f540beaf9acdb208421ce2a20 Mon Sep 17 00:00:00 2001 From: Ferry Huberts <ferry.huberts@pelagic.nl> Date: Tue, 7 Apr 2009 17:33:35 +0200 Subject: [PATCH 406/654] git-gui: Ensure consistent usage of mergetool.keepBackup In several places merge.keepBackup is used i.s.o. mergetool.keepBackup. This patch makes it all consistent. Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- git-gui.sh | 2 +- lib/mergetool.tcl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui.sh b/git-gui.sh index b70e1598dc..5404f7e4b5 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -699,7 +699,7 @@ proc apply_config {} { set default_config(branch.autosetupmerge) true set default_config(merge.tool) {} -set default_config(merge.keepbackup) true +set default_config(mergetool.keepbackup) true set default_config(merge.diffstat) true set default_config(merge.summary) false set default_config(merge.verbosity) 2 diff --git a/lib/mergetool.tcl b/lib/mergetool.tcl index 3e1b42beb0..3fe90e6970 100644 --- a/lib/mergetool.tcl +++ b/lib/mergetool.tcl @@ -382,7 +382,7 @@ proc merge_tool_finish {fd} { delete_temp_files $mtool_tmpfiles ui_status [mc "Merge tool failed."] } else { - if {[is_config_true merge.keepbackup]} { + if {[is_config_true mergetool.keepbackup]} { file rename -force -- $backup "$mtool_target.orig" } From b4c813bc71f83804302f1c896c91dc499adf1922 Mon Sep 17 00:00:00 2001 From: Jens Lehmann <Jens.Lehmann@web.de> Date: Mon, 6 Apr 2009 21:05:55 +0200 Subject: [PATCH 407/654] git-gui: run post-checkout hook after clone git-gui is using "git-read-tree -u" when cloning which doesn't invoke the post-checkout hook as a plain git-clone would. So git-gui must call the hook itself. Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- lib/choose_repository.tcl | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/choose_repository.tcl b/lib/choose_repository.tcl index 09277e9fa1..633cc572bb 100644 --- a/lib/choose_repository.tcl +++ b/lib/choose_repository.tcl @@ -966,7 +966,34 @@ method _readtree_wait {fd} { return } - set done 1 + # -- Run the post-checkout hook. + # + set fd_ph [githook_read post-checkout [string repeat 0 40] \ + [git rev-parse HEAD] 1] + if {$fd_ph ne {}} { + global pch_error + set pch_error {} + fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} + fileevent $fd_ph readable [cb _postcheckout_wait $fd_ph] + } else { + set done 1 + } +} + +method _postcheckout_wait {fd_ph} { + global pch_error + + append pch_error [read $fd_ph] + fconfigure $fd_ph -blocking 1 + if {[eof $fd_ph]} { + if {[catch {close $fd_ph}]} { + hook_failed_popup post-checkout $pch_error 0 + } + unset pch_error + set done 1 + return + } + fconfigure $fd_ph -blocking 0 } ###################################################################### From b9fdba7ff87d2e032df00508d06e586c17ea8216 Mon Sep 17 00:00:00 2001 From: Paul Mackerras <paulus@samba.org> Date: Thu, 9 Apr 2009 09:34:46 +1000 Subject: [PATCH 408/654] gitk: Add a way to mark a commit, plus a "find descendant" command This adds a context-menu command to put a mark on this commit. There is at most one marked commit at any time, and it is indicated by a box drawn around the headline. Once a commit is marked, two other context-menu commands become available: one to select the marked commit, and another to find the closest common descendant of this commit and the marked commit. The "find common descendant" command uses the displayed parent/child relationships (i.e. the rewritten parent pointers produced by git log), not the real parent/child relationships. Currently the UI will be unresponsive while gitk is working out the nearest common descendant; this should be improved in future. Signed-off-by: Paul Mackerras <paulus@samba.org> --- gitk | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 4 deletions(-) diff --git a/gitk b/gitk index a7294a1476..628f6e5c5b 100755 --- a/gitk +++ b/gitk @@ -2359,6 +2359,9 @@ proc makewindow {} { {mc "Create new branch" command mkbranch} {mc "Cherry-pick this commit" command cherrypick} {mc "Reset HEAD branch to here" command resethead} + {mc "Mark this commit" command markhere} + {mc "Return to mark" command gotomark} + {mc "Find descendant of this and mark" command find_common_desc} } $rowctxmenu configure -tearoff 0 @@ -4074,7 +4077,7 @@ proc ishighlighted {id} { } proc bolden {id font} { - global canv linehtag currentid boldids need_redisplay + global canv linehtag currentid boldids need_redisplay markedid # need_redisplay = 1 means the display is stale and about to be redrawn if {$need_redisplay} return @@ -4087,6 +4090,9 @@ proc bolden {id font} { -fill [$canv cget -selectbackground]] $canv lower $t } + if {[info exists markedid] && $id eq $markedid} { + make_idmark $id + } } proc bolden_name {id font} { @@ -5591,7 +5597,7 @@ proc drawcmittext {id row col} { global cmitlisted commitinfo rowidlist parentlist global rowtextx idpos idtags idheads idotherrefs global linehtag linentag linedtag selectedline - global canvxmax boldids boldnameids fgcolor + global canvxmax boldids boldnameids fgcolor markedid global mainheadid nullid nullid2 circleitem circlecolors ctxbut # listed is 0 for boundary, 1 for normal, 2 for negative, 3 for left, 4 for right @@ -5673,6 +5679,9 @@ proc drawcmittext {id row col} { if {$selectedline == $row} { make_secsel $id } + if {[info exists markedid] && $markedid eq $id} { + make_idmark $id + } set xr [expr {$xt + [font measure $font $headline]}] if {$xr > $canvxmax} { set canvxmax $xr @@ -6614,6 +6623,16 @@ proc make_secsel {id} { $canv3 lower $t } +proc make_idmark {id} { + global linehtag canv fgcolor + + if {![info exists linehtag($id)]} return + $canv delete markid + set t [eval $canv create rect [$canv bbox $linehtag($id)] \ + -tags markid -outline $fgcolor] + $canv raise $t +} + proc selectline {l isnew {desired_loc {}}} { global canv ctext commitinfo selectedline global canvy0 linespc parents children curview @@ -7999,7 +8018,7 @@ proc mstime {} { proc rowmenu {x y id} { global rowctxmenu selectedline rowmenuid curview - global nullid nullid2 fakerowmenu mainhead + global nullid nullid2 fakerowmenu mainhead markedid stopfinding set rowmenuid $id @@ -8015,6 +8034,13 @@ proc rowmenu {x y id} { } else { $menu entryconfigure 7 -label [mc "Detached head: can't reset" $mainhead] -state disabled } + if {[info exists markedid] && $markedid ne $id} { + $menu entryconfigure 9 -state normal + $menu entryconfigure 10 -state normal + } else { + $menu entryconfigure 9 -state disabled + $menu entryconfigure 10 -state disabled + } } else { set menu $fakerowmenu } @@ -8024,6 +8050,59 @@ proc rowmenu {x y id} { tk_popup $menu $x $y } +proc markhere {} { + global rowmenuid markedid canv + + set markedid $rowmenuid + make_idmark $markedid +} + +proc gotomark {} { + global markedid + + if {[info exists markedid]} { + selbyid $markedid + } +} + +proc replace_by_kids {l r} { + global curview children + + set id [commitonrow $r] + set l [lreplace $l 0 0] + foreach kid $children($curview,$id) { + lappend l [rowofcommit $kid] + } + return [lsort -integer -decreasing -unique $l] +} + +proc find_common_desc {} { + global markedid rowmenuid curview children + + if {![info exists markedid]} return + if {![commitinview $markedid $curview] || + ![commitinview $rowmenuid $curview]} return + #set t1 [clock clicks -milliseconds] + set l1 [list [rowofcommit $markedid]] + set l2 [list [rowofcommit $rowmenuid]] + while 1 { + set r1 [lindex $l1 0] + set r2 [lindex $l2 0] + if {$r1 eq {} || $r2 eq {}} break + if {$r1 == $r2} { + selectline $r1 1 + break + } + if {$r1 > $r2} { + set l1 [replace_by_kids $l1 $r1] + } else { + set l2 [replace_by_kids $l2 $r2] + } + } + #set t2 [clock clicks -milliseconds] + #puts "took [expr {$t2-$t1}]ms" +} + proc diffvssel {dirn} { global rowmenuid selectedline @@ -8218,7 +8297,7 @@ proc domktag {} { } proc redrawtags {id} { - global canv linehtag idpos currentid curview cmitlisted + global canv linehtag idpos currentid curview cmitlisted markedid global canvxmax iddrawn circleitem mainheadid circlecolors if {![commitinview $id $curview]} return @@ -8243,6 +8322,9 @@ proc redrawtags {id} { if {[info exists currentid] && $currentid == $id} { make_secsel $id } + if {[info exists markedid] && $markedid eq $id} { + make_idmark $id + } } proc mktagcan {} { @@ -10269,6 +10351,7 @@ proc setfg {c} { } allcanvs itemconf text -fill $c $canv itemconf circle -outline $c + $canv itemconf markid -outline $c } proc prefscan {} { From 499c29394ce1ead3ebd29b0d3c8014cdb7a32e63 Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Fri, 3 Apr 2009 15:32:20 -0400 Subject: [PATCH 409/654] Makefile: allow building without perl For systems with a missing or broken perl, it is nicer to explicitly say "we don't want perl" because: 1. The Makefile knows not to bother with Perl-ish things like Git.pm. 2. We can print a more user-friendly error message than "foo is not a git command" or whatever the broken perl might barf 3. Test scripts that require perl can mark themselves and such and be skipped This patch implements parts (1) and (2). The perl/ subdirectory is skipped entirely, gitweb is not built, and any git commands which rely on perl will print a human-readable message and exit with an error code. This patch is based on one from Robin H. Johnson. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 27 +++++++++++++++++++++++++-- unimplemented.sh | 4 ++++ 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 unimplemented.sh diff --git a/Makefile b/Makefile index bcf7cbb3fb..34b05397de 100644 --- a/Makefile +++ b/Makefile @@ -145,6 +145,8 @@ all:: # Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's # MakeMaker (e.g. using ActiveState under Cygwin). # +# Define NO_PERL if you do not want Perl scripts or libraries at all. +# # Define NO_TCLTK if you do not want Tcl/Tk GUI. # # The TCL_PATH variable governs the location of the Tcl interpreter @@ -353,7 +355,10 @@ BUILT_INS += git-whatchanged$X ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) # what 'all' will build but not install in gitexecdir -OTHER_PROGRAMS = git$X gitweb/gitweb.cgi +OTHER_PROGRAMS = git$X +ifndef NO_PERL +OTHER_PROGRAMS += gitweb/gitweb.cgi +endif # Set paths to tools early so that they can be used for version tests. ifndef SHELL_PATH @@ -1104,6 +1109,10 @@ ifeq ($(TCLTK_PATH),) NO_TCLTK=NoThanks endif +ifeq ($(PERL_PATH),) +NO_PERL=NoThanks +endif + QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir QUIET_SUBDIR1 = @@ -1178,7 +1187,9 @@ ifndef NO_TCLTK $(QUIET_SUBDIR0)git-gui $(QUIET_SUBDIR1) gitexecdir='$(gitexec_instdir_SQ)' all $(QUIET_SUBDIR0)gitk-git $(QUIET_SUBDIR1) all endif +ifndef NO_PERL $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all +endif $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) please_set_SHELL_PATH_to_a_more_modern_shell: @@ -1226,6 +1237,7 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh chmod +x $@+ && \ mv $@+ $@ +ifndef NO_PERL $(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak perl/perl.mak: GIT-CFLAGS perl/Makefile perl/Makefile.PL @@ -1285,6 +1297,15 @@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css $@.sh > $@+ && \ chmod +x $@+ && \ mv $@+ $@ +else # NO_PERL +$(patsubst %.perl,%,$(SCRIPT_PERL)) git-instaweb: % : unimplemented.sh + $(QUIET_GEN)$(RM) $@ $@+ && \ + sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ + -e 's|@@REASON@@|NO_PERL=$(NO_PERL)|g' \ + unimplemented.sh >$@+ && \ + chmod +x $@+ && \ + mv $@+ $@ +endif # NO_PERL configure: configure.ac $(QUIET_GEN)$(RM) $@ $<+ && \ @@ -1603,9 +1624,11 @@ clean: $(RM) -r $(GIT_TARNAME) .doc-tmp-dir $(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz $(RM) $(htmldocs).tar.gz $(manpages).tar.gz - $(RM) gitweb/gitweb.cgi $(MAKE) -C Documentation/ clean +ifndef NO_PERL + $(RM) gitweb/gitweb.cgi $(MAKE) -C perl clean +endif $(MAKE) -C templates/ clean $(MAKE) -C t/ clean ifndef NO_TCLTK diff --git a/unimplemented.sh b/unimplemented.sh new file mode 100644 index 0000000000..5252de4b25 --- /dev/null +++ b/unimplemented.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +echo >&2 "fatal: git was built without support for `basename $0` (@@REASON@@)." +exit 128 From 1b19ccd236e3369ac77d74ded207406ffbf9feca Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Fri, 3 Apr 2009 15:33:59 -0400 Subject: [PATCH 410/654] tests: skip perl tests if NO_PERL is defined These scripts all test git programs that are written in perl, and thus obviously won't work if NO_PERL is defined. We pass NO_PERL to the scripts from the building Makefile via the GIT-BUILD-OPTIONS file. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 1 + t/lib-git-svn.sh | 4 ++++ t/t3701-add-interactive.sh | 5 +++++ t/t7501-commit.sh | 4 ++-- t/t9001-send-email.sh | 5 +++++ t/t9200-git-cvsexportcommit.sh | 5 +++++ t/t9400-git-cvsserver-server.sh | 4 ++++ t/t9401-git-cvsserver-crlf.sh | 5 +++++ t/t9500-gitweb-standalone-no-errors.sh | 5 +++++ t/t9600-cvsimport.sh | 5 +++++ t/t9700-perl-git.sh | 5 +++++ t/test-lib.sh | 2 ++ 12 files changed, 48 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 34b05397de..a865a46053 100644 --- a/Makefile +++ b/Makefile @@ -1422,6 +1422,7 @@ GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@ @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@ @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@ + @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@ ### Detect Tck/Tk interpreter path changes ifndef NO_TCLTK diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh index cdd7ccdd2a..773d47cf3c 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -8,6 +8,10 @@ then say 'skipping git svn tests, NO_SVN_TESTS defined' test_done fi +if ! test_have_prereq PERL; then + say 'skipping git svn tests, perl not available' + test_done +fi GIT_DIR=$PWD/.git GIT_SVN_DIR=$GIT_DIR/svn/git-svn diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index fe017839c4..dfc65601aa 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -3,6 +3,11 @@ test_description='add -i basic tests' . ./test-lib.sh +if ! test_have_prereq PERL; then + say 'skipping git add -i tests, perl not available' + test_done +fi + test_expect_success 'setup (initial)' ' echo content >file && git add file && diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index b4e2b4db84..e2ef53228e 100755 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -38,7 +38,7 @@ test_expect_success \ "echo King of the bongo >file && test_must_fail git commit -m foo -a file" -test_expect_success \ +test_expect_success PERL \ "using paths with --interactive" \ "echo bong-o-bong >file && ! (echo 7 | git commit -m foo --interactive file)" @@ -119,7 +119,7 @@ test_expect_success \ "echo 'gak' >file && \ git commit -m 'author' --author 'Rubber Duck <rduck@convoy.org>' -a" -test_expect_success \ +test_expect_success PERL \ "interactive add" \ "echo 7 | git commit --interactive | grep 'What now'" diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 3c90c4fc1c..d9420e0a3b 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -3,6 +3,11 @@ test_description='git send-email' . ./test-lib.sh +if ! test_have_prereq PERL; then + say 'skipping git send-email tests, perl not available' + test_done +fi + PROG='git send-email' test_expect_success \ 'prepare reference tree' \ diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index 36656923ac..56b7c06921 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -6,6 +6,11 @@ test_description='Test export of commits to CVS' . ./test-lib.sh +if ! test_have_prereq PERL; then + say 'skipping git cvsexportcommit tests, perl not available' + test_done +fi + cvs >/dev/null 2>&1 if test $? -ne 1 then diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index 39185db6c9..64f947d75b 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -10,6 +10,10 @@ cvs CLI client via git-cvsserver server' . ./test-lib.sh +if ! test_have_prereq PERL; then + say 'skipping git cvsserver tests, perl not available' + test_done +fi cvs >/dev/null 2>&1 if test $? -ne 1 then diff --git a/t/t9401-git-cvsserver-crlf.sh b/t/t9401-git-cvsserver-crlf.sh index 12e0e50822..aca40c1b1f 100755 --- a/t/t9401-git-cvsserver-crlf.sh +++ b/t/t9401-git-cvsserver-crlf.sh @@ -52,6 +52,11 @@ then say 'skipping git-cvsserver tests, cvs not found' test_done fi +if ! test_have_prereq PERL +then + say 'skipping git-cvsserver tests, perl not available' + test_done +fi perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || { say 'skipping git-cvsserver tests, Perl SQLite interface unavailable' test_done diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 0bd332c493..f4210fbb04 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -65,6 +65,11 @@ gitweb_run () { . ./test-lib.sh +if ! test_have_prereq PERL; then + say 'skipping gitweb tests, perl not available' + test_done +fi + perl -MEncode -e 'decode_utf8("", Encode::FB_CROAK)' >/dev/null 2>&1 || { say 'skipping gitweb tests, perl version is too old' test_done diff --git a/t/t9600-cvsimport.sh b/t/t9600-cvsimport.sh index 33eb51938d..4322a0c1ed 100755 --- a/t/t9600-cvsimport.sh +++ b/t/t9600-cvsimport.sh @@ -3,6 +3,11 @@ test_description='git cvsimport basic tests' . ./test-lib.sh +if ! test_have_prereq PERL; then + say 'skipping git cvsimport tests, perl not available' + test_done +fi + CVSROOT=$(pwd)/cvsroot export CVSROOT unset CVS_SERVER diff --git a/t/t9700-perl-git.sh b/t/t9700-perl-git.sh index 4a501c6847..b4ca244626 100755 --- a/t/t9700-perl-git.sh +++ b/t/t9700-perl-git.sh @@ -6,6 +6,11 @@ test_description='perl interface (Git.pm)' . ./test-lib.sh +if ! test_have_prereq PERL; then + say 'skipping perl interface tests, perl not available' + test_done +fi + perl -MTest::More -e 0 2>/dev/null || { say "Perl Test::More unavailable, skipping test" test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index b050196cb7..4bd986f430 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -698,6 +698,8 @@ case $(uname -s) in ;; esac +test -z "$NO_PERL" && test_set_prereq PERL + # test whether the filesystem supports symbolic links ln -s x y 2>/dev/null && test -h y 2>/dev/null && test_set_prereq SYMLINKS rm -f y From e37347bba651f051998f23a3701b555f1a194557 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Thu, 9 Apr 2009 00:04:17 -0700 Subject: [PATCH 411/654] Update draft release notes to 1.6.3 Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/RelNotes-1.6.3.txt | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/Documentation/RelNotes-1.6.3.txt b/Documentation/RelNotes-1.6.3.txt index 517c783b5d..9aa143b199 100644 --- a/Documentation/RelNotes-1.6.3.txt +++ b/Documentation/RelNotes-1.6.3.txt @@ -40,6 +40,9 @@ Updates since v1.6.2 * many uses of lstat(2) in the codepath for "git checkout" have been optimized out. +* pruning reflog entries that are unreachable from the tip of the ref + during "git reflog prune" (hence "git gc") was very inefficient. + (usability, bells and whistles) * rsync:/path/to/repo can be used to run git over rsync for local @@ -56,7 +59,7 @@ Updates since v1.6.2 spelled as "--format=<style>". In addition, --format=%formatstring is a short-hand for --pretty=tformat:%formatstring. -* "--oneline" is a synonym for "--pretty=oneline --abbrev=commit". +* "--oneline" is a synonym for "--pretty=oneline --abbrev-commit". * If you realize that you botched the patch when you are editing hunks with the 'edit' action in git-add -i/-p, you can abort the editor to @@ -66,6 +69,10 @@ Updates since v1.6.2 messages given by "git checkout" and "git status" used to count merge commits; now it doesn't. +* @{-1} is a new way to refer to the last branch you were on introduced in + 1.6.2, but the initial implementation did not teach this to a few + commands. Now the syntax works with "branch -m @{-1} newname". + * git-archive learned --output=<file> option. * git-bisect shows not just the number of remaining commits whose goodness @@ -88,10 +95,16 @@ Updates since v1.6.2 * git-format-patch can be told to produce deep or shallow message threads. +* git-format-patch can be told to always add sign-off with a configuration + variable. + * git-format-patch learned format.headers configuration to add extra header fields to the output. This behaviour is similar to the existing --add-header=<header> option of the command. +* git-format-patch gives human readable names to the attached files, when + told to send patches as attachments. + * git-grep learned to highlight the found substrings in color. * git-imap-send learned to work around Thunderbird's inability to easily @@ -136,11 +149,23 @@ v1.6.2.X series. * The initial checkout did not read the attributes from the .gitattribute file that is being checked out. +* "git-checkout <tree-ish> <submodule>" did not update the index entry at + the named path; it now does. + * git-gc spent excessive amount of time to decide if an object appears in a locally existing pack (if needed, backport by merging 69e020a). +* "git-ls-tree" and "git-diff-tree" used a pathspec correctly when + deciding to descend into a subdirectory but they did not match the + individual paths correctly. This caused pathspecs "abc/d ab" to match + "abc/0" ("abc/d" made them decide to descend into the directory "abc/", + and then "ab" incorrectly matched "abc/0" when it shouldn't). + +* "git-merge-recursive" was broken when a submodule entry was involved in + a criss-cross merge situation. + --- exec >/var/tmp/1 -O=v1.6.2.2-403-g8130949 +O=v1.6.2.2-484-g796b137 echo O=$(git describe master) git shortlog --no-merges $O..master ^maint From 27845e9548b7b5b316d89f64546466f2004ee414 Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Mon, 6 Apr 2009 16:18:23 -0400 Subject: [PATCH 412/654] add tests for remote groups This tries to systematically cover existing behavior, and also mark some expect_failure cases for desired behavior. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t5506-remote-groups.sh | 81 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100755 t/t5506-remote-groups.sh diff --git a/t/t5506-remote-groups.sh b/t/t5506-remote-groups.sh new file mode 100755 index 0000000000..2a1806b0b4 --- /dev/null +++ b/t/t5506-remote-groups.sh @@ -0,0 +1,81 @@ +#!/bin/sh + +test_description='git remote group handling' +. ./test-lib.sh + +mark() { + echo "$1" >mark +} + +update_repo() { + (cd $1 && + echo content >>file && + git add file && + git commit -F ../mark) +} + +update_repos() { + update_repo one $1 && + update_repo two $1 +} + +repo_fetched() { + if test "`git log -1 --pretty=format:%s $1 --`" = "`cat mark`"; then + echo >&2 "repo was fetched: $1" + return 0 + fi + echo >&2 "repo was not fetched: $1" + return 1 +} + +test_expect_success 'setup' ' + mkdir one && (cd one && git init) && + mkdir two && (cd two && git init) && + git remote add -m master one one && + git remote add -m master two two +' + +test_expect_success 'no group updates all' ' + mark update-all && + update_repos && + git remote update && + repo_fetched one && + repo_fetched two +' + +test_expect_success 'nonexistant group produces error' ' + mark nonexistant && + update_repos && + test_must_fail git remote update nonexistant && + ! repo_fetched one && + ! repo_fetched two +' + +test_expect_success 'updating group updates all members' ' + mark group-all && + update_repos && + git config --add remotes.all one && + git config --add remotes.all two && + git remote update all && + repo_fetched one && + repo_fetched two +' + +test_expect_success 'updating group does not update non-members' ' + mark group-some && + update_repos && + git config --add remotes.some one && + git remote update some && + repo_fetched one && + ! repo_fetched two +' + +test_expect_success 'updating remote name updates that remote' ' + mark remote-name && + update_repos && + git remote update one && + repo_fetched one && + ! repo_fetched two +' + +test_done From 010509f2de86d14c1da26eeafffb0864269c1232 Mon Sep 17 00:00:00 2001 From: Paul Mackerras <paulus@samba.org> Date: Thu, 9 Apr 2009 22:10:20 +1000 Subject: [PATCH 413/654] gitk: Add a command to compare two strings of commits This adds a row context menu command to compare this commit and its descendants with the marked commit and its descendants. The results are shown in the bottom-left pane. Commits are compared by checking whether their headlines are the same and their patches have the same patch ID as generated by git patch-id. Merges are ignored and skipped over (as long as they have one descendant). If two commits have the same patch ID then the process will continue and compare their descendants, as long as they both have exactly one descendant. If either commit has 0 or 2 or more descendants, the comparison stops there. There is currently a limit of 100 comparisons. This can be useful for checking whether one string of commits is just a rebased version of another string of commits. Mark the end of one string (i.e. the oldest commit in the string) and invoke "Compare with marked commit" on the end of the other string. As this is implemented, the UI will be unresponsive while the results are being generated. This should be fixed. Signed-off-by: Paul Mackerras <paulus@samba.org> --- gitk | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/gitk b/gitk index 628f6e5c5b..bdd12236b8 100755 --- a/gitk +++ b/gitk @@ -2362,6 +2362,7 @@ proc makewindow {} { {mc "Mark this commit" command markhere} {mc "Return to mark" command gotomark} {mc "Find descendant of this and mark" command find_common_desc} + {mc "Compare with marked commit" command compare_commits} } $rowctxmenu configure -tearoff 0 @@ -8037,9 +8038,11 @@ proc rowmenu {x y id} { if {[info exists markedid] && $markedid ne $id} { $menu entryconfigure 9 -state normal $menu entryconfigure 10 -state normal + $menu entryconfigure 11 -state normal } else { $menu entryconfigure 9 -state disabled $menu entryconfigure 10 -state disabled + $menu entryconfigure 11 -state disabled } } else { set menu $fakerowmenu @@ -8103,6 +8106,92 @@ proc find_common_desc {} { #puts "took [expr {$t2-$t1}]ms" } +proc compare_commits {} { + global markedid rowmenuid curview children + + if {![info exists markedid]} return + if {![commitinview $markedid $curview]} return + addtohistory [list do_cmp_commits $markedid $rowmenuid] + do_cmp_commits $markedid $rowmenuid +} + +proc getpatchid {id} { + global patchids + + if {![info exists patchids($id)]} { + set x [exec git diff-tree -p --root $id | git patch-id] + set patchids($id) [lindex $x 0] + } + return $patchids($id) +} + +proc do_cmp_commits {a b} { + global ctext curview parents children patchids commitinfo + + $ctext conf -state normal + clear_ctext + init_flist {} + for {set i 0} {$i < 100} {incr i} { + set shorta [string range $a 0 7] + set shortb [string range $b 0 7] + set skipa 0 + set skipb 0 + if {[llength $parents($curview,$a)] > 1} { + appendwithlinks [mc "Skipping merge commit %s\n" $shorta] {} + set skipa 1 + } else { + set patcha [getpatchid $a] + } + if {[llength $parents($curview,$b)] > 1} { + appendwithlinks [mc "Skipping merge commit %s\n" $shortb] {} + set skipb 1 + } else { + set patchb [getpatchid $b] + } + if {!$skipa && !$skipb} { + set heada [lindex $commitinfo($a) 0] + set headb [lindex $commitinfo($b) 0] + if {$patcha eq $patchb} { + if {$heada eq $headb} { + appendwithlinks [mc "Commit %s == %s %s\n" \ + $shorta $shortb $heada] {} + } else { + appendwithlinks [mc "Commit %s %s\n" $shorta $heada] {} + appendwithlinks [mc " is the same patch as\n"] {} + appendwithlinks [mc " %s %s\n" $shortb $headb] {} + } + set skipa 1 + set skipb 1 + } else { + $ctext insert end "\n" + appendwithlinks [mc "Commit %s %s\n" $shorta $heada] {} + appendwithlinks [mc " differs from\n"] {} + appendwithlinks [mc " %s %s\n" $shortb $headb] {} + appendwithlinks [mc "- stopping\n"] + break + } + } + if {$skipa} { + if {[llength $children($curview,$a)] != 1} { + $ctext insert end "\n" + appendwithlinks [mc "Commit %s has %s children - stopping\n" \ + $shorta [llength $children($curview,$a)]] {} + break + } + set a [lindex $children($curview,$a) 0] + } + if {$skipb} { + if {[llength $children($curview,$b)] != 1} { + appendwithlinks [mc "Commit %s has %s children - stopping\n" \ + $shortb [llength $children($curview,$b)]] {} + break + } + set b [lindex $children($curview,$b) 0] + } + } + $ctext conf -state disabled +} + proc diffvssel {dirn} { global rowmenuid selectedline From 8f8c6fafd92fd547547bd7735e2d121a20997703 Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@linux-foundation.org> Date: Thu, 9 Apr 2009 12:40:39 -0700 Subject: [PATCH 414/654] Allow users to un-configure rename detection On Thu, 9 Apr 2009, Linus Torvalds wrote: > > [diff] > renames = no Btw, while doing this, I also though that "renames = on/off" made more sense, but while we allow yes/no and true/false for booleans, we don't allow on/off. Should we? Maybe. Here's a stupid patch. Linus Signed-off-by: Junio C Hamano <gitster@pobox.com> --- config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.c b/config.c index b76fe4c6dc..e7d91f5847 100644 --- a/config.c +++ b/config.c @@ -331,9 +331,9 @@ int git_config_bool_or_int(const char *name, const char *value, int *is_bool) return 1; if (!*value) return 0; - if (!strcasecmp(value, "true") || !strcasecmp(value, "yes")) + if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on")) return 1; - if (!strcasecmp(value, "false") || !strcasecmp(value, "no")) + if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off")) return 0; *is_bool = 0; return git_config_int(name, value); From 79f72b97633d1699f131e798bb9833339ba22f6a Mon Sep 17 00:00:00 2001 From: Erik Broes <erikbroes@ripe.net> Date: Thu, 9 Apr 2009 21:58:52 +0200 Subject: [PATCH 415/654] git-shell: Add 'git-upload-archive' to allowed commands. This allows for example gitosis to allow use of 'git archive --remote' in a controlled environment. Signed-off-by: Erik Broes <erikbroes@ripe.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-shell.txt | 6 +++--- shell.c | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Documentation/git-shell.txt b/Documentation/git-shell.txt index 3f8d973af1..0f3ad811cf 100644 --- a/Documentation/git-shell.txt +++ b/Documentation/git-shell.txt @@ -18,9 +18,9 @@ of server-side GIT commands implementing the pull/push functionality. The commands can be executed only by the '-c' option; the shell is not interactive. -Currently, only three commands are permitted to be called, 'git-receive-pack' -'git-upload-pack' with a single required argument or 'cvs server' (to invoke -'git-cvsserver'). +Currently, only four commands are permitted to be called, 'git-receive-pack' +'git-upload-pack' and 'git-upload-archive' with a single required argument, or +'cvs server' (to invoke 'git-cvsserver'). Author ------ diff --git a/shell.c b/shell.c index e3393690dd..b968be79f4 100644 --- a/shell.c +++ b/shell.c @@ -40,6 +40,7 @@ static struct commands { } cmd_list[] = { { "git-receive-pack", do_generic_cmd }, { "git-upload-pack", do_generic_cmd }, + { "git-upload-archive", do_generic_cmd }, { "cvs", do_cvs_cmd }, { NULL }, }; From 70af4e9bef988a98061237c78cbd0a71d8de48bb Mon Sep 17 00:00:00 2001 From: Ferry Huberts <ferry.huberts@pelagic.nl> Date: Fri, 10 Apr 2009 21:33:57 +0200 Subject: [PATCH 416/654] Fix misspelled mergetool.keepBackup In several places mergetool.keepBackup was misspelled as merge.keepBackup. Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-mergetool.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-mergetool.sh b/git-mergetool.sh index efa31a228e..2e3e02b3b5 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -257,7 +257,7 @@ prompt_after_failed_merge() { merge_tool=$(get_merge_tool "$merge_tool") || exit merge_tool_cmd="$(get_merge_tool_cmd "$merge_tool")" merge_tool_path="$(get_merge_tool_path "$merge_tool")" || exit -merge_keep_backup="$(git config --bool merge.keepBackup || echo true)" +merge_keep_backup="$(git config --bool mergetool.keepBackup || echo true)" merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)" merge_tool_trust_exit_code="$(git config --bool mergetool."$merge_tool".trustExitCode || echo false)" From c2abd83fea0c332e907f5bc23bea4eeca091a86b Mon Sep 17 00:00:00 2001 From: Jason Merrill <jason@redhat.com> Date: Mon, 6 Apr 2009 16:37:59 -0400 Subject: [PATCH 417/654] git-svn: add fetch --parent option Signed-off-by: Jason Merrill <jason@redhat.com> Acked-By: Eric Wong <normalperson@yhbt.net> --- Documentation/git-svn.txt | 3 +++ git-svn.perl | 18 ++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index b7b1af813d..85b2c8da5d 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -97,6 +97,9 @@ COMMANDS makes 'git-log' (even without --date=local) show the same times that `svn log` would in the local timezone. +--parent;; + Fetch only from the SVN parent of the current HEAD. + This doesn't interfere with interoperating with the Subversion repository you cloned from, but if you wish for your local Git repository to be able to interoperate with someone else's local Git diff --git a/git-svn.perl b/git-svn.perl index d9197989d2..cb718b8519 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -63,7 +63,7 @@ $sha1_short = qr/[a-f\d]{4,40}/; my ($_stdin, $_help, $_edit, $_message, $_file, $_template, $_shared, - $_version, $_fetch_all, $_no_rebase, + $_version, $_fetch_all, $_no_rebase, $_fetch_parent, $_merge, $_strategy, $_dry_run, $_local, $_prefix, $_no_checkout, $_url, $_verbose, $_git_format, $_commit_url, $_tag); @@ -112,6 +112,7 @@ my %cmd = ( fetch => [ \&cmd_fetch, "Download new revisions from SVN", { 'revision|r=s' => \$_revision, 'fetch-all|all' => \$_fetch_all, + 'parent|p' => \$_fetch_parent, %fc_opts } ], clone => [ \&cmd_clone, "Initialize and fetch revisions", { 'revision|r=s' => \$_revision, @@ -381,12 +382,21 @@ sub cmd_fetch { } my ($remote) = @_; if (@_ > 1) { - die "Usage: $0 fetch [--all] [svn-remote]\n"; + die "Usage: $0 fetch [--all] [--parent] [svn-remote]\n"; } - $remote ||= $Git::SVN::default_repo_id; - if ($_fetch_all) { + if ($_fetch_parent) { + my ($url, $rev, $uuid, $gs) = working_head_info('HEAD'); + unless ($gs) { + die "Unable to determine upstream SVN information from ", + "working tree history\n"; + } + # just fetch, don't checkout. + $_no_checkout = 'true'; + $_fetch_all ? $gs->fetch_all : $gs->fetch; + } elsif ($_fetch_all) { cmd_multi_fetch(); } else { + $remote ||= $Git::SVN::default_repo_id; Git::SVN::fetch_all($remote, Git::SVN::read_all_remotes()); } } From 6ea420328885603087b3f1df42683c911d1b3f29 Mon Sep 17 00:00:00 2001 From: Boris Byk <boris.byk@gmail.com> Date: Sat, 11 Apr 2009 00:32:41 +0400 Subject: [PATCH 418/654] git-svn: speed up blame command 'git svn blame' now uses the 'git cat-file --batch' command to speed up resolving SVN revision number out of commit SHA by removing fork+exec overhead. [ew: enforced 80-column line wrap] Signed-off-by: Boris Byk <boris.byk@gmail.com> Acked-by: Eric Wong <normalperson@yhbt.net> --- git-svn.perl | 54 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/git-svn.perl b/git-svn.perl index cb718b8519..50a398b3e7 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -47,7 +47,8 @@ BEGIN { # import functions from Git into our packages, en masse no strict 'refs'; foreach (qw/command command_oneline command_noisy command_output_pipe - command_input_pipe command_close_pipe/) { + command_input_pipe command_close_pipe + command_bidi_pipe command_close_bidi_pipe/) { for my $package ( qw(SVN::Git::Editor SVN::Git::Fetcher Git::SVN::Migration Git::SVN::Log Git::SVN), __PACKAGE__) { @@ -1264,6 +1265,40 @@ sub cmt_metadata { command(qw/cat-file commit/, shift)))[-1]); } +sub cmt_sha2rev_batch { + my %s2r; + my ($pid, $in, $out, $ctx) = command_bidi_pipe(qw/cat-file --batch/); + my $list = shift; + + foreach my $sha (@{$list}) { + my $first = 1; + my $size = 0; + print $out $sha, "\n"; + + while (my $line = <$in>) { + if ($first && $line =~ /^[[:xdigit:]]{40}\smissing$/) { + last; + } elsif ($first && + $line =~ /^[[:xdigit:]]{40}\scommit\s(\d+)$/) { + $first = 0; + $size = $1; + next; + } elsif ($line =~ /^(git-svn-id: )/) { + my (undef, $rev, undef) = + extract_metadata($line); + $s2r{$sha} = $rev; + } + + $size -= length($line); + last if ($size == 0); + } + } + + command_close_bidi_pipe($pid, $in, $out, $ctx); + + return \%s2r; +} + sub working_head_info { my ($head, $refs) = @_; my @args = ('log', '--no-color', '--first-parent', '--pretty=medium'); @@ -5001,11 +5036,22 @@ sub cmd_blame { '--', $path); my ($sha1); my %authors; + my @buffer; + my %dsha; #distinct sha keys + while (my $line = <$fh>) { + push @buffer, $line; if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) { - $sha1 = $1; - (undef, $rev, undef) = ::cmt_metadata($1); - $rev = '0' if (!$rev); + $dsha{$1} = 1; + } + } + + my $s2r = ::cmt_sha2rev_batch([keys %dsha]); + + foreach my $line (@buffer) { + if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) { + $rev = $s2r->{$1}; + $rev = '0' if (!$rev) } elsif ($line =~ /^author (.*)/) { $authors{$rev} = $1; From 0d8bee71af1cda3d13d896c210773216dcf87b7c Mon Sep 17 00:00:00 2001 From: Ben Jackson <ben@ben.com> Date: Sat, 11 Apr 2009 10:46:17 -0700 Subject: [PATCH 419/654] git-svn: Add per-svn-remote ignore-paths config The --ignore-paths option to fetch is very useful for working on a subset of a SVN repository. For proper operation, every command that causes a fetch (explicit or implied) must include a matching --ignore-paths option. This patch adds a persistent svn-remote.$repo_id.ignore-paths config by promoting Fetcher::is_path_ignored to a member function and initializing $self->{ignore_regex} in Fetcher::new. Command line --ignore-paths is still recognized and acts in addition to the config value. Signed-off-by: Ben Jackson <ben@ben.com> Acked-by: Eric Wong <normalperson@yhbt.net> --- Documentation/git-svn.txt | 22 ++++++++----- git-svn.perl | 26 +++++++++------- t/t9134-git-svn-ignore-paths.sh | 55 +++++++++++++++++++++++++++++++-- 3 files changed, 82 insertions(+), 21 deletions(-) diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index 85b2c8da5d..aad5e65c70 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -107,17 +107,25 @@ repository, either don't use this option or you should both use it in the same local timezone. --ignore-paths=<regex>;; - This allows one to specify Perl regular expression that will + This allows one to specify a Perl regular expression that will cause skipping of all matching paths from checkout from SVN. - Examples: + The '--ignore-paths' option should match for every 'fetch' + (including automatic fetches due to 'clone', 'dcommit', + 'rebase', etc) on a given repository. - --ignore-paths="^doc" - skip "doc*" directory for every fetch. +config key: svn-remote.<name>.ignore-paths - --ignore-paths="^[^/]+/(?:branches|tags)" - skip "branches" - and "tags" of first level directories. + If the ignore-paths config key is set and the command + line option is also given, both regular expressions + will be used. - Regular expression is not persistent, you should specify - it every time when fetching. +Examples: + + --ignore-paths="^doc" - skip "doc*" directory for every + fetch. + + --ignore-paths="^[^/]+/(?:branches|tags)" - skip + "branches" and "tags" of first level directories. 'clone':: Runs 'init' and 'fetch'. It will automatically create a diff --git a/git-svn.perl b/git-svn.perl index 50a398b3e7..279847921b 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -3331,6 +3331,8 @@ sub new { $self->{empty_symlinks} = _mark_empty_symlinks($git_svn, $switch_path); } + $self->{ignore_regex} = eval { command_oneline('config', '--get', + "svn-remote.$git_svn->{repo_id}.ignore-paths") }; $self->{empty} = {}; $self->{dir_prop} = {}; $self->{file_prop} = {}; @@ -3395,8 +3397,10 @@ sub in_dot_git { # return value: 0 -- don't ignore, 1 -- ignore sub is_path_ignored { - my ($path) = @_; + my ($self, $path) = @_; return 1 if in_dot_git($path); + return 1 if defined($self->{ignore_regex}) && + $path =~ m!$self->{ignore_regex}!; return 0 unless defined($_ignore_regex); return 1 if $path =~ m!$_ignore_regex!o; return 0; @@ -3427,7 +3431,7 @@ sub git_path { sub delete_entry { my ($self, $path, $rev, $pb) = @_; - return undef if is_path_ignored($path); + return undef if $self->is_path_ignored($path); my $gpath = $self->git_path($path); return undef if ($gpath eq ''); @@ -3460,7 +3464,7 @@ sub open_file { my ($self, $path, $pb, $rev) = @_; my ($mode, $blob); - goto out if is_path_ignored($path); + goto out if $self->is_path_ignored($path); my $gpath = $self->git_path($path); ($mode, $blob) = (command('ls-tree', '-z', $self->{c}, "./$gpath") @@ -3480,7 +3484,7 @@ sub add_file { my ($self, $path, $pb, $cp_path, $cp_rev) = @_; my $mode; - if (!is_path_ignored($path)) { + if (!$self->is_path_ignored($path)) { my ($dir, $file) = ($path =~ m#^(.*?)/?([^/]+)$#); delete $self->{empty}->{$dir}; $mode = '100644'; @@ -3491,7 +3495,7 @@ sub add_file { sub add_directory { my ($self, $path, $cp_path, $cp_rev) = @_; - goto out if is_path_ignored($path); + goto out if $self->is_path_ignored($path); my $gpath = $self->git_path($path); if ($gpath eq '') { my ($ls, $ctx) = command_output_pipe(qw/ls-tree @@ -3515,7 +3519,7 @@ out: sub change_dir_prop { my ($self, $db, $prop, $value) = @_; - return undef if is_path_ignored($db->{path}); + return undef if $self->is_path_ignored($db->{path}); $self->{dir_prop}->{$db->{path}} ||= {}; $self->{dir_prop}->{$db->{path}}->{$prop} = $value; undef; @@ -3523,7 +3527,7 @@ sub change_dir_prop { sub absent_directory { my ($self, $path, $pb) = @_; - return undef if is_path_ignored($path); + return undef if $self->is_path_ignored($path); $self->{absent_dir}->{$pb->{path}} ||= []; push @{$self->{absent_dir}->{$pb->{path}}}, $path; undef; @@ -3531,7 +3535,7 @@ sub absent_directory { sub absent_file { my ($self, $path, $pb) = @_; - return undef if is_path_ignored($path); + return undef if $self->is_path_ignored($path); $self->{absent_file}->{$pb->{path}} ||= []; push @{$self->{absent_file}->{$pb->{path}}}, $path; undef; @@ -3539,7 +3543,7 @@ sub absent_file { sub change_file_prop { my ($self, $fb, $prop, $value) = @_; - return undef if is_path_ignored($fb->{path}); + return undef if $self->is_path_ignored($fb->{path}); if ($prop eq 'svn:executable') { if ($fb->{mode_b} != 120000) { $fb->{mode_b} = defined $value ? 100755 : 100644; @@ -3555,7 +3559,7 @@ sub change_file_prop { sub apply_textdelta { my ($self, $fb, $exp) = @_; - return undef if is_path_ignored($fb->{path}); + return undef if $self->is_path_ignored($fb->{path}); my $fh = $::_repository->temp_acquire('svn_delta'); # $fh gets auto-closed() by SVN::TxDelta::apply(), # (but $base does not,) so dup() it for reading in close_file @@ -3602,7 +3606,7 @@ sub apply_textdelta { sub close_file { my ($self, $fb, $exp) = @_; - return undef if is_path_ignored($fb->{path}); + return undef if $self->is_path_ignored($fb->{path}); my $hash; my $path = $self->git_path($fb->{path}); diff --git a/t/t9134-git-svn-ignore-paths.sh b/t/t9134-git-svn-ignore-paths.sh index c4b5b8bcf7..b9a15978eb 100755 --- a/t/t9134-git-svn-ignore-paths.sh +++ b/t/t9134-git-svn-ignore-paths.sh @@ -31,6 +31,22 @@ test_expect_success 'clone an SVN repository with ignored www directory' ' test_cmp expect expect2 ' +test_expect_success 'init+fetch an SVN repository with ignored www directory' ' + git svn init "$svnrepo" c && + ( cd c && git svn fetch --ignore-paths="^www" ) && + rm expect2 && + echo test_qqq > expect && + for i in c/*/*.txt; do cat $i >> expect2; done && + test_cmp expect expect2 +' + +test_expect_success 'set persistent ignore-paths config' ' + ( + cd g && + git config svn-remote.svn.ignore-paths "^www" + ) +' + test_expect_success 'SVN-side change outside of www' ' ( cd s && @@ -41,9 +57,20 @@ test_expect_success 'SVN-side change outside of www' ' ) ' -test_expect_success 'update git svn-cloned repo' ' +test_expect_success 'update git svn-cloned repo (config ignore)' ' ( cd g && + git svn rebase && + printf "test_qqq\nb\n" > expect && + for i in */*.txt; do cat $i >> expect2; done && + test_cmp expect2 expect && + rm expect expect2 + ) +' + +test_expect_success 'update git svn-cloned repo (option ignore)' ' + ( + cd c && git svn rebase --ignore-paths="^www" && printf "test_qqq\nb\n" > expect && for i in */*.txt; do cat $i >> expect2; done && @@ -62,9 +89,20 @@ test_expect_success 'SVN-side change inside of ignored www' ' ) ' -test_expect_success 'update git svn-cloned repo' ' +test_expect_success 'update git svn-cloned repo (config ignore)' ' ( cd g && + git svn rebase && + printf "test_qqq\nb\n" > expect && + for i in */*.txt; do cat $i >> expect2; done && + test_cmp expect2 expect && + rm expect expect2 + ) +' + +test_expect_success 'update git svn-cloned repo (option ignore)' ' + ( + cd c && git svn rebase --ignore-paths="^www" && printf "test_qqq\nb\n" > expect && for i in */*.txt; do cat $i >> expect2; done && @@ -84,9 +122,20 @@ test_expect_success 'SVN-side change in and out of ignored www' ' ) ' -test_expect_success 'update git svn-cloned repo again' ' +test_expect_success 'update git svn-cloned repo again (config ignore)' ' ( cd g && + git svn rebase && + printf "test_qqq\nb\nygg\n" > expect && + for i in */*.txt; do cat $i >> expect2; done && + test_cmp expect2 expect && + rm expect expect2 + ) +' + +test_expect_success 'update git svn-cloned repo again (option ignore)' ' + ( + cd c && git svn rebase --ignore-paths="^www" && printf "test_qqq\nb\nygg\n" > expect && for i in */*.txt; do cat $i >> expect2; done && From 88ec205477e18e612ab854f20ef87aa244b8debe Mon Sep 17 00:00:00 2001 From: Ben Jackson <ben@ben.com> Date: Sat, 11 Apr 2009 10:46:18 -0700 Subject: [PATCH 420/654] git-svn: Save init/clone --ignore-paths in config The --ignored-paths argument is now stored as "svn-remote.$REMOTE_NAME.ignore-paths" in the config file. [ew: edited subject and message] Signed-off-by: Ben Jackson <ben@ben.com> Acked-by: Eric Wong <normalperson@yhbt.net> --- Documentation/git-svn.txt | 4 ++++ git-svn.perl | 3 +++ t/t9134-git-svn-ignore-paths.sh | 4 ++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index aad5e65c70..9229d45ad9 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -85,6 +85,10 @@ COMMANDS specified, the prefix must include a trailing slash. Setting a prefix is useful if you wish to track multiple projects that share a common repository. +--ignore-paths=<regex>;; + When passed to 'init' or 'clone' this regular expression will + be preserved as a config key. See 'fetch' for a description + of '--ignore-paths'. 'fetch':: Fetch unfetched revisions from the Subversion remote we are diff --git a/git-svn.perl b/git-svn.perl index 279847921b..bc3ba064e4 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -336,6 +336,9 @@ sub do_git_init_db { command_noisy('config', "$pfx.$i", $icv{$i}); $set = $i; } + my $ignore_regex = \$SVN::Git::Fetcher::_ignore_regex; + command_noisy('config', "$pfx.ignore-paths", $$ignore_regex) + if defined $$ignore_regex; } sub init_subdir { diff --git a/t/t9134-git-svn-ignore-paths.sh b/t/t9134-git-svn-ignore-paths.sh index b9a15978eb..71fdc4a69d 100755 --- a/t/t9134-git-svn-ignore-paths.sh +++ b/t/t9134-git-svn-ignore-paths.sh @@ -40,10 +40,10 @@ test_expect_success 'init+fetch an SVN repository with ignored www directory' ' test_cmp expect expect2 ' -test_expect_success 'set persistent ignore-paths config' ' +test_expect_success 'verify ignore-paths config saved by clone' ' ( cd g && - git config svn-remote.svn.ignore-paths "^www" + git config --get svn-remote.svn.ignore-paths | fgrep "www" ) ' From b6c29915d2efd0d2cb56eca88bd8e6b4999546dc Mon Sep 17 00:00:00 2001 From: Dan McGee <dpmcgee@gmail.com> Date: Thu, 9 Apr 2009 10:45:39 -0500 Subject: [PATCH 421/654] Update delta compression message to be less misleading In the case of a small repository, pack-objects is smart enough to not start more threads than necessary. However, the output to the user always reports the value of the pack.threads configuration and not the real number of threads to be used. Signed-off-by: Dan McGee <dpmcgee@gmail.com> Acked-by: Nicolas Pitre <nico@cam.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-pack-objects.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 9fc3b35547..99181fd7ee 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -1612,7 +1612,7 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, return; } if (progress > pack_to_stdout) - fprintf(stderr, "Delta compression using %d threads.\n", + fprintf(stderr, "Delta compression using up to %d threads.\n", delta_search_threads); /* Partition the work amongst work threads. */ From d3c9634eacdcaa71cbd69a160e6f4e80ddb7ab63 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Thu, 9 Apr 2009 13:29:57 +0200 Subject: [PATCH 422/654] git-svn: always initialize with core.autocrlf=false It has been reported time and time again in relation to msysGit that git-svn does not work well when core.autocrlf has any value other than 'false'. So let's make it so by default. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Acked-by: Eric Wong <normalperson@yhbt.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-svn.perl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-svn.perl b/git-svn.perl index bc3ba064e4..c5965c9aaf 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -328,6 +328,7 @@ sub do_git_init_db { command_noisy(@init_db); $_repository = Git->repository(Repository => ".git"); } + command_noisy('config', 'core.autocrlf', 'false'); my $set; my $pfx = "svn-remote.$Git::SVN::default_repo_id"; foreach my $i (keys %icv) { From 519d05be9015871e422cd16ebced620cb01f8b3c Mon Sep 17 00:00:00 2001 From: Mike Hommey <mh@glandium.org> Date: Fri, 10 Apr 2009 00:25:37 +0200 Subject: [PATCH 423/654] Replace ",<,>,& with their respective XML entities in DAV requests If the repo url or the user email contain XML special characters, the remote DAV server is likely to reject the LOCK requests because the XML is then malformed. Signed-off-by: Mike Hommey <mh@glandium.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- http-push.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/http-push.c b/http-push.c index feeb340daf..5138224cc3 100644 --- a/http-push.c +++ b/http-push.c @@ -186,6 +186,32 @@ enum dav_header_flag { DAV_HEADER_TIMEOUT = (1u << 2) }; +static char *xml_entities(char *s) +{ + struct strbuf buf = STRBUF_INIT; + while (*s) { + size_t len = strcspn(s, "\"<>&"); + strbuf_add(&buf, s, len); + s += len; + switch (*s) { + case '"': + strbuf_addstr(&buf, """); + break; + case '<': + strbuf_addstr(&buf, "<"); + break; + case '>': + strbuf_addstr(&buf, ">"); + break; + case '&': + strbuf_addstr(&buf, "&"); + break; + } + s++; + } + return strbuf_detach(&buf, NULL); +} + static struct curl_slist *get_dav_token_headers(struct remote_lock *lock, enum dav_header_flag options) { struct strbuf buf = STRBUF_INIT; @@ -1225,6 +1251,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout) struct remote_lock *lock = NULL; struct curl_slist *dav_headers = NULL; struct xml_ctx ctx; + char *escaped; url = xmalloc(strlen(repo->url) + strlen(path) + 1); sprintf(url, "%s%s", repo->url, path); @@ -1259,7 +1286,9 @@ static struct remote_lock *lock_remote(const char *path, long timeout) ep = strchr(ep + 1, '/'); } - strbuf_addf(&out_buffer.buf, LOCK_REQUEST, git_default_email); + escaped = xml_entities(git_default_email); + strbuf_addf(&out_buffer.buf, LOCK_REQUEST, escaped); + free(escaped); sprintf(timeout_header, "Timeout: Second-%ld", timeout); dav_headers = curl_slist_append(dav_headers, timeout_header); @@ -1584,8 +1613,11 @@ static int locking_available(void) struct curl_slist *dav_headers = NULL; struct xml_ctx ctx; int lock_flags = 0; + char *escaped; - strbuf_addf(&out_buffer.buf, PROPFIND_SUPPORTEDLOCK_REQUEST, repo->url); + escaped = xml_entities(repo->url); + strbuf_addf(&out_buffer.buf, PROPFIND_SUPPORTEDLOCK_REQUEST, escaped); + free(escaped); dav_headers = curl_slist_append(dav_headers, "Depth: 0"); dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml"); From cced5fbc241f1274ba532040b985f38c15bbf555 Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@linux-foundation.org> Date: Thu, 9 Apr 2009 11:46:15 -0700 Subject: [PATCH 424/654] Allow users to un-configure rename detection I told people on the kernel mailing list to please use "-M" when sending me rename patches, so that I can see what they do while reading email rather than having to apply the patch and then look at the end result. I also told them that if they want to make it the default, they can just add [diff] renames to their ~/.gitconfig file. And while I was thinking about that, I wanted to also check whether you can then mark individual projects to _not_ have that default in the per-repository .git/config file. And you can't. Currently you cannot have a global "enable renames by default" and then a local ".. but not for _this_ project". Why? Because if somebody writes [diff] renames = no we simply ignore it, rather than resetting "diff_detect_rename_default" back to zero. Fixed thusly. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- diff.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/diff.c b/diff.c index e0fa78c84d..3ac71686eb 100644 --- a/diff.c +++ b/diff.c @@ -62,6 +62,15 @@ static int parse_diff_color_slot(const char *var, int ofs) die("bad config variable '%s'", var); } +static int git_config_rename(const char *var, const char *value) +{ + if (!value) + return DIFF_DETECT_RENAME; + if (!strcasecmp(value, "copies") || !strcasecmp(value, "copy")) + return DIFF_DETECT_COPY; + return git_config_bool(var,value) ? DIFF_DETECT_RENAME : 0; +} + /* * These are to give UI layer defaults. * The core-level commands such as git-diff-files should @@ -75,13 +84,7 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) return 0; } if (!strcmp(var, "diff.renames")) { - if (!value) - diff_detect_rename_default = DIFF_DETECT_RENAME; - else if (!strcasecmp(value, "copies") || - !strcasecmp(value, "copy")) - diff_detect_rename_default = DIFF_DETECT_COPY; - else if (git_config_bool(var,value)) - diff_detect_rename_default = DIFF_DETECT_RENAME; + diff_detect_rename_default = git_config_rename(var, value); return 0; } if (!strcmp(var, "diff.autorefreshindex")) { From ee7ec2f9ded03700f2b95cc1d4b3d60ed374132a Mon Sep 17 00:00:00 2001 From: Ben Walton <bwalton@artsci.utoronto.ca> Date: Sun, 22 Mar 2009 09:20:44 -0400 Subject: [PATCH 425/654] documentation: Makefile accounts for SHELL_PATH setting Ensure that the Makefile that generates and installs the Documentation is aware of any SHELL_PATH setting. Use this value if found or the current setting for SHELL if not. This is an accommodation for systems where sh is not POSIX enough. Signed-off-by: Ben Walton <bwalton@artsci.utoronto.ca> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/Makefile | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Documentation/Makefile b/Documentation/Makefile index dba97dc21d..e18242a6d4 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -103,6 +103,10 @@ ifdef DOCBOOK_SUPPRESS_SP XMLTO_EXTRA += -m manpage-suppress-sp.xsl endif +SHELL_PATH ?= $(SHELL) +# Shell quote; +SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) + # # Please note that there is a minor bug in asciidoc. # The version after 6.0.3 _will_ include the patch found here: @@ -178,7 +182,7 @@ install-pdf: pdf $(INSTALL) -m 644 user-manual.pdf $(DESTDIR)$(pdfdir) install-html: html - sh ./install-webdoc.sh $(DESTDIR)$(htmldir) + '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir) ../GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) GIT-VERSION-FILE @@ -240,7 +244,7 @@ user-manual.xml: user-manual.txt user-manual.conf technical/api-index.txt: technical/api-index-skel.txt \ technical/api-index.sh $(patsubst %,%.txt,$(API_DOCS)) - $(QUIET_GEN)cd technical && sh ./api-index.sh + $(QUIET_GEN)cd technical && '$(SHELL_PATH_SQ)' ./api-index.sh $(patsubst %,%.html,$(API_DOCS) technical/api-index): %.html : %.txt $(QUIET_ASCIIDOC)$(ASCIIDOC) -b xhtml11 -f asciidoc.conf \ @@ -285,7 +289,7 @@ $(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml howto-index.txt: howto-index.sh $(wildcard howto/*.txt) $(QUIET_GEN)$(RM) $@+ $@ && \ - sh ./howto-index.sh $(wildcard howto/*.txt) >$@+ && \ + '$(SHELL_PATH_SQ)' ./howto-index.sh $(wildcard howto/*.txt) >$@+ && \ mv $@+ $@ $(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt @@ -299,14 +303,14 @@ $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt mv $@+ $@ install-webdoc : html - sh ./install-webdoc.sh $(WEBDOC_DEST) + '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST) quick-install: quick-install-man quick-install-man: - sh ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir) + '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir) quick-install-html: - sh ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir) + '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir) .PHONY: .FORCE-GIT-VERSION-FILE From c59cb03a8bfc4b09758b07b23b6fe70a909ff9f4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Wed, 8 Apr 2009 23:30:24 +0200 Subject: [PATCH 426/654] git-add: introduce --edit (to edit the diff vs. the index) With "git add -e [<files>]", Git will fire up an editor with the current diff relative to the index (i.e. what you would get with "git diff [<files>]"). Now you can edit the patch as much as you like, including adding/removing lines, editing the text, whatever. Make sure, though, that the first character of the hunk lines is still a space, a plus or a minus. After you closed the editor, Git will adjust the line counts of the hunks if necessary, thanks to the --recount option of apply, and commit the patch. Except if you deleted everything, in which case nothing happens (for obvious reasons). Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-add.txt | 11 +++- builtin-add.c | 59 +++++++++++++++++++-- t/t3702-add-edit.sh | 109 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+), 4 deletions(-) create mode 100755 t/t3702-add-edit.sh diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt index ce71838b9e..25e6667736 100644 --- a/Documentation/git-add.txt +++ b/Documentation/git-add.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] 'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p] - [--all | [--update | -u]] [--intent-to-add | -N] + [--edit | -e] [--all | [--update | -u]] [--intent-to-add | -N] [--refresh] [--ignore-errors] [--] <filepattern>... DESCRIPTION @@ -76,6 +76,15 @@ OPTIONS bypassed and the 'patch' subcommand is invoked using each of the specified filepatterns before exiting. +-e, \--edit:: + Open the diff vs. the index in an editor and let the user + edit it. After the editor was closed, adjust the hunk headers + and apply the patch to the index. ++ +*NOTE*: Obviously, if you change anything else than the first character +on lines beginning with a space or a minus, the patch will no longer +apply. + -u:: --update:: Update only files that git already knows about, staging modified diff --git a/builtin-add.c b/builtin-add.c index cb67d2c17e..314380eed0 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -10,12 +10,14 @@ #include "cache-tree.h" #include "run-command.h" #include "parse-options.h" +#include "diff.h" +#include "revision.h" static const char * const builtin_add_usage[] = { "git add [options] [--] <filepattern>...", NULL }; -static int patch_interactive, add_interactive; +static int patch_interactive, add_interactive, edit_interactive; static int take_worktree_changes; static void fill_pathspec_matches(const char **pathspec, char *seen, int specs) @@ -187,6 +189,51 @@ int interactive_add(int argc, const char **argv, const char *prefix) return status; } +int edit_patch(int argc, const char **argv, const char *prefix) +{ + char *file = xstrdup(git_path("ADD_EDIT.patch")); + const char *apply_argv[] = { "apply", "--recount", "--cached", + file, NULL }; + struct child_process child; + struct rev_info rev; + int out; + struct stat st; + + git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ + + if (read_cache() < 0) + die ("Could not read the index"); + + init_revisions(&rev, prefix); + rev.diffopt.context = 7; + + argc = setup_revisions(argc, argv, &rev, NULL); + rev.diffopt.output_format = DIFF_FORMAT_PATCH; + out = open(file, O_CREAT | O_WRONLY, 0644); + if (out < 0) + die ("Could not open '%s' for writing.", file); + rev.diffopt.file = fdopen(out, "w"); + rev.diffopt.close_file = 1; + if (run_diff_files(&rev, 0)) + die ("Could not write patch"); + + launch_editor(file, NULL, NULL); + + if (stat(file, &st)) + die("Could not stat '%s'", file); + if (!st.st_size) + die("Empty patch. Aborted."); + + memset(&child, 0, sizeof(child)); + child.git_cmd = 1; + child.argv = apply_argv; + if (run_command(&child)) + die ("Could not apply '%s'", file); + + unlink(file); + return 0; +} + static struct lock_file lock_file; static const char ignore_error[] = @@ -201,6 +248,7 @@ static struct option builtin_add_options[] = { OPT_GROUP(""), OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"), OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"), + OPT_BOOLEAN('e', "edit", &edit_interactive, "edit current diff and apply"), OPT_BOOLEAN('f', "force", &ignored_too, "allow adding otherwise ignored files"), OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"), OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"), @@ -251,14 +299,19 @@ int cmd_add(int argc, const char **argv, const char *prefix) int require_pathspec; argc = parse_options(argc, argv, builtin_add_options, - builtin_add_usage, 0); + builtin_add_usage, PARSE_OPT_KEEP_ARGV0); if (patch_interactive) add_interactive = 1; if (add_interactive) - exit(interactive_add(argc, argv, prefix)); + exit(interactive_add(argc - 1, argv + 1, prefix)); git_config(add_config, NULL); + if (edit_interactive) + return(edit_patch(argc, argv, prefix)); + argc--; + argv++; + if (addremove && take_worktree_changes) die("-A and -u are mutually incompatible"); if ((addremove || take_worktree_changes) && !argc) { diff --git a/t/t3702-add-edit.sh b/t/t3702-add-edit.sh new file mode 100755 index 0000000000..72627863e5 --- /dev/null +++ b/t/t3702-add-edit.sh @@ -0,0 +1,109 @@ +#!/bin/sh +# +# Copyright (c) 2007 Johannes E. Schindelin +# + +test_description='add -e basic tests' +. ./test-lib.sh + + +cat > file << EOF +LO, praise of the prowess of people-kings +of spear-armed Danes, in days long sped, +we have heard, and what honor the athelings won! +Oft Scyld the Scefing from squadroned foes, +from many a tribe, the mead-bench tore, +awing the earls. Since erst he lay +friendless, a foundling, fate repaid him: +for he waxed under welkin, in wealth he throve, +till before him the folk, both far and near, +who house by the whale-path, heard his mandate, +gave him gifts: a good king he! +EOF + +test_expect_success 'setup' ' + + git add file && + test_tick && + git commit -m initial file + +' + +cat > expected-patch << EOF +diff --git a/file b/file +index b9834b5..0b8f197 100644 +--- a/file ++++ b/file +@@ -1,11 +1,3 @@ +-LO, praise of the prowess of people-kings +-of spear-armed Danes, in days long sped, +-we have heard, and what honor the athelings won! +-Oft Scyld the Scefing from squadroned foes, +-from many a tribe, the mead-bench tore, +-awing the earls. Since erst he lay +-friendless, a foundling, fate repaid him: +-for he waxed under welkin, in wealth he throve, +-till before him the folk, both far and near, +-who house by the whale-path, heard his mandate, +-gave him gifts: a good king he! ++#!$SHELL_PATH ++mv -f "\$1" orig-patch && ++mv -f patch "\$1" +EOF + +cat > patch << EOF +diff --git a/file b/file +index b9834b5..ef6e94c 100644 +--- a/file ++++ b/file +@@ -3,1 +3,333 @@ of spear-armed Danes, in days long sped, + we have heard, and what honor the athelings won! ++ + Oft Scyld the Scefing from squadroned foes, +@@ -2,7 +1,5 @@ awing the earls. Since erst he lay + friendless, a foundling, fate repaid him: ++ + for he waxed under welkin, in wealth he throve, +EOF + +cat > expected << EOF +diff --git a/file b/file +index b9834b5..ef6e94c 100644 +--- a/file ++++ b/file +@@ -1,10 +1,12 @@ + LO, praise of the prowess of people-kings + of spear-armed Danes, in days long sped, + we have heard, and what honor the athelings won! ++ + Oft Scyld the Scefing from squadroned foes, + from many a tribe, the mead-bench tore, + awing the earls. Since erst he lay + friendless, a foundling, fate repaid him: ++ + for he waxed under welkin, in wealth he throve, + till before him the folk, both far and near, + who house by the whale-path, heard his mandate, +EOF + +echo "#!$SHELL_PATH" >fake-editor.sh +cat >> fake-editor.sh <<\EOF +mv -f "$1" orig-patch && +mv -f patch "$1" +EOF + +test_set_editor "$(pwd)/fake-editor.sh" +chmod a+x fake-editor.sh + +test_expect_success 'add -e' ' + + cp fake-editor.sh file && + git add -e && + test_cmp fake-editor.sh file && + test_cmp orig-patch expected-patch && + git diff --cached > out && + test_cmp out expected + +' + +test_done From 47d65924a69576bd9f3254f7055de6b37a359596 Mon Sep 17 00:00:00 2001 From: David Aguilar <davvid@gmail.com> Date: Sat, 11 Apr 2009 20:41:56 -0700 Subject: [PATCH 427/654] mergetool--lib: simplify API usage by removing more global variables The mergetool--lib scriplet was tricky to use because it relied upon the existance of several global shell variables. This removes more global variables so that things are simpler for callers. A side effect is that some variables are recomputed each time run_merge_tool() is called, but the overhead for recomputing them is justified by the simpler implementation. Signed-off-by: David Aguilar <davvid@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-mergetool--lib.txt | 16 ++-- git-difftool--helper.sh | 6 +- git-mergetool--lib.sh | 111 ++++++++++++++------------- git-mergetool.sh | 15 ++-- 4 files changed, 77 insertions(+), 71 deletions(-) diff --git a/Documentation/git-mergetool--lib.txt b/Documentation/git-mergetool--lib.txt index 3d57031d78..78eb03f0ae 100644 --- a/Documentation/git-mergetool--lib.txt +++ b/Documentation/git-mergetool--lib.txt @@ -7,7 +7,7 @@ git-mergetool--lib - Common git merge tool shell scriptlets SYNOPSIS -------- -'. "$(git --exec-path)/git-mergetool--lib"' +'TOOL_MODE=(diff|merge) . "$(git --exec-path)/git-mergetool--lib"' DESCRIPTION ----------- @@ -20,14 +20,14 @@ The 'git-mergetool--lib' scriptlet is designed to be sourced (using `.`) by other shell scripts to set up functions for working with git merge tools. -Before sourcing it, your script should set up a few variables; -`TOOL_MODE` is used to define the operation mode for various -functions. 'diff' and 'merge' are valid values. +Before sourcing 'git-mergetool--lib', your script must set `TOOL_MODE` +to define the operation mode for the functions listed below. +'diff' and 'merge' are valid values. FUNCTIONS --------- get_merge_tool:: - returns a merge tool + returns a merge tool. get_merge_tool_cmd:: returns the custom command for a merge tool. @@ -38,10 +38,8 @@ get_merge_tool_path:: run_merge_tool:: launches a merge tool given the tool name and a true/false flag to indicate whether a merge base is present. - '$merge_tool', '$merge_tool_path', and for custom commands, - '$merge_tool_cmd', must be defined prior to calling - run_merge_tool. Additionally, '$MERGED', '$LOCAL', '$REMOTE', - and '$BASE' must be defined for use by the merge tool. + '$MERGED', '$LOCAL', '$REMOTE', and '$BASE' must be defined + for use by the merge tool. Author ------ diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh index b4500368c3..57e8e3256d 100755 --- a/git-difftool--helper.sh +++ b/git-difftool--helper.sh @@ -47,9 +47,9 @@ launch_merge_tool () { test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL" test -n "$GIT_DIFF_TOOL" && merge_tool="$GIT_DIFF_TOOL" -merge_tool=$(get_merge_tool "$merge_tool") || exit -merge_tool_cmd="$(get_merge_tool_cmd "$merge_tool")" -merge_tool_path="$(get_merge_tool_path "$merge_tool")" || exit +if test -z "$merge_tool"; then + merge_tool="$(get_merge_tool)" || exit +fi # Launch the merge tool on each path provided by 'git diff' while test $# -gt 6 diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh index c5db24e45d..a16a2795d7 100644 --- a/git-mergetool--lib.sh +++ b/git-mergetool--lib.sh @@ -8,25 +8,20 @@ merge_mode() { } translate_merge_tool_path () { - if test -n "$2"; then - echo "$2" - else - case "$1" in - vimdiff) - path=vim - ;; - gvimdiff) - path=gvim - ;; - emerge) - path=emacs - ;; - *) - path="$1" - ;; - esac - echo "$path" - fi + case "$1" in + vimdiff) + echo vim + ;; + gvimdiff) + echo gvim + ;; + emerge) + echo emacs + ;; + *) + echo "$1" + ;; + esac } check_unchanged () { @@ -69,15 +64,22 @@ valid_tool () { } get_merge_tool_cmd () { - diff_mode && - custom_cmd="$(git config difftool.$1.cmd)" - test -z "$custom_cmd" && - custom_cmd="$(git config mergetool.$1.cmd)" - test -n "$custom_cmd" && - echo "$custom_cmd" + # Prints the custom command for a merge tool + if test -n "$1"; then + merge_tool="$1" + else + merge_tool="$(get_merge_tool)" + fi + if diff_mode; then + echo "$(git config difftool.$merge_tool.cmd || + git config mergetool.$merge_tool.cmd)" + else + echo "$(git config mergetool.$merge_tool.cmd)" + fi } run_merge_tool () { + merge_tool_path="$(get_merge_tool_path "$1")" || exit base_present="$2" status=0 @@ -103,9 +105,9 @@ run_merge_tool () { status=$? else ("$merge_tool_path" --auto \ - --L1 "$MERGED (A)" \ - --L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \ - > /dev/null 2>&1) + --L1 "$MERGED (A)" \ + --L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \ + > /dev/null 2>&1) fi ;; kompare) @@ -262,6 +264,7 @@ run_merge_tool () { fi ;; *) + merge_tool_cmd="$(get_merge_tool_cmd "$1")" if test -z "$merge_tool_cmd"; then if merge_mode; then status=1 @@ -269,7 +272,9 @@ run_merge_tool () { break fi if merge_mode; then - if test "$merge_tool_trust_exit_code" = "false"; then + trust_exit_code="$(git config --bool \ + mergetool."$1".trustExitCode || echo false)" + if test "$trust_exit_code" = "false"; then touch "$BACKUP" ( eval $merge_tool_cmd ) check_unchanged @@ -315,64 +320,66 @@ guess_merge_tool () { do merge_tool_path="$(translate_merge_tool_path "$i")" if type "$merge_tool_path" > /dev/null 2>&1; then - merge_tool="$i" - break + echo "$i" + return 0 fi done - if test -z "$merge_tool" ; then - echo >&2 "No known merge resolution program available." - return 1 - fi - echo "$merge_tool" + echo >&2 "No known merge resolution program available." + return 1 } get_configured_merge_tool () { # Diff mode first tries diff.tool and falls back to merge.tool. # Merge mode only checks merge.tool if diff_mode; then - tool=$(git config diff.tool) - fi - if test -z "$tool"; then - tool=$(git config merge.tool) + merge_tool=$(git config diff.tool || git config merge.tool) + else + merge_tool=$(git config merge.tool) fi if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then echo >&2 "git config option $TOOL_MODE.tool set to unknown tool: $merge_tool" echo >&2 "Resetting to default..." return 1 fi - echo "$tool" + echo "$merge_tool" } get_merge_tool_path () { # A merge tool has been set, so verify that it's valid. + if test -n "$1"; then + merge_tool="$1" + else + merge_tool="$(get_merge_tool)" + fi if ! valid_tool "$merge_tool"; then echo >&2 "Unknown merge tool $merge_tool" exit 1 fi if diff_mode; then - merge_tool_path=$(git config difftool."$merge_tool".path) - fi - if test -z "$merge_tool_path"; then + merge_tool_path=$(git config difftool."$merge_tool".path || + git config mergetool."$merge_tool".path) + else merge_tool_path=$(git config mergetool."$merge_tool".path) fi - merge_tool_path="$(translate_merge_tool_path "$merge_tool" "$merge_tool_path")" - if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then - echo >&2 "The $TOOL_MODE tool $merge_tool is not available as '$merge_tool_path'" + if test -z "$merge_tool_path"; then + merge_tool_path="$(translate_merge_tool_path "$merge_tool")" + fi + if test -z "$(get_merge_tool_cmd "$merge_tool")" && + ! type "$merge_tool_path" > /dev/null 2>&1; then + echo >&2 "The $TOOL_MODE tool $merge_tool is not available as"\ + "'$merge_tool_path'" exit 1 fi echo "$merge_tool_path" } get_merge_tool () { - merge_tool="$1" # Check if a merge tool has been configured - if test -z "$merge_tool"; then - merge_tool=$(get_configured_merge_tool) - fi + merge_tool=$(get_configured_merge_tool) # Try to guess an appropriate merge tool if no tool has been set. if test -z "$merge_tool"; then - merge_tool=$(guess_merge_tool) || exit + merge_tool="$(guess_merge_tool)" || exit fi echo "$merge_tool" } diff --git a/git-mergetool.sh b/git-mergetool.sh index 2e3e02b3b5..b52a7410bc 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -174,9 +174,11 @@ merge_file () { read ans fi - present=false - base_present && - present=true + if base_present; then + present=true + else + present=false + fi if ! run_merge_tool "$merge_tool" "$present"; then echo "merge of $MERGED failed" 1>&2 @@ -254,12 +256,11 @@ prompt_after_failed_merge() { done } -merge_tool=$(get_merge_tool "$merge_tool") || exit -merge_tool_cmd="$(get_merge_tool_cmd "$merge_tool")" -merge_tool_path="$(get_merge_tool_path "$merge_tool")" || exit +if test -z "$merge_tool"; then + merge_tool=$(get_merge_tool "$merge_tool") || exit +fi merge_keep_backup="$(git config --bool mergetool.keepBackup || echo true)" merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)" -merge_tool_trust_exit_code="$(git config --bool mergetool."$merge_tool".trustExitCode || echo false)" last_status=0 rollup_status=0 From 54a47493a34fbf25370c526a03c38894d709f3e4 Mon Sep 17 00:00:00 2001 From: Nanako Shiraishi <nanako3@lavabit.com> Date: Fri, 10 Apr 2009 09:34:40 +0900 Subject: [PATCH 428/654] Documentation/git.txt: GIT 1.6.2.2 has been out for a while These links inside "stalenotes" section need to be updated on the master branch every time a new stable or maintenance release is made. Signed-off-by: Nanako Shiraishi <nanako3@lavabit.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/git.txt b/Documentation/git.txt index 2ce5e6b451..eca29f00ea 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,10 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.6.2.1/git.html[documentation for release 1.6.2.1] +* link:v1.6.2.2/git.html[documentation for release 1.6.2.2] * release notes for + link:RelNotes-1.6.2.2.txt[1.6.2.2], link:RelNotes-1.6.2.1.txt[1.6.2.1], link:RelNotes-1.6.2.txt[1.6.2]. From c965c029330b1f81cc107c5d829e7fd79c61d8ea Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Sun, 12 Apr 2009 17:05:55 -0700 Subject: [PATCH 429/654] GIT 1.6.3-rc0 Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/RelNotes-1.6.3.txt | 14 ++++++++++++-- Documentation/git.txt | 3 ++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Documentation/RelNotes-1.6.3.txt b/Documentation/RelNotes-1.6.3.txt index 9aa143b199..839498c38a 100644 --- a/Documentation/RelNotes-1.6.3.txt +++ b/Documentation/RelNotes-1.6.3.txt @@ -35,6 +35,8 @@ Updates since v1.6.2 (subsystems) +* various git-svn updates. + (performance) * many uses of lstat(2) in the codepath for "git checkout" have been @@ -80,9 +82,12 @@ Updates since v1.6.2 * You can give --date=<format> option to git-blame. -* git-branch -r shows HEAD symref that points at a remote branch in +* "git-branch -r" shows HEAD symref that points at a remote branch in interest of each tracked remote repository. +* "git-branch -v -v" is a new way to get list of names for branches and the + "upstream" branch for them. + * git-config learned -e option to open an editor to edit the config file directly. @@ -90,6 +95,8 @@ Updates since v1.6.2 * git-fast-export choked when seeing a tag that does not point at commit. +* git-for-each-ref learned a new "upstream" token. + * git-format-patch can be told to use attachment with a new configuration, format.attach. @@ -118,6 +125,9 @@ Updates since v1.6.2 * Output from git-remote command has been vastly improved. +* "git remote update --prune $remote" updates from the named remote and + then prunes stale tracking branches. + * git-send-email learned --confirm option to review the Cc: list before sending the messages out. @@ -166,6 +176,6 @@ v1.6.2.X series. --- exec >/var/tmp/1 -O=v1.6.2.2-484-g796b137 +O=v1.6.2.3-497-g54a4749 echo O=$(git describe master) git shortlog --no-merges $O..master ^maint diff --git a/Documentation/git.txt b/Documentation/git.txt index eca29f00ea..470fdc5ecd 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,10 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.6.2.2/git.html[documentation for release 1.6.2.2] +* link:v1.6.2.3/git.html[documentation for release 1.6.2.3] * release notes for + link:RelNotes-1.6.2.3.txt[1.6.2.3], link:RelNotes-1.6.2.2.txt[1.6.2.2], link:RelNotes-1.6.2.1.txt[1.6.2.1], link:RelNotes-1.6.2.txt[1.6.2]. From f79d4c8a0f22d7fd25018be846c7e48127ed3200 Mon Sep 17 00:00:00 2001 From: Nanako Shiraishi <nanako3@lavabit.com> Date: Fri, 10 Apr 2009 09:34:42 +0900 Subject: [PATCH 430/654] git-am: teach git-am to apply a patch to an unborn branch People sometimes wonder why they cannot apply a patch that only creates new files to an unborn branch. Signed-off-by: Nanako Shiraishi <nanako3@lavabit.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-am.sh | 29 ++++++++++++++++++++++++----- t/t4150-am.sh | 15 +++++++++++++++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/git-am.sh b/git-am.sh index d3390755fc..774383fb68 100755 --- a/git-am.sh +++ b/git-am.sh @@ -36,6 +36,13 @@ cd_to_toplevel git var GIT_COMMITTER_IDENT >/dev/null || die "You need to set your committer info first" +if git rev-parse --verify -q HEAD >/dev/null +then + HAS_HEAD=yes +else + HAS_HEAD= +fi + sq () { for sqarg do @@ -290,16 +297,26 @@ else : >"$dotest/rebasing" else : >"$dotest/applying" - git update-ref ORIG_HEAD HEAD + if test -n "$HAS_HEAD" + then + git update-ref ORIG_HEAD HEAD + else + git update-ref -d ORIG_HEAD >/dev/null 2>&1 + fi fi fi case "$resolved" in '') - files=$(git diff-index --cached --name-only HEAD --) || exit + case "$HAS_HEAD" in + '') + files=$(git ls-files) ;; + ?*) + files=$(git diff-index --cached --name-only HEAD --) ;; + esac || exit if test "$files" then - : >"$dotest/dirtyindex" + test -n "$HAS_HEAD" && : >"$dotest/dirtyindex" die "Dirty index: cannot apply patches (dirty: $files)" fi esac @@ -541,18 +558,20 @@ do fi tree=$(git write-tree) && - parent=$(git rev-parse --verify HEAD) && commit=$( if test -n "$ignore_date" then GIT_AUTHOR_DATE= fi + parent=$(git rev-parse --verify -q HEAD) || + echo >&2 "applying to an empty history" + if test -n "$committer_date_is_author_date" then GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" export GIT_COMMITTER_DATE fi && - git commit-tree $tree -p $parent <"$dotest/final-commit" + git commit-tree $tree ${parent:+-p $parent} <"$dotest/final-commit" ) && git update-ref -m "$GIT_REFLOG_ACTION: $FIRSTLINE" HEAD $commit $parent || stop_here $this diff --git a/t/t4150-am.sh b/t/t4150-am.sh index 5e65afa0c1..d6ebbaebe2 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -290,4 +290,19 @@ test_expect_success 'am --ignore-date' ' echo "$at" | grep "+0000" ' +test_expect_success 'am into an unborn branch' ' + rm -fr subdir && + mkdir -p subdir && + git format-patch --numbered-files -o subdir -1 first && + ( + cd subdir && + git init && + git am 1 + ) && + result=$( + cd subdir && git rev-parse HEAD^{tree} + ) && + test "z$result" = "z$(git rev-parse first^{tree})" +' + test_done From f800b65bea1504299747e7be03ee279508a74e1f Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Sun, 12 Apr 2009 21:15:59 -0700 Subject: [PATCH 431/654] gitignore git-bisect--helper Signed-off-by: Junio C Hamano <gitster@pobox.com> --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1c57d4c958..16f7a97d97 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ git-apply git-archimport git-archive git-bisect +git-bisect--helper git-blame git-branch git-bundle From 70e966477aacf46d4d6cb8c01f8bd9a9ceb5e80f Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Mon, 13 Apr 2009 07:11:16 -0400 Subject: [PATCH 432/654] doc: clarify --no-track option It is not really about ignoring the config option; it is about turning off tracking, _even if_ the config option is set. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-branch.txt | 3 ++- Documentation/git-checkout.txt | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index ba3dea6840..19f1b0d9f9 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -124,7 +124,8 @@ OPTIONS start-point is either a local or remote branch. --no-track:: - Ignore the branch.autosetupmerge configuration variable. + Do not set up tracking configuration, even if the + branch.autosetupmerge configuration variable is true. --contains <commit>:: Only list branches which contain the specified commit. diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 223ea9caef..4992fc61eb 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -90,7 +90,8 @@ guessing results in an empty name, the guessing is aborted. You can explicitly give a name with '-b' in such a case. --no-track:: - Ignore the branch.autosetupmerge configuration variable. + Do not set up tracking configuration, even if the + branch.autosetupmerge configuration variable is true. -l:: Create the new branch's reflog. This activates recording of From 167d7445433bb6dfac6b844b99ae455129326141 Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Mon, 13 Apr 2009 07:11:56 -0400 Subject: [PATCH 433/654] doc: refer to tracking configuration as "upstream" The term "tracking" often creates confusion between remote tracking branches and local branches which track a remote branch. The term "upstream" captures more clearly the idea of "branch A is based on branch B in some way", so it makes sense to mention it. At the same time, upstream branches are used for more than just git-pull these days; let's mention that here. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-branch.txt | 24 +++++++++++++----------- Documentation/git-checkout.txt | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index 19f1b0d9f9..cbd4275871 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -112,19 +112,21 @@ OPTIONS Display the full sha1s in the output listing rather than abbreviating them. --track:: - When creating a new branch, set up the configuration so that 'git-pull' - will automatically retrieve data from the start point, which must be - a branch. Use this if you always pull from the same upstream branch - into the new branch, and if you do not want to use "git pull - <repository> <refspec>" explicitly. This behavior is the default - when the start point is a remote branch. Set the - branch.autosetupmerge configuration variable to `false` if you want - 'git-checkout' and 'git-branch' to always behave as if '--no-track' were - given. Set it to `always` if you want this behavior when the - start-point is either a local or remote branch. + When creating a new branch, set up configuration to mark the + start-point branch as "upstream" from the new branch. This + configuration will tell git to show the relationship between the + two branches in `git status` and `git branch -v`. Furthermore, + it directs `git pull` without arguments to pull from the + upstream when the new branch is checked out. ++ +This behavior is the default when the start point is a remote branch. +Set the branch.autosetupmerge configuration variable to `false` if you +want `git checkout` and `git branch` to always behave as if '--no-track' +were given. Set it to `always` if you want this behavior when the +start-point is either a local or remote branch. --no-track:: - Do not set up tracking configuration, even if the + Do not set up "upstream" configuration, even if the branch.autosetupmerge configuration variable is true. --contains <commit>:: diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 4992fc61eb..16d3c872a0 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -90,7 +90,7 @@ guessing results in an empty name, the guessing is aborted. You can explicitly give a name with '-b' in such a case. --no-track:: - Do not set up tracking configuration, even if the + Do not set up "upstream" configuration, even if the branch.autosetupmerge configuration variable is true. -l:: From 26d22dc64ad2373eb918f004a1d0ba2649e7e1a5 Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Mon, 13 Apr 2009 07:18:52 -0400 Subject: [PATCH 434/654] doc/checkout: refer to git-branch(1) as appropriate Most of description for the branch creation options is simply cut and paste from git-branch. There are two reasons to fix this: 1. It can grow stale with respect to what's in "git branch" (which it is now is). 2. It is not just an implementation detail, but rather the desired mental model for the command that we are using "git branch" here. Being explicit about that can help the user understand what is going on. It also makes sense to strip the branch creation options from the synopsis, as they are making it a long, hard-to-read line. They are still easily discovered by reading the options list, and --track is explicitly referenced when branch creation is described. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-checkout.txt | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 16d3c872a0..22ad10d952 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -8,7 +8,7 @@ git-checkout - Checkout a branch or paths to the working tree SYNOPSIS -------- [verse] -'git checkout' [-q] [-f] [-t | --track | --no-track] [-b <new_branch> [-l]] [-m] [<branch>] +'git checkout' [-q] [-f] [-m] [-b <new_branch>] [<branch>] 'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>... DESCRIPTION @@ -18,8 +18,9 @@ When <paths> are not given, this command switches branches by updating the index and working tree to reflect the specified branch, <branch>, and updating HEAD to be <branch> or, if specified, <new_branch>. Using -b will cause <new_branch> to -be created; in this case you can use the --track or --no-track -options, which will be passed to `git branch`. +be created as if linkgit:git-branch[1] were called; in this case you can +use the --track or --no-track options, which will be passed to `git +branch`. As a convenience, --track will default to creating a branch whose name is constructed from the specified branch name by stripping @@ -62,22 +63,12 @@ entries; instead, unmerged entries are ignored. -b:: Create a new branch named <new_branch> and start it at - <branch>. The new branch name must pass all checks defined - by linkgit:git-check-ref-format[1]. Some of these checks - may restrict the characters allowed in a branch name. + <branch>; see linkgit:git-branch[1] for details. -t:: --track:: - When creating a new branch, set up configuration so that 'git-pull' - will automatically retrieve data from the start point, which must be - a branch. Use this if you always pull from the same upstream branch - into the new branch, and if you don't want to use "git pull - <repository> <refspec>" explicitly. This behavior is the default - when the start point is a remote branch. Set the - branch.autosetupmerge configuration variable to `false` if you want - 'git checkout' and 'git branch' to always behave as if '--no-track' were - given. Set it to `always` if you want this behavior when the - start point is either a local or remote branch. + When creating a new branch, set up "upstream" configuration. See + "--track" in linkgit:git-branch[1] for details. + If no '-b' option is given, the name of the new branch will be derived from the remote branch. If "remotes/" or "refs/remotes/" @@ -94,9 +85,8 @@ explicitly give a name with '-b' in such a case. branch.autosetupmerge configuration variable is true. -l:: - Create the new branch's reflog. This activates recording of - all changes made to the branch ref, enabling use of date - based sha1 expressions such as "<branchname>@\{yesterday}". + Create the new branch's reflog; see linkgit:git-branch[1] for + details. -m:: --merge:: From 76cfadfc17e9e9c7da87a6f9a4710c04107ae0cd Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Mon, 13 Apr 2009 07:19:33 -0400 Subject: [PATCH 435/654] doc/checkout: split checkout and branch creation in synopsis These can really be thought of as two different modes, since the "<branch>" parameter is treated differently in the two (in one it is the branch to be checked out, but in the other it is really a start-point for branch creation). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-checkout.txt | 40 +++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 22ad10d952..4a1fb53096 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -8,23 +8,22 @@ git-checkout - Checkout a branch or paths to the working tree SYNOPSIS -------- [verse] -'git checkout' [-q] [-f] [-m] [-b <new_branch>] [<branch>] +'git checkout' [-q] [-f] [-m] [<branch>] +'git checkout' [-q] [-f] [-m] [-b <new_branch>] [<start_point>] 'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>... DESCRIPTION ----------- When <paths> are not given, this command switches branches by -updating the index and working tree to reflect the specified -branch, <branch>, and updating HEAD to be <branch> or, if -specified, <new_branch>. Using -b will cause <new_branch> to -be created as if linkgit:git-branch[1] were called; in this case you can -use the --track or --no-track options, which will be passed to `git -branch`. +updating the index, working tree, and HEAD to reflect the specified +branch. -As a convenience, --track will default to creating a branch whose -name is constructed from the specified branch name by stripping -the first namespace level. +If `-b` is given, a new branch is created and checked out, as if +linkgit:git-branch[1] were called; in this case you can +use the --track or --no-track options, which will be passed to `git +branch`. As a convenience, --track without `-b` implies branch +creation; see the description of --track below. When <paths> are given, this command does *not* switch branches. It updates the named paths in the working tree from @@ -63,7 +62,7 @@ entries; instead, unmerged entries are ignored. -b:: Create a new branch named <new_branch> and start it at - <branch>; see linkgit:git-branch[1] for details. + <start_point>; see linkgit:git-branch[1] for details. -t:: --track:: @@ -114,13 +113,6 @@ the conflicted merge in the specified paths. "merge" (default) and "diff3" (in addition to what is shown by "merge" style, shows the original contents). -<new_branch>:: - Name for the new branch. - -<tree-ish>:: - Tree to checkout from (when paths are given). If not specified, - the index will be used. - <branch>:: Branch to checkout (when no paths are given); may be any object ID that resolves to a commit. Defaults to HEAD. @@ -132,6 +124,18 @@ As a special case, the `"@\{-N\}"` syntax for the N-th last branch checks out the branch (instead of detaching). You may also specify `-` which is synonymous with `"@\{-1\}"`. +<new_branch>:: + Name for the new branch. + +<start_point>:: + The name of a commit at which to start the new branch; see + linkgit:git-branch[1] for details. Defaults to HEAD. + +<tree-ish>:: + Tree to checkout from (when paths are given). If not specified, + the index will be used. + + Detached HEAD ------------- From 0808723b5065cc2141c2715a2df78882c158d4ef Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Mon, 13 Apr 2009 07:21:04 -0400 Subject: [PATCH 436/654] docs/checkout: clarify what "non-branch" means In the code we literally stick "refs/heads/" on the front and see if it resolves, so that is probably the best explanation. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-checkout.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 4a1fb53096..ad4b31e892 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -114,11 +114,11 @@ the conflicted merge in the specified paths. "merge" style, shows the original contents). <branch>:: - Branch to checkout (when no paths are given); may be any object - ID that resolves to a commit. Defaults to HEAD. -+ -When this parameter names a non-branch (but still a valid commit object), -your HEAD becomes 'detached'. + Branch to checkout; if it refers to a branch (i.e., a name that, + when prepended with "refs/heads/", is a valid ref), then that + branch is checked out. Otherwise, if it refers to a valid + commit, your HEAD becomes "detached" and you are no longer on + any branch (see below for details). + As a special case, the `"@\{-N\}"` syntax for the N-th last branch checks out the branch (instead of detaching). You may also specify From 6e7b3309d356077337b8222683a743c27fa7276c Mon Sep 17 00:00:00 2001 From: Bert Wesarg <bert.wesarg@googlemail.com> Date: Mon, 13 Apr 2009 12:25:46 +0200 Subject: [PATCH 437/654] shorten_unambiguous_ref(): add strict mode Add the strict mode of abbreviation to shorten_unambiguous_ref(), i.e. the resulting ref won't trigger the ambiguous ref warning. All users of shorten_unambiguous_ref() still use the loose mode. Signed-off-by: Bert Wesarg <bert.wesarg@googlemail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-branch.c | 4 ++-- builtin-for-each-ref.c | 2 +- refs.c | 18 +++++++++++++++--- refs.h | 2 +- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/builtin-branch.c b/builtin-branch.c index 3275821696..91098ca9b1 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -311,14 +311,14 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name, if (branch && branch->merge && branch->merge[0]->dst && show_upstream_ref) strbuf_addf(stat, "[%s] ", - shorten_unambiguous_ref(branch->merge[0]->dst)); + shorten_unambiguous_ref(branch->merge[0]->dst, 0)); return; } strbuf_addch(stat, '['); if (show_upstream_ref) strbuf_addf(stat, "%s: ", - shorten_unambiguous_ref(branch->merge[0]->dst)); + shorten_unambiguous_ref(branch->merge[0]->dst, 0)); if (!ours) strbuf_addf(stat, "behind %d] ", theirs); else if (!theirs) diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index c8114c8afd..cfff686ac8 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -601,7 +601,7 @@ static void populate_value(struct refinfo *ref) if (formatp) { formatp++; if (!strcmp(formatp, "short")) - refname = shorten_unambiguous_ref(refname); + refname = shorten_unambiguous_ref(refname, 0); else die("unknown %.*s format %s", (int)(formatp - name), name, formatp); diff --git a/refs.c b/refs.c index 82afb87684..e65a3b4c4e 100644 --- a/refs.c +++ b/refs.c @@ -1681,7 +1681,7 @@ static void gen_scanf_fmt(char *scanf_fmt, const char *rule) return; } -char *shorten_unambiguous_ref(const char *ref) +char *shorten_unambiguous_ref(const char *ref, int strict) { int i; static char **scanf_fmts; @@ -1718,6 +1718,7 @@ char *shorten_unambiguous_ref(const char *ref) /* skip first rule, it will always match */ for (i = nr_rules - 1; i > 0 ; --i) { int j; + int rules_to_fail = i; int short_name_len; if (1 != sscanf(ref, scanf_fmts[i], short_name)) @@ -1725,15 +1726,26 @@ char *shorten_unambiguous_ref(const char *ref) short_name_len = strlen(short_name); + /* + * in strict mode, all (except the matched one) rules + * must fail to resolve to a valid non-ambiguous ref + */ + if (strict) + rules_to_fail = nr_rules; + /* * check if the short name resolves to a valid ref, * but use only rules prior to the matched one */ - for (j = 0; j < i; j++) { + for (j = 0; j < rules_to_fail; j++) { const char *rule = ref_rev_parse_rules[j]; unsigned char short_objectname[20]; char refname[PATH_MAX]; + /* skip matched rule */ + if (i == j) + continue; + /* * the short name is ambiguous, if it resolves * (with this previous rule) to a valid ref @@ -1749,7 +1761,7 @@ char *shorten_unambiguous_ref(const char *ref) * short name is non-ambiguous if all previous rules * haven't resolved to a valid ref */ - if (j == i) + if (j == rules_to_fail) return short_name; } diff --git a/refs.h b/refs.h index 50abbbb2aa..29d17a48e4 100644 --- a/refs.h +++ b/refs.h @@ -81,7 +81,7 @@ extern int for_each_reflog(each_ref_fn, void *); extern int check_ref_format(const char *target); extern const char *prettify_ref(const struct ref *ref); -extern char *shorten_unambiguous_ref(const char *ref); +extern char *shorten_unambiguous_ref(const char *ref, int strict); /** rename ref, return 0 on success **/ extern int rename_ref(const char *oldref, const char *newref, const char *logmsg); From 2bb98169be7b0ac4f70815b4490904c652edae61 Mon Sep 17 00:00:00 2001 From: Bert Wesarg <bert.wesarg@googlemail.com> Date: Mon, 13 Apr 2009 12:25:47 +0200 Subject: [PATCH 438/654] for-each-ref: utilize core.warnAmbiguousRefs for :short-format core.warnAmbiguousRefs is used to select strict mode for the abbreviation for the ":short" format specifier of "refname" and "upstream". In strict mode, the abbreviated ref will never trigger the 'warn_ambiguous_refs' warning. I.e. for these refs: refs/heads/xyzzy refs/tags/xyzzy the abbreviated forms are: heads/xyzzy tags/xyzzy Signed-off-by: Bert Wesarg <bert.wesarg@googlemail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-for-each-ref.txt | 2 ++ builtin-for-each-ref.c | 6 +++++- t/t6300-for-each-ref.sh | 18 +++++++++++++++--- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index b362e9ed12..8dc873fd44 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -75,6 +75,8 @@ For all objects, the following names can be used: refname:: The name of the ref (the part after $GIT_DIR/). For a non-ambiguous short name of the ref append `:short`. + The option core.warnAmbiguousRefs is used to select the strict + abbreviation mode. objecttype:: The type of the object (`blob`, `tree`, `commit`, `tag`). diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index cfff686ac8..91e8f95fd2 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -601,7 +601,8 @@ static void populate_value(struct refinfo *ref) if (formatp) { formatp++; if (!strcmp(formatp, "short")) - refname = shorten_unambiguous_ref(refname, 0); + refname = shorten_unambiguous_ref(refname, + warn_ambiguous_refs); else die("unknown %.*s format %s", (int)(formatp - name), name, formatp); @@ -917,6 +918,9 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix) sort = default_sort(); sort_atom_limit = used_atom_cnt; + /* for warn_ambiguous_refs */ + git_config(git_default_config, NULL); + memset(&cbdata, 0, sizeof(cbdata)); cbdata.grab_pattern = argv; for_each_ref(grab_single_ref, &cbdata); diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index daf02d5c10..8052c86ad3 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -301,10 +301,11 @@ test_expect_success 'Check for invalid refname format' ' cat >expected <<\EOF heads/master -master +tags/master EOF -test_expect_success 'Check ambiguous head and tag refs' ' +test_expect_success 'Check ambiguous head and tag refs (strict)' ' + git config --bool core.warnambiguousrefs true && git checkout -b newtag && echo "Using $datestamp" > one && git add one && @@ -315,12 +316,23 @@ test_expect_success 'Check ambiguous head and tag refs' ' test_cmp expected actual ' +cat >expected <<\EOF +heads/master +master +EOF + +test_expect_success 'Check ambiguous head and tag refs (loose)' ' + git config --bool core.warnambiguousrefs false && + git for-each-ref --format "%(refname:short)" refs/heads/master refs/tags/master >actual && + test_cmp expected actual +' + cat >expected <<\EOF heads/ambiguous ambiguous EOF -test_expect_success 'Check ambiguous head and tag refs II' ' +test_expect_success 'Check ambiguous head and tag refs II (loose)' ' git checkout master && git tag ambiguous testtag^0 && git branch ambiguous testtag^0 && From a45d34691ea624e93863e95706eeb1b1909304f3 Mon Sep 17 00:00:00 2001 From: Bert Wesarg <bert.wesarg@googlemail.com> Date: Mon, 13 Apr 2009 13:20:26 +0200 Subject: [PATCH 439/654] rev-parse: --abbrev-ref option to shorten ref name This applies the shorten_unambiguous_ref function to the object name. Default mode is controlled by core.warnAmbiguousRefs. Else it is given as optional argument to --abbrev-ref={strict|loose}. This should be faster than 'git for-each-ref --format="%(refname:short)" <ref>' for single refs. Signed-off-by: Bert Wesarg <bert.wesarg@googlemail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-rev-parse.txt | 5 +++++ builtin-rev-parse.c | 23 +++++++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index 5ed2bc840f..fba30b12ed 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -84,6 +84,11 @@ OPTIONS unfortunately named tag "master"), and show them as full refnames (e.g. "refs/heads/master"). +--abbrev-ref[={strict|loose}]:: + A non-ambiguous short name of the objects name. + The option core.warnAmbiguousRefs is used to select the strict + abbreviation mode. + --all:: Show all refs found in `$GIT_DIR/refs`. diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c index 81d5a6ffc9..22c6d6ad16 100644 --- a/builtin-rev-parse.c +++ b/builtin-rev-parse.c @@ -26,6 +26,8 @@ static int show_type = NORMAL; #define SHOW_SYMBOLIC_FULL 2 static int symbolic; static int abbrev; +static int abbrev_ref; +static int abbrev_ref_strict; static int output_sq; /* @@ -109,8 +111,8 @@ static void show_rev(int type, const unsigned char *sha1, const char *name) return; def = NULL; - if (symbolic && name) { - if (symbolic == SHOW_SYMBOLIC_FULL) { + if ((symbolic || abbrev_ref) && name) { + if (symbolic == SHOW_SYMBOLIC_FULL || abbrev_ref) { unsigned char discard[20]; char *full; @@ -125,6 +127,9 @@ static void show_rev(int type, const unsigned char *sha1, const char *name) */ break; case 1: /* happy */ + if (abbrev_ref) + full = shorten_unambiguous_ref(full, + abbrev_ref_strict); show_with_type(type, full); break; default: /* ambiguous */ @@ -506,6 +511,20 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) symbolic = SHOW_SYMBOLIC_FULL; continue; } + if (!prefixcmp(arg, "--abbrev-ref") && + (!arg[12] || arg[12] == '=')) { + abbrev_ref = 1; + abbrev_ref_strict = warn_ambiguous_refs; + if (arg[12] == '=') { + if (!strcmp(arg + 13, "strict")) + abbrev_ref_strict = 1; + else if (!strcmp(arg + 13, "loose")) + abbrev_ref_strict = 0; + else + die("unknown mode for %s", arg); + } + continue; + } if (!strcmp(arg, "--all")) { for_each_ref(show_reference, NULL); continue; From d8c81dfcaf3ac4bab0f0f8f54d2c4ae0425abcbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kiedrowicz?= <michal.kiedrowicz@gmail.com> Date: Sat, 11 Apr 2009 17:26:24 +0200 Subject: [PATCH 440/654] tests: test applying criss-cross rename patch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Originally reported by Linus in $gmane/116198 Signed-off-by: Michał Kiedrowicz <michal.kiedrowicz@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t4130-apply-criss-cross-rename.sh | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100755 t/t4130-apply-criss-cross-rename.sh diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh new file mode 100755 index 0000000000..08c5f38b01 --- /dev/null +++ b/t/t4130-apply-criss-cross-rename.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +test_description='git apply handling criss-cross rename patch.' +. ./test-lib.sh + +create_file() { + cnt=0 + while test $cnt -le 100 + do + cnt=$(($cnt + 1)) + echo "$2" >> "$1" + done +} + +test_expect_success 'setup' ' + create_file file1 "File1 contents" && + create_file file2 "File2 contents" && + git add file1 file2 && + git commit -m 1 +' + +test_expect_success 'criss-cross rename' ' + mv file1 tmp && + mv file2 file1 && + mv tmp file2 +' + +test_expect_success 'diff -M -B' ' + git diff -M -B > diff && + git reset --hard + +' + +test_expect_failure 'apply' ' + git apply diff +' + +test_done From 427fc5b8885d269359c8eff187925e3d49f103b4 Mon Sep 17 00:00:00 2001 From: Allan Caffee <allan.caffee@gmail.com> Date: Mon, 13 Apr 2009 15:53:41 -0400 Subject: [PATCH 441/654] graph API: Added logic for colored edges Modified the graph drawing logic to colorize edges based on parent-child relationships similiarly to gitk. Signed-off-by: Allan Caffee <allan.caffee@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- color.h | 1 + graph.c | 246 +++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 199 insertions(+), 48 deletions(-) diff --git a/color.h b/color.h index 6846be1706..18abeb7c7d 100644 --- a/color.h +++ b/color.h @@ -11,6 +11,7 @@ #define GIT_COLOR_GREEN "\033[32m" #define GIT_COLOR_YELLOW "\033[33m" #define GIT_COLOR_BLUE "\033[34m" +#define GIT_COLOR_MAGENTA "\033[35m" #define GIT_COLOR_CYAN "\033[36m" #define GIT_COLOR_BG_RED "\033[41m" diff --git a/graph.c b/graph.c index 162a516ee1..d4571cf31d 100644 --- a/graph.c +++ b/graph.c @@ -1,5 +1,6 @@ #include "cache.h" #include "commit.h" +#include "color.h" #include "graph.h" #include "diff.h" #include "revision.h" @@ -43,10 +44,6 @@ static void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb); /* * TODO: - * - Add colors to the graph. - * Pick a color for each column, and print all characters - * in that column with the specified color. - * * - Limit the number of columns, similar to the way gitk does. * If we reach more than a specified number of columns, omit * sections of some columns. @@ -72,9 +69,10 @@ struct column { */ struct commit *commit; /* - * XXX: Once we add support for colors, struct column could also - * contain the color of its branch line. + * The color to (optionally) print this column in. This is an + * index into column_colors. */ + unsigned short color; }; enum graph_state { @@ -86,6 +84,41 @@ enum graph_state { GRAPH_COLLAPSING }; +/* + * The list of available column colors. + */ +static char column_colors[][COLOR_MAXLEN] = { + GIT_COLOR_RED, + GIT_COLOR_GREEN, + GIT_COLOR_YELLOW, + GIT_COLOR_BLUE, + GIT_COLOR_MAGENTA, + GIT_COLOR_CYAN, + GIT_COLOR_BOLD GIT_COLOR_RED, + GIT_COLOR_BOLD GIT_COLOR_GREEN, + GIT_COLOR_BOLD GIT_COLOR_YELLOW, + GIT_COLOR_BOLD GIT_COLOR_BLUE, + GIT_COLOR_BOLD GIT_COLOR_MAGENTA, + GIT_COLOR_BOLD GIT_COLOR_CYAN, +}; + +#define COLUMN_COLORS_MAX (ARRAY_SIZE(column_colors)) + +static const char *column_get_color_code(const struct column *c) +{ + return column_colors[c->color]; +} + +static void strbuf_write_column(struct strbuf *sb, const struct column *c, + char col_char) +{ + if (c->color < COLUMN_COLORS_MAX) + strbuf_addstr(sb, column_get_color_code(c)); + strbuf_addch(sb, col_char); + if (c->color < COLUMN_COLORS_MAX) + strbuf_addstr(sb, GIT_COLOR_RESET); +} + struct git_graph { /* * The commit currently being processed @@ -185,6 +218,11 @@ struct git_graph { * temporary array each time we have to output a collapsing line. */ int *new_mapping; + /* + * The current default column color being used. This is + * stored as an index into the array column_colors. + */ + unsigned short default_column_color; }; struct git_graph *graph_init(struct rev_info *opt) @@ -201,6 +239,7 @@ struct git_graph *graph_init(struct rev_info *opt) graph->num_columns = 0; graph->num_new_columns = 0; graph->mapping_size = 0; + graph->default_column_color = 0; /* * Allocate a reasonably large default number of columns @@ -312,6 +351,33 @@ static struct commit_list *first_interesting_parent(struct git_graph *graph) return next_interesting_parent(graph, parents); } +static unsigned short graph_get_current_column_color(const struct git_graph *graph) +{ + if (!DIFF_OPT_TST(&graph->revs->diffopt, COLOR_DIFF)) + return COLUMN_COLORS_MAX; + return graph->default_column_color; +} + +/* + * Update the graph's default column color. + */ +static void graph_increment_column_color(struct git_graph *graph) +{ + graph->default_column_color = (graph->default_column_color + 1) % + COLUMN_COLORS_MAX; +} + +static unsigned short graph_find_commit_color(const struct git_graph *graph, + const struct commit *commit) +{ + int i; + for (i = 0; i < graph->num_columns; i++) { + if (graph->columns[i].commit == commit) + return graph->columns[i].color; + } + return graph_get_current_column_color(graph); +} + static void graph_insert_into_new_columns(struct git_graph *graph, struct commit *commit, int *mapping_index) @@ -334,6 +400,7 @@ static void graph_insert_into_new_columns(struct git_graph *graph, * This commit isn't already in new_columns. Add it. */ graph->new_columns[graph->num_new_columns].commit = commit; + graph->new_columns[graph->num_new_columns].color = graph_find_commit_color(graph, commit); graph->mapping[*mapping_index] = graph->num_new_columns; *mapping_index += 2; graph->num_new_columns++; @@ -445,6 +512,12 @@ static void graph_update_columns(struct git_graph *graph) for (parent = first_interesting_parent(graph); parent; parent = next_interesting_parent(graph, parent)) { + /* + * If this is a merge increment the current + * color. + */ + if (graph->num_parents > 1) + graph_increment_column_color(graph); graph_insert_into_new_columns(graph, parent->item, &mapping_idx); @@ -560,7 +633,8 @@ static int graph_is_mapping_correct(struct git_graph *graph) return 1; } -static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb) +static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb, + int chars_written) { /* * Add additional spaces to the end of the strbuf, so that all @@ -570,10 +644,10 @@ static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb) * aligned for the entire commit. */ int extra; - if (sb->len >= graph->width) + if (chars_written >= graph->width) return; - extra = graph->width - sb->len; + extra = graph->width - chars_written; strbuf_addf(sb, "%*s", (int) extra, ""); } @@ -596,10 +670,11 @@ static void graph_output_padding_line(struct git_graph *graph, * Output a padding row, that leaves all branch lines unchanged */ for (i = 0; i < graph->num_new_columns; i++) { - strbuf_addstr(sb, "| "); + strbuf_write_column(sb, &graph->new_columns[i], '|'); + strbuf_addch(sb, ' '); } - graph_pad_horizontally(graph, sb); + graph_pad_horizontally(graph, sb, graph->num_new_columns * 2); } static void graph_output_skip_line(struct git_graph *graph, struct strbuf *sb) @@ -609,7 +684,7 @@ static void graph_output_skip_line(struct git_graph *graph, struct strbuf *sb) * of the graph is missing. */ strbuf_addstr(sb, "..."); - graph_pad_horizontally(graph, sb); + graph_pad_horizontally(graph, sb, 3); if (graph->num_parents >= 3 && graph->commit_index < (graph->num_columns - 1)) @@ -623,6 +698,7 @@ static void graph_output_pre_commit_line(struct git_graph *graph, { int num_expansion_rows; int i, seen_this; + int chars_written; /* * This function formats a row that increases the space around a commit @@ -645,11 +721,14 @@ static void graph_output_pre_commit_line(struct git_graph *graph, * Output the row */ seen_this = 0; + chars_written = 0; for (i = 0; i < graph->num_columns; i++) { struct column *col = &graph->columns[i]; if (col->commit == graph->commit) { seen_this = 1; - strbuf_addf(sb, "| %*s", graph->expansion_row, ""); + strbuf_write_column(sb, col, '|'); + strbuf_addf(sb, " %*s", graph->expansion_row, ""); + chars_written += 2 + graph->expansion_row; } else if (seen_this && (graph->expansion_row == 0)) { /* * This is the first line of the pre-commit output. @@ -662,17 +741,22 @@ static void graph_output_pre_commit_line(struct git_graph *graph, */ if (graph->prev_state == GRAPH_POST_MERGE && graph->prev_commit_index < i) - strbuf_addstr(sb, "\\ "); + strbuf_write_column(sb, col, '\\'); else - strbuf_addstr(sb, "| "); + strbuf_write_column(sb, col, '|'); + chars_written++; } else if (seen_this && (graph->expansion_row > 0)) { - strbuf_addstr(sb, "\\ "); + strbuf_write_column(sb, col, '\\'); + chars_written++; } else { - strbuf_addstr(sb, "| "); + strbuf_write_column(sb, col, '|'); + chars_written++; } + strbuf_addch(sb, ' '); + chars_written++; } - graph_pad_horizontally(graph, sb); + graph_pad_horizontally(graph, sb, chars_written); /* * Increment graph->expansion_row, @@ -714,10 +798,34 @@ static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb) strbuf_addch(sb, '*'); } +/* + * Draw an octopus merge and return the number of characters written. + */ +static int graph_draw_octopus_merge(struct git_graph *graph, + struct strbuf *sb) +{ + /* + * Here dashless_commits represents the number of parents + * which don't need to have dashes (because their edges fit + * neatly under the commit). + */ + const int dashless_commits = 2; + int col_num, i; + int num_dashes = + ((graph->num_parents - dashless_commits) * 2) - 1; + for (i = 0; i < num_dashes; i++) { + col_num = (i / 2) + dashless_commits; + strbuf_write_column(sb, &graph->new_columns[col_num], '-'); + } + col_num = (i / 2) + dashless_commits; + strbuf_write_column(sb, &graph->new_columns[col_num], '.'); + return num_dashes + 1; +} + static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb) { int seen_this = 0; - int i, j; + int i, chars_written; /* * Output the row containing this commit @@ -727,7 +835,9 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb) * children that we have already processed.) */ seen_this = 0; + chars_written = 0; for (i = 0; i <= graph->num_columns; i++) { + struct column *col = &graph->columns[i]; struct commit *col_commit; if (i == graph->num_columns) { if (seen_this) @@ -740,18 +850,14 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb) if (col_commit == graph->commit) { seen_this = 1; graph_output_commit_char(graph, sb); + chars_written++; - if (graph->num_parents < 3) - strbuf_addch(sb, ' '); - else { - int num_dashes = - ((graph->num_parents - 2) * 2) - 1; - for (j = 0; j < num_dashes; j++) - strbuf_addch(sb, '-'); - strbuf_addstr(sb, ". "); - } + if (graph->num_parents > 3) + chars_written += graph_draw_octopus_merge(graph, + sb); } else if (seen_this && (graph->num_parents > 2)) { - strbuf_addstr(sb, "\\ "); + strbuf_write_column(sb, col, '\\'); + chars_written++; } else if (seen_this && (graph->num_parents == 2)) { /* * This is a 2-way merge commit. @@ -768,15 +874,19 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb) */ if (graph->prev_state == GRAPH_POST_MERGE && graph->prev_commit_index < i) - strbuf_addstr(sb, "\\ "); + strbuf_write_column(sb, col, '\\'); else - strbuf_addstr(sb, "| "); + strbuf_write_column(sb, col, '|'); + chars_written++; } else { - strbuf_addstr(sb, "| "); + strbuf_write_column(sb, col, '|'); + chars_written++; } + strbuf_addch(sb, ' '); + chars_written++; } - graph_pad_horizontally(graph, sb); + graph_pad_horizontally(graph, sb, chars_written); /* * Update graph->state @@ -789,37 +899,75 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb) graph_update_state(graph, GRAPH_COLLAPSING); } +static struct column *find_new_column_by_commit(struct git_graph *graph, + struct commit *commit) +{ + int i; + for (i = 0; i < graph->num_new_columns; i++) { + if (graph->new_columns[i].commit == commit) + return &graph->new_columns[i]; + } + return 0; +} + static void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb) { int seen_this = 0; - int i, j; + int i, j, chars_written; /* * Output the post-merge row */ + chars_written = 0; for (i = 0; i <= graph->num_columns; i++) { + struct column *col = &graph->columns[i]; struct commit *col_commit; if (i == graph->num_columns) { if (seen_this) break; col_commit = graph->commit; } else { - col_commit = graph->columns[i].commit; + col_commit = col->commit; } if (col_commit == graph->commit) { + /* + * Since the current commit is a merge find + * the columns for the parent commits in + * new_columns and use those to format the + * edges. + */ + struct commit_list *parents = NULL; + struct column *par_column; seen_this = 1; - strbuf_addch(sb, '|'); - for (j = 0; j < graph->num_parents - 1; j++) - strbuf_addstr(sb, "\\ "); + parents = first_interesting_parent(graph); + assert(parents); + par_column = find_new_column_by_commit(graph, parents->item); + assert(par_column); + + strbuf_write_column(sb, par_column, '|'); + chars_written++; + for (j = 0; j < graph->num_parents - 1; j++) { + parents = next_interesting_parent(graph, parents); + assert(parents); + par_column = find_new_column_by_commit(graph, parents->item); + assert(par_column); + strbuf_write_column(sb, par_column, '\\'); + strbuf_addch(sb, ' '); + } + chars_written += j * 2; } else if (seen_this) { - strbuf_addstr(sb, "\\ "); + strbuf_write_column(sb, col, '\\'); + strbuf_addch(sb, ' '); + chars_written += 2; } else { - strbuf_addstr(sb, "| "); + strbuf_write_column(sb, col, '|'); + strbuf_addch(sb, ' '); + chars_written += 2; } } - graph_pad_horizontally(graph, sb); + graph_pad_horizontally(graph, sb, chars_written); /* * Update graph->state @@ -912,12 +1060,12 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf if (target < 0) strbuf_addch(sb, ' '); else if (target * 2 == i) - strbuf_addch(sb, '|'); + strbuf_write_column(sb, &graph->new_columns[target], '|'); else - strbuf_addch(sb, '/'); + strbuf_write_column(sb, &graph->new_columns[target], '/'); } - graph_pad_horizontally(graph, sb); + graph_pad_horizontally(graph, sb, graph->mapping_size); /* * Swap mapping and new_mapping @@ -979,9 +1127,10 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb) * children that we have already processed.) */ for (i = 0; i < graph->num_columns; i++) { - struct commit *col_commit = graph->columns[i].commit; + struct column *col = &graph->columns[i]; + struct commit *col_commit = col->commit; if (col_commit == graph->commit) { - strbuf_addch(sb, '|'); + strbuf_write_column(sb, col, '|'); if (graph->num_parents < 3) strbuf_addch(sb, ' '); @@ -991,11 +1140,12 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb) strbuf_addch(sb, ' '); } } else { - strbuf_addstr(sb, "| "); + strbuf_write_column(sb, col, '|'); + strbuf_addch(sb, ' '); } } - graph_pad_horizontally(graph, sb); + graph_pad_horizontally(graph, sb, graph->num_columns); /* * Update graph->prev_state since we have output a padding line From 7fac0eef91cf930ef827b00934701fa5543dce76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kiedrowicz?= <michal.kiedrowicz@gmail.com> Date: Sat, 11 Apr 2009 21:31:00 +0200 Subject: [PATCH 442/654] builtin-apply: keep information about files to be deleted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Example correct diff generated by `diff -M -B' might look like this: diff --git a/file1 b/file2 similarity index 100% rename from file1 rename to file2 diff --git a/file2 b/file1 similarity index 100% rename from file2 rename to file1 Information about removing `file2' comes after information about creation of new `file2' (renamed from `file1'). Existing implementation isn't able to apply such patch, because it has to know in advance which files will be removed. This patch populates fn_table with information about removal of files before calling check_patch() for each patch to be applied. Signed-off-by: Michał Kiedrowicz <michal.kiedrowicz@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-apply.c | 53 +++++++++++++++++++++++++---- t/t4130-apply-criss-cross-rename.sh | 2 +- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/builtin-apply.c b/builtin-apply.c index 1926cd8055..7b404ef660 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2271,6 +2271,25 @@ static struct patch *in_fn_table(const char *name) return NULL; } +/* + * item->util in the filename table records the status of the path. + * Usually it points at a patch (whose result records the contents + * of it after applying it), but it could be PATH_WAS_DELETED for a + * path that a previously applied patch has already removed. + */ + #define PATH_TO_BE_DELETED ((struct patch *) -2) +#define PATH_WAS_DELETED ((struct patch *) -1) + +static int to_be_deleted(struct patch *patch) +{ + return patch == PATH_TO_BE_DELETED; +} + +static int was_deleted(struct patch *patch) +{ + return patch == PATH_WAS_DELETED; +} + static void add_to_fn_table(struct patch *patch) { struct string_list_item *item; @@ -2291,7 +2310,22 @@ static void add_to_fn_table(struct patch *patch) */ if ((patch->new_name == NULL) || (patch->is_rename)) { item = string_list_insert(patch->old_name, &fn_table); - item->util = (struct patch *) -1; + item->util = PATH_WAS_DELETED; + } +} + +static void prepare_fn_table(struct patch *patch) +{ + /* + * store information about incoming file deletion + */ + while (patch) { + if ((patch->new_name == NULL) || (patch->is_rename)) { + struct string_list_item *item; + item = string_list_insert(patch->old_name, &fn_table); + item->util = PATH_TO_BE_DELETED; + } + patch = patch->next; } } @@ -2304,8 +2338,8 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry * struct patch *tpatch; if (!(patch->is_copy || patch->is_rename) && - ((tpatch = in_fn_table(patch->old_name)) != NULL)) { - if (tpatch == (struct patch *) -1) { + (tpatch = in_fn_table(patch->old_name)) != NULL && !to_be_deleted(tpatch)) { + if (was_deleted(tpatch)) { return error("patch %s has been renamed/deleted", patch->old_name); } @@ -2399,10 +2433,9 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s assert(patch->is_new <= 0); if (!(patch->is_copy || patch->is_rename) && - (tpatch = in_fn_table(old_name)) != NULL) { - if (tpatch == (struct patch *) -1) { + (tpatch = in_fn_table(old_name)) != NULL && !to_be_deleted(tpatch)) { + if (was_deleted(tpatch)) return error("%s: has been deleted/renamed", old_name); - } st_mode = tpatch->new_mode; } else if (!cached) { stat_ret = lstat(old_name, st); @@ -2410,6 +2443,9 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s return error("%s: %s", old_name, strerror(errno)); } + if (to_be_deleted(tpatch)) + tpatch = NULL; + if (check_index && !tpatch) { int pos = cache_name_pos(old_name, strlen(old_name)); if (pos < 0) { @@ -2471,6 +2507,7 @@ static int check_patch(struct patch *patch) const char *new_name = patch->new_name; const char *name = old_name ? old_name : new_name; struct cache_entry *ce = NULL; + struct patch *tpatch; int ok_if_exists; int status; @@ -2481,7 +2518,8 @@ static int check_patch(struct patch *patch) return status; old_name = patch->old_name; - if (in_fn_table(new_name) == (struct patch *) -1) + if ((tpatch = in_fn_table(new_name)) && + (was_deleted(tpatch) || to_be_deleted(tpatch))) /* * A type-change diff is always split into a patch to * delete old, immediately followed by a patch to @@ -2533,6 +2571,7 @@ static int check_patch_list(struct patch *patch) { int err = 0; + prepare_fn_table(patch); while (patch) { if (apply_verbosely) say_patch_name(stderr, diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 08c5f38b01..8623dbebab 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -31,7 +31,7 @@ test_expect_success 'diff -M -B' ' ' -test_expect_failure 'apply' ' +test_expect_success 'apply' ' git apply diff ' From 9a7a1e03d5e530cdad98c41c109e3319c008ce69 Mon Sep 17 00:00:00 2001 From: Matthieu Moy <Matthieu.Moy@imag.fr> Date: Fri, 10 Apr 2009 16:57:01 +0200 Subject: [PATCH 443/654] git add -p: new "quit" command at the prompt. There's already 'd' to stop staging hunks in a file, but no explicit command to stop the interactive staging (for the current files and the remaining ones). Of course you can do 'd' and then ^C, but it would be more intuitive to allow 'quit' action. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-add.txt | 1 + git-add--interactive.perl | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt index ce71838b9e..709e04b335 100644 --- a/Documentation/git-add.txt +++ b/Documentation/git-add.txt @@ -245,6 +245,7 @@ patch:: y - stage this hunk n - do not stage this hunk + q - quite, do not stage this hunk nor any of the remaining ones a - stage this and all the remaining hunks in the file d - do not stage this hunk nor any of the remaining hunks in the file j - leave this hunk undecided, see next undecided hunk diff --git a/git-add--interactive.perl b/git-add--interactive.perl index def062a9e2..210d23022d 100755 --- a/git-add--interactive.perl +++ b/git-add--interactive.perl @@ -894,6 +894,7 @@ sub help_patch_cmd { print colored $help_color, <<\EOF ; y - stage this hunk n - do not stage this hunk +q - quit, do not stage this hunk nor any of the remaining ones a - stage this and all the remaining hunks in the file d - do not stage this hunk nor any of the remaining hunks in the file g - select a hunk to go to @@ -930,7 +931,7 @@ sub patch_update_cmd { @mods); } for (@them) { - patch_update_file($_->{VALUE}); + return 0 if patch_update_file($_->{VALUE}); } } @@ -976,6 +977,7 @@ sub display_hunks { } sub patch_update_file { + my $quit = 0; my ($ix, $num); my $path = shift; my ($head, @hunk) = parse_diff($path); @@ -1006,6 +1008,11 @@ sub patch_update_file { $_->{USE} = 0 foreach ($mode, @hunk); last; } + elsif ($line =~ /^q/i) { + $_->{USE} = 0 foreach ($mode, @hunk); + $quit = 1; + last; + } else { help_patch_cmd(''); next; @@ -1113,6 +1120,16 @@ sub patch_update_file { } next; } + elsif ($line =~ /^q/i) { + while ($ix < $num) { + if (!defined $hunk[$ix]{USE}) { + $hunk[$ix]{USE} = 0; + } + $ix++; + } + $quit = 1; + next; + } elsif ($line =~ m|^/(.*)|) { my $regex = $1; if ($1 eq "") { @@ -1239,6 +1256,7 @@ sub patch_update_file { } print "\n"; + return $quit; } sub diff_cmd { From 0392513fdc7e98f5ca5dff1ad80962c28029267b Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Thu, 16 Apr 2009 03:14:15 -0400 Subject: [PATCH 444/654] add-interactive: refactor mode hunk handling The original implementation considered the mode separately from the rest of the hunks, asking about it outside the main hunk-selection loop. This patch instead places a mode change as the first hunk in the loop. This has two advantages: 1. less duplicated code (since we use the main selection loop). This also cleans up an inconsistency, which is that the main selection loop separates options with a comma, whereas the mode prompt used slashes. 2. users can now skip the mode change and come back to it, search for it (via "/mode"), etc, as they can with other hunks. To facilitate this, each hunk is now marked with a "type". Mode hunks are not considered for splitting (which would make no sense, and also confuses the split_hunk function), nor are they editable. In theory, one could edit the mode lines and change to a new mode. In practice, there are only two modes that git cares about (0644 and 0755), so either you want to move from one to the other or not (and you can do that by staging or not staging). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-add--interactive.perl | 64 +++++++++++++-------------------------- 1 file changed, 21 insertions(+), 43 deletions(-) diff --git a/git-add--interactive.perl b/git-add--interactive.perl index 210d23022d..60dd1b5be2 100755 --- a/git-add--interactive.perl +++ b/git-add--interactive.perl @@ -620,11 +620,12 @@ sub parse_diff { if ($diff_use_color) { @colored = run_cmd_pipe(qw(git diff-files -p --color --), $path); } - my (@hunk) = { TEXT => [], DISPLAY => [] }; + my (@hunk) = { TEXT => [], DISPLAY => [], TYPE => 'header' }; for (my $i = 0; $i < @diff; $i++) { if ($diff[$i] =~ /^@@ /) { - push @hunk, { TEXT => [], DISPLAY => [] }; + push @hunk, { TEXT => [], DISPLAY => [], + TYPE => 'hunk' }; } push @{$hunk[-1]{TEXT}}, $diff[$i]; push @{$hunk[-1]{DISPLAY}}, @@ -636,8 +637,8 @@ sub parse_diff { sub parse_diff_header { my $src = shift; - my $head = { TEXT => [], DISPLAY => [] }; - my $mode = { TEXT => [], DISPLAY => [] }; + my $head = { TEXT => [], DISPLAY => [], TYPE => 'header' }; + my $mode = { TEXT => [], DISPLAY => [], TYPE => 'mode' }; for (my $i = 0; $i < @{$src->{TEXT}}; $i++) { my $dest = $src->{TEXT}->[$i] =~ /^(old|new) mode (\d+)$/ ? @@ -684,6 +685,7 @@ sub split_hunk { my $this = +{ TEXT => [], DISPLAY => [], + TYPE => 'hunk', OLD => $o_ofs, NEW => $n_ofs, OCNT => 0, @@ -873,7 +875,11 @@ sub edit_hunk_loop { if (!defined $text) { return undef; } - my $newhunk = { TEXT => $text, USE => 1 }; + my $newhunk = { + TEXT => $text, + TYPE => $hunk->[$ix]->{TYPE}, + USE => 1 + }; if (diff_applies($head, @{$hunk}[0..$ix-1], $newhunk, @@ -987,37 +993,7 @@ sub patch_update_file { } if (@{$mode->{TEXT}}) { - while (1) { - print @{$mode->{DISPLAY}}; - print colored $prompt_color, - "Stage mode change [y/n/a/d/?]? "; - my $line = prompt_single_character; - if ($line =~ /^y/i) { - $mode->{USE} = 1; - last; - } - elsif ($line =~ /^n/i) { - $mode->{USE} = 0; - last; - } - elsif ($line =~ /^a/i) { - $_->{USE} = 1 foreach ($mode, @hunk); - last; - } - elsif ($line =~ /^d/i) { - $_->{USE} = 0 foreach ($mode, @hunk); - last; - } - elsif ($line =~ /^q/i) { - $_->{USE} = 0 foreach ($mode, @hunk); - $quit = 1; - last; - } - else { - help_patch_cmd(''); - next; - } - } + unshift @hunk, $mode; } $num = scalar @hunk; @@ -1061,14 +1037,19 @@ sub patch_update_file { } last if (!$undecided); - if (hunk_splittable($hunk[$ix]{TEXT})) { + if ($hunk[$ix]{TYPE} eq 'hunk' && + hunk_splittable($hunk[$ix]{TEXT})) { $other .= ',s'; } - $other .= ',e'; + if ($hunk[$ix]{TYPE} eq 'hunk') { + $other .= ',e'; + } for (@{$hunk[$ix]{DISPLAY}}) { print; } - print colored $prompt_color, "Stage this hunk [y,n,a,d,/$other,?]? "; + print colored $prompt_color, 'Stage ', + ($hunk[$ix]{TYPE} eq 'mode' ? 'mode change' : 'this hunk'), + " [y,n,a,d,/$other,?]? "; my $line = prompt_single_character; if ($line) { if ($line =~ /^y/i) { @@ -1210,7 +1191,7 @@ sub patch_update_file { $num = scalar @hunk; next; } - elsif ($line =~ /^e/) { + elsif ($other =~ /e/ && $line =~ /^e/) { my $newhunk = edit_hunk_loop($head, \@hunk, $ix); if (defined $newhunk) { splice @hunk, $ix, 1, $newhunk; @@ -1231,9 +1212,6 @@ sub patch_update_file { my $n_lofs = 0; my @result = (); - if ($mode->{USE}) { - push @result, @{$mode->{TEXT}}; - } for (@hunk) { if ($_->{USE}) { push @result, @{$_->{TEXT}}; From 595f6948232a2e37df4f63476662cba20ecf9d8d Mon Sep 17 00:00:00 2001 From: Matthieu Moy <Matthieu.Moy@imag.fr> Date: Thu, 16 Apr 2009 18:46:23 +0200 Subject: [PATCH 445/654] Update git-add.txt according to the new possibilities of 'git add -p'. The text is merely cut-and-pasted from git-add--interactive.perl. The cut-and-paste also fixes a typo. Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-add.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt index 709e04b335..d938b42289 100644 --- a/Documentation/git-add.txt +++ b/Documentation/git-add.txt @@ -245,9 +245,11 @@ patch:: y - stage this hunk n - do not stage this hunk - q - quite, do not stage this hunk nor any of the remaining ones + q - quit, do not stage this hunk nor any of the remaining ones a - stage this and all the remaining hunks in the file d - do not stage this hunk nor any of the remaining hunks in the file + g - select a hunk to go to + / - search for a hunk matching the given regex j - leave this hunk undecided, see next undecided hunk J - leave this hunk undecided, see next hunk k - leave this hunk undecided, see previous undecided hunk From 9832e4f29b82e0072f40ef73279da3cd09e4a75c Mon Sep 17 00:00:00 2001 From: Paul Mackerras <paulus@samba.org> Date: Mon, 23 Mar 2009 21:37:51 +1100 Subject: [PATCH 446/654] gitk: Make .gitk a hidden file under windows This sets the hidden attribute on the ~/.gitk file so it doesn't appear in the windows user profile. Signed-off-by: Paul Mackerras <paulus@samba.org> --- gitk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gitk b/gitk index bdd12236b8..0bc2f30929 100755 --- a/gitk +++ b/gitk @@ -2519,6 +2519,9 @@ proc savestuff {w} { if {![winfo viewable .]} return catch { set f [open "~/.gitk-new" w] + if {$::tcl_platform(platform) eq {windows}} { + file attributes "~/.gitk-new" -hidden true + } puts $f [list set mainfont $mainfont] puts $f [list set textfont $textfont] puts $f [list set uifont $uifont] From 84b4b832eb39aaf85f9363405123afbaeb1ecb49 Mon Sep 17 00:00:00 2001 From: Christian Stimming <stimming@tuhh.de> Date: Thu, 26 Mar 2009 21:13:45 +0100 Subject: [PATCH 447/654] gitk: Mark forgotten string for translation Signed-off-by: Paul Mackerras <paulus@samba.org> --- gitk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitk b/gitk index 0bc2f30929..d151ddb078 100755 --- a/gitk +++ b/gitk @@ -6540,7 +6540,7 @@ proc appendrefs {pos ids var} { } } if {[llength $tags] > $maxrefs} { - $ctext insert $pos "many ([llength $tags])" + $ctext insert $pos "[mc "many"] ([llength $tags])" } else { set tags [lsort -index 0 -decreasing $tags] set sep {} From b56e0a9afd63a54e2c51fba56a79b136a4e978f3 Mon Sep 17 00:00:00 2001 From: Michele Ballabio <barra_cuda@katamail.com> Date: Mon, 30 Mar 2009 21:17:25 +0200 Subject: [PATCH 448/654] gitk: Mark some more strings for translation Signed-off-by: Michele Ballabio <barra_cuda@katamail.com> Signed-off-by: Paul Mackerras <paulus@samba.org> --- gitk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gitk b/gitk index d151ddb078..afb2241419 100755 --- a/gitk +++ b/gitk @@ -521,7 +521,7 @@ proc updatecommits {} { incr viewactive($view) set viewcomplete($view) 0 reset_pending_select {} - nowbusy $view "Reading" + nowbusy $view [mc "Reading"] if {$showneartags} { getallcommits } @@ -3772,7 +3772,7 @@ proc editview {} { set newviewopts($curview,perm) $viewperm($curview) set newviewopts($curview,cmd) $viewargscmd($curview) decode_view_opts $curview $viewargs($curview) - vieweditor $top $curview "Gitk: edit view $viewname($curview)" + vieweditor $top $curview "[mc "Gitk: edit view"] $viewname($curview)" } proc vieweditor {top n title} { @@ -10400,7 +10400,7 @@ proc doprefs {} { proc choose_extdiff {} { global extdifftool - set prog [tk_getOpenFile -title "External diff tool" -multiple false] + set prog [tk_getOpenFile -title [mc "External diff tool"] -multiple false] if {$prog ne {}} { set extdifftool $prog } From b6e192dbf73397da0f76252b7e39770150a8763f Mon Sep 17 00:00:00 2001 From: Michele Ballabio <barra_cuda@katamail.com> Date: Mon, 30 Mar 2009 14:55:21 +0200 Subject: [PATCH 449/654] gitk: Map KP_Divide to focus the search box Commit 97bed034 changed the behavior of the '/' key on the keyboard, but the '/' on the keypad was left unused. They now both do the same thing. Signed-off-by: Michele Ballabio <barra_cuda@katamail.com> Signed-off-by: Paul Mackerras <paulus@samba.org> --- gitk | 1 + 1 file changed, 1 insertion(+) diff --git a/gitk b/gitk index afb2241419..a65d961a07 100755 --- a/gitk +++ b/gitk @@ -2313,6 +2313,7 @@ proc makewindow {} { bindkey d "$ctext yview scroll 18 units" bindkey u "$ctext yview scroll -18 units" bindkey / {focus $fstring} + bindkey <Key-KP_Divide> {focus $fstring} bindkey <Key-Return> {dofind 1 1} bindkey ? {dofind -1 1} bindkey f nextfile From c876dbadc2d44386962296f09a060c3ae69e2029 Mon Sep 17 00:00:00 2001 From: Pat Thoyts <patthoyts@users.sourceforge.net> Date: Tue, 14 Apr 2009 22:09:53 +0100 Subject: [PATCH 450/654] gitk: Remember and restore the window state with the geometry This records the window state in ~/.gitk. On startup, if the gitk window was previously maximized (zoomed), then we restore that state. Signed-off-by: Pat Thoyts <patthoyts@users.sourceforge.net> Signed-off-by: Paul Mackerras <paulus@samba.org> --- gitk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gitk b/gitk index a65d961a07..045e4abba8 100755 --- a/gitk +++ b/gitk @@ -2251,6 +2251,10 @@ proc makewindow {} { } } + if {[info exists geometry(state)] && $geometry(state) eq "zoomed"} { + wm state . $geometry(state) + } + if {[tk windowingsystem] eq {aqua}} { set M1B M1 set ::BM "3" @@ -2548,6 +2552,7 @@ proc savestuff {w} { puts $f [list set perfile_attrs $perfile_attrs] puts $f "set geometry(main) [wm geometry .]" + puts $f "set geometry(state) [wm state .]" puts $f "set geometry(topwidth) [winfo width .tf]" puts $f "set geometry(topheight) [winfo height .tf]" puts $f "set geometry(pwsash0) \"[.tf.histframe.pwclist sash coord 0]\"" From b575b2f1f420bf82557beab0f4ec12e5aa832bea Mon Sep 17 00:00:00 2001 From: Pat Thoyts <patthoyts@users.sourceforge.net> Date: Wed, 15 Apr 2009 16:54:19 +0100 Subject: [PATCH 451/654] gitk: Handle external diff tool with spaces in the path This fixes the launching of external diff to handle a diff tool that has spaces in the path. This ensures a correctly formed tcl list is passed to the open command with a single pipe character prefixing the list (as per the tcl manual page for open). The specific fault observed was that selecting WinMerge as the diff tool from the default installed location in Program Files failed to be launched from the context menu. Signed-off-by: Pat Thoyts <patthoyts@users.sourceforge.net> Signed-off-by: Paul Mackerras <paulus@samba.org> --- gitk | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gitk b/gitk index 045e4abba8..488286f6a1 100755 --- a/gitk +++ b/gitk @@ -3245,9 +3245,8 @@ proc external_diff {} { set difftofile [external_diff_get_one_file $diffidto $flist_menu_file $diffdir] if {$difffromfile ne {} && $difftofile ne {}} { - set cmd [concat | [shellsplit $extdifftool] \ - [list $difffromfile $difftofile]] - if {[catch {set fl [open $cmd r]} err]} { + set cmd [list [shellsplit $extdifftool] $difffromfile $difftofile] + if {[catch {set fl [open |$cmd r]} err]} { file delete -force $diffdir error_popup "$extdifftool: [mc "command failed:"] $err" } else { From 478afad697e58433f34d69b5fe08511405f23506 Mon Sep 17 00:00:00 2001 From: Pat Thoyts <patthoyts@users.sourceforge.net> Date: Wed, 15 Apr 2009 17:14:03 +0100 Subject: [PATCH 452/654] gitk: Avoid crash if closed while reading references As recorded in msysGit issue 125, if the user closes gitk while it reports itself as still reading references then Tk will crash in the geometry management code. This has been fixed for Tk 8.5.7 and above. This patch avoids the problem by flushing outstanding geometry events before calling the readrefs procedure. See also http://code.google.com/p/msysgit/issues/detail?id=125 Signed-off-by: Pat Thoyts <patthoyts@users.sourceforge.net> Signed-off-by: Paul Mackerras <paulus@samba.org> --- gitk | 1 + 1 file changed, 1 insertion(+) diff --git a/gitk b/gitk index 488286f6a1..dca1741c71 100755 --- a/gitk +++ b/gitk @@ -11128,6 +11128,7 @@ catch { # wait for the window to become visible tkwait visibility . wm title . "[file tail $argv0]: [file tail [pwd]]" +update readrefs if {$cmdline_files ne {} || $revtreeargs ne {} || $revtreeargscmd ne {}} { From 0cbcf7ad71559245b59b90a324011fcf0657af8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kiedrowicz?= <michal.kiedrowicz@gmail.com> Date: Fri, 17 Apr 2009 22:34:25 +0200 Subject: [PATCH 453/654] Documentation: boolean value may be given by on/off MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michał Kiedrowicz <michal.kiedrowicz@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 3afd124749..103ea9bc29 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -61,7 +61,7 @@ Internal whitespace within a variable value is retained verbatim. The values following the equals sign in variable assign are all either a string, an integer, or a boolean. Boolean values may be given as yes/no, -0/1 or true/false. Case is not significant in boolean values, when +0/1, true/false or on/off. Case is not significant in boolean values, when converting value to the canonical form using '--bool' type specifier; 'git-config' will ensure that the output is "true" or "false". From 55f0566f6d7269a56751333e0943b50237ce6a85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= <pclouds@gmail.com> Date: Fri, 17 Apr 2009 08:16:23 +1000 Subject: [PATCH 454/654] get_local_heads(): do not return random pointer if there is no head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit it's silly to do this: mkdir foo && cd foo && git init && git push somewhere.git but segfault should not happen even in that case. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- remote.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/remote.c b/remote.c index a06761ace8..e4c89b8b6d 100644 --- a/remote.c +++ b/remote.c @@ -1504,7 +1504,7 @@ static int one_local_ref(const char *refname, const unsigned char *sha1, int fla struct ref *get_local_heads(void) { - struct ref *local_refs, **local_tail = &local_refs; + struct ref *local_refs = NULL, **local_tail = &local_refs; for_each_ref(one_local_ref, &local_tail); return local_refs; } From 45972ffbedf8175555434006595c71a5b0e643f1 Mon Sep 17 00:00:00 2001 From: Michael J Gruber <git@drmicha.warpmail.net> Date: Thu, 16 Apr 2009 10:20:44 +0200 Subject: [PATCH 455/654] remote.c: use shorten_unambiguous_ref Use the new shorten_unambiguous_ref() for simplifying the output of upstream branch names. This affects status and checkout. Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- remote.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/remote.c b/remote.c index a06761ace8..54230ad558 100644 --- a/remote.c +++ b/remote.c @@ -1461,11 +1461,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb) return 0; base = branch->merge[0]->dst; - if (!prefixcmp(base, "refs/remotes/")) { - base += strlen("refs/remotes/"); - } else if (!prefixcmp(base, "refs/heads/")) { - base += strlen("refs/heads/"); - } + base = shorten_unambiguous_ref(base, 0); if (!num_theirs) strbuf_addf(sb, "Your branch is ahead of '%s' " "by %d commit%s.\n", From ad94657fdb8b177b07d94887e1b5259f590f11a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Sat, 18 Apr 2009 00:17:49 +0200 Subject: [PATCH 456/654] archive tests: do not use .gitattributes in working directory We are interested in using archive mostly from a bare repository, so it should not add .gitattributes to the work tree. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t5000-tar-tree.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 7641e0dd46..abb41b07ef 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -50,7 +50,7 @@ test_expect_success \ test_expect_success \ 'add ignored file' \ 'echo ignore me >a/ignored && - echo ignored export-ignore >.gitattributes' + echo ignored export-ignore >.git/info/attributes' test_expect_success \ 'add files to repository' \ @@ -64,7 +64,7 @@ test_expect_success \ test_expect_success \ 'create bare clone' \ 'git clone --bare . bare.git && - cp .gitattributes bare.git/info/attributes' + cp .git/info/attributes bare.git/info/attributes' test_expect_success \ 'remove ignored file' \ @@ -139,10 +139,11 @@ test_expect_success \ test_expect_success \ 'create archives with substfiles' \ - 'echo "substfile?" export-subst >a/.gitattributes && + 'cp .git/info/attributes .git/info/attributes.before && + echo "substfile?" export-subst >>.git/info/attributes && git archive HEAD >f.tar && git archive --prefix=prefix/ HEAD >g.tar && - rm a/.gitattributes' + mv .git/info/attributes.before .git/info/attributes' test_expect_success \ 'extract substfiles' \ From 4191e80a3e8ee0fa0b8f97f9fba81c3549813fd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= <pclouds@gmail.com> Date: Sat, 18 Apr 2009 00:17:58 +0200 Subject: [PATCH 457/654] attr: add GIT_ATTR_INDEX "direction" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This instructs attr mechanism, not to look into working .gitattributes at all. Needed by tools that does not handle working directory, such as "git archive". Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- attr.c | 12 +++++++++--- attr.h | 3 ++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/attr.c b/attr.c index 43259e5b01..f1ca4f5859 100644 --- a/attr.c +++ b/attr.c @@ -405,7 +405,7 @@ static struct attr_stack *read_attr(const char *path, int macro_ok) if (!res) res = read_attr_from_file(path, macro_ok); } - else { + else if (direction == GIT_ATTR_CHECKIN) { res = read_attr_from_file(path, macro_ok); if (!res) /* @@ -415,6 +415,8 @@ static struct attr_stack *read_attr(const char *path, int macro_ok) */ res = read_attr_from_index(path, macro_ok); } + else + res = read_attr_from_index(path, macro_ok); if (!res) res = xcalloc(1, sizeof(*res)); return res; @@ -466,7 +468,7 @@ static void bootstrap_attr_stack(void) elem->prev = attr_stack; attr_stack = elem; - if (!is_bare_repository()) { + if (!is_bare_repository() || direction == GIT_ATTR_INDEX) { elem = read_attr(GITATTRIBUTES_FILE, 1); elem->origin = strdup(""); elem->prev = attr_stack; @@ -533,7 +535,7 @@ static void prepare_attr_stack(const char *path, int dirlen) /* * Read from parent directories and push them down */ - if (!is_bare_repository()) { + if (!is_bare_repository() || direction == GIT_ATTR_INDEX) { while (1) { char *cp; @@ -674,6 +676,10 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check) void git_attr_set_direction(enum git_attr_direction new, struct index_state *istate) { enum git_attr_direction old = direction; + + if (is_bare_repository() && new != GIT_ATTR_INDEX) + die("BUG: non-INDEX attr direction in a bare repo"); + direction = new; if (new != old) drop_attr_stack(); diff --git a/attr.h b/attr.h index 3a2f4ec1a0..69b5767ebc 100644 --- a/attr.h +++ b/attr.h @@ -33,7 +33,8 @@ int git_checkattr(const char *path, int, struct git_attr_check *); enum git_attr_direction { GIT_ATTR_CHECKIN, - GIT_ATTR_CHECKOUT + GIT_ATTR_CHECKOUT, + GIT_ATTR_INDEX, }; void git_attr_set_direction(enum git_attr_direction, struct index_state *); From 66985e6629c4325ec6b1508bf4bda907c2a538cb Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Sat, 18 Apr 2009 00:18:01 +0200 Subject: [PATCH 458/654] unpack-trees: do not muck with attributes when we are not checking out Signed-off-by: Junio C Hamano <gitster@pobox.com> --- unpack-trees.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/unpack-trees.c b/unpack-trees.c index 6847c2d966..e4eb8fa3af 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -87,7 +87,8 @@ static int check_updates(struct unpack_trees_options *o) cnt = 0; } - git_attr_set_direction(GIT_ATTR_CHECKOUT, &o->result); + if (o->update) + git_attr_set_direction(GIT_ATTR_CHECKOUT, &o->result); for (i = 0; i < index->cache_nr; i++) { struct cache_entry *ce = index->cache[i]; @@ -112,7 +113,8 @@ static int check_updates(struct unpack_trees_options *o) } } stop_progress(&progress); - git_attr_set_direction(GIT_ATTR_CHECKIN, NULL); + if (o->update) + git_attr_set_direction(GIT_ATTR_CHECKIN, NULL); return errs != 0; } From ba053ea96c252e04729dcd439e3c35d394d69914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= <pclouds@gmail.com> Date: Sat, 18 Apr 2009 00:18:05 +0200 Subject: [PATCH 459/654] archive: do not read .gitattributes in working directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old behaviour still remains with --worktree-attributes, and it is always on for the legacy "git tar-tree". Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-archive.txt | 5 ++++- archive.c | 23 +++++++++++++++++++++++ archive.h | 1 + builtin-tar-tree.c | 9 ++++++++- 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt index c1adf59497..bc132c87e1 100644 --- a/Documentation/git-archive.txt +++ b/Documentation/git-archive.txt @@ -10,7 +10,7 @@ SYNOPSIS -------- [verse] 'git archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>] - [--output=<file>] + [--output=<file>] [--worktree-attributes] [--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish> [path...] @@ -51,6 +51,9 @@ OPTIONS --output=<file>:: Write the archive to <file> instead of stdout. +--worktree-attributes:: + Look for attributes in .gitattributes in working directory too. + <extra>:: This can be any options that the archiver backend understands. See next section. diff --git a/archive.c b/archive.c index 96b62d4309..b2b90d3170 100644 --- a/archive.c +++ b/archive.c @@ -4,6 +4,7 @@ #include "attr.h" #include "archive.h" #include "parse-options.h" +#include "unpack-trees.h" static char const * const archive_usage[] = { "git archive [options] <tree-ish> [path...]", @@ -150,6 +151,8 @@ int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry) { struct archiver_context context; + struct unpack_trees_options opts; + struct tree_desc t; int err; if (args->baselen > 0 && args->base[args->baselen - 1] == '/') { @@ -168,6 +171,22 @@ int write_archive_entries(struct archiver_args *args, context.args = args; context.write_entry = write_entry; + /* + * Setup index and instruct attr to read index only + */ + if (!args->worktree_attributes) { + memset(&opts, 0, sizeof(opts)); + opts.index_only = 1; + opts.head_idx = -1; + opts.src_index = &the_index; + opts.dst_index = &the_index; + opts.fn = oneway_merge; + init_tree_desc(&t, args->tree->buffer, args->tree->size); + if (unpack_trees(1, &t, &opts)) + return -1; + git_attr_set_direction(GIT_ATTR_INDEX, &the_index); + } + err = read_tree_recursive(args->tree, args->base, args->baselen, 0, args->pathspec, write_archive_entry, &context); if (err == READ_TREE_RECURSIVE) @@ -258,6 +277,7 @@ static int parse_archive_args(int argc, const char **argv, int verbose = 0; int i; int list = 0; + int worktree_attributes = 0; struct option opts[] = { OPT_GROUP(""), OPT_STRING(0, "format", &format, "fmt", "archive format"), @@ -265,6 +285,8 @@ static int parse_archive_args(int argc, const char **argv, "prepend prefix to each pathname in the archive"), OPT_STRING(0, "output", &output, "file", "write the archive to this file"), + OPT_BOOLEAN(0, "worktree-attributes", &worktree_attributes, + "read .gitattributes in working directory"), OPT__VERBOSE(&verbose), OPT__COMPR('0', &compression_level, "store only", 0), OPT__COMPR('1', &compression_level, "compress faster", 1), @@ -324,6 +346,7 @@ static int parse_archive_args(int argc, const char **argv, args->verbose = verbose; args->base = base; args->baselen = strlen(base); + args->worktree_attributes = worktree_attributes; return argc; } diff --git a/archive.h b/archive.h index 0b15b35143..038ac353d4 100644 --- a/archive.h +++ b/archive.h @@ -10,6 +10,7 @@ struct archiver_args { time_t time; const char **pathspec; unsigned int verbose : 1; + unsigned int worktree_attributes : 1; int compression_level; }; diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c index 0713bca778..f88e721936 100644 --- a/builtin-tar-tree.c +++ b/builtin-tar-tree.c @@ -24,7 +24,7 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix) * git archive --format-tar --prefix=basedir tree-ish */ int i; - const char **nargv = xcalloc(sizeof(*nargv), argc + 2); + const char **nargv = xcalloc(sizeof(*nargv), argc + 3); char *basedir_arg; int nargc = 0; @@ -36,6 +36,13 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix) argv++; argc--; } + + /* + * Because it's just a compatibility wrapper, tar-tree supports only + * the old behaviour of reading attributes from the work tree. + */ + nargv[nargc++] = "--worktree-attributes"; + switch (argc) { default: usage(tar_tree_usage); From 8aece7ff0611846c9f8d6c12566d6ac26d84a184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Sat, 18 Apr 2009 00:18:10 +0200 Subject: [PATCH 460/654] archive test: attributes Add a test script for all archive attributes and their handling in normal and bare repositories. export-ignore and export-subst are tested, as well as the effect of the option --worktree-attributes. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t5001-archive-attr.sh | 91 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100755 t/t5001-archive-attr.sh diff --git a/t/t5001-archive-attr.sh b/t/t5001-archive-attr.sh new file mode 100755 index 0000000000..426b319bd3 --- /dev/null +++ b/t/t5001-archive-attr.sh @@ -0,0 +1,91 @@ +#!/bin/sh + +test_description='git archive attribute tests' + +. ./test-lib.sh + +SUBSTFORMAT=%H%n + +test_expect_exists() { + test_expect_success " $1 exists" "test -e $1" +} + +test_expect_missing() { + test_expect_success " $1 does not exist" "test ! -e $1" +} + +test_expect_success 'setup' ' + echo ignored >ignored && + echo ignored export-ignore >>.git/info/attributes && + git add ignored && + + echo ignored by tree >ignored-by-tree && + echo ignored-by-tree export-ignore >.gitattributes && + git add ignored-by-tree .gitattributes && + + echo ignored by worktree >ignored-by-worktree && + echo ignored-by-worktree export-ignore >.gitattributes && + git add ignored-by-worktree && + + printf "A\$Format:%s\$O" "$SUBSTFORMAT" >nosubstfile && + printf "A\$Format:%s\$O" "$SUBSTFORMAT" >substfile1 && + printf "A not substituted O" >substfile2 && + echo "substfile?" export-subst >>.git/info/attributes && + git add nosubstfile substfile1 substfile2 && + + git commit -m. && + + git clone --bare . bare && + cp .git/info/attributes bare/info/attributes +' + +test_expect_success 'git archive' ' + git archive HEAD >archive.tar && + (mkdir archive && cd archive && "$TAR" xf -) <archive.tar +' + +test_expect_missing archive/ignored +test_expect_missing archive/ignored-by-tree +test_expect_exists archive/ignored-by-worktree + +test_expect_success 'git archive with worktree attributes' ' + git archive --worktree-attributes HEAD >worktree.tar && + (mkdir worktree && cd worktree && "$TAR" xf -) <worktree.tar +' + +test_expect_missing worktree/ignored +test_expect_exists worktree/ignored-by-tree +test_expect_missing worktree/ignored-by-worktree + +test_expect_success 'git archive vs. bare' ' + (cd bare && git archive HEAD) >bare-archive.tar && + test_cmp archive.tar bare-archive.tar +' + +test_expect_success 'git archive with worktree attributes, bare' ' + (cd bare && git archive --worktree-attributes HEAD) >bare-worktree.tar && + (mkdir bare-worktree && cd bare-worktree && "$TAR" xf -) <bare-worktree.tar +' + +test_expect_missing bare-worktree/ignored +test_expect_exists bare-worktree/ignored-by-tree +test_expect_exists bare-worktree/ignored-by-worktree + +test_expect_success 'export-subst' ' + git log "--pretty=format:A${SUBSTFORMAT}O" HEAD >substfile1.expected && + test_cmp nosubstfile archive/nosubstfile && + test_cmp substfile1.expected archive/substfile1 && + test_cmp substfile2 archive/substfile2 +' + +test_expect_success 'git tar-tree vs. git archive with worktree attributes' ' + git tar-tree HEAD >tar-tree.tar && + test_cmp worktree.tar tar-tree.tar +' + +test_expect_success 'git tar-tree vs. git archive with worktree attrs, bare' ' + (cd bare && git tar-tree HEAD) >bare-tar-tree.tar && + test_cmp bare-worktree.tar bare-tar-tree.tar +' + +test_done From aed97c677cdfd1b9bbc9b33b5418ad4a29109082 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit <madcoder@debian.org> Date: Thu, 16 Apr 2009 22:00:44 +0200 Subject: [PATCH 461/654] hook/update: example of how to prevent branch creation Since git doesn't provide a receive.denyBranchCreation or similar, here is an example of how to be sure users cannot create branches remotely by pushing a new reference. This setup has been proven useful to prevent creation of spurious branches because of users having their remote.origin.push set to HEAD, when they use `git push` while being on a local topic branch of theirs instead of the proper one. Signed-off-by: Pierre Habouzit <madcoder@debian.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- templates/hooks--update.sample | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/templates/hooks--update.sample b/templates/hooks--update.sample index a3f68ae3b4..f8bf490cff 100755 --- a/templates/hooks--update.sample +++ b/templates/hooks--update.sample @@ -16,6 +16,9 @@ # hooks.allowdeletebranch # This boolean sets whether deleting branches will be allowed in the # repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. # # --- Command line @@ -39,6 +42,7 @@ fi # --- Config allowunannotated=$(git config --bool hooks.allowunannotated) allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) allowdeletetag=$(git config --bool hooks.allowdeletetag) # check for no description @@ -52,7 +56,8 @@ esac # --- Check types # if $newrev is 0000...0000, it's a commit to delete a ref. -if [ "$newrev" = "0000000000000000000000000000000000000000" ]; then +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then newrev_type=delete else newrev_type=$(git-cat-file -t $newrev) @@ -80,6 +85,10 @@ case "$refname","$newrev_type" in ;; refs/heads/*,commit) # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi ;; refs/heads/*,delete) # delete branch From 77b96d6dbf65f736a63b8a0bb5f810edbf895a09 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Sat, 18 Apr 2009 14:32:02 -0700 Subject: [PATCH 462/654] Update draft release notes to 1.6.3 Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/RelNotes-1.6.3.txt | 34 ++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/Documentation/RelNotes-1.6.3.txt b/Documentation/RelNotes-1.6.3.txt index 839498c38a..ca38decb37 100644 --- a/Documentation/RelNotes-1.6.3.txt +++ b/Documentation/RelNotes-1.6.3.txt @@ -47,6 +47,8 @@ Updates since v1.6.2 (usability, bells and whistles) +* Boolean configuration variable yes/no can be written as on/off. + * rsync:/path/to/repo can be used to run git over rsync for local repositories. It may not be useful in practice; meant primarily for testing. @@ -63,6 +65,9 @@ Updates since v1.6.2 * "--oneline" is a synonym for "--pretty=oneline --abbrev-commit". +* "--graph" to the "git log" family can draw the commit ancestry graph + in colors. + * If you realize that you botched the patch when you are editing hunks with the 'edit' action in git-add -i/-p, you can abort the editor to tell git not to apply it. @@ -75,8 +80,16 @@ Updates since v1.6.2 1.6.2, but the initial implementation did not teach this to a few commands. Now the syntax works with "branch -m @{-1} newname". +* "git-add -p" now supports "q"uit action. + * git-archive learned --output=<file> option. +* git-archive takes attributes from the tree being archived; strictly + speaking, this is an incompatible behaviour change, but is a good one. + Use --worktree-attributes option to allow it to read attributes from + the work tree as before (deprecated git-tar tree command always reads + attributes from the work tree). + * git-bisect shows not just the number of remaining commits whose goodness is unknown, but also shows the estimated number of remaining rounds. @@ -93,6 +106,9 @@ Updates since v1.6.2 * git-clone runs post-checkout hook when run without --no-checkout. +* git-difftool is now part of the officially supported command, primarily + maintained by David Aguilar. + * git-fast-export choked when seeing a tag that does not point at commit. * git-for-each-ref learned a new "upstream" token. @@ -156,26 +172,18 @@ release, unless otherwise noted. Here are fixes that this release has, but have not been backported to v1.6.2.X series. +* "git-apply" rejected a patch that swaps two files (i.e. renames A to B + and B to A at the same time). May need to be backported by cherry + picking d8c81df and then 7fac0ee). + * The initial checkout did not read the attributes from the .gitattribute file that is being checked out. -* "git-checkout <tree-ish> <submodule>" did not update the index entry at - the named path; it now does. - * git-gc spent excessive amount of time to decide if an object appears in a locally existing pack (if needed, backport by merging 69e020a). -* "git-ls-tree" and "git-diff-tree" used a pathspec correctly when - deciding to descend into a subdirectory but they did not match the - individual paths correctly. This caused pathspecs "abc/d ab" to match - "abc/0" ("abc/d" made them decide to descend into the directory "abc/", - and then "ab" incorrectly matched "abc/0" when it shouldn't). - -* "git-merge-recursive" was broken when a submodule entry was involved in - a criss-cross merge situation. - --- exec >/var/tmp/1 -O=v1.6.2.3-497-g54a4749 +O=v1.6.3-rc0-74-g9824a38 echo O=$(git describe master) git shortlog --no-merges $O..master ^maint From ea10b60c910e4a23483f47f17becc5e58f07ebe9 Mon Sep 17 00:00:00 2001 From: Ben Jackson <ben@ben.com> Date: Sat, 18 Apr 2009 20:42:07 -0700 Subject: [PATCH 463/654] Work around ash "alternate value" expansion bug Ash (used as /bin/sh on many distros) has a shell expansion bug for the form ${var:+word word}. The result is a single argument "word word". Work around by using ${var:+word} ${var:+word} or equivalent. Signed-off-by: Ben Jackson <ben@ben.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-am.sh | 2 +- git-submodule.sh | 11 +++++++++-- t/t7400-submodule-basic.sh | 10 ++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/git-am.sh b/git-am.sh index 774383fb68..6d1848b6cc 100755 --- a/git-am.sh +++ b/git-am.sh @@ -571,7 +571,7 @@ do GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" export GIT_COMMITTER_DATE fi && - git commit-tree $tree ${parent:+-p $parent} <"$dotest/final-commit" + git commit-tree $tree ${parent:+-p} $parent <"$dotest/final-commit" ) && git update-ref -m "$GIT_REFLOG_ACTION: $FIRSTLINE" HEAD $commit $parent || stop_here $this diff --git a/git-submodule.sh b/git-submodule.sh index 7c2e060ae7..8e234a4028 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -204,8 +204,15 @@ cmd_add() else module_clone "$path" "$realrepo" || exit - (unset GIT_DIR; cd "$path" && git checkout -f -q ${branch:+-b "$branch" "origin/$branch"}) || - die "Unable to checkout submodule '$path'" + ( + unset GIT_DIR + cd "$path" && + # ash fails to wordsplit ${branch:+-b "$branch"...} + case "$branch" in + '') git checkout -f -q ;; + ?*) git checkout -f -q -b "$branch" "origin/$branch" ;; + esac + ) || die "Unable to checkout submodule '$path'" fi git add "$path" || diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index af690ec6c1..0f2ccc6cf0 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -64,6 +64,16 @@ test_expect_success 'submodule add' ' ) ' +test_expect_success 'submodule add --branch' ' + ( + cd addtest && + git submodule add -b initial "$submodurl" submod-branch && + git submodule init && + cd submod-branch && + git branch | grep initial + ) +' + test_expect_success 'submodule add with ./ in path' ' ( cd addtest && From ccb4b5391382f4cdb5e5be49036e82e7d837b7af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Holger=20Wei=C3=9F?= <holger@zedat.fu-berlin.de> Date: Tue, 31 Mar 2009 18:16:36 +0200 Subject: [PATCH 464/654] gitweb: Fix snapshots requested via PATH_INFO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the detection of the requested snapshot format, which failed for PATH_INFO URLs since the references to the hashes which describe the supported snapshot formats weren't dereferenced appropriately. Signed-off-by: Holger Weiß <holger@zedat.fu-berlin.de> Acked-by: Jakub Narebski <jnareb@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- gitweb/gitweb.perl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 33ef190ceb..3f99361ed0 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -688,10 +688,10 @@ sub evaluate_path_info { # extensions. Allowed extensions are both the defined suffix # (which includes the initial dot already) and the snapshot # format key itself, with a prepended dot - while (my ($fmt, %opt) = each %known_snapshot_formats) { + while (my ($fmt, $opt) = each %known_snapshot_formats) { my $hash = $refname; my $sfx; - $hash =~ s/(\Q$opt{'suffix'}\E|\Q.$fmt\E)$//; + $hash =~ s/(\Q$opt->{'suffix'}\E|\Q.$fmt\E)$//; next unless $sfx = $1; # a valid suffix was found, so set the snapshot format # and reset the hash parameter From 6ac6f87818edfd33fea8ce3c95b47fe00a4e4b91 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Fri, 3 Apr 2009 08:49:59 +0200 Subject: [PATCH 465/654] Windows: Work around intermittent failures in mingw_rename We have replaced rename() with a version that can rename a file to a destination that already exists. Nevertheless, many users, the author included, observe failures in the code that are not reproducible. The theory is that the failures are due to some other process that happens to have opened the destination file briefly at the wrong moment. (And there is no way on Windows to delete or replace a file that is currently open.) The most likely candidate for such a process is a virus scanner. The failure is more often observed while there is heavy git activity (for example while the test suite is running or during a rebase operation). We work around the failure by retrying the rename operation if it failed due to ERROR_ACCESS_DENIED. The retries are delayed a bit: The first only by giving up the time slice, the next after the minimal scheduling granularity, and if more retries are needed, then we wait some non-trivial amount of time with exponential back-off. Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- compat/mingw.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 2839d9df6e..1a17cf6cce 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -934,7 +934,9 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz) #undef rename int mingw_rename(const char *pold, const char *pnew) { - DWORD attrs; + DWORD attrs, gle; + int tries = 0; + static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. @@ -944,10 +946,12 @@ int mingw_rename(const char *pold, const char *pnew) return 0; if (errno != EEXIST) return -1; +repeat: if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) return 0; /* TODO: translate more errors */ - if (GetLastError() == ERROR_ACCESS_DENIED && + gle = GetLastError(); + if (gle == ERROR_ACCESS_DENIED && (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) { if (attrs & FILE_ATTRIBUTE_DIRECTORY) { errno = EISDIR; @@ -957,10 +961,23 @@ int mingw_rename(const char *pold, const char *pnew) SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) { if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) return 0; + gle = GetLastError(); /* revert file attributes on failure */ SetFileAttributes(pnew, attrs); } } + if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) { + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + goto repeat; + } errno = EACCES; return -1; } From 34779c535c4e121414197ab08b4b502a22a75433 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Mon, 20 Apr 2009 10:17:00 +0200 Subject: [PATCH 466/654] Windows: Skip fstat/lstat optimization in write_entry() Commit e4c72923 (write_entry(): use fstat() instead of lstat() when file is open, 2009-02-09) introduced an optimization of write_entry(). Unfortunately, we cannot take advantage of this optimization on Windows because there is no guarantee that the time stamps are updated before the file is closed: "The only guarantee about a file timestamp is that the file time is correctly reflected when the handle that makes the change is closed." (http://msdn.microsoft.com/en-us/library/ms724290(VS.85).aspx) The failure of this optimization on Windows can be observed most easily by running a 'git checkout' that has to update several large files. In this case, 'git checkout' will report modified files, but infact only the timestamps were incorrectly recorded in the index, as can be verified by a subsequent 'git diff', which shows no change. Dmitry Potapov reports the same fix needs on Cygwin; this commit contains his updates for that. Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 9 +++++++++ entry.c | 3 ++- git-compat-util.h | 6 ++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6e0838b03a..49f36f5787 100644 --- a/Makefile +++ b/Makefile @@ -167,6 +167,10 @@ all:: # Define NO_EXTERNAL_GREP if you don't want "git grep" to ever call # your external grep (e.g., if your system lacks grep, if its grep is # broken, or spawning external process is slower than built-in grep git has). +# +# Define UNRELIABLE_FSTAT if your system's fstat does not return the same +# information on a not yet closed file that lstat would return for the same +# file after it was closed. GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE @$(SHELL_PATH) ./GIT-VERSION-GEN @@ -803,6 +807,7 @@ ifeq ($(uname_S),HP-UX) endif ifneq (,$(findstring CYGWIN,$(uname_S))) COMPAT_OBJS += compat/cygwin.o + UNRELIABLE_FSTAT = UnfortunatelyYes endif ifneq (,$(findstring MINGW,$(uname_S))) NO_PREAD = YesPlease @@ -829,6 +834,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease NO_NSEC = YesPlease USE_WIN32_MMAP = YesPlease + UNRELIABLE_FSTAT = UnfortunatelyYes COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" @@ -1107,6 +1113,9 @@ endif ifdef NO_EXTERNAL_GREP BASIC_CFLAGS += -DNO_EXTERNAL_GREP endif +ifdef UNRELIABLE_FSTAT + BASIC_CFLAGS += -DUNRELIABLE_FSTAT +endif ifeq ($(TCLTK_PATH),) NO_TCLTK=NoThanks diff --git a/entry.c b/entry.c index 5daacc2fe5..915514aa5c 100644 --- a/entry.c +++ b/entry.c @@ -147,7 +147,8 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout wrote = write_in_full(fd, new, size); /* use fstat() only when path == ce->name */ - if (state->refresh_cache && !to_tempfile && !state->base_dir_len) { + if (fstat_is_reliable() && + state->refresh_cache && !to_tempfile && !state->base_dir_len) { fstat(fd, &st); fstat_done = 1; } diff --git a/git-compat-util.h b/git-compat-util.h index f09f244061..785aa31b46 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -408,4 +408,10 @@ void git_qsort(void *base, size_t nmemb, size_t size, #endif #endif +#ifdef UNRELIABLE_FSTAT +#define fstat_is_reliable() 0 +#else +#define fstat_is_reliable() 1 +#endif + #endif From a162e78df082d4f885bda2e51067d9788a7f65e4 Mon Sep 17 00:00:00 2001 From: Matthieu Moy <Matthieu.Moy@imag.fr> Date: Mon, 20 Apr 2009 13:09:37 +0200 Subject: [PATCH 467/654] clone: add test for push on an empty clone. Commit 55f0566 (get_local_heads(): do not return random pointer if there is no head, 2009-04-17) fixed a segfault for git push, this patch adds a test-case to avoid future regressions. Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t5701-clone-local.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh index 3559d17964..f26b511c3e 100755 --- a/t/t5701-clone-local.sh +++ b/t/t5701-clone-local.sh @@ -132,4 +132,14 @@ test_expect_success 'clone empty repository' ' test $actual = $expected) ' +test_expect_success 'clone empty repository, and then push should not segfault.' ' + cd "$D" && + rm -fr empty/ empty-clone/ && + mkdir empty && + (cd empty && git init) && + git clone empty empty-clone && + cd empty-clone && + test_must_fail git push +' + test_done From 7c0282bfb9038516b0eeb3b7cb3c1d6ee3cb20de Mon Sep 17 00:00:00 2001 From: Mike Ralphson <mike@abacus.co.uk> Date: Fri, 17 Apr 2009 19:13:29 +0100 Subject: [PATCH 468/654] builtin-remote: fix typo in option description Signed-off-by: Mike Ralphson <mike@abacus.co.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-remote.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-remote.c b/builtin-remote.c index ca7c639ad3..2ed752cbf1 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -1216,7 +1216,7 @@ static int update(int argc, const char **argv) struct option options[] = { OPT_GROUP("update specific options"), OPT_BOOLEAN('p', "prune", &prune, - "prune remotes after fecthing"), + "prune remotes after fetching"), OPT_END() }; From 680ebc01806187b33cab9093c39102468298350f Mon Sep 17 00:00:00 2001 From: Mike Ralphson <mike@abacus.co.uk> Date: Fri, 17 Apr 2009 19:13:28 +0100 Subject: [PATCH 469/654] Documentation: fix typos / spelling mistakes Signed-off-by: Mike Ralphson <mike@abacus.co.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-cvsimport.txt | 2 +- Documentation/git-format-patch.txt | 2 +- contrib/thunderbird-patch-inline/README | 4 ++-- gitweb/README | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt index d7bab13f6c..614e769f4e 100644 --- a/Documentation/git-cvsimport.txt +++ b/Documentation/git-cvsimport.txt @@ -196,7 +196,7 @@ Problems related to tags: If you suspect that any of these issues may apply to the repository you want to import consider using these alternative tools which proved to be -more stable in practise: +more stable in practice: * cvs2git (part of cvs2svn), `http://cvs2svn.tigris.org` * parsecvs, `http://cgit.freedesktop.org/~keithp/parsecvs` diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index eb2fbcff1a..5eddca92c4 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -194,7 +194,7 @@ CONFIGURATION ------------- You can specify extra mail header lines to be added to each message in the repository configuration, new defaults for the subject prefix -and file suffix, control attachements, and number patches when outputting +and file suffix, control attachments, and number patches when outputting more than one. ------------ diff --git a/contrib/thunderbird-patch-inline/README b/contrib/thunderbird-patch-inline/README index 39f96aa115..000147bbe4 100644 --- a/contrib/thunderbird-patch-inline/README +++ b/contrib/thunderbird-patch-inline/README @@ -1,12 +1,12 @@ appp.sh is a script that is supposed to be used together with ExternalEditor -for Mozilla Thundebird. It will let you include patches inline in e-mails +for Mozilla Thunderbird. It will let you include patches inline in e-mails in an easy way. Usage: - Generate the patch with git format-patch. - Start writing a new e-mail in Thunderbird. - Press the external editor button (or Ctrl-E) to run appp.sh -- Select the previosly generated patch file. +- Select the previously generated patch file. - Finish editing the e-mail. Any text that is entered into the message editor before appp.sh is called diff --git a/gitweb/README b/gitweb/README index 8433dd1d45..ccda890c0e 100644 --- a/gitweb/README +++ b/gitweb/README @@ -206,7 +206,7 @@ not include variables usually directly set during build): * $fallback_encoding Gitweb assumes this charset if line contains non-UTF-8 characters. Fallback decoding is used without error checking, so it can be even - 'utf-8'. Value mist be valid encodig; see Encoding::Supported(3pm) man + 'utf-8'. Value must be valid encoding; see Encoding::Supported(3pm) man page for a list. By default 'latin1', aka. 'iso-8859-1'. * @diff_opts Rename detection options for git-diff and git-diff-tree. By default From fe3420b616eba8027b080dc81020b0e0990f4809 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg <markus.heidelberg@web.de> Date: Tue, 21 Apr 2009 00:58:15 +0200 Subject: [PATCH 470/654] grep: don't support "grep.color"-like config options color.grep and color.grep.* is the official and documented way to highlight grep matches. Comparable options like diff.color.* and status.color.* exist for backward compatibility reasons only and are not documented any more. Signed-off-by: Markus Heidelberg <markus.heidelberg@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-grep.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/builtin-grep.c b/builtin-grep.c index 89489ddcf8..f88a912ace 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -26,16 +26,13 @@ static int grep_config(const char *var, const char *value, void *cb) { struct grep_opt *opt = cb; - if (!strcmp(var, "grep.color") || !strcmp(var, "color.grep")) { + if (!strcmp(var, "color.grep")) { opt->color = git_config_colorbool(var, value, -1); return 0; } - if (!strcmp(var, "grep.color.external") || - !strcmp(var, "color.grep.external")) { + if (!strcmp(var, "color.grep.external")) return git_config_string(&(opt->color_external), var, value); - } - if (!strcmp(var, "grep.color.match") || - !strcmp(var, "color.grep.match")) { + if (!strcmp(var, "color.grep.match")) { if (!value) return config_error_nonbool(var); color_parse(value, var, opt->color_match); From 47abd85ba06ed7209d1caa3e5ac7cc6b232bece4 Mon Sep 17 00:00:00 2001 From: Andreas Ericsson <ae@op5.se> Date: Fri, 17 Apr 2009 10:20:11 +0200 Subject: [PATCH 471/654] fetch: Strip usernames from url's before storing them When pulling from a remote, the full URL including username is by default added to the commit message. Since it adds very little value but could be used by malicious people to glean valid usernames (with matching hostnames), we're far better off just stripping the username before storing the remote URL locally. Note that this patch has no lasting visible effect when "git pull" does not create a merge commit. It simply alters what gets written to .git/FETCH_HEAD, which is used by "git merge" to automagically create its messages. Signed-off-by: Andreas Ericsson <ae@op5.se> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-fetch.c | 7 +++++-- transport.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ transport.h | 1 + 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/builtin-fetch.c b/builtin-fetch.c index 3c998ea740..0bb290bf2f 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -289,7 +289,7 @@ static int update_local_ref(struct ref *ref, } } -static int store_updated_refs(const char *url, const char *remote_name, +static int store_updated_refs(const char *raw_url, const char *remote_name, struct ref *ref_map) { FILE *fp; @@ -298,11 +298,13 @@ static int store_updated_refs(const char *url, const char *remote_name, char note[1024]; const char *what, *kind; struct ref *rm; - char *filename = git_path("FETCH_HEAD"); + char *url, *filename = git_path("FETCH_HEAD"); fp = fopen(filename, "a"); if (!fp) return error("cannot open %s: %s\n", filename, strerror(errno)); + + url = transport_anonymize_url(raw_url); for (rm = ref_map; rm; rm = rm->next) { struct ref *ref = NULL; @@ -376,6 +378,7 @@ static int store_updated_refs(const char *url, const char *remote_name, fprintf(stderr, " %s\n", note); } } + free(url); fclose(fp); if (rc & 2) error("some local refs could not be updated; try running\n" diff --git a/transport.c b/transport.c index 3dfb03c06e..8ad317bf32 100644 --- a/transport.c +++ b/transport.c @@ -1083,3 +1083,51 @@ int transport_disconnect(struct transport *transport) free(transport); return ret; } + +/* + * Strip username (and password) from an url and return + * it in a newly allocated string. + */ +char *transport_anonymize_url(const char *url) +{ + char *anon_url, *scheme_prefix, *anon_part; + size_t anon_len, prefix_len = 0; + + anon_part = strchr(url, '@'); + if (is_local(url) || !anon_part) + goto literal_copy; + + anon_len = strlen(++anon_part); + scheme_prefix = strstr(url, "://"); + if (!scheme_prefix) { + if (!strchr(anon_part, ':')) + /* cannot be "me@there:/path/name" */ + goto literal_copy; + } else { + const char *cp; + /* make sure scheme is reasonable */ + for (cp = url; cp < scheme_prefix; cp++) { + switch (*cp) { + /* RFC 1738 2.1 */ + case '+': case '.': case '-': + break; /* ok */ + default: + if (isalnum(*cp)) + break; + /* it isn't */ + goto literal_copy; + } + } + /* @ past the first slash does not count */ + cp = strchr(scheme_prefix + 3, '/'); + if (cp && cp < anon_part) + goto literal_copy; + prefix_len = scheme_prefix - url + 3; + } + anon_url = xcalloc(1, 1 + prefix_len + anon_len); + memcpy(anon_url, url, prefix_len); + memcpy(anon_url + prefix_len, anon_part, anon_len); + return anon_url; +literal_copy: + return xstrdup(url); +} diff --git a/transport.h b/transport.h index b1c2252766..27bfc528ac 100644 --- a/transport.h +++ b/transport.h @@ -74,5 +74,6 @@ const struct ref *transport_get_remote_refs(struct transport *transport); int transport_fetch_refs(struct transport *transport, const struct ref *refs); void transport_unlock_pack(struct transport *transport); int transport_disconnect(struct transport *transport); +char *transport_anonymize_url(const char *url); #endif From 6f63fc18b6197f9a582fbfe23a5c7938fe593951 Mon Sep 17 00:00:00 2001 From: Paul Mackerras <paulus@samba.org> Date: Tue, 21 Apr 2009 22:22:31 +1000 Subject: [PATCH 472/654] gitk: Fix compare-commits function when we have local changes This fixes a bug in the compare-commits function added in commit 010509f2 ("gitk: Add a command to compare two strings of commits") where gitk would show an error dialog if the comparison of commits got to a fake commit (one showing local changes). It extends getpatchid to handle these fake commits by using [diffcmd] to get the git diff command variant to use, and also handles the situation where an error occurs. Now that we can have the fake commit IDs showing up, which are 00..00 and 00..01, the short ID is ambiguous. To make sure the links point to the right commit, this adds a new [appendshortlink] procedure which takes the full link destination, and uses that rather than appendwithlinks. Signed-off-by: Paul Mackerras <paulus@samba.org> --- gitk | 66 +++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/gitk b/gitk index dca1741c71..1a7887b252 100755 --- a/gitk +++ b/gitk @@ -6489,6 +6489,17 @@ proc setlink {id lk} { } } +proc appendshortlink {id {pre {}} {post {}}} { + global ctext linknum + + $ctext insert end $pre + $ctext tag delete link$linknum + $ctext insert end [string range $id 0 7] link$linknum + $ctext insert end $post + setlink $id link$linknum + incr linknum +} + proc makelink {id} { global pendinglinks @@ -8127,8 +8138,15 @@ proc getpatchid {id} { global patchids if {![info exists patchids($id)]} { - set x [exec git diff-tree -p --root $id | git patch-id] - set patchids($id) [lindex $x 0] + set cmd [diffcmd [list $id] {-p --root}] + # trim off the initial "|" + set cmd [lrange $cmd 1 end] + if {[catch { + set x [eval exec $cmd | git patch-id] + set patchids($id) [lindex $x 0] + }]} { + set patchids($id) "error" + } } return $patchids($id) } @@ -8140,18 +8158,16 @@ proc do_cmp_commits {a b} { clear_ctext init_flist {} for {set i 0} {$i < 100} {incr i} { - set shorta [string range $a 0 7] - set shortb [string range $b 0 7] set skipa 0 set skipb 0 if {[llength $parents($curview,$a)] > 1} { - appendwithlinks [mc "Skipping merge commit %s\n" $shorta] {} + appendshortlink $a [mc "Skipping merge commit "] "\n" set skipa 1 } else { set patcha [getpatchid $a] } if {[llength $parents($curview,$b)] > 1} { - appendwithlinks [mc "Skipping merge commit %s\n" $shortb] {} + appendshortlink $b [mc "Skipping merge commit "] "\n" set skipb 1 } else { set patchb [getpatchid $b] @@ -8159,39 +8175,51 @@ proc do_cmp_commits {a b} { if {!$skipa && !$skipb} { set heada [lindex $commitinfo($a) 0] set headb [lindex $commitinfo($b) 0] + if {$patcha eq "error"} { + appendshortlink $a [mc "Error getting patch ID for "] \ + [mc " - stopping\n"] + break + } + if {$patchb eq "error"} { + appendshortlink $b [mc "Error getting patch ID for "] \ + [mc " - stopping\n"] + break + } if {$patcha eq $patchb} { if {$heada eq $headb} { - appendwithlinks [mc "Commit %s == %s %s\n" \ - $shorta $shortb $heada] {} + appendshortlink $a [mc "Commit "] + appendshortlink $b " == " " $heada\n" } else { - appendwithlinks [mc "Commit %s %s\n" $shorta $heada] {} - appendwithlinks [mc " is the same patch as\n"] {} - appendwithlinks [mc " %s %s\n" $shortb $headb] {} + appendshortlink $a [mc "Commit "] " $heada\n" + appendshortlink $b [mc " is the same patch as\n "] \ + " $headb\n" } set skipa 1 set skipb 1 } else { $ctext insert end "\n" - appendwithlinks [mc "Commit %s %s\n" $shorta $heada] {} - appendwithlinks [mc " differs from\n"] {} - appendwithlinks [mc " %s %s\n" $shortb $headb] {} - appendwithlinks [mc "- stopping\n"] + appendshortlink $a [mc "Commit "] " $heada\n" + appendshortlink $b [mc " differs from\n "] \ + " $headb\n" + $ctext insert end [mc "- stopping\n"] break } } if {$skipa} { if {[llength $children($curview,$a)] != 1} { $ctext insert end "\n" - appendwithlinks [mc "Commit %s has %s children - stopping\n" \ - $shorta [llength $children($curview,$a)]] {} + appendshortlink $a [mc "Commit "] \ + [mc " has %s children - stopping\n" \ + [llength $children($curview,$a)]] break } set a [lindex $children($curview,$a) 0] } if {$skipb} { if {[llength $children($curview,$b)] != 1} { - appendwithlinks [mc "Commit %s has %s children - stopping\n" \ - $shortb [llength $children($curview,$b)]] {} + appendshortlink $b [mc "Commit "] \ + [mc " has %s children - stopping\n" \ + [llength $children($curview,$b)]] break } set b [lindex $children($curview,$b) 0] From 3a0483281afbb6660aaf86c7b228a523782a4d6a Mon Sep 17 00:00:00 2001 From: Michael J Gruber <git@drmicha.warpmail.net> Date: Tue, 21 Apr 2009 11:21:59 +0200 Subject: [PATCH 473/654] test-lib.sh: Help test_create_repo() find the templates dir Currently, test_create_repo() expects that templates can be found below `pwd`/.. This assumption fails when tests are run against a git installed somewhere else or test_create_repo() is called from subdirectiories (several tests do this). Therefore, use $TEST_DIRECTORY as introduced in 2d84e9fb and expect templates to be present in $TEST_DIRECTORY/.. which should be the root dir of the git checkout. Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/test-lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index 4bd986f430..dad1437fa4 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -491,7 +491,7 @@ test_create_repo () { repo="$1" mkdir -p "$repo" cd "$repo" || error "Cannot setup test environment" - "$GIT_EXEC_PATH/git-init" "--template=$owd/../templates/blt/" >&3 2>&4 || + "$GIT_EXEC_PATH/git-init" "--template=$TEST_DIRECTORY/../templates/blt/" >&3 2>&4 || error "cannot run git init -- have you built things yet?" mv .git/hooks .git/hooks-disabled cd "$owd" From 8fbf879ed75b67417b0e36eb7b03b79611f1f8a0 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Tue, 21 Apr 2009 16:32:18 -0700 Subject: [PATCH 474/654] Revert "stat_tracking_info(): only count real commits" This reverts commit 19de5d6913b9681d2bde533bccc8445c9236a648. It produces a misleading output to decide if a merge can fast-forward. --- Documentation/RelNotes-1.6.3.txt | 4 ---- remote.c | 3 +-- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Documentation/RelNotes-1.6.3.txt b/Documentation/RelNotes-1.6.3.txt index b53e7b86e7..efce29ddf3 100644 --- a/Documentation/RelNotes-1.6.3.txt +++ b/Documentation/RelNotes-1.6.3.txt @@ -69,10 +69,6 @@ Updates since v1.6.2 with the 'edit' action in git-add -i/-p, you can abort the editor to tell git not to apply it. -* The number of commits shown in "you are ahead/behind your upstream" - messages given by "git checkout" and "git status" used to count merge - commits; now it doesn't. - * @{-1} is a new way to refer to the last branch you were on introduced in 1.6.2, but the initial implementation did not teach this to a few commands. Now the syntax works with "branch -m @{-1} newname". diff --git a/remote.c b/remote.c index 41c5b59736..91f748550e 100644 --- a/remote.c +++ b/remote.c @@ -1413,10 +1413,9 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs) if (theirs == ours) return 0; - /* Run "rev-list --no-merges --left-right ours...theirs" internally... */ + /* Run "rev-list --left-right ours...theirs" internally... */ rev_argc = 0; rev_argv[rev_argc++] = NULL; - rev_argv[rev_argc++] = "--no-merges"; rev_argv[rev_argc++] = "--left-right"; rev_argv[rev_argc++] = symmetric; rev_argv[rev_argc++] = "--"; From 7b1d6269eebb0701c287d3ed8732384c115d2e1f Mon Sep 17 00:00:00 2001 From: Allan Caffee <allan.caffee@gmail.com> Date: Wed, 22 Apr 2009 17:27:15 -0400 Subject: [PATCH 475/654] t4202-log: extend test coverage of graphing Extend this test to cover the rendering of graphs with octopus merges and pre_commit lines. Signed-off-by: Allan Caffee <allan.caffee@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t4202-log.sh | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/t/t4202-log.sh b/t/t4202-log.sh index b98619035c..46bd24f502 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -284,10 +284,36 @@ test_expect_success 'set up more tangled history' ' git merge master~3 && git merge side~1 && git checkout master && - git merge tangle + git merge tangle && + git checkout -b reach && + test_commit reach && + git checkout master && + git checkout -b octopus-a && + test_commit octopus-a && + git checkout master && + git checkout -b octopus-b && + test_commit octopus-b && + git checkout master && + test_commit seventh && + git merge octopus-a octopus-b + git merge reach ' cat > expect <<\EOF +* Merge branch 'reach' +|\ +| \ +| \ +*-. \ Merge branches 'octopus-a' and 'octopus-b' +|\ \ \ +* | | | seventh +| | * | octopus-b +| |/ / +|/| | +| * | octopus-a +|/ / +| * reach +|/ * Merge branch 'tangle' |\ | * Merge branch 'side' (early part) into tangle @@ -316,7 +342,7 @@ cat > expect <<\EOF * initial EOF -test_expect_success 'log --graph with merge' ' +test_expect_failure 'log --graph with merge' ' git log --graph --date-order --pretty=tformat:%s | sed "s/ *$//" >actual && test_cmp expect actual From 36a31feae23ac45a130fa38b2934a74e4e7156b4 Mon Sep 17 00:00:00 2001 From: Allan Caffee <allan.caffee@gmail.com> Date: Wed, 22 Apr 2009 15:52:13 -0400 Subject: [PATCH 476/654] graph API: fix extra space during pre_commit_line state An extra space is being inserted between the "commit" column and all of the successive edges. Remove this space. This regression was introduced by 427fc5b. Signed-off-by: Allan Caffee <allan.caffee@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- graph.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graph.c b/graph.c index d4571cf31d..31e09eb2c7 100644 --- a/graph.c +++ b/graph.c @@ -727,8 +727,8 @@ static void graph_output_pre_commit_line(struct git_graph *graph, if (col->commit == graph->commit) { seen_this = 1; strbuf_write_column(sb, col, '|'); - strbuf_addf(sb, " %*s", graph->expansion_row, ""); - chars_written += 2 + graph->expansion_row; + strbuf_addf(sb, "%*s", graph->expansion_row, ""); + chars_written += 1 + graph->expansion_row; } else if (seen_this && (graph->expansion_row == 0)) { /* * This is the first line of the pre-commit output. From a6c1a3827c934872726bafb35f51f2ad9b9e897f Mon Sep 17 00:00:00 2001 From: Allan Caffee <allan.caffee@gmail.com> Date: Wed, 22 Apr 2009 17:27:59 -0400 Subject: [PATCH 477/654] graph API: fix a bug in the rendering of octopus merges An off by one error was causing octopus merges with 3 parents to not be rendered correctly. This regression was introduced by 427fc5. Signed-off-by: Allan Caffee <allan.caffee@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- graph.c | 2 +- t/t4202-log.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/graph.c b/graph.c index 31e09eb2c7..b7879f8c66 100644 --- a/graph.c +++ b/graph.c @@ -852,7 +852,7 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb) graph_output_commit_char(graph, sb); chars_written++; - if (graph->num_parents > 3) + if (graph->num_parents > 2) chars_written += graph_draw_octopus_merge(graph, sb); } else if (seen_this && (graph->num_parents > 2)) { diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 46bd24f502..67f983fea4 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -342,7 +342,7 @@ cat > expect <<\EOF * initial EOF -test_expect_failure 'log --graph with merge' ' +test_expect_sucess 'log --graph with merge' ' git log --graph --date-order --pretty=tformat:%s | sed "s/ *$//" >actual && test_cmp expect actual From eaf158f8bd7615562e1fa84711ea465f387a3c9d Mon Sep 17 00:00:00 2001 From: Allan Caffee <allan.caffee@gmail.com> Date: Tue, 21 Apr 2009 08:47:01 -0400 Subject: [PATCH 478/654] graph API: Use horizontal lines for more compact graphs Use horizontal lines instead of long diagonal lines during the collapsing state of graph rendering. For example what used to be: | | | | | | | | |/ | | |/| | |/| | |/| | | | | | | is now | | | | | | |_|_|/ |/| | | | | | | This results in more compact and legible graphs. Signed-off-by: Allan Caffee <allan.caffee@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- graph.c | 62 ++++++++++++++++++++++++++++++++++++++------------ t/t4202-log.sh | 6 ++--- 2 files changed, 49 insertions(+), 19 deletions(-) diff --git a/graph.c b/graph.c index d4571cf31d..47bce05c98 100644 --- a/graph.c +++ b/graph.c @@ -47,20 +47,6 @@ static void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb); * - Limit the number of columns, similar to the way gitk does. * If we reach more than a specified number of columns, omit * sections of some columns. - * - * - The output during the GRAPH_PRE_COMMIT and GRAPH_COLLAPSING states - * could be made more compact by printing horizontal lines, instead of - * long diagonal lines. For example, during collapsing, something like - * this: instead of this: - * | | | | | | | | | | - * | |_|_|/ | | | |/ - * |/| | | | | |/| - * | | | | | |/| | - * |/| | | - * | | | | - * - * If there are several parallel diagonal lines, they will need to be - * replaced with horizontal lines on subsequent rows. */ struct column { @@ -982,6 +968,9 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf { int i; int *tmp_mapping; + short used_horizontal = 0; + int horizontal_edge = -1; + int horizontal_edge_target = -1; /* * Clear out the new_mapping array @@ -1019,6 +1008,23 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf * Move to the left by one */ graph->new_mapping[i - 1] = target; + /* + * If there isn't already an edge moving horizontally + * select this one. + */ + if (horizontal_edge == -1) { + int j; + horizontal_edge = i; + horizontal_edge_target = target; + /* + * The variable target is the index of the graph + * column, and therefore target*2+3 is the + * actual screen column of the first horizontal + * line. + */ + for (j = (target * 2)+3; j < (i - 2); j += 2) + graph->new_mapping[j] = target; + } } else if (graph->new_mapping[i - 1] == target) { /* * There is a branch line to our left @@ -1039,10 +1045,21 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf * * The space just to the left of this * branch should always be empty. + * + * The branch to the left of that space + * should be our eventual target. */ assert(graph->new_mapping[i - 1] > target); assert(graph->new_mapping[i - 2] < 0); + assert(graph->new_mapping[i - 3] == target); graph->new_mapping[i - 2] = target; + /* + * Mark this branch as the horizontal edge to + * prevent any other edges from moving + * horizontally. + */ + if (horizontal_edge == -1) + horizontal_edge = i; } } @@ -1061,8 +1078,23 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf strbuf_addch(sb, ' '); else if (target * 2 == i) strbuf_write_column(sb, &graph->new_columns[target], '|'); - else + else if (target == horizontal_edge_target && + i != horizontal_edge - 1) { + /* + * Set the mappings for all but the + * first segment to -1 so that they + * won't continue into the next line. + */ + if (i != (target * 2)+3) + graph->new_mapping[i] = -1; + used_horizontal = 1; + strbuf_write_column(sb, &graph->new_columns[target], '_'); + } else { + if (used_horizontal && i < horizontal_edge) + graph->new_mapping[i] = -1; strbuf_write_column(sb, &graph->new_columns[target], '/'); + + } } graph_pad_horizontally(graph, sb, graph->mapping_size); diff --git a/t/t4202-log.sh b/t/t4202-log.sh index b98619035c..a3b0cb88d1 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -298,14 +298,12 @@ cat > expect <<\EOF * | | | Merge branch 'side' |\ \ \ \ | * | | | side-2 -| | | |/ -| | |/| +| | |_|/ | |/| | | * | | side-1 * | | | Second * | | | sixth -| | |/ -| |/| +| |_|/ |/| | * | | fifth * | | fourth From ab07ba2a2436cc717b872387320297bb806d35d9 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg <markus.heidelberg@web.de> Date: Wed, 22 Apr 2009 23:41:25 +0200 Subject: [PATCH 479/654] show-branch: color the commit status signs Make it possible to color the status character ('*' '!' '+' '-') of each commit corresponding to the branch it's in. This makes it easier to follow a particular branch, especially if there are larger gaps in the output. Add the config option color.showbranch and the command line options --color and --no-color to control the colored output. Signed-off-by: Markus Heidelberg <markus.heidelberg@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 6 ++++ Documentation/git-show-branch.txt | 9 ++++++ builtin-show-branch.c | 51 ++++++++++++++++++++++++++++--- 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 35056e1a9c..1383a29b00 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -595,6 +595,12 @@ color.pager:: A boolean to enable/disable colored output when the pager is in use (default is true). +color.showbranch:: + A boolean to enable/disable color in the output of + linkgit:git-show-branch[1]. May be set to `always`, + `false` (or `never`) or `auto` (or `true`), in which case colors are used + only when the output is to a terminal. Defaults to false. + color.status:: A boolean to enable/disable color in the output of linkgit:git-status[1]. May be set to `always`, diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt index 7e9ff3762b..05868b68f6 100644 --- a/Documentation/git-show-branch.txt +++ b/Documentation/git-show-branch.txt @@ -10,6 +10,7 @@ SYNOPSIS [verse] 'git show-branch' [--all] [--remotes] [--topo-order] [--current] [--more=<n> | --list | --independent | --merge-base] + [--color | --no-color] [--no-name | --sha1-name] [--topics] [<rev> | <glob>]... 'git show-branch' (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>] @@ -107,6 +108,14 @@ OPTIONS When no explicit <ref> parameter is given, it defaults to the current branch (or `HEAD` if it is detached). +--color:: + Color the status sign (one of these: `*` `!` `+` `-`) of each commit + corresponding to the branch it's in. + +--no-color:: + Turn off colored output, even when the configuration file gives the + default to color output. + Note that --more, --list, --independent and --merge-base options are mutually exclusive. diff --git a/builtin-show-branch.c b/builtin-show-branch.c index 828e6f86de..fc38f5e005 100644 --- a/builtin-show-branch.c +++ b/builtin-show-branch.c @@ -2,12 +2,25 @@ #include "commit.h" #include "refs.h" #include "builtin.h" +#include "color.h" static const char show_branch_usage[] = "git show-branch [--sparse] [--current] [--all] [--remotes] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...] | --reflog[=n[,b]] <branch>"; static const char show_branch_usage_reflog[] = "--reflog is incompatible with --all, --remotes, --independent or --merge-base"; +static int showbranch_use_color = -1; +static char column_colors[][COLOR_MAXLEN] = { + GIT_COLOR_RED, + GIT_COLOR_GREEN, + GIT_COLOR_YELLOW, + GIT_COLOR_BLUE, + GIT_COLOR_MAGENTA, + GIT_COLOR_CYAN, +}; + +#define COLUMN_COLORS_MAX (ARRAY_SIZE(column_colors)) + static int default_num; static int default_alloc; static const char **default_arg; @@ -19,6 +32,20 @@ static const char **default_arg; #define DEFAULT_REFLOG 4 +static const char *get_color_code(int idx) +{ + if (showbranch_use_color) + return column_colors[idx]; + return ""; +} + +static const char *get_color_reset_code(void) +{ + if (showbranch_use_color) + return GIT_COLOR_RESET; + return ""; +} + static struct commit *interesting(struct commit_list *list) { while (list) { @@ -545,7 +572,12 @@ static int git_show_branch_config(const char *var, const char *value, void *cb) return 0; } - return git_default_config(var, value, cb); + if (!strcmp(var, "color.showbranch")) { + showbranch_use_color = git_config_colorbool(var, value, -1); + return 0; + } + + return git_color_default_config(var, value, cb); } static int omit_in_dense(struct commit *commit, struct commit **rev, int n) @@ -611,6 +643,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) git_config(git_show_branch_config, NULL); + if (showbranch_use_color == -1) + showbranch_use_color = git_use_color_default; + /* If nothing is specified, try the default first */ if (ac == 1 && default_num) { ac = default_num + 1; @@ -658,6 +693,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) parse_reflog_param(arg + 9, &reflog, &reflog_base); else if (!prefixcmp(arg, "-g=")) parse_reflog_param(arg + 3, &reflog, &reflog_base); + else if (!strcmp(arg, "--color")) + showbranch_use_color = 1; + else if (!strcmp(arg, "--no-color")) + showbranch_use_color = 0; else usage(show_branch_usage); ac--; av++; @@ -843,8 +882,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) else { for (j = 0; j < i; j++) putchar(' '); - printf("%c [%s] ", - is_head ? '*' : '!', ref_name[i]); + printf("%s%c%s [%s] ", + get_color_code(i % COLUMN_COLORS_MAX), + is_head ? '*' : '!', + get_color_reset_code(), ref_name[i]); } if (!reflog) { @@ -903,7 +944,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) mark = '*'; else mark = '+'; - putchar(mark); + printf("%s%c%s", + get_color_code(i % COLUMN_COLORS_MAX), + mark, get_color_reset_code()); } putchar(' '); } From e8d1180467da98c53663e462800f793d2341f5a1 Mon Sep 17 00:00:00 2001 From: Alex Riesen <raa.lkml@gmail.com> Date: Wed, 22 Apr 2009 09:27:22 +0200 Subject: [PATCH 480/654] Wait for git diff to finish in git difftool In ActivetState Perl, exec does not wait for the started program. This breaks difftool tests and may cause unexpected behaviour: git difftool has returned, but the rest of code (diff and possibly the interactive program are still running in the background. Acked-by: David Aguilar <davvid@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-difftool.perl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/git-difftool.perl b/git-difftool.perl index 948ff7f6fd..bd828c2a6f 100755 --- a/git-difftool.perl +++ b/git-difftool.perl @@ -82,4 +82,5 @@ sub generate_command } setup_environment(); -exec(generate_command()); +my $rc = system(generate_command()); +exit($rc | ($rc >> 8)); From 4ddef0e67d879bf7e18ce2655b057243d894adc1 Mon Sep 17 00:00:00 2001 From: "Wesley J. Landaker" <wjl@icecavern.net> Date: Wed, 22 Apr 2009 09:48:57 -0600 Subject: [PATCH 481/654] Documentation: git-svn: fix spurious bolding that mangles the output Without this fix, the output looks like: "Keep in mind that the (asterisk) wildcard of the local ref (right of the :) *must be the ..." -- with half the sentence spuriously bold. This fixes the problem by simply escaping asciidoc syntax as suggested by Jeff King <peff@peff.net>. Signed-off-by: Wesley J. Landaker <wjl@icecavern.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-svn.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index 9229d45ad9..3e22e4096f 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -693,7 +693,7 @@ listed below are allowed: tags = tags/*/project-a:refs/remotes/project-a/tags/* ------------------------------------------------------------------------ -Keep in mind that the '*' (asterisk) wildcard of the local ref +Keep in mind that the '\*' (asterisk) wildcard of the local ref (right of the ':') *must* be the farthest right path component; however the remote wildcard may be anywhere as long as it's own independent path component (surrounded by '/' or EOL). This From bad542f0b1bca3b57e300a21fc7268c1800e6752 Mon Sep 17 00:00:00 2001 From: "Wesley J. Landaker" <wjl@icecavern.net> Date: Wed, 22 Apr 2009 09:48:58 -0600 Subject: [PATCH 482/654] Documentation: git-svn: fix a grammatical error without awkwardness The way the sentence is currently written, there needs to be an "its", but this leads to: "however the remote wildcard may be anywhere as long as it's its own" which is awkward to read. Instead, this patch fixes he grammar in a simpler way. Signed-off-by: Wesley J. Landaker <wjl@icecavern.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-svn.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index 3e22e4096f..1c40894669 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -695,7 +695,7 @@ listed below are allowed: Keep in mind that the '\*' (asterisk) wildcard of the local ref (right of the ':') *must* be the farthest right path component; -however the remote wildcard may be anywhere as long as it's own +however the remote wildcard may be anywhere as long as it's an independent path component (surrounded by '/' or EOL). This type of configuration is not automatically created by 'init' and should be manually entered with a text-editor or using 'git-config'. From 3ea3c215c02dc4a4e7d0881c25b2223540960797 Mon Sep 17 00:00:00 2001 From: Mike Ralphson <mike@abacus.co.uk> Date: Fri, 17 Apr 2009 19:13:30 +0100 Subject: [PATCH 483/654] Fix typos / spelling in comments Signed-off-by: Mike Ralphson <mike@abacus.co.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-checkout.c | 2 +- builtin-ls-files.c | 2 +- builtin-pack-objects.c | 2 +- builtin-reflog.c | 2 +- builtin-reset.c | 2 +- compat/cygwin.c | 2 +- compat/fnmatch/fnmatch.c | 4 ++-- compat/mingw.c | 2 +- compat/regex/regex.c | 4 ++-- diffcore-rename.c | 2 +- fast-import.c | 6 +++--- fsck.h | 2 +- git.c | 2 +- graph.c | 2 +- levenshtein.c | 2 +- parse-options.h | 8 ++++---- revision.c | 2 +- strbuf.h | 2 +- tree-diff.c | 2 +- xdiff/xdiffi.c | 2 +- 20 files changed, 27 insertions(+), 27 deletions(-) diff --git a/builtin-checkout.c b/builtin-checkout.c index ee1edd406f..383598c9bf 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -178,7 +178,7 @@ static int checkout_merged(int pos, struct checkout *state) /* * NEEDSWORK: * There is absolutely no reason to write this as a blob object - * and create a phoney cache entry just to leak. This hack is + * and create a phony cache entry just to leak. This hack is * primarily to get to the write_entry() machinery that massages * the contents to work-tree format and writes out which only * allows it for a cache entry. The code in write_entry() needs diff --git a/builtin-ls-files.c b/builtin-ls-files.c index 88e2697aeb..da2daf45ac 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -512,7 +512,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) pathspec = get_pathspec(prefix, argv); - /* be nice with submodule patsh ending in a slash */ + /* be nice with submodule paths ending in a slash */ read_cache(); if (pathspec) strip_trailing_slash_from_submodules(); diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 419f29aa1a..9742b45c4d 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -293,7 +293,7 @@ static unsigned long write_object(struct sha1file *f, die("unable to read %s", sha1_to_hex(entry->idx.sha1)); /* * make sure no cached delta data remains from a - * previous attempt before a pack split occured. + * previous attempt before a pack split occurred. */ free(entry->delta_data); entry->delta_data = NULL; diff --git a/builtin-reflog.c b/builtin-reflog.c index 249ad2a311..ff8b4f615b 100644 --- a/builtin-reflog.c +++ b/builtin-reflog.c @@ -243,7 +243,7 @@ static void mark_reachable(struct commit *commit, unsigned long expire_limit) * We need to compute if commit on either side of an reflog * entry is reachable from the tip of the ref for all entries. * Mark commits that are reachable from the tip down to the - * time threashold first; we know a commit marked thusly is + * time threshold first; we know a commit marked thusly is * reachable from the tip without running in_merge_bases() * at all. */ diff --git a/builtin-reset.c b/builtin-reset.c index c0cb915c26..7e7ebabaa8 100644 --- a/builtin-reset.c +++ b/builtin-reset.c @@ -228,7 +228,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) } /* * Otherwise, argv[i] could be either <rev> or <paths> and - * has to be unambigous. + * has to be unambiguous. */ else if (!get_sha1(argv[i], sha1)) { /* diff --git a/compat/cygwin.c b/compat/cygwin.c index ebac148392..119287412d 100644 --- a/compat/cygwin.c +++ b/compat/cygwin.c @@ -92,7 +92,7 @@ static int cygwin_stat(const char *path, struct stat *buf) * Reading this option is not always possible immediately as git_dir may be * not be set yet. So until it is set, use cygwin lstat/stat functions. * However, if core.filemode is set, we must use the Cygwin posix - * stat/lstat as the Windows stat fuctions do not determine posix filemode. + * stat/lstat as the Windows stat functions do not determine posix filemode. * * Note that git_cygwin_config() does NOT call git_default_config() and this * is deliberate. Many commands read from config to establish initial diff --git a/compat/fnmatch/fnmatch.c b/compat/fnmatch/fnmatch.c index 1f4ead5f98..03157a4ab5 100644 --- a/compat/fnmatch/fnmatch.c +++ b/compat/fnmatch/fnmatch.c @@ -39,7 +39,7 @@ # include <stdlib.h> #endif -/* For platform which support the ISO C amendement 1 functionality we +/* For platform which support the ISO C amendment 1 functionality we support user defined character classes. */ #if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) /* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */ @@ -90,7 +90,7 @@ # if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) /* The GNU C library provides support for user-defined character classes - and the functions from ISO C amendement 1. */ + and the functions from ISO C amendment 1. */ # ifdef CHARCLASS_NAME_MAX # define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX # else diff --git a/compat/mingw.c b/compat/mingw.c index 1a17cf6cce..2a047019e8 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -396,7 +396,7 @@ repeat: * its own input data to become available. But since * the process (pack-objects) is itself CPU intensive, * it will happily pick up the time slice that we are - * relinguishing here. + * relinquishing here. */ Sleep(0); goto repeat; diff --git a/compat/regex/regex.c b/compat/regex/regex.c index 87b33e4669..5ea007567d 100644 --- a/compat/regex/regex.c +++ b/compat/regex/regex.c @@ -1043,7 +1043,7 @@ regex_compile (pattern, size, syntax, bufp) they can be reliably used as array indices. */ register unsigned char c, c1; - /* A random tempory spot in PATTERN. */ + /* A random temporary spot in PATTERN. */ const char *p1; /* Points to the end of the buffer, where we should append. */ @@ -1796,7 +1796,7 @@ regex_compile (pattern, size, syntax, bufp) we're all done, the pattern will look like: set_number_at <jump count> <upper bound> set_number_at <succeed_n count> <lower bound> - succeed_n <after jump addr> <succed_n count> + succeed_n <after jump addr> <succeed_n count> <body of loop> jump_n <succeed_n addr> <jump count> (The upper bound and `jump_n' are omitted if diff --git a/diffcore-rename.c b/diffcore-rename.c index 0b0d6b8c8c..63ac998bfa 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -267,7 +267,7 @@ static int find_identical_files(struct file_similarity *src, int score; struct diff_filespec *source = p->filespec; - /* False hash collission? */ + /* False hash collision? */ if (hashcmp(source->sha1, target->sha1)) continue; /* Non-regular files? If so, the modes must match! */ diff --git a/fast-import.c b/fast-import.c index 23c496d683..53617a10d2 100644 --- a/fast-import.c +++ b/fast-import.c @@ -76,7 +76,7 @@ Format of STDIN stream: delim lf; # note: declen indicates the length of binary_data in bytes. - # declen does not include the lf preceeding the binary data. + # declen does not include the lf preceding the binary data. # exact_data ::= 'data' sp declen lf binary_data; @@ -134,7 +134,7 @@ Format of STDIN stream: # # In case it is not clear, the '#' that starts the comment # must be the first character on that the line (an lf have - # preceeded it). + # preceded it). # comment ::= '#' not_lf* lf; not_lf ::= # Any byte that is not ASCII newline (LF); @@ -953,7 +953,7 @@ static void end_packfile(void) close(pack_data->pack_fd); idx_name = keep_pack(create_index()); - /* Register the packfile with core git's machinary. */ + /* Register the packfile with core git's machinery. */ new_p = add_packed_git(idx_name, strlen(idx_name), 1); if (!new_p) die("core git rejected index %s", idx_name); diff --git a/fsck.h b/fsck.h index 990ee02335..008456b675 100644 --- a/fsck.h +++ b/fsck.h @@ -23,7 +23,7 @@ int fsck_error_function(struct object *obj, int type, const char *fmt, ...); * the return value is: * -1 error in processing the object * <0 return value of the callback, which lead to an abort - * >0 return value of the first sigaled error >0 (in the case of no other errors) + * >0 return value of the first signaled error >0 (in the case of no other errors) * 0 everything OK */ int fsck_walk(struct object *obj, fsck_walk_func walk, void *data); diff --git a/git.c b/git.c index bfb6508ad0..cc5aaa76f1 100644 --- a/git.c +++ b/git.c @@ -497,7 +497,7 @@ int main(int argc, const char **argv) /* * We use PATH to find git commands, but we prepend some higher - * precidence paths: the "--exec-path" option, the GIT_EXEC_PATH + * precedence paths: the "--exec-path" option, the GIT_EXEC_PATH * environment, and the $(gitexecdir) from the Makefile at build * time. */ diff --git a/graph.c b/graph.c index b7879f8c66..06fbeb6c24 100644 --- a/graph.c +++ b/graph.c @@ -35,7 +35,7 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb); * newline. A new graph line will not be printed after the final newline. * If the strbuf is empty, no output will be printed. * - * Since the first line will not include the graph ouput, the caller is + * Since the first line will not include the graph output, the caller is * responsible for printing this line's graph (perhaps via * graph_show_commit() or graph_show_oneline()) before calling * graph_show_strbuf(). diff --git a/levenshtein.c b/levenshtein.c index a32f4cdc45..fc281597fd 100644 --- a/levenshtein.c +++ b/levenshtein.c @@ -27,7 +27,7 @@ * * It does so by calculating the costs of the path ending in characters * i (in string1) and j (in string2), respectively, given that the last - * operation is a substition, a swap, a deletion, or an insertion. + * operation is a substitution, a swap, a deletion, or an insertion. * * This implementation allows the costs to be weighted: * diff --git a/parse-options.h b/parse-options.h index f8ef1db128..b54eec128b 100644 --- a/parse-options.h +++ b/parse-options.h @@ -52,7 +52,7 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset); * * `argh`:: * token to explain the kind of argument this option wants. Keep it - * homogenous across the repository. + * homogeneous across the repository. * * `help`:: * the short help associated to what the option does. @@ -61,7 +61,7 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset); * * `flags`:: * mask of parse_opt_option_flags. - * PARSE_OPT_OPTARG: says that the argument is optionnal (not for BOOLEANs) + * PARSE_OPT_OPTARG: says that the argument is optional (not for BOOLEANs) * PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs * PARSE_OPT_NONEG: says that this option cannot be negated * PARSE_OPT_HIDDEN this option is skipped in the default usage, showed in @@ -105,7 +105,7 @@ struct option { { OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) } /* parse_options() will filter out the processed options and leave the - * non-option argments in argv[]. + * non-option arguments in argv[]. * Returns the number of arguments left in argv[]. */ extern int parse_options(int argc, const char **argv, @@ -115,7 +115,7 @@ extern int parse_options(int argc, const char **argv, extern NORETURN void usage_with_options(const char * const *usagestr, const struct option *options); -/*----- incremantal advanced APIs -----*/ +/*----- incremental advanced APIs -----*/ enum { PARSE_OPT_HELP = -1, diff --git a/revision.c b/revision.c index bd0ea34af0..18b7ebbbd5 100644 --- a/revision.c +++ b/revision.c @@ -209,7 +209,7 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object } /* - * Tree object? Either mark it uniniteresting, or add it + * Tree object? Either mark it uninteresting, or add it * to the list of objects to look at later.. */ if (object->type == OBJ_TREE) { diff --git a/strbuf.h b/strbuf.h index 9ee908a3ec..eaa8704d5f 100644 --- a/strbuf.h +++ b/strbuf.h @@ -11,7 +11,7 @@ * build complex strings/buffers whose final size isn't easily known. * * It is NOT legal to copy the ->buf pointer away. - * `strbuf_detach' is the operation that detachs a buffer from its shell + * `strbuf_detach' is the operation that detaches a buffer from its shell * while keeping the shell valid wrt its invariants. * * 2. the ->buf member is a byte array that has at least ->len + 1 bytes diff --git a/tree-diff.c b/tree-diff.c index b05d0f4355..edd83949bf 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -374,7 +374,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co } /* - * Then, discard all the non-relevane file pairs... + * Then, discard all the non-relevant file pairs... */ for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; diff --git a/xdiff/xdiffi.c b/xdiff/xdiffi.c index 02184d9cde..1ebab687f7 100644 --- a/xdiff/xdiffi.c +++ b/xdiff/xdiffi.c @@ -456,7 +456,7 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { /* * Record the end-of-group position in case we are matched * with a group of changes in the other file (that is, the - * change record before the enf-of-group index in the other + * change record before the end-of-group index in the other * file is set). */ ixref = rchgo[ixo - 1] ? ix: nrec; From b18cc5a3b2f64364d2c7d3560066852728a6c666 Mon Sep 17 00:00:00 2001 From: Michael J Gruber <git@drmicha.warpmail.net> Date: Wed, 22 Apr 2009 23:15:56 +0200 Subject: [PATCH 484/654] Fix more typos/spelling in comments A few more fixes on top of the automatic spell checker generated ones. Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-reflog.c | 2 +- compat/cygwin.c | 2 +- compat/fnmatch/fnmatch.c | 2 +- fast-import.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/builtin-reflog.c b/builtin-reflog.c index ff8b4f615b..ddfdf5a3cb 100644 --- a/builtin-reflog.c +++ b/builtin-reflog.c @@ -240,7 +240,7 @@ static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsig static void mark_reachable(struct commit *commit, unsigned long expire_limit) { /* - * We need to compute if commit on either side of an reflog + * We need to compute whether the commit on either side of a reflog * entry is reachable from the tip of the ref for all entries. * Mark commits that are reachable from the tip down to the * time threshold first; we know a commit marked thusly is diff --git a/compat/cygwin.c b/compat/cygwin.c index 119287412d..b4a51b958c 100644 --- a/compat/cygwin.c +++ b/compat/cygwin.c @@ -89,7 +89,7 @@ static int cygwin_stat(const char *path, struct stat *buf) /* * At start up, we are trying to determine whether Win32 API or cygwin stat * functions should be used. The choice is determined by core.ignorecygwinfstricks. - * Reading this option is not always possible immediately as git_dir may be + * Reading this option is not always possible immediately as git_dir may * not be set yet. So until it is set, use cygwin lstat/stat functions. * However, if core.filemode is set, we must use the Cygwin posix * stat/lstat as the Windows stat functions do not determine posix filemode. diff --git a/compat/fnmatch/fnmatch.c b/compat/fnmatch/fnmatch.c index 03157a4ab5..14feac7fe1 100644 --- a/compat/fnmatch/fnmatch.c +++ b/compat/fnmatch/fnmatch.c @@ -39,7 +39,7 @@ # include <stdlib.h> #endif -/* For platform which support the ISO C amendment 1 functionality we +/* For platforms which support the ISO C amendment 1 functionality we support user defined character classes. */ #if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) /* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */ diff --git a/fast-import.c b/fast-import.c index 53617a10d2..8d959af3b2 100644 --- a/fast-import.c +++ b/fast-import.c @@ -133,7 +133,7 @@ Format of STDIN stream: # always escapes the related input from comment processing. # # In case it is not clear, the '#' that starts the comment - # must be the first character on that the line (an lf have + # must be the first character on that line (an lf # preceded it). # comment ::= '#' not_lf* lf; From 7bd93c1c625ce5fa03f0d13d728f34f8ab868991 Mon Sep 17 00:00:00 2001 From: Dan Loewenherz <daniel.loewenherz@yale.edu> Date: Wed, 22 Apr 2009 21:46:02 -0400 Subject: [PATCH 485/654] Convert to use quiet option when available A minor fix that eliminates usage of "2>/dev/null" when --quiet or -q has already been implemented. Signed-off-by: Dan Loewenherz <daniel.loewenherz@yale.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-filter-branch.sh | 2 +- git-merge-resolve.sh | 4 ++-- git-parse-remote.sh | 2 +- git-pull.sh | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/git-filter-branch.sh b/git-filter-branch.sh index b90d3df3a7..37e044db40 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -430,7 +430,7 @@ if [ "$filter_tag_name" ]; then if [ "$type" = "tag" ]; then # Dereference to a commit sha1t="$sha1" - sha1="$(git rev-parse "$sha1"^{commit} 2>/dev/null)" || continue + sha1="$(git rev-parse -q "$sha1"^{commit})" || continue fi [ -f "../map/$sha1" ] || continue diff --git a/git-merge-resolve.sh b/git-merge-resolve.sh index 93bcfc2f5d..c9da747fcf 100755 --- a/git-merge-resolve.sh +++ b/git-merge-resolve.sh @@ -37,10 +37,10 @@ then exit 2 fi -git update-index --refresh 2>/dev/null +git update-index -q --refresh git read-tree -u -m --aggressive $bases $head $remotes || exit 2 echo "Trying simple merge." -if result_tree=$(git write-tree 2>/dev/null) +if result_tree=$(git write-tree 2>/dev/null) then exit 0 else diff --git a/git-parse-remote.sh b/git-parse-remote.sh index 695a4094bb..a296719861 100755 --- a/git-parse-remote.sh +++ b/git-parse-remote.sh @@ -2,7 +2,7 @@ # git-ls-remote could be called from outside a git managed repository; # this would fail in that case and would issue an error message. -GIT_DIR=$(git rev-parse --git-dir 2>/dev/null) || :; +GIT_DIR=$(git rev-parse -q --git-dir) || :; get_data_source () { case "$1" in diff --git a/git-pull.sh b/git-pull.sh index 8c750270e9..35261539ab 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -147,7 +147,7 @@ then echo >&2 "Warning: fetch updated the current branch head." echo >&2 "Warning: fast forwarding your working tree from" echo >&2 "Warning: commit $orig_head." - git update-index --refresh 2>/dev/null + git update-index -q --refresh git read-tree -u -m "$orig_head" "$curr_head" || die 'Cannot fast-forward your working tree. After making sure that you saved anything precious from From 7613ea3595f3a56f0f9d827944775940f1e72ef6 Mon Sep 17 00:00:00 2001 From: Bill Pemberton <wfp5p@virginia.edu> Date: Wed, 22 Apr 2009 09:41:29 -0400 Subject: [PATCH 486/654] Add parsing of elm aliases to git-send-email elm stores a text file version of the aliases that is <alias> = <comment> = <email address> This adds the parsing of this file to git-send-email Signed-off-by: Bill Pemberton <wfp5p@virginia.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-send-email.txt | 2 +- git-send-email.perl | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index 0b1f183ce8..794224b1b3 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -262,7 +262,7 @@ sendemail.aliasesfile:: sendemail.aliasfiletype:: Format of the file(s) specified in sendemail.aliasesfile. Must be - one of 'mutt', 'mailrc', 'pine', or 'gnus'. + one of 'mutt', 'mailrc', 'pine', 'elm', or 'gnus'. sendemail.multiedit:: If true (default), a single editor instance will be spawned to edit diff --git a/git-send-email.perl b/git-send-email.perl index 172b53c2d5..cccbf4517a 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -418,6 +418,14 @@ my %parse_alias = ( $x =~ /^(\S+)$f\t\(?([^\t]+?)\)?(:?$f){0,2}$/ or next; $aliases{$1} = [ split_addrs($2) ]; }}, + elm => sub { my $fh = shift; + while (<$fh>) { + if (/^(\S+)\s+=\s+[^=]+=\s(\S+)/) { + my ($alias, $addr) = ($1, $2); + $aliases{$alias} = [ split_addrs($addr) ]; + } + } }, + gnus => sub { my $fh = shift; while (<$fh>) { if (/\(define-mail-alias\s+"(\S+?)"\s+"(\S+?)"\)/) { $aliases{$1} = [ $2 ]; From 48d3448dd5700f9ea8a142935fd4263ba1fb79c6 Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Thu, 23 Apr 2009 02:37:56 -0700 Subject: [PATCH 487/654] config.txt: add missing format.{subjectprefix,cc,attach} variables Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Documentation/config.txt b/Documentation/config.txt index 35056e1a9c..a9055c94ac 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -707,6 +707,13 @@ fetch.unpackLimit:: especially on slow filesystems. If not set, the value of `transfer.unpackLimit` is used instead. +format.attach:: + Enable multipart/mixed attachments as the default for + 'format-patch'. The value can also be a double quoted string + which will enable attachments as the default and set the + value as the boundary. See the --attach option in + linkgit:git-format-patch[1]. + format.numbered:: A boolean which can enable or disable sequence numbers in patch subjects. It defaults to "auto" which enables it only if there @@ -718,6 +725,14 @@ format.headers:: Additional email headers to include in a patch to be submitted by mail. See linkgit:git-format-patch[1]. +format.cc:: + Additional "Cc:" headers to include in a patch to be submitted + by mail. See the --cc option in linkgit:git-format-patch[1]. + +format.subjectprefix:: + The default for format-patch is to output files with the '[PATCH]' + subject prefix. Use this variable to change that prefix. + format.suffix:: The default for format-patch is to output files with the suffix `.patch`. Use this variable to change that suffix (make sure to From fd1ff306b7a02f9412f8ed4881dd239d8a4a709a Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Thu, 23 Apr 2009 02:37:57 -0700 Subject: [PATCH 488/654] Documentation: use lowercase for shallow and deep threading Even when a sentence is started with 'shallow' or 'deep' use the lowercase version to maintain consistency. Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 4 ++-- Documentation/git-format-patch.txt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index a9055c94ac..0c1224a017 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -745,11 +745,11 @@ format.pretty:: format.thread:: The default threading style for 'git-format-patch'. Can be - either a boolean value, `shallow` or `deep`. 'Shallow' + either a boolean value, `shallow` or `deep`. `shallow` threading makes every mail a reply to the head of the series, where the head is chosen from the cover letter, the `\--in-reply-to`, and the first patch mail, in this order. - 'Deep' threading makes every mail a reply to the previous one. + `deep` threading makes every mail a reply to the previous one. A true boolean value is the same as `shallow`, and a false value disables threading. diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index 5eddca92c4..4a43c64bb8 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -128,9 +128,9 @@ include::diff-options.txt[] the Message-Id header to reference. + The optional <style> argument can be either `shallow` or `deep`. -'Shallow' threading makes every mail a reply to the head of the +'shallow' threading makes every mail a reply to the head of the series, where the head is chosen from the cover letter, the -`\--in-reply-to`, and the first patch mail, in this order. 'Deep' +`\--in-reply-to`, and the first patch mail, in this order. 'deep' threading makes every mail a reply to the previous one. If not specified, defaults to the 'format.thread' configuration, or `shallow` if that is not set. From a12397877146b3fa8f791a4a38987942f35a5e82 Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Thu, 23 Apr 2009 02:37:58 -0700 Subject: [PATCH 489/654] git-show-branch.txt: cleanup example description Add a missing quote and properly escape the ' character so docs don't look odd. Add 'the' to make some sentences more gramatically correct. Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-show-branch.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt index 7e9ff3762b..51a4e9d6d7 100644 --- a/Documentation/git-show-branch.txt +++ b/Documentation/git-show-branch.txt @@ -148,9 +148,10 @@ $ git show-branch master fixes mhf ------------------------------------------------ These three branches all forked from a common commit, [master], -whose commit message is "Add 'git show-branch'. "fixes" branch -adds one commit 'Introduce "reset type"'. "mhf" branch has many -other commits. The current branch is "master". +whose commit message is "Add \'git show-branch\'". The "fixes" +branch adds one commit "Introduce "reset type" flag to "git reset"". +The "mhf" branch adds many other commits. The current branch +is "master". EXAMPLE From 50710ce49b8e66204cc6147345db9c99bb7cfe82 Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Thu, 23 Apr 2009 09:16:52 -0700 Subject: [PATCH 490/654] git-format-patch.txt: general rewordings and cleanups Clarify --no-binary description using some words from the original commit 37c22a4b (add --no-binary, 2008-05-9). Cleanup --suffix description. Add --thread style option to synopsis and reorganize it a bit. Clarify renaming patches example and the configuration paragraph. Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-format-patch.txt | 38 +++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index 4a43c64bb8..6f1fc80119 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -9,10 +9,10 @@ git-format-patch - Prepare patches for e-mail submission SYNOPSIS -------- [verse] -'git format-patch' [-k] [-o <dir> | --stdout] [--thread] - [--attach[=<boundary>] | --inline[=<boundary>] | - [--no-attach]] - [-s | --signoff] [<common diff options>] +'git format-patch' [-k] [(-o|--output-directory) <dir> | --stdout] + [--thread[=<style>]] + [(--attach|--inline)[=<boundary>] | --no-attach] + [-s | --signoff] [-n | --numbered | -N | --no-numbered] [--start-number <n>] [--numbered-files] [--in-reply-to=Message-Id] [--suffix=.<sfx>] @@ -20,6 +20,7 @@ SYNOPSIS [--subject-prefix=Subject-Prefix] [--cc=<email>] [--cover-letter] + [<common diff options>] [ <since> | <revision range> ] DESCRIPTION @@ -170,18 +171,17 @@ if that is not set. --suffix=.<sfx>:: Instead of using `.patch` as the suffix for generated filenames, use specified suffix. A common alternative is - `--suffix=.txt`. + `--suffix=.txt`. Leaving this empty will remove the `.patch` + suffix. + -Note that you would need to include the leading dot `.` if you -want a filename like `0001-description-of-my-change.patch`, and -the first letter does not have to be a dot. Leaving it empty would -not add any suffix. +Note that the leading character does not have to be a dot; for example, +you can use `--suffix=-patch` to get `0001-description-of-my-change-patch`. --no-binary:: - Don't output contents of changes in binary files, just take note - that they differ. Note that this disable the patch to be properly - applied. By default the contents of changes in those files are - encoded in the patch. + Do not output contents of changes in binary files, instead + display a notice that those files changed. Patches generated + using this option cannot be applied properly, but they are + still useful for code review. --root:: Treat the revision argument as a <revision range>, even if it @@ -192,10 +192,10 @@ not add any suffix. CONFIGURATION ------------- -You can specify extra mail header lines to be added to each message -in the repository configuration, new defaults for the subject prefix -and file suffix, control attachments, and number patches when outputting -more than one. +You can specify extra mail header lines to be added to each message, +defaults for the subject prefix and file suffix, number patches when +outputting more than one patch, add "Cc:" headers, configure attachments, +and sign off patches with configuration variables. ------------ [format] @@ -243,8 +243,8 @@ $ git format-patch -M -B origin + Additionally, it detects and handles renames and complete rewrites intelligently to produce a renaming patch. A renaming patch reduces -the amount of text output, and generally makes it easier to review it. -Note that the "patch" program does not understand renaming patches, so +the amount of text output, and generally makes it easier to review. +Note that non-git "patch" programs won't understand renaming patches, so use it only when you know the recipient uses git to apply your patch. * Extract three topmost commits from the current branch and format them From 773002a78c69b91a3e5904137c23cae5363d6059 Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Thu, 23 Apr 2009 02:38:00 -0700 Subject: [PATCH 491/654] config.txt: add missing 'the's and make words plural Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 0c1224a017..5bff4005fc 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -2,10 +2,10 @@ CONFIGURATION FILE ------------------ The git configuration file contains a number of variables that affect -the git command's behavior. `.git/config` file for each repository +the git command's behavior. The `.git/config` file in each repository is used to store the information for that repository, and -`$HOME/.gitconfig` is used to store per user information to give -fallback values for `.git/config` file. The file `/etc/gitconfig` +`$HOME/.gitconfig` is used to store per user information as +fallback values for the `.git/config` file. The file `/etc/gitconfig` can be used to store system-wide defaults. They can be used by both the git plumbing @@ -26,28 +26,28 @@ The file consists of sections and variables. A section begins with the name of the section in square brackets and continues until the next section begins. Section names are not case sensitive. Only alphanumeric characters, `-` and `.` are allowed in section names. Each variable -must belong to some section, which means that there must be section -header before first setting of a variable. +must belong to some section, which means that there must be a section +header before the first setting of a variable. Sections can be further divided into subsections. To begin a subsection put its name in double quotes, separated by space from the section name, -in the section header, like in example below: +in the section header, like in the example below: -------- [section "subsection"] -------- -Subsection names can contain any characters except newline (doublequote +Subsection names can contain any character except newline (doublequote `"` and backslash have to be escaped as `\"` and `\\`, -respectively) and are case sensitive. Section header cannot span multiple +respectively) and are case sensitive. Section headers cannot span multiple lines. Variables may belong directly to a section or to a given subsection. You can have `[section]` if you have `[section "subsection"]`, but you don't need to. -There is also (case insensitive) alternative `[section.subsection]` syntax. -In this syntax subsection names follow the same restrictions as for section -name. +There is also a case insensitive alternative `[section.subsection]` syntax. +In this syntax, subsection names follow the same restrictions as for section +names. All the other lines are recognized as setting variables, in the form 'name = value'. If there is no equal sign on the line, the entire line @@ -66,10 +66,10 @@ converting value to the canonical form using '--bool' type specifier; 'git-config' will ensure that the output is "true" or "false". String values may be entirely or partially enclosed in double quotes. -You need to enclose variable value in double quotes if you want to -preserve leading or trailing whitespace, or if variable value contains -beginning of comment characters (if it contains '#' or ';'). -Double quote `"` and backslash `\` characters in variable value must +You need to enclose variable values in double quotes if you want to +preserve leading or trailing whitespace, or if the variable value contains +comment characters (i.e. it contains '#' or ';'). +Double quote `"` and backslash `\` characters in variable values must be escaped: use `\"` for `"` and `\\` for `\`. The following escape sequences (beside `\"` and `\\`) are recognized: @@ -77,10 +77,10 @@ The following escape sequences (beside `\"` and `\\`) are recognized: and `\b` for backspace (BS). No other char escape sequence, nor octal char sequences are valid. -Variable value ending in a `\` is continued on the next line in the +Variable values ending in a `\` are continued on the next line in the customary UNIX fashion. -Some variables may require special value format. +Some variables may require a special value format. Example ~~~~~~~ From b7ee2266fe2d8593d4c2affdc3361836ce826230 Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Thu, 23 Apr 2009 02:38:01 -0700 Subject: [PATCH 492/654] config.txt: clarify sentences in the configuration and syntax sections Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 5bff4005fc..01b752cd3e 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -8,9 +8,9 @@ is used to store the information for that repository, and fallback values for the `.git/config` file. The file `/etc/gitconfig` can be used to store system-wide defaults. -They can be used by both the git plumbing -and the porcelains. The variables are divided into sections, where -in the fully qualified variable name the variable itself is the last +The configuration variables are used by both the git plumbing +and the porcelains. The variables are divided into sections, wherein +the fully qualified variable name of the variable itself is the last dot-separated segment and the section name is everything before the last dot. The variable names are case-insensitive and only alphanumeric characters are allowed. Some variables may appear multiple times. @@ -38,9 +38,9 @@ in the section header, like in the example below: -------- -Subsection names can contain any character except newline (doublequote -`"` and backslash have to be escaped as `\"` and `\\`, -respectively) and are case sensitive. Section headers cannot span multiple +Subsection names are case sensitive and can contain any characters except +newline (doublequote `"` and backslash have to be escaped as `\"` and `\\`, +respectively). Section headers cannot span multiple lines. Variables may belong directly to a section or to a given subsection. You can have `[section]` if you have `[section "subsection"]`, but you don't need to. From 66e35fcb79cad5a2ec2366da956db55da855b20d Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Thu, 23 Apr 2009 02:38:02 -0700 Subject: [PATCH 493/654] config.txt: Make configuration paragraph more consistent By renaming 'information' to 'configuration' we capture more clearly what a configuration file holds. Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 01b752cd3e..31885690f0 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -3,10 +3,10 @@ CONFIGURATION FILE The git configuration file contains a number of variables that affect the git command's behavior. The `.git/config` file in each repository -is used to store the information for that repository, and -`$HOME/.gitconfig` is used to store per user information as +is used to store the configuration for that repository, and +`$HOME/.gitconfig` is used to store a per-user configuration as fallback values for the `.git/config` file. The file `/etc/gitconfig` -can be used to store system-wide defaults. +can be used to store a system-wide default configuration. The configuration variables are used by both the git plumbing and the porcelains. The variables are divided into sections, wherein From 5be3b17f094d832458238e4d2979cf9ab7118b6f Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Wed, 22 Apr 2009 22:42:28 -0700 Subject: [PATCH 494/654] Makefile: ignore perl/ subdirectory under NO_PERL The install target still descends into perl subdirectory when NO_PERL is requested. Fix this. Acked-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 49f36f5787..6f602c7bbf 100644 --- a/Makefile +++ b/Makefile @@ -1529,7 +1529,9 @@ install: all $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' $(INSTALL) git$X git-upload-pack$X git-receive-pack$X git-upload-archive$X git-shell$X git-cvsserver '$(DESTDIR_SQ)$(bindir_SQ)' $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install +ifndef NO_PERL $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install +endif ifndef NO_TCLTK $(MAKE) -C gitk-git install $(MAKE) -C git-gui gitexecdir='$(gitexec_instdir_SQ)' install From 677fbff88f368ed6ac52438ddbb530166ec1d5d1 Mon Sep 17 00:00:00 2001 From: Alex Riesen <raa.lkml@gmail.com> Date: Thu, 23 Apr 2009 21:18:09 +0200 Subject: [PATCH 495/654] Explain seemingly pointless use of system in difftool Portability reasons. Signed-off-by: Alex Riesen <raa.lkml@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-difftool.perl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/git-difftool.perl b/git-difftool.perl index bd828c2a6f..ba5e60a45e 100755 --- a/git-difftool.perl +++ b/git-difftool.perl @@ -82,5 +82,11 @@ sub generate_command } setup_environment(); + +# ActiveState Perl for Win32 does not implement POSIX semantics of +# exec* system call. It just spawns the given executable and finishes +# the starting program, exiting with code 0. +# system will at least catch the errors returned by git diff, +# allowing the caller of git difftool better handling of failures. my $rc = system(generate_command()); exit($rc | ($rc >> 8)); From 178b513eb78ac8099588c5bed1f1f74f660cf009 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Thu, 23 Apr 2009 15:49:06 +0200 Subject: [PATCH 496/654] builtin-help: silently tolerate unknown keys If for some reason the config file contains a key without a subkey like [man] foo = bar then even a plain git help produces an error message. With this patch such an entry is ignored. Additionally, the warning about unknown sub-keys is removed. It could become annoying if new sub-keys are introduced in the future, and then the configuration is read by an old version of git that does not know about it. Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-help.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/builtin-help.c b/builtin-help.c index 9b57a74618..e7fbe9af63 100644 --- a/builtin-help.c +++ b/builtin-help.c @@ -236,7 +236,7 @@ static int add_man_viewer_info(const char *var, const char *value) const char *subkey = strrchr(name, '.'); if (!subkey) - return error("Config with no key for man viewer: %s", name); + return 0; if (!strcmp(subkey, ".path")) { if (!value) @@ -249,7 +249,6 @@ static int add_man_viewer_info(const char *var, const char *value) return add_man_viewer_cmd(name, subkey - name, value); } - warning("'%s': unsupported man viewer sub key.", subkey); return 0; } From cd294bc3f3a7b1277551a8c6e0682fdfbe794260 Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Thu, 23 Apr 2009 15:49:05 +0200 Subject: [PATCH 497/654] remote.c: do not trigger remote.<name>.<var> codepath for two-level names If the config file contains a section like this: [remote] default = foo (it should be '[remotes]') then commands like git status git checkout git branch -v fail even though they are not obviously related to remotes. (These commands write "ahead, behind" information and, therefore, access the per-remote information). Unknown configuration keys should be ignored, not trigger errors. Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- remote.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/remote.c b/remote.c index 91f748550e..d66e2f3c93 100644 --- a/remote.c +++ b/remote.c @@ -366,7 +366,7 @@ static int handle_config(const char *key, const char *value, void *cb) } subkey = strrchr(name, '.'); if (!subkey) - return error("Config with no key for remote %s", name); + return 0; remote = make_remote(name, subkey - name); remote->origin = REMOTE_CONFIG; if (!strcmp(subkey, ".mirror")) From a766829458d2ecdc09f42076775ce4d6d4c9d1a8 Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Fri, 24 Apr 2009 09:56:14 -0400 Subject: [PATCH 498/654] t7800: respect NO_PERL Difftool is written in perl, so we don't build it if NO_PERL is set. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t7800-difftool.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index 2586f864a0..ebdccf9a1e 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -10,6 +10,11 @@ Testing basic diff tool invocation . ./test-lib.sh +if ! test_have_prereq PERL; then + say 'skipping difftool tests, perl not available' + test_done +fi + remove_config_vars() { # Unset all config variables used by git-difftool From f29ac4f1b04c9cf84509e4a80f27f10b4373a446 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Fri, 24 Apr 2009 22:54:40 -0700 Subject: [PATCH 499/654] GIT 1.6.3-rc2 Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/RelNotes-1.6.3.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/RelNotes-1.6.3.txt b/Documentation/RelNotes-1.6.3.txt index efce29ddf3..7270ef893b 100644 --- a/Documentation/RelNotes-1.6.3.txt +++ b/Documentation/RelNotes-1.6.3.txt @@ -152,6 +152,10 @@ Updates since v1.6.2 knobs you can tweak to work around issues with various versions of the docbook-xsl package. See comments in Documentation/Makefile for details. +* Support for building and testing a subset of git on a system without a + working perl has been improved. + + Fixes since v1.6.2 ------------------ @@ -173,6 +177,6 @@ v1.6.2.X series. --- exec >/var/tmp/1 -O=v1.6.3-rc1-1-gea10b60 +O=v1.6.3-rc2 echo O=$(git describe master) git shortlog --no-merges $O..master ^maint From 6123d7196fdd9ac9aed24b4aeed854813fe9a6b1 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg <markus.heidelberg@web.de> Date: Sat, 25 Apr 2009 13:46:14 +0200 Subject: [PATCH 500/654] bash completion: show-branch color support This implements completion of --color and --no-color for "git show-branch" and color.showbranch for "git config". Signed-off-by: Markus Heidelberg <markus.heidelberg@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 1a90cb87f5..b588387262 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1333,7 +1333,8 @@ _git_config () __gitcomp "$(__git_merge_strategies)" return ;; - color.branch|color.diff|color.interactive|color.status|color.ui) + color.branch|color.diff|color.interactive|\ + color.showbranch|color.status|color.ui) __gitcomp "always never auto" return ;; @@ -1415,6 +1416,7 @@ _git_config () color.interactive.help color.interactive.prompt color.pager + color.showbranch color.status color.status.added color.status.changed @@ -1676,6 +1678,7 @@ _git_show_branch () __gitcomp " --all --remotes --topo-order --current --more= --list --independent --merge-base --no-name + --color --no-color --sha1-name --topics --reflog " return From 66913284f06da58e2243acfad951a57501b8d813 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre <nico@cam.org> Date: Fri, 24 Apr 2009 17:46:15 -0400 Subject: [PATCH 501/654] progress bar: round to the nearest instead of truncating down Often the throughput output is requested when the data read so far is one smaller than multiple of 1024; because 1023/1024 is ~0.999, it often shows up as 0.99 because the code currently truncates. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- progress.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/progress.c b/progress.c index 55a8687ad1..621c34edc2 100644 --- a/progress.c +++ b/progress.c @@ -121,13 +121,13 @@ static void throughput_string(struct throughput *tp, off_t total, (int)(total >> 30), (int)(total & ((1 << 30) - 1)) / 10737419); } else if (total > 1 << 20) { + int x = total + 5243; /* for rounding */ l -= snprintf(tp->display, l, ", %u.%2.2u MiB", - (int)(total >> 20), - ((int)(total & ((1 << 20) - 1)) * 100) >> 20); + x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20); } else if (total > 1 << 10) { + int x = total + 5; /* for rounding */ l -= snprintf(tp->display, l, ", %u.%2.2u KiB", - (int)(total >> 10), - ((int)(total & ((1 << 10) - 1)) * 100) >> 10); + x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10); } else { l -= snprintf(tp->display, l, ", %u bytes", (int)total); } From 84eeb687de7a6c7c42af3fb51b176e0f412a979e Mon Sep 17 00:00:00 2001 From: Brandon Casey <casey@nrlssc.navy.mil> Date: Fri, 24 Apr 2009 18:18:52 -0500 Subject: [PATCH 502/654] t9001: use older Getopt::Long boolean prefix '--no' rather than '--no-' The '--no-thread' option is a Getopt::Long boolean option. The '--no-' prefix (as in --no-thread) for boolean options is not supported in Getopt::Long version 2.32 which was released with Perl 5.8.0. This version only supports '--no' as in '--nothread'. More recent versions of Getopt::Long, such as version 2.34, support either prefix. So use the older form in the tests. Signed-off-by: Brandon Casey <casey@nrlssc.navy.mil> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t9001-send-email.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index d9420e0a3b..ce26ea4ac5 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -616,7 +616,7 @@ test_expect_success 'in-reply-to but no threading' ' --from="Example <nobody@example.com>" \ --to=nobody@example.com \ --in-reply-to="<in-reply-id@example.com>" \ - --no-thread \ + --nothread \ $patches | grep "In-Reply-To: <in-reply-id@example.com>" ' From 1ef2d5a640d14e924751adb500224a36d87f9771 Mon Sep 17 00:00:00 2001 From: Brandon Casey <casey@nrlssc.navy.mil> Date: Fri, 24 Apr 2009 18:18:53 -0500 Subject: [PATCH 503/654] t7700-repack: repack -a now works properly, expect success from test Since the recent rework of the object listing mechanism of pack-objects/rev-list, git-repack now properly packs objects from alternate repositories even when the local repository contains packs. Signed-off-by: Brandon Casey <casey@nrlssc.navy.mil> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t7700-repack.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh index 6b29bff782..87c9b0e121 100755 --- a/t/t7700-repack.sh +++ b/t/t7700-repack.sh @@ -69,7 +69,7 @@ test_expect_success 'packed obs in alt ODB are repacked even when local repo is done ' -test_expect_failure 'packed obs in alt ODB are repacked when local repo has packs' ' +test_expect_success 'packed obs in alt ODB are repacked when local repo has packs' ' rm -f .git/objects/pack/* && echo new_content >> file1 && git add file1 && From c5fe5b6de94c1dffac697b29920819f08e2c11fc Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty <sitaramc@gmail.com> Date: Sat, 25 Apr 2009 16:26:52 +0530 Subject: [PATCH 504/654] Remove obsolete bug warning in man git-update-server-info The bug referred to was fixed in 60d0526 Signed-off-by: Sitaram Chamarty <sitaramc@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-update-server-info.txt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Documentation/git-update-server-info.txt b/Documentation/git-update-server-info.txt index 35d27b0c7f..035cc3018f 100644 --- a/Documentation/git-update-server-info.txt +++ b/Documentation/git-update-server-info.txt @@ -39,12 +39,6 @@ what they are for: * info/refs -BUGS ----- -When you remove an existing ref, the command fails to update -info/refs file unless `--force` flag is given. - - Author ------ Written by Junio C Hamano <gitster@pobox.com> From 926337fe89f99c690b721f00239e298f8b7cad28 Mon Sep 17 00:00:00 2001 From: "Wesley J. Landaker" <wjl@icecavern.net> Date: Sat, 25 Apr 2009 09:13:40 -0600 Subject: [PATCH 505/654] Documentation: git-clean: fix minor grammatical errors There were a few minor grammatical errors that made this paragraph hard to read. This patch fixes the errors in a very minimal manner. Signed-off-by: Wesley J. Landaker <wjl@icecavern.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-clean.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt index 8a114509f4..932d44daff 100644 --- a/Documentation/git-clean.txt +++ b/Documentation/git-clean.txt @@ -12,9 +12,9 @@ SYNOPSIS DESCRIPTION ----------- -Removes files unknown to git. This allows to clean the working tree -from files that are not under version control. If the '-x' option is -specified, ignored files are also removed, allowing to remove all +Removes files unknown to git. This allows cleaning the working tree +of files that are not under version control. If the '-x' option is +specified, ignored files are also removed, allowing the removal of all build products. If any optional `<path>...` arguments are given, only those paths are affected. From 911198f6c09e2a60451cf1a295ce4532ff11781c Mon Sep 17 00:00:00 2001 From: "Wesley J. Landaker" <wjl@icecavern.net> Date: Sat, 25 Apr 2009 09:13:41 -0600 Subject: [PATCH 506/654] Documentation: git-clean: make description more readable The existing text is a little bit awkward. This rewrites the description section to be more readable and friendly. Signed-off-by: Wesley J. Landaker <wjl@icecavern.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-clean.txt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt index 932d44daff..43b2de7db3 100644 --- a/Documentation/git-clean.txt +++ b/Documentation/git-clean.txt @@ -12,14 +12,17 @@ SYNOPSIS DESCRIPTION ----------- -Removes files unknown to git. This allows cleaning the working tree -of files that are not under version control. If the '-x' option is -specified, ignored files are also removed, allowing the removal of all -build products. + +This allows cleaning the working tree by removing files that are not +under version control. + +Normally, only files unknown to git are removed, but if the '-x' +option is specified, ignored files are also removed. This can, for +example, be useful to remove all build products. + If any optional `<path>...` arguments are given, only those paths are affected. - OPTIONS ------- -d:: From 785a9857496ae1b71b168f6d79306ca233ec0cd6 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer <benny.kra@googlemail.com> Date: Fri, 24 Apr 2009 14:16:41 +0200 Subject: [PATCH 507/654] connect: replace inet_ntop with getnameinfo inet_ntop is not protocol independent. getnameinfo(3) is part of POSIX and is available when getaddrinfo(3) is. This code is only compiled when NO_IPV6 isn't defined. The old method was buggy anyway, not every ipv6 address was converted properly because the buffer (addr) was too small. Signed-off-by: Benjamin Kramer <benny.kra@googlemail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- connect.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/connect.c b/connect.c index 7636bf976e..f6b8ba6fec 100644 --- a/connect.c +++ b/connect.c @@ -177,18 +177,11 @@ static enum protocol get_protocol(const char *name) static const char *ai_name(const struct addrinfo *ai) { - static char addr[INET_ADDRSTRLEN]; - if ( AF_INET == ai->ai_family ) { - struct sockaddr_in *in; - in = (struct sockaddr_in *)ai->ai_addr; - inet_ntop(ai->ai_family, &in->sin_addr, addr, sizeof(addr)); - } else if ( AF_INET6 == ai->ai_family ) { - struct sockaddr_in6 *in; - in = (struct sockaddr_in6 *)ai->ai_addr; - inet_ntop(ai->ai_family, &in->sin6_addr, addr, sizeof(addr)); - } else { + static char addr[NI_MAXHOST]; + if (getnameinfo(ai->ai_addr, ai->ai_addrlen, addr, sizeof(addr), NULL, 0, + NI_NUMERICHOST) != 0) strcpy(addr, "(unknown)"); - } + return addr; } From be66a6c43dcba42c56f66a8706721a76098f8e25 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <Johannes.Schindelin@gmx.de> Date: Sat, 25 Apr 2009 11:57:14 +0200 Subject: [PATCH 508/654] Add an option not to use link(src, dest) && unlink(src) when that is unreliable It seems that accessing NTFS partitions with ufsd (at least on my EeePC) has an unnerving bug: if you link() a file and unlink() it right away, the target of the link() will have the correct size, but consist of NULs. It seems as if the calls are simply not serialized correctly, as single-stepping through the function move_temp_to_file() works flawlessly. As ufsd is "Commertial software" (sic!), I cannot fix it, and have to work around it in Git. At the same time, it seems that this fixes msysGit issues 222 and 229 to assume that Windows cannot handle link() && unlink(). Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Acked-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 5 +++++ Makefile | 8 ++++++++ cache.h | 2 ++ config.c | 5 +++++ environment.c | 4 ++++ sha1_file.c | 5 ++++- 6 files changed, 28 insertions(+), 1 deletion(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 31885690f0..d31adb6719 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -429,6 +429,11 @@ relatively high IO latencies. With this set to 'true', git will do the index comparison to the filesystem data in parallel, allowing overlapping IO's. +core.unreliableHardlinks:: + Some filesystem drivers cannot properly handle hardlinking a file + and deleting the source right away. In such a case, you need to + set this config variable to 'true'. + alias.*:: Command aliases for the linkgit:git[1] command wrapper - e.g. after defining "alias.last = cat-file commit HEAD", the invocation diff --git a/Makefile b/Makefile index 6f602c7bbf..5c8e83a997 100644 --- a/Makefile +++ b/Makefile @@ -171,6 +171,10 @@ all:: # Define UNRELIABLE_FSTAT if your system's fstat does not return the same # information on a not yet closed file that lstat would return for the same # file after it was closed. +# +# Define UNRELIABLE_HARDLINKS if your operating systems has problems when +# hardlinking a file to another name and unlinking the original file right +# away (some NTFS drivers seem to zero the contents in that scenario). GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE @$(SHELL_PATH) ./GIT-VERSION-GEN @@ -835,6 +839,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_NSEC = YesPlease USE_WIN32_MMAP = YesPlease UNRELIABLE_FSTAT = UnfortunatelyYes + UNRELIABLE_HARDLINKS = UnfortunatelySometimes COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" @@ -1018,6 +1023,9 @@ else COMPAT_OBJS += compat/win32mmap.o endif endif +ifdef UNRELIABLE_HARDLINKS + COMPAT_CFLAGS += -DUNRELIABLE_HARDLINKS=1 +endif ifdef NO_PREAD COMPAT_CFLAGS += -DNO_PREAD COMPAT_OBJS += compat/pread.o diff --git a/cache.h b/cache.h index ab1294d6fb..ff9e145be0 100644 --- a/cache.h +++ b/cache.h @@ -554,6 +554,8 @@ extern enum branch_track git_branch_track; extern enum rebase_setup_type autorebase; extern enum push_default_type push_default; +extern int unreliable_hardlinks; + #define GIT_REPO_VERSION 0 extern int repository_format_version; extern int check_repository_format(void); diff --git a/config.c b/config.c index 8c1ae598a9..1750cfb85e 100644 --- a/config.c +++ b/config.c @@ -495,6 +495,11 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.unreliablehardlinks")) { + unreliable_hardlinks = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 4696885b22..10578d24d7 100644 --- a/environment.c +++ b/environment.c @@ -43,6 +43,10 @@ unsigned whitespace_rule_cfg = WS_DEFAULT_RULE; enum branch_track git_branch_track = BRANCH_TRACK_REMOTE; enum rebase_setup_type autorebase = AUTOREBASE_NEVER; enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED; +#ifndef UNRELIABLE_HARDLINKS +#define UNRELIABLE_HARDLINKS 0 +#endif +int unreliable_hardlinks = UNRELIABLE_HARDLINKS; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/sha1_file.c b/sha1_file.c index 8fe135dc61..11969fc161 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -2225,7 +2225,9 @@ int move_temp_to_file(const char *tmpfile, const char *filename) { int ret = 0; - if (link(tmpfile, filename)) + if (unreliable_hardlinks) + goto try_rename; + else if (link(tmpfile, filename)) ret = errno; /* @@ -2240,6 +2242,7 @@ int move_temp_to_file(const char *tmpfile, const char *filename) * left to unlink. */ if (ret && ret != EEXIST) { + try_rename: if (!rename(tmpfile, filename)) goto out; ret = errno; From a408e0e649b79ede7422bf837a31d281e4188cef Mon Sep 17 00:00:00 2001 From: Markus Heidelberg <markus.heidelberg@web.de> Date: Sat, 25 Apr 2009 00:06:47 +0200 Subject: [PATCH 509/654] diff: do not color --stat output like patch context The diffstat used the color.diff.plain slot (context text) for coloring filenames and the whole summary line. This didn't look nice and the affected text isn't patch context at all. Signed-off-by: Markus Heidelberg <markus.heidelberg@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- diff.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/diff.c b/diff.c index 3ac71686eb..d581d4d9ff 100644 --- a/diff.c +++ b/diff.c @@ -839,10 +839,9 @@ static int scale_linear(int it, int width, int max_change) } static void show_name(FILE *file, - const char *prefix, const char *name, int len, - const char *reset, const char *set) + const char *prefix, const char *name, int len) { - fprintf(file, " %s%s%-*s%s |", set, prefix, len, name, reset); + fprintf(file, " %s%-*s |", prefix, len, name); } static void show_graph(FILE *file, char ch, int cnt, const char *set, const char *reset) @@ -956,7 +955,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) } if (data->files[i]->is_binary) { - show_name(options->file, prefix, name, len, reset, set); + show_name(options->file, prefix, name, len); fprintf(options->file, " Bin "); fprintf(options->file, "%s%d%s", del_c, deleted, reset); fprintf(options->file, " -> "); @@ -966,7 +965,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) continue; } else if (data->files[i]->is_unmerged) { - show_name(options->file, prefix, name, len, reset, set); + show_name(options->file, prefix, name, len); fprintf(options->file, " Unmerged\n"); continue; } @@ -988,7 +987,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) add = scale_linear(add, width, max_change); del = scale_linear(del, width, max_change); } - show_name(options->file, prefix, name, len, reset, set); + show_name(options->file, prefix, name, len); fprintf(options->file, "%5d%s", added + deleted, added + deleted ? " " : ""); show_graph(options->file, '+', add, add_c, reset); @@ -996,8 +995,8 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) fprintf(options->file, "\n"); } fprintf(options->file, - "%s %d files changed, %d insertions(+), %d deletions(-)%s\n", - set, total_files, adds, dels, reset); + " %d files changed, %d insertions(+), %d deletions(-)\n", + total_files, adds, dels); } static void show_shortstats(struct diffstat_t* data, struct diff_options *options) From 95110d75d972dfdd317829ae7feaf42d4f14ab25 Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@linux-foundation.org> Date: Sun, 26 Apr 2009 12:29:13 -0700 Subject: [PATCH 510/654] t4202: fix typo While I did a make -j64 test > ~/t.out to check my previous patch (in case some test actually tested 'trustctime' or something), I noticed this one. Somebody has speeling trouble: t4202-log.sh: line 345: test_expect_sucess: command not found Fixed thus. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t4202-log.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 67f983fea4..64502e2be7 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -342,7 +342,7 @@ cat > expect <<\EOF * initial EOF -test_expect_sucess 'log --graph with merge' ' +test_expect_success 'log --graph with merge' ' git log --graph --date-order --pretty=tformat:%s | sed "s/ *$//" >actual && test_cmp expect actual From 531e6daa038c68ca8fd5a8b042907a618fb7722d Mon Sep 17 00:00:00 2001 From: Johannes Sixt <j6t@kdbg.org> Date: Mon, 27 Apr 2009 09:44:58 +0200 Subject: [PATCH 511/654] prune-packed: advanced progress even for non-existing fan-out directories A progress indicator is used to count through the 256 object fan-out directories while unused object files are removed. (However, it becomes visible only if this process takes long enough.) Previously, display_progress() was only called if object files were actually removed. But if directories towards the end (fd/, fe/, ff/) did not exist, this could leave a strange line Removing duplicate objects: 99% (255/256), done. in the terminal instead of the expected "100% (256/256)". Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-prune-packed.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c index 2d5b2cd353..4942892e9f 100644 --- a/builtin-prune-packed.c +++ b/builtin-prune-packed.c @@ -55,6 +55,7 @@ void prune_packed_objects(int opts) for (i = 0; i < 256; i++) { DIR *d; + display_progress(progress, i + 1); sprintf(pathname + len, "%02x/", i); d = opendir(pathname); if (!d) From fe4a9c36a3905d5aefc9740ba1689d3000c2762e Mon Sep 17 00:00:00 2001 From: Mark Drago <markdrago@gmail.com> Date: Sun, 26 Apr 2009 22:36:48 -0400 Subject: [PATCH 512/654] Add semicolon to curly brace group in main Makefile This semicolon is technically required by POSIX shell and indeed causes a syntax error with e.g. bash-2.04.0. Cf. http://www.opengroup.org/onlinepubs/000095399/utilities/xcu_chap02.html#tag_02_09_04_01 Signed-off-by: Mark Drago <markdrago@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5c8e83a997..f006d2ccad 100644 --- a/Makefile +++ b/Makefile @@ -1557,7 +1557,7 @@ endif ln "$$execdir/git-add$X" "$$execdir/$$p" 2>/dev/null || \ ln -s "git-add$X" "$$execdir/$$p" 2>/dev/null || \ cp "$$execdir/git-add$X" "$$execdir/$$p" || exit; \ - done } && \ + done; } && \ ./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X" install-doc: From 9a695fbf388263794ccbd16a342f4e2f8c5d400d Mon Sep 17 00:00:00 2001 From: Patrick Welche <prlw1@cam.ac.uk> Date: Sun, 26 Apr 2009 14:49:00 +0100 Subject: [PATCH 513/654] NetBSD compilation fix Similar to other BSD variants, it needs USE_ST_TIMESPEC. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 1 + git-compat-util.h | 1 + 2 files changed, 2 insertions(+) diff --git a/Makefile b/Makefile index f006d2ccad..bb15c6b929 100644 --- a/Makefile +++ b/Makefile @@ -764,6 +764,7 @@ ifeq ($(uname_S),NetBSD) BASIC_CFLAGS += -I/usr/pkg/include BASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib THREADED_DELTA_SEARCH = YesPlease + USE_ST_TIMESPEC = YesPlease endif ifeq ($(uname_S),AIX) NO_STRCASESTR=YesPlease diff --git a/git-compat-util.h b/git-compat-util.h index 785aa31b46..1ac16bde5a 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -46,6 +46,7 @@ #define _ALL_SOURCE 1 #define _GNU_SOURCE 1 #define _BSD_SOURCE 1 +#define _NETBSD_SOURCE 1 #include <unistd.h> #include <stdio.h> From b9d622e711f0bf0280996bd79ec8509475ae80e5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Tue, 28 Apr 2009 00:12:31 +0200 Subject: [PATCH 514/654] t5701: do not get stuck in empty-push/ A test might happen to be the last one in the script, but other people later may want to add more tests after your test is done. Do not surprise them by going in a subdirectory to run a part of your test and never coming out of it. This fixes a162e78 in that respect. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t5701-clone-local.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh index f26b511c3e..19b5c0d552 100755 --- a/t/t5701-clone-local.sh +++ b/t/t5701-clone-local.sh @@ -138,8 +138,8 @@ test_expect_success 'clone empty repository, and then push should not segfault.' mkdir empty && (cd empty && git init) && git clone empty empty-clone && - cd empty-clone && - test_must_fail git push + (cd empty-clone && + test_must_fail git push) ' test_done From 7c8224b6a8c16c84938ad7c31cb98e55cb1e8cfd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <Johannes.Schindelin@gmx.de> Date: Mon, 27 Apr 2009 19:51:42 +0200 Subject: [PATCH 515/654] t3702: fix reliance on SHELL_PATH being '/bin/sh' Trying to be lazy and comparing files with fake-editor.sh to avoid having to provide another example text does not work well: the blob name changes when SHELL_PATH changes, and so does the 'index' line in the diff. Therefore provide a second example text. Noticed by Mike Ralphson. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t3702-add-edit.sh | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/t/t3702-add-edit.sh b/t/t3702-add-edit.sh index 72627863e5..4ee47cc9a8 100755 --- a/t/t3702-add-edit.sh +++ b/t/t3702-add-edit.sh @@ -21,6 +21,15 @@ who house by the whale-path, heard his mandate, gave him gifts: a good king he! EOF +cat > second-part << EOF +To him an heir was afterward born, +a son in his halls, whom heaven sent +to favor the folk, feeling their woe +that erst they had lacked an earl for leader +so long a while; the Lord endowed him, +the Wielder of Wonder, with world's renown. +EOF + test_expect_success 'setup' ' git add file && @@ -31,10 +40,10 @@ test_expect_success 'setup' ' cat > expected-patch << EOF diff --git a/file b/file -index b9834b5..0b8f197 100644 +index b9834b5..9020acb 100644 --- a/file +++ b/file -@@ -1,11 +1,3 @@ +@@ -1,11 +1,6 @@ -LO, praise of the prowess of people-kings -of spear-armed Danes, in days long sped, -we have heard, and what honor the athelings won! @@ -46,9 +55,12 @@ index b9834b5..0b8f197 100644 -till before him the folk, both far and near, -who house by the whale-path, heard his mandate, -gave him gifts: a good king he! -+#!$SHELL_PATH -+mv -f "\$1" orig-patch && -+mv -f patch "\$1" ++To him an heir was afterward born, ++a son in his halls, whom heaven sent ++to favor the folk, feeling their woe ++that erst they had lacked an earl for leader ++so long a while; the Lord endowed him, ++the Wielder of Wonder, with world's renown. EOF cat > patch << EOF @@ -97,9 +109,9 @@ chmod a+x fake-editor.sh test_expect_success 'add -e' ' - cp fake-editor.sh file && + cp second-part file && git add -e && - test_cmp fake-editor.sh file && + test_cmp second-part file && test_cmp orig-patch expected-patch && git diff --cached > out && test_cmp out expected From 62f780dcc6a5f1a38d9f8e25234a91d16ab8fbbd Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Mon, 27 Apr 2009 23:34:24 -0400 Subject: [PATCH 516/654] Makefile: fix NO_PERL bug with gitweb When the user has defined NO_PERL, we want to skip building gitweb entirely. However, the conditional to add gitweb/gitweb.cgi to OTHER_PROGRAMS was evaluated before we actually parsed the user's config.mak. This meant that "make NO_PERL=NoThanks" worked fine, but putting "NO_PERL=NoThanks" into your config.mak broke the build (it wanted gitweb.cgi to satisfy "all", but the rule to build it was conditionally ignored, so it complained). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile b/Makefile index bb15c6b929..8b220ada7c 100644 --- a/Makefile +++ b/Makefile @@ -365,9 +365,6 @@ ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) # what 'all' will build but not install in gitexecdir OTHER_PROGRAMS = git$X -ifndef NO_PERL -OTHER_PROGRAMS += gitweb/gitweb.cgi -endif # Set paths to tools early so that they can be used for version tests. ifndef SHELL_PATH @@ -1280,6 +1277,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl chmod +x $@+ && \ mv $@+ $@ +OTHER_PROGRAMS += gitweb/gitweb.cgi gitweb/gitweb.cgi: gitweb/gitweb.perl $(QUIET_GEN)$(RM) $@ $@+ && \ sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \ From 47afed5dc17faf10fde18789b17cf6ebff829cf4 Mon Sep 17 00:00:00 2001 From: Sam Vilain <sam@vilain.net> Date: Tue, 28 Apr 2009 02:38:47 +1200 Subject: [PATCH 517/654] SubmittingPatches: itemize and reflect upon well written changes The SubmittingPatches file was trimmed down from a somewhat overwhelming set of requirements from the Linux Kernel equivalent; however perhaps a little of it can be returned without making the text too long. Signed-off-by: Sam Vilain <sam@vilain.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/SubmittingPatches | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 8d818a2160..76fc84d878 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -6,9 +6,13 @@ Checklist (and a short version for the impatient): - check for unnecessary whitespace with "git diff --check" before committing - do not check in commented out code or unneeded files - - provide a meaningful commit message - the first line of the commit message should be a short description and should skip the full stop + - the body should provide a meaningful commit message, which: + - uses the imperative, present tense: "change", + not "changed" or "changes". + - includes motivation for the change, and contrasts + its implementation with previous behaviour - if you want your work included in git.git, add a "Signed-off-by: Your Name <you@example.com>" line to the commit message (or just use the option "-s" when @@ -62,6 +66,14 @@ Describe the technical detail of the change(s). If your description starts to get too long, that's a sign that you probably need to split up your commit to finer grained pieces. +That being said, patches which plainly describe the things that +help reviewers check the patch, and future maintainers understand +the code, are the most beautiful patches. Descriptions that summarise +the point in the subject well, and describe the motivation for the +change, the approach taken by the change, and if relevant how this +differs substantially from the prior version, can be found on Usenet +archives back into the late 80's. Consider it like good Netiquette, +but for code. Oh, another thing. I am picky about whitespaces. Make sure your changes do not trigger errors with the sample pre-commit hook shipped From d4b190271549c0b3f036884092b973696a34ea3a Mon Sep 17 00:00:00 2001 From: Eric Blake <ebb9@byu.net> Date: Tue, 28 Apr 2009 06:28:31 -0600 Subject: [PATCH 518/654] Makefile: installing git in cygwin 1.7.0 On platforms with $X, make removes any leftover scripts 'a' from earlier builds if a new binary 'a.exe' is now built. However, on cygwin 1.7.0, 'git' and 'git.exe' now consistently name the same file. Test for file equality before attempting a remove, in order to avoid nuking just-built binaries. This repeats commit 0d768f7 for the installation destdir. Signed-off-by: Eric Blake <ebb9@byu.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8b220ada7c..6b80f81d60 100644 --- a/Makefile +++ b/Makefile @@ -1544,7 +1544,7 @@ ifndef NO_TCLTK $(MAKE) -C git-gui gitexecdir='$(gitexec_instdir_SQ)' install endif ifneq (,$X) - $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p';) + $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p' -ef '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p$X' || $(RM) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p';) endif bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \ execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \ From 26e47f25402ad51c6cfa1cd784a3431dd00deeb2 Mon Sep 17 00:00:00 2001 From: Eric Blake <ebb9@byu.net> Date: Tue, 28 Apr 2009 06:28:32 -0600 Subject: [PATCH 519/654] doc: consistently use ASCIIDOC_EXTRA For all uses of $(ASCIIDOC) in Documentation/Makefile, supply the same options via $(ASCIIDOC_EXTRA). Signed-off-by: Eric Blake <ebb9@byu.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/Makefile b/Documentation/Makefile index e18242a6d4..7a8037f586 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -240,7 +240,7 @@ $(MAN_HTML): %.html : %.txt mv $@+ $@ user-manual.xml: user-manual.txt user-manual.conf - $(QUIET_ASCIIDOC)$(ASCIIDOC) -b docbook -d book $< + $(QUIET_ASCIIDOC)$(ASCIIDOC) $(ASCIIDOC_EXTRA) -b docbook -d book $< technical/api-index.txt: technical/api-index-skel.txt \ technical/api-index.sh $(patsubst %,%.txt,$(API_DOCS)) @@ -293,13 +293,13 @@ howto-index.txt: howto-index.sh $(wildcard howto/*.txt) mv $@+ $@ $(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt - $(QUIET_ASCIIDOC)$(ASCIIDOC) -b xhtml11 $*.txt + $(QUIET_ASCIIDOC)$(ASCIIDOC) $(ASCIIDOC_EXTRA) -b xhtml11 $*.txt WEBDOC_DEST = /pub/software/scm/git/docs $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ - sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+ && \ + sed -e '1,/^$$/d' $< | $(ASCIIDOC) $(ASCIIDOC_EXTRA) -b xhtml11 - >$@+ && \ mv $@+ $@ install-webdoc : html From c736b4c83b929bdcb3fac2cc9e063258cc75cbe2 Mon Sep 17 00:00:00 2001 From: Alex Riesen <raa.lkml@gmail.com> Date: Wed, 29 Apr 2009 07:56:06 +0200 Subject: [PATCH 520/654] git-gui: Update Russian translation Also, the previous translations of the words 'tag' and 'merge' were changed. Added translation of the 'Tool' submenu. Thanks go to Alexander Gavrilov and Dmitry Potapov for proofreading and suggestions. Signed-off-by: Alex Riesen <raa.lkml@gmail.com> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- po/ru.po | 1418 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 998 insertions(+), 420 deletions(-) diff --git a/po/ru.po b/po/ru.po index 04df2aac26..0ffc4a418f 100644 --- a/po/ru.po +++ b/po/ru.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: git-gui\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2008-03-14 07:18+0100\n" +"POT-Creation-Date: 2008-12-08 08:31-0800\n" "PO-Revision-Date: 2007-10-22 22:30-0200\n" "Last-Translator: Alex Riesen <raa.lkml@gmail.com>\n" "Language-Team: Russian Translation <git@vger.kernel.org>\n" @@ -15,33 +15,33 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: git-gui.sh:41 git-gui.sh:634 git-gui.sh:648 git-gui.sh:661 git-gui.sh:744 -#: git-gui.sh:763 +#: git-gui.sh:41 git-gui.sh:737 git-gui.sh:751 git-gui.sh:764 git-gui.sh:847 +#: git-gui.sh:866 msgid "git-gui: fatal error" msgstr "git-gui: критическая ошибка" -#: git-gui.sh:593 +#: git-gui.sh:689 #, tcl-format msgid "Invalid font specified in %s:" msgstr "В %s установлен неверный шрифт:" -#: git-gui.sh:620 +#: git-gui.sh:723 msgid "Main Font" msgstr "Шрифт интерфейса" -#: git-gui.sh:621 +#: git-gui.sh:724 msgid "Diff/Console Font" msgstr "Шрифт консоли и изменений (diff)" -#: git-gui.sh:635 +#: git-gui.sh:738 msgid "Cannot find git in PATH." msgstr "git не найден в PATH." -#: git-gui.sh:662 +#: git-gui.sh:765 msgid "Cannot parse Git version string:" msgstr "Невозможно распознать строку версии Git: " -#: git-gui.sh:680 +#: git-gui.sh:783 #, tcl-format msgid "" "Git version cannot be determined.\n" @@ -53,384 +53,451 @@ msgid "" "Assume '%s' is version 1.5.0?\n" msgstr "" "Невозможно определить версию Git\n" +"\n" "%s указывает на версию '%s'.\n" "\n" "для %s требуется версия Git, начиная с 1.5.0\n" "\n" "Принять '%s' как версию 1.5.0?\n" -#: git-gui.sh:918 +#: git-gui.sh:1062 msgid "Git directory not found:" msgstr "Каталог Git не найден:" -#: git-gui.sh:925 +#: git-gui.sh:1069 msgid "Cannot move to top of working directory:" msgstr "Невозможно перейти к корню рабочего каталога репозитория: " -#: git-gui.sh:932 +#: git-gui.sh:1076 msgid "Cannot use funny .git directory:" -msgstr "Каталог.git испорчен: " +msgstr "Каталог .git испорчен: " -#: git-gui.sh:937 +#: git-gui.sh:1081 msgid "No working directory" msgstr "Отсутствует рабочий каталог" -#: git-gui.sh:1084 lib/checkout_op.tcl:283 +#: git-gui.sh:1247 lib/checkout_op.tcl:305 msgid "Refreshing file status..." msgstr "Обновление информации о состоянии файлов..." -#: git-gui.sh:1149 +#: git-gui.sh:1303 msgid "Scanning for modified files ..." msgstr "Поиск измененных файлов..." -#: git-gui.sh:1324 lib/browser.tcl:246 +#: git-gui.sh:1367 +msgid "Calling prepare-commit-msg hook..." +msgstr "Вызов программы поддержки репозитория prepare-commit-msg..." + +#: git-gui.sh:1384 +msgid "Commit declined by prepare-commit-msg hook." +msgstr "Сохранение прервано программой поддержки репозитория prepare-commit-msg" + +#: git-gui.sh:1542 lib/browser.tcl:246 msgid "Ready." msgstr "Готово." -#: git-gui.sh:1590 +#: git-gui.sh:1819 msgid "Unmodified" msgstr "Не изменено" -#: git-gui.sh:1592 +#: git-gui.sh:1821 msgid "Modified, not staged" msgstr "Изменено, не подготовлено" -#: git-gui.sh:1593 git-gui.sh:1598 +#: git-gui.sh:1822 git-gui.sh:1830 msgid "Staged for commit" msgstr "Подготовлено для сохранения" -#: git-gui.sh:1594 git-gui.sh:1599 +#: git-gui.sh:1823 git-gui.sh:1831 msgid "Portions staged for commit" msgstr "Части, подготовленные для сохранения" -#: git-gui.sh:1595 git-gui.sh:1600 +#: git-gui.sh:1824 git-gui.sh:1832 msgid "Staged for commit, missing" msgstr "Подготовлено для сохранения, отсутствует" -#: git-gui.sh:1597 +#: git-gui.sh:1826 +msgid "File type changed, not staged" +msgstr "Тип файла изменён, не подготовлено" + +#: git-gui.sh:1827 +msgid "File type changed, staged" +msgstr "Тип файла изменён, подготовлено" + +#: git-gui.sh:1829 msgid "Untracked, not staged" msgstr "Не отслеживается, не подготовлено" -#: git-gui.sh:1602 +#: git-gui.sh:1834 msgid "Missing" msgstr "Отсутствует" -#: git-gui.sh:1603 +#: git-gui.sh:1835 msgid "Staged for removal" msgstr "Подготовлено для удаления" -#: git-gui.sh:1604 +#: git-gui.sh:1836 msgid "Staged for removal, still present" msgstr "Подготовлено для удаления, еще не удалено" -#: git-gui.sh:1606 git-gui.sh:1607 git-gui.sh:1608 git-gui.sh:1609 +#: git-gui.sh:1838 git-gui.sh:1839 git-gui.sh:1840 git-gui.sh:1841 +#: git-gui.sh:1842 git-gui.sh:1843 msgid "Requires merge resolution" -msgstr "Требуется разрешение конфликта при объединении" +msgstr "Требуется разрешение конфликта при слиянии" -#: git-gui.sh:1644 +#: git-gui.sh:1878 msgid "Starting gitk... please wait..." -msgstr "Запускается gitk... пожалуйста, ждите..." +msgstr "Запускается gitk... Подождите, пожалуйста..." -#: git-gui.sh:1653 -#, tcl-format -msgid "" -"Unable to start gitk:\n" -"\n" -"%s does not exist" -msgstr "" -"Не удалось запустить gitk:\n" -"\n" -"%s не существует" +#: git-gui.sh:1887 +msgid "Couldn't find gitk in PATH" +msgstr "gitk не найден в PATH." -#: git-gui.sh:1860 lib/choose_repository.tcl:36 +#: git-gui.sh:2280 lib/choose_repository.tcl:36 msgid "Repository" msgstr "Репозиторий" -#: git-gui.sh:1861 +#: git-gui.sh:2281 msgid "Edit" msgstr "Редактировать" -#: git-gui.sh:1863 lib/choose_rev.tcl:561 +#: git-gui.sh:2283 lib/choose_rev.tcl:561 msgid "Branch" msgstr "Ветвь" -#: git-gui.sh:1866 lib/choose_rev.tcl:548 +#: git-gui.sh:2286 lib/choose_rev.tcl:548 msgid "Commit@@noun" msgstr "Состояние" -#: git-gui.sh:1869 lib/merge.tcl:120 lib/merge.tcl:149 lib/merge.tcl:167 +#: git-gui.sh:2289 lib/merge.tcl:121 lib/merge.tcl:150 lib/merge.tcl:168 msgid "Merge" -msgstr "Объединить" +msgstr "Слияние" -#: git-gui.sh:1870 lib/choose_rev.tcl:557 +#: git-gui.sh:2290 lib/choose_rev.tcl:557 msgid "Remote" msgstr "Внешние репозитории" -#: git-gui.sh:1879 +#: git-gui.sh:2293 +msgid "Tools" +msgstr "Вспомогательные операции" + +#: git-gui.sh:2302 +msgid "Explore Working Copy" +msgstr "Просмотр рабочего каталога" + +#: git-gui.sh:2307 msgid "Browse Current Branch's Files" msgstr "Просмотреть файлы текущей ветви" -#: git-gui.sh:1883 +#: git-gui.sh:2311 msgid "Browse Branch Files..." msgstr "Показать файлы ветви..." -#: git-gui.sh:1888 +#: git-gui.sh:2316 msgid "Visualize Current Branch's History" -msgstr "История текущей ветви наглядно" +msgstr "Показать историю текущей ветви" -#: git-gui.sh:1892 +#: git-gui.sh:2320 msgid "Visualize All Branch History" -msgstr "История всех ветвей наглядно" +msgstr "Показать историю всех ветвей" -#: git-gui.sh:1899 +#: git-gui.sh:2327 #, tcl-format msgid "Browse %s's Files" msgstr "Показать файлы ветви %s" -#: git-gui.sh:1901 +#: git-gui.sh:2329 #, tcl-format msgid "Visualize %s's History" -msgstr "История ветви %s наглядно" +msgstr "Показать историю ветви %s" -#: git-gui.sh:1906 lib/database.tcl:27 lib/database.tcl:67 +#: git-gui.sh:2334 lib/database.tcl:27 lib/database.tcl:67 msgid "Database Statistics" msgstr "Статистика базы данных" -#: git-gui.sh:1909 lib/database.tcl:34 +#: git-gui.sh:2337 lib/database.tcl:34 msgid "Compress Database" msgstr "Сжать базу данных" -#: git-gui.sh:1912 +#: git-gui.sh:2340 msgid "Verify Database" msgstr "Проверить базу данных" -#: git-gui.sh:1919 git-gui.sh:1923 git-gui.sh:1927 lib/shortcut.tcl:7 +#: git-gui.sh:2347 git-gui.sh:2351 git-gui.sh:2355 lib/shortcut.tcl:7 #: lib/shortcut.tcl:39 lib/shortcut.tcl:71 msgid "Create Desktop Icon" msgstr "Создать ярлык на рабочем столе" -#: git-gui.sh:1932 lib/choose_repository.tcl:177 lib/choose_repository.tcl:185 +#: git-gui.sh:2363 lib/choose_repository.tcl:183 lib/choose_repository.tcl:191 msgid "Quit" msgstr "Выход" -#: git-gui.sh:1939 +#: git-gui.sh:2371 msgid "Undo" msgstr "Отменить" -#: git-gui.sh:1942 +#: git-gui.sh:2374 msgid "Redo" msgstr "Повторить" -#: git-gui.sh:1946 git-gui.sh:2443 +#: git-gui.sh:2378 git-gui.sh:2937 msgid "Cut" msgstr "Вырезать" -#: git-gui.sh:1949 git-gui.sh:2446 git-gui.sh:2520 git-gui.sh:2614 +#: git-gui.sh:2381 git-gui.sh:2940 git-gui.sh:3014 git-gui.sh:3096 #: lib/console.tcl:69 msgid "Copy" msgstr "Копировать" -#: git-gui.sh:1952 git-gui.sh:2449 +#: git-gui.sh:2384 git-gui.sh:2943 msgid "Paste" msgstr "Вставить" -#: git-gui.sh:1955 git-gui.sh:2452 lib/branch_delete.tcl:26 +#: git-gui.sh:2387 git-gui.sh:2946 lib/branch_delete.tcl:26 #: lib/remote_branch_delete.tcl:38 msgid "Delete" msgstr "Удалить" -#: git-gui.sh:1959 git-gui.sh:2456 git-gui.sh:2618 lib/console.tcl:71 +#: git-gui.sh:2391 git-gui.sh:2950 git-gui.sh:3100 lib/console.tcl:71 msgid "Select All" msgstr "Выделить все" -#: git-gui.sh:1968 +#: git-gui.sh:2400 msgid "Create..." msgstr "Создать..." -#: git-gui.sh:1974 +#: git-gui.sh:2406 msgid "Checkout..." msgstr "Перейти..." -#: git-gui.sh:1980 +#: git-gui.sh:2412 msgid "Rename..." msgstr "Переименовать..." -#: git-gui.sh:1985 git-gui.sh:2085 +#: git-gui.sh:2417 msgid "Delete..." msgstr "Удалить..." -#: git-gui.sh:1990 +#: git-gui.sh:2422 msgid "Reset..." msgstr "Сбросить..." -#: git-gui.sh:2002 git-gui.sh:2389 -msgid "New Commit" -msgstr "Новое состояние" +#: git-gui.sh:2432 +msgid "Done" +msgstr "Завершено" -#: git-gui.sh:2010 git-gui.sh:2396 -msgid "Amend Last Commit" -msgstr "Исправить последнее состояние" - -#: git-gui.sh:2019 git-gui.sh:2356 lib/remote_branch_delete.tcl:99 -msgid "Rescan" -msgstr "Перечитать" - -#: git-gui.sh:2025 -msgid "Stage To Commit" -msgstr "Подготовить для сохранения" - -#: git-gui.sh:2031 -msgid "Stage Changed Files To Commit" -msgstr "Подготовить измененные файлы для сохранения" - -#: git-gui.sh:2037 -msgid "Unstage From Commit" -msgstr "Убрать из подготовленного" - -#: git-gui.sh:2042 lib/index.tcl:395 -msgid "Revert Changes" -msgstr "Отменить изменения" - -#: git-gui.sh:2049 git-gui.sh:2368 git-gui.sh:2467 -msgid "Sign Off" -msgstr "Подписать" - -#: git-gui.sh:2053 git-gui.sh:2372 +#: git-gui.sh:2434 msgid "Commit@@verb" msgstr "Сохранить" -#: git-gui.sh:2064 +#: git-gui.sh:2443 git-gui.sh:2878 +msgid "New Commit" +msgstr "Новое состояние" + +#: git-gui.sh:2451 git-gui.sh:2885 +msgid "Amend Last Commit" +msgstr "Исправить последнее состояние" + +#: git-gui.sh:2461 git-gui.sh:2839 lib/remote_branch_delete.tcl:99 +msgid "Rescan" +msgstr "Перечитать" + +#: git-gui.sh:2467 +msgid "Stage To Commit" +msgstr "Подготовить для сохранения" + +#: git-gui.sh:2473 +msgid "Stage Changed Files To Commit" +msgstr "Подготовить измененные файлы для сохранения" + +#: git-gui.sh:2479 +msgid "Unstage From Commit" +msgstr "Убрать из подготовленного" + +#: git-gui.sh:2484 lib/index.tcl:410 +msgid "Revert Changes" +msgstr "Отменить изменения" + +#: git-gui.sh:2491 git-gui.sh:3083 +msgid "Show Less Context" +msgstr "Меньше контекста" + +#: git-gui.sh:2495 git-gui.sh:3087 +msgid "Show More Context" +msgstr "Больше контекста" + +#: git-gui.sh:2502 git-gui.sh:2852 git-gui.sh:2961 +msgid "Sign Off" +msgstr "Вставить Signed-off-by" + +#: git-gui.sh:2518 msgid "Local Merge..." -msgstr "Локальное объединение..." +msgstr "Локальное слияние..." -#: git-gui.sh:2069 +#: git-gui.sh:2523 msgid "Abort Merge..." -msgstr "Прервать объединение..." +msgstr "Прервать слияние..." -#: git-gui.sh:2081 +#: git-gui.sh:2535 git-gui.sh:2575 +msgid "Add..." +msgstr "Добавить..." + +#: git-gui.sh:2539 msgid "Push..." msgstr "Отправить..." -#: git-gui.sh:2092 lib/choose_repository.tcl:41 -msgid "Apple" -msgstr "" +#: git-gui.sh:2543 +msgid "Delete Branch..." +msgstr "Удалить ветвь..." -#: git-gui.sh:2095 git-gui.sh:2117 lib/about.tcl:14 -#: lib/choose_repository.tcl:44 lib/choose_repository.tcl:50 +#: git-gui.sh:2553 git-gui.sh:2589 lib/about.tcl:14 +#: lib/choose_repository.tcl:44 lib/choose_repository.tcl:53 #, tcl-format msgid "About %s" msgstr "О %s" -#: git-gui.sh:2099 +#: git-gui.sh:2557 msgid "Preferences..." msgstr "Настройки..." -#: git-gui.sh:2107 git-gui.sh:2639 +#: git-gui.sh:2565 git-gui.sh:3129 msgid "Options..." msgstr "Настройки..." -#: git-gui.sh:2113 lib/choose_repository.tcl:47 +#: git-gui.sh:2576 +msgid "Remove..." +msgstr "Удалить..." + +#: git-gui.sh:2585 lib/choose_repository.tcl:50 msgid "Help" msgstr "Помощь" -#: git-gui.sh:2154 +#: git-gui.sh:2611 msgid "Online Documentation" msgstr "Документация в интернете" -#: git-gui.sh:2238 +#: git-gui.sh:2614 lib/choose_repository.tcl:47 lib/choose_repository.tcl:56 +msgid "Show SSH Key" +msgstr "Показать ключ SSH" + +#: git-gui.sh:2721 #, tcl-format msgid "fatal: cannot stat path %s: No such file or directory" msgstr "критическая ошибка: %s: нет такого файла или каталога" -#: git-gui.sh:2271 +#: git-gui.sh:2754 msgid "Current Branch:" msgstr "Текущая ветвь:" -#: git-gui.sh:2292 +#: git-gui.sh:2775 msgid "Staged Changes (Will Commit)" msgstr "Подготовлено (будет сохранено)" -#: git-gui.sh:2312 +#: git-gui.sh:2795 msgid "Unstaged Changes" msgstr "Изменено (не будет сохранено)" -#: git-gui.sh:2362 +#: git-gui.sh:2845 msgid "Stage Changed" msgstr "Подготовить все" -#: git-gui.sh:2378 lib/transport.tcl:93 lib/transport.tcl:182 +#: git-gui.sh:2864 lib/transport.tcl:104 lib/transport.tcl:193 msgid "Push" msgstr "Отправить" -#: git-gui.sh:2408 +#: git-gui.sh:2899 msgid "Initial Commit Message:" msgstr "Комментарий к первому состоянию:" -#: git-gui.sh:2409 +#: git-gui.sh:2900 msgid "Amended Commit Message:" msgstr "Комментарий к исправленному состоянию:" -#: git-gui.sh:2410 +#: git-gui.sh:2901 msgid "Amended Initial Commit Message:" msgstr "Комментарий к исправленному первоначальному состоянию:" -#: git-gui.sh:2411 +#: git-gui.sh:2902 msgid "Amended Merge Commit Message:" -msgstr "Комментарий к исправленному объединению:" +msgstr "Комментарий к исправленному слиянию:" -#: git-gui.sh:2412 +#: git-gui.sh:2903 msgid "Merge Commit Message:" -msgstr "Комментарий к объединению:" +msgstr "Комментарий к слиянию:" -#: git-gui.sh:2413 +#: git-gui.sh:2904 msgid "Commit Message:" msgstr "Комментарий к состоянию:" -#: git-gui.sh:2459 git-gui.sh:2622 lib/console.tcl:73 +#: git-gui.sh:2953 git-gui.sh:3104 lib/console.tcl:73 msgid "Copy All" msgstr "Копировать все" -#: git-gui.sh:2483 lib/blame.tcl:107 +#: git-gui.sh:2977 lib/blame.tcl:104 msgid "File:" msgstr "Файл:" -#: git-gui.sh:2589 -msgid "Apply/Reverse Hunk" -msgstr "Применить/Убрать изменение" - -#: git-gui.sh:2595 -msgid "Show Less Context" -msgstr "Меньше контекста" - -#: git-gui.sh:2602 -msgid "Show More Context" -msgstr "Больше контекста" - -#: git-gui.sh:2610 +#: git-gui.sh:3092 msgid "Refresh" msgstr "Обновить" -#: git-gui.sh:2631 +#: git-gui.sh:3113 msgid "Decrease Font Size" msgstr "Уменьшить размер шрифта" -#: git-gui.sh:2635 +#: git-gui.sh:3117 msgid "Increase Font Size" msgstr "Увеличить размер шрифта" -#: git-gui.sh:2646 +#: git-gui.sh:3125 lib/blame.tcl:281 +msgid "Encoding" +msgstr "Кодировка" + +#: git-gui.sh:3136 +msgid "Apply/Reverse Hunk" +msgstr "Применить/Убрать изменение" + +#: git-gui.sh:3141 +msgid "Apply/Reverse Line" +msgstr "Применить/Убрать строку" + +#: git-gui.sh:3151 +msgid "Run Merge Tool" +msgstr "Запустить программу слияния" + +#: git-gui.sh:3156 +msgid "Use Remote Version" +msgstr "Взять внешнюю версию" + +#: git-gui.sh:3160 +msgid "Use Local Version" +msgstr "Взять локальную версию" + +#: git-gui.sh:3164 +msgid "Revert To Base" +msgstr "Отменить изменения" + +#: git-gui.sh:3183 msgid "Unstage Hunk From Commit" msgstr "Не сохранять часть" -#: git-gui.sh:2648 +#: git-gui.sh:3184 +msgid "Unstage Line From Commit" +msgstr "Убрать строку из подготовленного" + +#: git-gui.sh:3186 msgid "Stage Hunk For Commit" msgstr "Подготовить часть для сохранения" -#: git-gui.sh:2667 +#: git-gui.sh:3187 +msgid "Stage Line For Commit" +msgstr "Подготовить строку для сохранения" + +#: git-gui.sh:3210 msgid "Initializing..." msgstr "Инициализация..." -#: git-gui.sh:2762 +#: git-gui.sh:3315 #, tcl-format msgid "" "Possible environment issues exist.\n" @@ -447,7 +514,7 @@ msgstr "" "запущенными из %s\n" "\n" -#: git-gui.sh:2792 +#: git-gui.sh:3345 msgid "" "\n" "This is due to a known issue with the\n" @@ -457,7 +524,7 @@ msgstr "" "Это известная проблема с Tcl,\n" "распространяемым Cygwin." -#: git-gui.sh:2797 +#: git-gui.sh:3350 #, tcl-format msgid "" "\n" @@ -478,64 +545,108 @@ msgstr "" msgid "git-gui - a graphical user interface for Git." msgstr "git-gui - графический пользовательский интерфейс к Git." -#: lib/blame.tcl:77 +#: lib/blame.tcl:72 msgid "File Viewer" msgstr "Просмотр файла" -#: lib/blame.tcl:81 +#: lib/blame.tcl:78 msgid "Commit:" msgstr "Сохраненное состояние:" -#: lib/blame.tcl:264 +#: lib/blame.tcl:271 msgid "Copy Commit" msgstr "Скопировать SHA-1" -#: lib/blame.tcl:384 +#: lib/blame.tcl:275 +msgid "Find Text..." +msgstr "Найти текст..." + +#: lib/blame.tcl:284 +msgid "Do Full Copy Detection" +msgstr "Провести полный поиск копий" + +#: lib/blame.tcl:288 +msgid "Show History Context" +msgstr "Показать исторический контекст" + +#: lib/blame.tcl:291 +msgid "Blame Parent Commit" +msgstr "Рассмотреть состояние предка" + +#: lib/blame.tcl:450 #, tcl-format msgid "Reading %s..." msgstr "Чтение %s..." -#: lib/blame.tcl:488 +#: lib/blame.tcl:557 msgid "Loading copy/move tracking annotations..." msgstr "Загрузка аннотации копирований/переименований..." -#: lib/blame.tcl:508 +#: lib/blame.tcl:577 msgid "lines annotated" msgstr "строк прокомментировано" -#: lib/blame.tcl:689 +#: lib/blame.tcl:769 msgid "Loading original location annotations..." msgstr "Загрузка аннотаций первоначального положения объекта..." -#: lib/blame.tcl:692 +#: lib/blame.tcl:772 msgid "Annotation complete." msgstr "Аннотация завершена." -#: lib/blame.tcl:746 +#: lib/blame.tcl:802 +msgid "Busy" +msgstr "Занят" + +#: lib/blame.tcl:803 +msgid "Annotation process is already running." +msgstr "Аннотация уже запущена" + +#: lib/blame.tcl:842 +msgid "Running thorough copy detection..." +msgstr "Выполнение полного поиска копий..." + +#: lib/blame.tcl:910 msgid "Loading annotation..." msgstr "Загрузка аннотации..." -#: lib/blame.tcl:802 +#: lib/blame.tcl:963 msgid "Author:" msgstr "Автор:" -#: lib/blame.tcl:806 +#: lib/blame.tcl:967 msgid "Committer:" msgstr "Сохранил:" -#: lib/blame.tcl:811 +#: lib/blame.tcl:972 msgid "Original File:" msgstr "Исходный файл:" -#: lib/blame.tcl:925 +#: lib/blame.tcl:1020 +msgid "Cannot find HEAD commit:" +msgstr "Невозможно найти текущее состояние:" + +#: lib/blame.tcl:1075 +msgid "Cannot find parent commit:" +msgstr "Невозможно найти состояние предка:" + +#: lib/blame.tcl:1090 +msgid "Unable to display parent" +msgstr "Не могу показать предка" + +#: lib/blame.tcl:1091 lib/diff.tcl:297 +msgid "Error loading diff:" +msgstr "Ошибка загрузки изменений:" + +#: lib/blame.tcl:1231 msgid "Originally By:" msgstr "Источник:" -#: lib/blame.tcl:931 +#: lib/blame.tcl:1237 msgid "In File:" msgstr "Файл:" -#: lib/blame.tcl:936 +#: lib/blame.tcl:1242 msgid "Copied Or Moved Here By:" msgstr "Скопировано/перемещено в:" @@ -549,16 +660,18 @@ msgstr "Перейти" #: lib/branch_checkout.tcl:27 lib/branch_create.tcl:35 #: lib/branch_delete.tcl:32 lib/branch_rename.tcl:30 lib/browser.tcl:282 -#: lib/checkout_op.tcl:522 lib/choose_font.tcl:43 lib/merge.tcl:171 -#: lib/option.tcl:103 lib/remote_branch_delete.tcl:42 lib/transport.tcl:97 +#: lib/checkout_op.tcl:544 lib/choose_font.tcl:43 lib/merge.tcl:172 +#: lib/option.tcl:125 lib/remote_add.tcl:32 lib/remote_branch_delete.tcl:42 +#: lib/tools_dlg.tcl:40 lib/tools_dlg.tcl:204 lib/tools_dlg.tcl:352 +#: lib/transport.tcl:108 msgid "Cancel" -msgstr "Отменить" +msgstr "Отмена" -#: lib/branch_checkout.tcl:32 lib/browser.tcl:287 +#: lib/branch_checkout.tcl:32 lib/browser.tcl:287 lib/tools_dlg.tcl:328 msgid "Revision" msgstr "Версия" -#: lib/branch_checkout.tcl:36 lib/branch_create.tcl:69 lib/option.tcl:242 +#: lib/branch_checkout.tcl:36 lib/branch_create.tcl:69 lib/option.tcl:280 msgid "Options" msgstr "Настройки" @@ -578,7 +691,7 @@ msgstr "Создание ветви" msgid "Create New Branch" msgstr "Создать новую ветвь" -#: lib/branch_create.tcl:31 lib/choose_repository.tcl:371 +#: lib/branch_create.tcl:31 lib/choose_repository.tcl:377 msgid "Create" msgstr "Создать" @@ -586,7 +699,7 @@ msgstr "Создать" msgid "Branch Name" msgstr "Название ветви" -#: lib/branch_create.tcl:43 +#: lib/branch_create.tcl:43 lib/remote_add.tcl:39 lib/tools_dlg.tcl:50 msgid "Name:" msgstr "Название:" @@ -610,7 +723,7 @@ msgstr "Нет" msgid "Fast Forward Only" msgstr "Только Fast Forward" -#: lib/branch_create.tcl:85 lib/checkout_op.tcl:514 +#: lib/branch_create.tcl:85 lib/checkout_op.tcl:536 msgid "Reset" msgstr "Сброс" @@ -650,16 +763,16 @@ msgstr "Локальные ветви" #: lib/branch_delete.tcl:52 msgid "Delete Only If Merged Into" -msgstr "Удалить только в случае, если было объединение с" +msgstr "Удалить только в случае, если было слияние с" #: lib/branch_delete.tcl:54 msgid "Always (Do not perform merge test.)" -msgstr "Всегда (не выполнять проверку на объединение)" +msgstr "Всегда (не выполнять проверку на слияние)" #: lib/branch_delete.tcl:103 #, tcl-format msgid "The following branches are not completely merged into %s:" -msgstr "Следующие ветви объединены с %s не полностью:" +msgstr "Ветви, которые не полностью сливаются с %s:" #: lib/branch_delete.tcl:141 #, tcl-format @@ -690,7 +803,7 @@ msgstr "Новое название:" msgid "Please select a branch to rename." msgstr "Укажите ветвь для переименования." -#: lib/branch_rename.tcl:96 lib/checkout_op.tcl:179 +#: lib/branch_rename.tcl:96 lib/checkout_op.tcl:201 #, tcl-format msgid "Branch '%s' already exists." msgstr "Ветвь '%s' уже существует." @@ -721,32 +834,38 @@ msgstr "[На уровень выше]" msgid "Browse Branch Files" msgstr "Показать файлы ветви" -#: lib/browser.tcl:278 lib/choose_repository.tcl:387 -#: lib/choose_repository.tcl:474 lib/choose_repository.tcl:484 -#: lib/choose_repository.tcl:987 +#: lib/browser.tcl:278 lib/choose_repository.tcl:394 +#: lib/choose_repository.tcl:480 lib/choose_repository.tcl:491 +#: lib/choose_repository.tcl:995 msgid "Browse" msgstr "Показать" -#: lib/checkout_op.tcl:79 +#: lib/checkout_op.tcl:84 #, tcl-format msgid "Fetching %s from %s" msgstr "Получение %s из %s " -#: lib/checkout_op.tcl:127 +#: lib/checkout_op.tcl:132 #, tcl-format msgid "fatal: Cannot resolve %s" msgstr "критическая ошибка: невозможно разрешить %s" -#: lib/checkout_op.tcl:140 lib/console.tcl:81 lib/database.tcl:31 +#: lib/checkout_op.tcl:145 lib/console.tcl:81 lib/database.tcl:31 +#: lib/sshkey.tcl:53 msgid "Close" msgstr "Закрыть" -#: lib/checkout_op.tcl:169 +#: lib/checkout_op.tcl:174 #, tcl-format msgid "Branch '%s' does not exist." msgstr "Ветвь '%s' не существует " -#: lib/checkout_op.tcl:206 +#: lib/checkout_op.tcl:193 +#, tcl-format +msgid "Failed to configure simplified git-pull for '%s'." +msgstr "Ошибка создания упрощённой конфигурации git pull для '%s'." + +#: lib/checkout_op.tcl:228 #, tcl-format msgid "" "Branch '%s' already exists.\n" @@ -757,23 +876,23 @@ msgstr "" "Ветвь '%s' уже существует.\n" "\n" "Она не может быть прокручена(fast-forward) к %s.\n" -"Требуется объединение." +"Требуется слияние." -#: lib/checkout_op.tcl:220 +#: lib/checkout_op.tcl:242 #, tcl-format msgid "Merge strategy '%s' not supported." -msgstr "Стратегия объединения '%s' не поддерживается." +msgstr "Неизвестная стратегия слияния: '%s'." -#: lib/checkout_op.tcl:239 +#: lib/checkout_op.tcl:261 #, tcl-format msgid "Failed to update '%s'." msgstr "Не удалось обновить '%s'." -#: lib/checkout_op.tcl:251 +#: lib/checkout_op.tcl:273 msgid "Staging area (index) is already locked." msgstr "Рабочая область заблокирована другим процессом." -#: lib/checkout_op.tcl:266 +#: lib/checkout_op.tcl:288 msgid "" "Last scanned state does not match repository state.\n" "\n" @@ -789,30 +908,30 @@ msgstr "" "\n" "Это будет сделано сейчас автоматически.\n" -#: lib/checkout_op.tcl:322 +#: lib/checkout_op.tcl:344 #, tcl-format msgid "Updating working directory to '%s'..." msgstr "Обновление рабочего каталога из '%s'..." -#: lib/checkout_op.tcl:323 +#: lib/checkout_op.tcl:345 msgid "files checked out" msgstr "файлы извлечены" -#: lib/checkout_op.tcl:353 +#: lib/checkout_op.tcl:375 #, tcl-format msgid "Aborted checkout of '%s' (file level merging is required)." -msgstr "Прерван переход на '%s' (требуется объединение на уровне файлов)" +msgstr "Прерван переход на '%s' (требуется слияние содержания файлов)" -#: lib/checkout_op.tcl:354 +#: lib/checkout_op.tcl:376 msgid "File level merge required." -msgstr "Требуется объединение на уровне файлов." +msgstr "Требуется слияние содержания файлов." -#: lib/checkout_op.tcl:358 +#: lib/checkout_op.tcl:380 #, tcl-format msgid "Staying on branch '%s'." msgstr "Ветвь '%s' остается текущей." -#: lib/checkout_op.tcl:429 +#: lib/checkout_op.tcl:451 msgid "" "You are no longer on a local branch.\n" "\n" @@ -824,30 +943,30 @@ msgstr "" "Если вы хотите снова вернуться к какой-нибудь ветви, создайте ее сейчас, " "начиная с 'Текущего отсоединенного состояния'." -#: lib/checkout_op.tcl:446 lib/checkout_op.tcl:450 +#: lib/checkout_op.tcl:468 lib/checkout_op.tcl:472 #, tcl-format msgid "Checked out '%s'." msgstr "Ветвь '%s' сделана текущей." -#: lib/checkout_op.tcl:478 +#: lib/checkout_op.tcl:500 #, tcl-format msgid "Resetting '%s' to '%s' will lose the following commits:" msgstr "Сброс '%s' в '%s' приведет к потере следующих сохраненных состояний: " -#: lib/checkout_op.tcl:500 +#: lib/checkout_op.tcl:522 msgid "Recovering lost commits may not be easy." msgstr "Восстановить потерянные сохраненные состояния будет сложно." -#: lib/checkout_op.tcl:505 +#: lib/checkout_op.tcl:527 #, tcl-format msgid "Reset '%s'?" msgstr "Сбросить '%s'?" -#: lib/checkout_op.tcl:510 lib/merge.tcl:163 +#: lib/checkout_op.tcl:532 lib/merge.tcl:164 lib/tools_dlg.tcl:343 msgid "Visualize" msgstr "Наглядно" -#: lib/checkout_op.tcl:578 +#: lib/checkout_op.tcl:600 #, tcl-format msgid "" "Failed to set current branch.\n" @@ -890,224 +1009,228 @@ msgstr "" #: lib/choose_repository.tcl:28 msgid "Git Gui" -msgstr "" +msgstr "Git Gui" -#: lib/choose_repository.tcl:81 lib/choose_repository.tcl:376 +#: lib/choose_repository.tcl:87 lib/choose_repository.tcl:382 msgid "Create New Repository" msgstr "Создать новый репозиторий" -#: lib/choose_repository.tcl:87 +#: lib/choose_repository.tcl:93 msgid "New..." msgstr "Новый..." -#: lib/choose_repository.tcl:94 lib/choose_repository.tcl:460 +#: lib/choose_repository.tcl:100 lib/choose_repository.tcl:465 msgid "Clone Existing Repository" msgstr "Склонировать существующий репозиторий" -#: lib/choose_repository.tcl:100 +#: lib/choose_repository.tcl:106 msgid "Clone..." msgstr "Склонировать..." -#: lib/choose_repository.tcl:107 lib/choose_repository.tcl:976 +#: lib/choose_repository.tcl:113 lib/choose_repository.tcl:983 msgid "Open Existing Repository" msgstr "Выбрать существующий репозиторий" -#: lib/choose_repository.tcl:113 +#: lib/choose_repository.tcl:119 msgid "Open..." msgstr "Открыть..." -#: lib/choose_repository.tcl:126 +#: lib/choose_repository.tcl:132 msgid "Recent Repositories" msgstr "Недавние репозитории" -#: lib/choose_repository.tcl:132 +#: lib/choose_repository.tcl:138 msgid "Open Recent Repository:" msgstr "Открыть последний репозиторий" -#: lib/choose_repository.tcl:296 lib/choose_repository.tcl:303 -#: lib/choose_repository.tcl:310 +#: lib/choose_repository.tcl:302 lib/choose_repository.tcl:309 +#: lib/choose_repository.tcl:316 #, tcl-format msgid "Failed to create repository %s:" msgstr "Не удалось создать репозиторий %s:" -#: lib/choose_repository.tcl:381 lib/choose_repository.tcl:478 +#: lib/choose_repository.tcl:387 msgid "Directory:" msgstr "Каталог:" -#: lib/choose_repository.tcl:412 lib/choose_repository.tcl:537 -#: lib/choose_repository.tcl:1011 +#: lib/choose_repository.tcl:417 lib/choose_repository.tcl:544 +#: lib/choose_repository.tcl:1017 msgid "Git Repository" msgstr "Репозиторий" -#: lib/choose_repository.tcl:437 +#: lib/choose_repository.tcl:442 #, tcl-format msgid "Directory %s already exists." msgstr "Каталог '%s' уже существует." -#: lib/choose_repository.tcl:441 +#: lib/choose_repository.tcl:446 #, tcl-format msgid "File %s already exists." msgstr "Файл '%s' уже существует." -#: lib/choose_repository.tcl:455 +#: lib/choose_repository.tcl:460 msgid "Clone" msgstr "Склонировать" -#: lib/choose_repository.tcl:468 -msgid "URL:" -msgstr "Ссылка:" +#: lib/choose_repository.tcl:473 +msgid "Source Location:" +msgstr "Исходное положение:" -#: lib/choose_repository.tcl:489 +#: lib/choose_repository.tcl:484 +msgid "Target Directory:" +msgstr "Каталог назначения:" + +#: lib/choose_repository.tcl:496 msgid "Clone Type:" msgstr "Тип клона:" -#: lib/choose_repository.tcl:495 +#: lib/choose_repository.tcl:502 msgid "Standard (Fast, Semi-Redundant, Hardlinks)" msgstr "Стандартный (Быстрый, полуизбыточный, \"жесткие\" ссылки)" -#: lib/choose_repository.tcl:501 +#: lib/choose_repository.tcl:508 msgid "Full Copy (Slower, Redundant Backup)" msgstr "Полная копия (Медленный, создает резервную копию)" -#: lib/choose_repository.tcl:507 +#: lib/choose_repository.tcl:514 msgid "Shared (Fastest, Not Recommended, No Backup)" msgstr "Общий (Самый быстрый, не рекомендуется, без резервной копии)" -#: lib/choose_repository.tcl:543 lib/choose_repository.tcl:590 -#: lib/choose_repository.tcl:736 lib/choose_repository.tcl:806 -#: lib/choose_repository.tcl:1017 lib/choose_repository.tcl:1025 +#: lib/choose_repository.tcl:550 lib/choose_repository.tcl:597 +#: lib/choose_repository.tcl:743 lib/choose_repository.tcl:813 +#: lib/choose_repository.tcl:1023 lib/choose_repository.tcl:1031 #, tcl-format msgid "Not a Git repository: %s" msgstr "Каталог не является репозиторием: %s" -#: lib/choose_repository.tcl:579 +#: lib/choose_repository.tcl:586 msgid "Standard only available for local repository." msgstr "Стандартный клон возможен только для локального репозитория." -#: lib/choose_repository.tcl:583 +#: lib/choose_repository.tcl:590 msgid "Shared only available for local repository." msgstr "Общий клон возможен только для локального репозитория." -#: lib/choose_repository.tcl:604 +#: lib/choose_repository.tcl:611 #, tcl-format msgid "Location %s already exists." msgstr "Путь '%s' уже существует." -#: lib/choose_repository.tcl:615 +#: lib/choose_repository.tcl:622 msgid "Failed to configure origin" msgstr "Не могу сконфигурировать исходный репозиторий." -#: lib/choose_repository.tcl:627 +#: lib/choose_repository.tcl:634 msgid "Counting objects" msgstr "Считаю объекты" -#: lib/choose_repository.tcl:628 +#: lib/choose_repository.tcl:635 msgid "buckets" msgstr "" -#: lib/choose_repository.tcl:652 +#: lib/choose_repository.tcl:659 #, tcl-format msgid "Unable to copy objects/info/alternates: %s" msgstr "Не могу скопировать objects/info/alternates: %s" -#: lib/choose_repository.tcl:688 +#: lib/choose_repository.tcl:695 #, tcl-format msgid "Nothing to clone from %s." msgstr "Нечего клонировать с %s." -#: lib/choose_repository.tcl:690 lib/choose_repository.tcl:904 -#: lib/choose_repository.tcl:916 +#: lib/choose_repository.tcl:697 lib/choose_repository.tcl:911 +#: lib/choose_repository.tcl:923 msgid "The 'master' branch has not been initialized." msgstr "Не инициализирована ветвь 'master'." -#: lib/choose_repository.tcl:703 +#: lib/choose_repository.tcl:710 msgid "Hardlinks are unavailable. Falling back to copying." -msgstr "\"Жесткие ссылки\" не доступны. Буду использовать копирование." +msgstr "\"Жесткие ссылки\" недоступны. Будет использовано копирование." -#: lib/choose_repository.tcl:715 +#: lib/choose_repository.tcl:722 #, tcl-format msgid "Cloning from %s" msgstr "Клонирование %s" -#: lib/choose_repository.tcl:746 +#: lib/choose_repository.tcl:753 msgid "Copying objects" msgstr "Копирование objects" -#: lib/choose_repository.tcl:747 +#: lib/choose_repository.tcl:754 msgid "KiB" msgstr "КБ" -#: lib/choose_repository.tcl:771 +#: lib/choose_repository.tcl:778 #, tcl-format msgid "Unable to copy object: %s" msgstr "Не могу скопировать объект: %s" -#: lib/choose_repository.tcl:781 +#: lib/choose_repository.tcl:788 msgid "Linking objects" msgstr "Создание ссылок на objects" -#: lib/choose_repository.tcl:782 +#: lib/choose_repository.tcl:789 msgid "objects" msgstr "объекты" -#: lib/choose_repository.tcl:790 +#: lib/choose_repository.tcl:797 #, tcl-format msgid "Unable to hardlink object: %s" msgstr "Не могу \"жестко связать\" объект: %s" -#: lib/choose_repository.tcl:845 +#: lib/choose_repository.tcl:852 msgid "Cannot fetch branches and objects. See console output for details." msgstr "" "Не могу получить ветви и объекты. Дополнительная информация на консоли." -#: lib/choose_repository.tcl:856 +#: lib/choose_repository.tcl:863 msgid "Cannot fetch tags. See console output for details." msgstr "Не могу получить метки. Дополнительная информация на консоли." -#: lib/choose_repository.tcl:880 +#: lib/choose_repository.tcl:887 msgid "Cannot determine HEAD. See console output for details." msgstr "Не могу определить HEAD. Дополнительная информация на консоли." -#: lib/choose_repository.tcl:889 +#: lib/choose_repository.tcl:896 #, tcl-format msgid "Unable to cleanup %s" msgstr "Не могу очистить %s" -#: lib/choose_repository.tcl:895 +#: lib/choose_repository.tcl:902 msgid "Clone failed." msgstr "Клонирование не удалось." -#: lib/choose_repository.tcl:902 +#: lib/choose_repository.tcl:909 msgid "No default branch obtained." msgstr "Не было получено ветви по умолчанию." -#: lib/choose_repository.tcl:913 +#: lib/choose_repository.tcl:920 #, tcl-format msgid "Cannot resolve %s as a commit." msgstr "Не могу распознать %s как состояние." -#: lib/choose_repository.tcl:925 +#: lib/choose_repository.tcl:932 msgid "Creating working directory" msgstr "Создаю рабочий каталог" -#: lib/choose_repository.tcl:926 lib/index.tcl:65 lib/index.tcl:127 -#: lib/index.tcl:193 +#: lib/choose_repository.tcl:933 lib/index.tcl:65 lib/index.tcl:128 +#: lib/index.tcl:196 msgid "files" msgstr "файлов" -#: lib/choose_repository.tcl:955 +#: lib/choose_repository.tcl:962 msgid "Initial file checkout failed." msgstr "Не удалось получить начальное состояние файлов репозитория." -#: lib/choose_repository.tcl:971 +#: lib/choose_repository.tcl:978 msgid "Open" msgstr "Открыть" -#: lib/choose_repository.tcl:981 +#: lib/choose_repository.tcl:988 msgid "Repository:" msgstr "Репозиторий:" -#: lib/choose_repository.tcl:1031 +#: lib/choose_repository.tcl:1037 #, tcl-format msgid "Failed to open repository %s:" msgstr "Не удалось открыть репозиторий %s:" @@ -1130,7 +1253,7 @@ msgstr "Ветвь слежения" #: lib/choose_rev.tcl:84 lib/choose_rev.tcl:538 msgid "Tag" -msgstr "Таг" +msgstr "Метка" #: lib/choose_rev.tcl:317 #, tcl-format @@ -1172,24 +1295,24 @@ msgid "" "completed. You cannot amend the prior commit unless you first abort the " "current merge activity.\n" msgstr "" -"Невозможно исправить состояние во время объединения.\n" +"Невозможно исправить состояние во время операции слияния.\n" "\n" -"Текущее объединение не завершено. Невозможно исправить предыдущее " -"сохраненное состояние не прерывая текущее объединение.\n" +"Текущее слияние не завершено. Невозможно исправить предыдущее " +"сохраненное состояние, не прерывая эту операцию.\n" -#: lib/commit.tcl:49 +#: lib/commit.tcl:48 msgid "Error loading commit data for amend:" msgstr "Ошибка при загрузке данных для исправления сохраненного состояния:" -#: lib/commit.tcl:76 +#: lib/commit.tcl:75 msgid "Unable to obtain your identity:" msgstr "Невозможно получить информацию об авторстве:" -#: lib/commit.tcl:81 +#: lib/commit.tcl:80 msgid "Invalid GIT_COMMITTER_IDENT:" msgstr "Неверный GIT_COMMITTER_IDENT:" -#: lib/commit.tcl:133 +#: lib/commit.tcl:132 msgid "" "Last scanned state does not match repository state.\n" "\n" @@ -1205,7 +1328,7 @@ msgstr "" "\n" "Это будет сделано сейчас автоматически.\n" -#: lib/commit.tcl:154 +#: lib/commit.tcl:155 #, tcl-format msgid "" "Unmerged files cannot be committed.\n" @@ -1213,12 +1336,12 @@ msgid "" "File %s has merge conflicts. You must resolve them and stage the file " "before committing.\n" msgstr "" -"Нельзя сохранить необъединенные файлы.\n" +"Нельзя сохранить файлы с незавершённой операцей слияния.\n" "\n" -"Для файла %s возник конфликт объединения. Разрешите конфликт и добавьте к " +"Для файла %s возник конфликт слияния. Разрешите конфликт и добавьте к " "подготовленным файлам перед сохранением.\n" -#: lib/commit.tcl:162 +#: lib/commit.tcl:163 #, tcl-format msgid "" "Unknown file state %s detected.\n" @@ -1229,7 +1352,7 @@ msgstr "" "\n" "Файл %s не может быть сохранен данной программой.\n" -#: lib/commit.tcl:170 +#: lib/commit.tcl:171 msgid "" "No changes to commit.\n" "\n" @@ -1239,7 +1362,7 @@ msgstr "" "\n" "Подготовьте хотя бы один файл до создания сохраненного состояния.\n" -#: lib/commit.tcl:183 +#: lib/commit.tcl:186 msgid "" "Please supply a commit message.\n" "\n" @@ -1257,45 +1380,45 @@ msgstr "" "- вторая строка пустая\n" "- оставшиеся строки: опишите, что дают ваши изменения.\n" -#: lib/commit.tcl:207 +#: lib/commit.tcl:210 #, tcl-format msgid "warning: Tcl does not support encoding '%s'." msgstr "предупреждение: Tcl не поддерживает кодировку '%s'." -#: lib/commit.tcl:221 +#: lib/commit.tcl:226 msgid "Calling pre-commit hook..." msgstr "Вызов программы поддержки репозитория pre-commit..." -#: lib/commit.tcl:236 +#: lib/commit.tcl:241 msgid "Commit declined by pre-commit hook." msgstr "Сохранение прервано программой поддержки репозитория pre-commit" -#: lib/commit.tcl:259 +#: lib/commit.tcl:264 msgid "Calling commit-msg hook..." msgstr "Вызов программы поддержки репозитория commit-msg..." -#: lib/commit.tcl:274 +#: lib/commit.tcl:279 msgid "Commit declined by commit-msg hook." msgstr "Сохранение прервано программой поддержки репозитория commit-msg" -#: lib/commit.tcl:287 +#: lib/commit.tcl:292 msgid "Committing changes..." msgstr "Сохранение изменений..." -#: lib/commit.tcl:303 +#: lib/commit.tcl:308 msgid "write-tree failed:" msgstr "Программа write-tree завершилась с ошибкой:" -#: lib/commit.tcl:304 lib/commit.tcl:348 lib/commit.tcl:368 +#: lib/commit.tcl:309 lib/commit.tcl:353 lib/commit.tcl:373 msgid "Commit failed." msgstr "Сохранить состояние не удалось." -#: lib/commit.tcl:321 +#: lib/commit.tcl:326 #, tcl-format msgid "Commit %s appears to be corrupt" msgstr "Состояние %s выглядит поврежденным" -#: lib/commit.tcl:326 +#: lib/commit.tcl:331 msgid "" "No changes to commit.\n" "\n" @@ -1305,23 +1428,23 @@ msgid "" msgstr "" "Отсутствуют изменения для сохранения.\n" "\n" -"Ни один файл не был изменен и не было объединения.\n" +"Ни один файл не был изменен и не было слияния.\n" "\n" "Сейчас автоматически запустится перечитывание репозитория.\n" -#: lib/commit.tcl:333 +#: lib/commit.tcl:338 msgid "No changes to commit." msgstr "Отуствуют измения для сохранения." -#: lib/commit.tcl:347 +#: lib/commit.tcl:352 msgid "commit-tree failed:" msgstr "Программа commit-tree завершилась с ошибкой:" -#: lib/commit.tcl:367 +#: lib/commit.tcl:372 msgid "update-ref failed:" msgstr "Программа update-ref завершилась с ошибкой:" -#: lib/commit.tcl:454 +#: lib/commit.tcl:460 #, tcl-format msgid "Created commit %s: %s" msgstr "Создано состояние %s: %s " @@ -1396,7 +1519,7 @@ msgstr "" msgid "Invalid date from Git: %s" msgstr "Неправильная дата в репозитории: %s" -#: lib/diff.tcl:42 +#: lib/diff.tcl:59 #, tcl-format msgid "" "No differences detected.\n" @@ -1418,40 +1541,101 @@ msgstr "" "\n" "Сейчас будет запущено перечитывание репозитория, чтобы найти подобные файлы." -#: lib/diff.tcl:81 +#: lib/diff.tcl:99 #, tcl-format msgid "Loading diff of %s..." msgstr "Загрузка изменений в %s..." -#: lib/diff.tcl:114 lib/diff.tcl:184 +#: lib/diff.tcl:120 +msgid "" +"LOCAL: deleted\n" +"REMOTE:\n" +msgstr "" +"ЛОКАЛЬНО: удалён\n" +"ВНЕШНИЙ:\n" + +#: lib/diff.tcl:125 +msgid "" +"REMOTE: deleted\n" +"LOCAL:\n" +msgstr "" +"ВНЕШНИЙ: удалён\n" +"ЛОКАЛЬНО:\n" + +#: lib/diff.tcl:132 +msgid "LOCAL:\n" +msgstr "ЛОКАЛЬНО:\n" + +#: lib/diff.tcl:135 +msgid "REMOTE:\n" +msgstr "ВНЕШНИЙ:\n" + +#: lib/diff.tcl:197 lib/diff.tcl:296 #, tcl-format msgid "Unable to display %s" msgstr "Не могу показать %s" -#: lib/diff.tcl:115 +#: lib/diff.tcl:198 msgid "Error loading file:" msgstr "Ошибка загрузки файла:" -#: lib/diff.tcl:122 +#: lib/diff.tcl:205 msgid "Git Repository (subproject)" msgstr "Репозиторий Git (подпроект)" -#: lib/diff.tcl:134 +#: lib/diff.tcl:217 msgid "* Binary file (not showing content)." msgstr "* Двоичный файл (содержимое не показано)" -#: lib/diff.tcl:185 -msgid "Error loading diff:" -msgstr "Ошибка загрузки diff:" +#: lib/diff.tcl:222 +#, tcl-format +msgid "" +"* Untracked file is %d bytes.\n" +"* Showing only first %d bytes.\n" +msgstr "" +"* Размер неподготовленого файла %d байт.\n" +"* Показано первых %d байт.\n" -#: lib/diff.tcl:303 +#: lib/diff.tcl:228 +#, tcl-format +msgid "" +"\n" +"* Untracked file clipped here by %s.\n" +"* To see the entire file, use an external editor.\n" +msgstr "" +"\n" +"* Неподготовленый файл обрезан: %s.\n" +"* Чтобы увидеть весь файл, используйте программу-редактор.\n" + +#: lib/diff.tcl:436 msgid "Failed to unstage selected hunk." msgstr "Не удалось исключить выбранную часть." -#: lib/diff.tcl:310 +#: lib/diff.tcl:443 msgid "Failed to stage selected hunk." msgstr "Не удалось подготовить к сохранению выбранную часть." +#: lib/diff.tcl:509 +msgid "Failed to unstage selected line." +msgstr "Не удалось исключить выбранную строку." + +#: lib/diff.tcl:517 +msgid "Failed to stage selected line." +msgstr "Не удалось подготовить к сохранению выбранную строку." + +#: lib/encoding.tcl:443 +msgid "Default" +msgstr "По умолчанию" + +#: lib/encoding.tcl:448 +#, tcl-format +msgid "System (%s)" +msgstr "Системная (%s)" + +#: lib/encoding.tcl:459 lib/encoding.tcl:465 +msgid "Other" +msgstr "Другая" + #: lib/error.tcl:20 lib/error.tcl:114 msgid "error" msgstr "ошибка" @@ -1470,7 +1654,7 @@ msgstr "Не удалось разблокировать индекс" #: lib/index.tcl:15 msgid "Index Error" -msgstr "Ошибка индекса" +msgstr "Ошибка в индексе" #: lib/index.tcl:21 msgid "" @@ -1488,50 +1672,59 @@ msgstr "Продолжить" msgid "Unlock Index" msgstr "Разблокировать индекс" -#: lib/index.tcl:282 +#: lib/index.tcl:287 #, tcl-format msgid "Unstaging %s from commit" msgstr "Удаление %s из подготовленного" -#: lib/index.tcl:313 +#: lib/index.tcl:326 msgid "Ready to commit." msgstr "Подготовлено для сохранения" -#: lib/index.tcl:326 +#: lib/index.tcl:339 #, tcl-format msgid "Adding %s" msgstr "Добавление %s..." -#: lib/index.tcl:381 +#: lib/index.tcl:396 #, tcl-format msgid "Revert changes in file %s?" msgstr "Отменить изменения в файле %s?" -#: lib/index.tcl:383 +#: lib/index.tcl:398 #, tcl-format msgid "Revert changes in these %i files?" msgstr "Отменить изменения в %i файле(-ах)?" -#: lib/index.tcl:391 +#: lib/index.tcl:406 msgid "Any unstaged changes will be permanently lost by the revert." msgstr "" "Любые изменения, не подготовленные к сохранению, будут потеряны при данной " "операции." -#: lib/index.tcl:394 +#: lib/index.tcl:409 msgid "Do Nothing" msgstr "Ничего не делать" +#: lib/index.tcl:427 +msgid "Reverting selected files" +msgstr "Удаление изменений в выбраных файлах" + +#: lib/index.tcl:431 +#, tcl-format +msgid "Reverting %s" +msgstr "Отмена изменений в %s" + #: lib/merge.tcl:13 msgid "" "Cannot merge while amending.\n" "\n" "You must finish amending this commit before starting any type of merge.\n" msgstr "" -"Невозможно выполнить объединение во время исправления.\n" +"Невозможно выполнить слияние во время исправления.\n" "\n" "Завершите исправление данного состояния перед выполнением операции " -"объединения.\n" +"слияния.\n" #: lib/merge.tcl:27 msgid "" @@ -1549,7 +1742,7 @@ msgstr "" "\n" "Это будет сделано сейчас автоматически.\n" -#: lib/merge.tcl:44 +#: lib/merge.tcl:45 #, tcl-format msgid "" "You are in the middle of a conflicted merge.\n" @@ -1559,14 +1752,14 @@ msgid "" "You must resolve them, stage the file, and commit to complete the current " "merge. Only then can you begin another merge.\n" msgstr "" -"Предыдущее объединение не завершено из-за конфликта.\n" +"Предыдущее слияние не завершено из-за конфликта.\n" "\n" -"Для файла %s возник конфликт объединения.\n" +"Для файла %s возник конфликт слияния.\n" "\n" "Разрешите конфликт, подготовьте файл и сохраните. Только после этого можно " -"начать следующее объединение.\n" +"начать следующее слияние.\n" -#: lib/merge.tcl:54 +#: lib/merge.tcl:55 #, tcl-format msgid "" "You are in the middle of a change.\n" @@ -1580,36 +1773,37 @@ msgstr "" "\n" "Файл %s изменен.\n" "\n" -"Подготовьте и сохраните измения перед началом объединения. В случае " -"необходимости это позволит прервать операцию объединения.\n" +"Подготовьте и сохраните измения перед началом слияния. В случае " +"необходимости это позволит прервать операцию слияния.\n" -#: lib/merge.tcl:106 +#: lib/merge.tcl:107 #, tcl-format msgid "%s of %s" msgstr "%s из %s" -#: lib/merge.tcl:119 +#: lib/merge.tcl:120 +#, tcl-format msgid "Merging %s and %s..." -msgstr "Объединение %s и %s..." +msgstr "Слияние %s и %s..." -#: lib/merge.tcl:130 +#: lib/merge.tcl:131 msgid "Merge completed successfully." -msgstr "Объединение успешно завершено." +msgstr "Слияние успешно завершено." -#: lib/merge.tcl:132 +#: lib/merge.tcl:133 msgid "Merge failed. Conflict resolution is required." -msgstr "Не удалось завершить объединение. Требуется разрешение конфликта." +msgstr "Не удалось завершить слияние. Требуется разрешение конфликта." -#: lib/merge.tcl:157 +#: lib/merge.tcl:158 #, tcl-format msgid "Merge Into %s" -msgstr "Объединить с %s" +msgstr "Слияние с %s" -#: lib/merge.tcl:176 +#: lib/merge.tcl:177 msgid "Revision To Merge" -msgstr "Версия для объединения" +msgstr "Версия, с которой провести слияние" -#: lib/merge.tcl:211 +#: lib/merge.tcl:212 msgid "" "Cannot abort while amending.\n" "\n" @@ -1619,7 +1813,7 @@ msgstr "" "\n" "Завершите текущее исправление сохраненного состояния.\n" -#: lib/merge.tcl:221 +#: lib/merge.tcl:222 msgid "" "Abort merge?\n" "\n" @@ -1627,13 +1821,13 @@ msgid "" "\n" "Continue with aborting the current merge?" msgstr "" -"Прервать объединение?\n" +"Прервать операцию слияния?\n" "\n" -"Прерывание объединения приведет к потере *ВСЕХ* несохраненных изменений.\n" +"Прерывание этой операции приведет к потере *ВСЕХ* несохраненных изменений.\n" "\n" "Продолжить?" -#: lib/merge.tcl:227 +#: lib/merge.tcl:228 msgid "" "Reset changes?\n" "\n" @@ -1641,130 +1835,346 @@ msgid "" "\n" "Continue with resetting the current changes?" msgstr "" -"Прервать объединение?\n" +"Прервать операцию слияния?\n" "\n" -"Прерывание объединения приведет к потере *ВСЕХ* несохраненных изменений.\n" +"Прерывание этой операции приведет к потере *ВСЕХ* несохраненных изменений.\n" "\n" "Продолжить?" -#: lib/merge.tcl:238 +#: lib/merge.tcl:239 msgid "Aborting" msgstr "Прерываю" -#: lib/merge.tcl:238 +#: lib/merge.tcl:239 msgid "files reset" msgstr "изменения в файлах отменены" -#: lib/merge.tcl:265 +#: lib/merge.tcl:267 msgid "Abort failed." msgstr "Прервать не удалось." -#: lib/merge.tcl:267 +#: lib/merge.tcl:269 msgid "Abort completed. Ready." msgstr "Прервано." -#: lib/option.tcl:95 +#: lib/mergetool.tcl:8 +msgid "Force resolution to the base version?" +msgstr "Использовать базовую версию для разрешения конфликта?" + +#: lib/mergetool.tcl:9 +msgid "Force resolution to this branch?" +msgstr "Использовать версию этой ветви для разрешения конфликта?" + +#: lib/mergetool.tcl:10 +msgid "Force resolution to the other branch?" +msgstr "Использовать версию другой ветви для разрешения конфликта?" + +#: lib/mergetool.tcl:14 +#, tcl-format +msgid "" +"Note that the diff shows only conflicting changes.\n" +"\n" +"%s will be overwritten.\n" +"\n" +"This operation can be undone only by restarting the merge." +msgstr "" +"Внимание! Список изменений показывает только конфликтующие отличия.\n" +"\n" +"%s будет переписан.\n" +"\n" +"Это действие можно отменить только перезапуском операции слияния." + +#: lib/mergetool.tcl:45 +#, tcl-format +msgid "File %s seems to have unresolved conflicts, still stage?" +msgstr "" +"Файл %s кажется содержит необработаные конфликты. " +"Продолжить подготовку к сохранению?" + +#: lib/mergetool.tcl:60 +#, tcl-format +msgid "Adding resolution for %s" +msgstr "Добавляю результат разрешения для %s" + +#: lib/mergetool.tcl:141 +msgid "Cannot resolve deletion or link conflicts using a tool" +msgstr "" +"Программа слияния не обрабатывает конфликты с удалением или участием ссылок" + +#: lib/mergetool.tcl:146 +msgid "Conflict file does not exist" +msgstr "Конфликтующий файл не существует" + +#: lib/mergetool.tcl:264 +#, tcl-format +msgid "Not a GUI merge tool: '%s'" +msgstr "'%s' не является программой слияния" + +#: lib/mergetool.tcl:268 +#, tcl-format +msgid "Unsupported merge tool '%s'" +msgstr "Неизвестная программа слияния '%s'" + +#: lib/mergetool.tcl:303 +msgid "Merge tool is already running, terminate it?" +msgstr "Программа слияния уже работает. Прервать?" + +#: lib/mergetool.tcl:323 +#, tcl-format +msgid "" +"Error retrieving versions:\n" +"%s" +msgstr "" +"Ошибка получения версий:\n" +"%s" + +#: lib/mergetool.tcl:343 +#, tcl-format +msgid "" +"Could not start the merge tool:\n" +"\n" +"%s" +msgstr "" +"Ошибка запуска программы слияния:\n" +"\n" +"%s" + +#: lib/mergetool.tcl:347 +msgid "Running merge tool..." +msgstr "Запуск программы слияния..." + +#: lib/mergetool.tcl:375 lib/mergetool.tcl:383 +msgid "Merge tool failed." +msgstr "Ошибка выполнения программы слияния." + +#: lib/option.tcl:11 +#, tcl-format +msgid "Invalid global encoding '%s'" +msgstr "Ошибка в глобальной установке кодировки '%s'" + +#: lib/option.tcl:19 +#, tcl-format +msgid "Invalid repo encoding '%s'" +msgstr "Неверная кодировка репозитория: '%s'" + +#: lib/option.tcl:117 msgid "Restore Defaults" msgstr "Восстановить настройки по умолчанию" -#: lib/option.tcl:99 +#: lib/option.tcl:121 msgid "Save" msgstr "Сохранить" -#: lib/option.tcl:109 +#: lib/option.tcl:131 #, tcl-format msgid "%s Repository" -msgstr "для репозитория %s" +msgstr "Для репозитория %s" -#: lib/option.tcl:110 +#: lib/option.tcl:132 msgid "Global (All Repositories)" msgstr "Общие (для всех репозиториев)" -#: lib/option.tcl:116 +#: lib/option.tcl:138 msgid "User Name" msgstr "Имя пользователя" -#: lib/option.tcl:117 +#: lib/option.tcl:139 msgid "Email Address" msgstr "Адрес электронной почты" -#: lib/option.tcl:119 +#: lib/option.tcl:141 msgid "Summarize Merge Commits" -msgstr "Суммарный комментарий при объединении" +msgstr "Суммарный комментарий при слиянии" -#: lib/option.tcl:120 +#: lib/option.tcl:142 msgid "Merge Verbosity" -msgstr "Уровень детальности сообщений при объединении" +msgstr "Уровень детальности сообщений при слиянии" -#: lib/option.tcl:121 +#: lib/option.tcl:143 msgid "Show Diffstat After Merge" -msgstr "Показать отчет об изменениях после объединения" +msgstr "Показать отчет об изменениях после слияния" -#: lib/option.tcl:123 +#: lib/option.tcl:144 +msgid "Use Merge Tool" +msgstr "Использовать для слияния программу" + +#: lib/option.tcl:146 msgid "Trust File Modification Timestamps" msgstr "Доверять времени модификации файла" -#: lib/option.tcl:124 +#: lib/option.tcl:147 msgid "Prune Tracking Branches During Fetch" msgstr "Чистка ветвей слежения при получении изменений" -#: lib/option.tcl:125 +#: lib/option.tcl:148 msgid "Match Tracking Branches" msgstr "Имя новой ветви взять из имен ветвей слежения" -#: lib/option.tcl:126 +#: lib/option.tcl:149 +msgid "Blame Copy Only On Changed Files" +msgstr "Поиск копий только в изменённых файлах" + +#: lib/option.tcl:150 +msgid "Minimum Letters To Blame Copy On" +msgstr "Минимальное количество символов для поиска копий" + +#: lib/option.tcl:151 +msgid "Blame History Context Radius (days)" +msgstr "Радиус исторического контекста (в днях)" + +#: lib/option.tcl:152 msgid "Number of Diff Context Lines" msgstr "Число строк в контексте diff" -#: lib/option.tcl:127 +#: lib/option.tcl:153 msgid "Commit Message Text Width" -msgstr "Ширина комментария к состоянию:" +msgstr "Ширина текста комментария" -#: lib/option.tcl:128 +#: lib/option.tcl:154 msgid "New Branch Name Template" msgstr "Шаблон для имени новой ветви" -#: lib/option.tcl:192 +#: lib/option.tcl:155 +msgid "Default File Contents Encoding" +msgstr "Кодировка содержания файла по умолчанию" + +#: lib/option.tcl:203 +msgid "Change" +msgstr "Изменить" + +#: lib/option.tcl:230 msgid "Spelling Dictionary:" msgstr "Словарь для проверки правописания:" -#: lib/option.tcl:216 +#: lib/option.tcl:254 msgid "Change Font" -msgstr "Изменить шрифт" +msgstr "Изменить" -#: lib/option.tcl:220 +#: lib/option.tcl:258 #, tcl-format msgid "Choose %s" msgstr "Выберите %s" # carbon copy -#: lib/option.tcl:226 +#: lib/option.tcl:264 msgid "pt." -msgstr "" +msgstr "pt." -#: lib/option.tcl:240 +#: lib/option.tcl:278 msgid "Preferences" msgstr "Настройки" -#: lib/option.tcl:275 +#: lib/option.tcl:314 msgid "Failed to completely save options:" msgstr "Не удалось полностью сохранить настройки:" +#: lib/remote.tcl:163 +msgid "Remove Remote" +msgstr "Удалить ссылку на внешний репозиторий" + +#: lib/remote.tcl:168 +msgid "Prune from" +msgstr "Чистка" + +#: lib/remote.tcl:173 +msgid "Fetch from" +msgstr "Получение из" + +#: lib/remote.tcl:215 +msgid "Push to" +msgstr "Отправить" + +#: lib/remote_add.tcl:19 +msgid "Add Remote" +msgstr "Зарегистрировать внешний репозиторий" + +#: lib/remote_add.tcl:24 +msgid "Add New Remote" +msgstr "Добавить внешний репозиторий" + +#: lib/remote_add.tcl:28 lib/tools_dlg.tcl:36 +msgid "Add" +msgstr "" + +#: lib/remote_add.tcl:37 +msgid "Remote Details" +msgstr "Информация о внешнем репозитории" + +#: lib/remote_add.tcl:50 +msgid "Location:" +msgstr "Положение:" + +#: lib/remote_add.tcl:62 +msgid "Further Action" +msgstr "Следующая операция" + +#: lib/remote_add.tcl:65 +msgid "Fetch Immediately" +msgstr "Скачать сразу" + +#: lib/remote_add.tcl:71 +msgid "Initialize Remote Repository and Push" +msgstr "Инициализировать внешний репозиторий и отправить" + +#: lib/remote_add.tcl:77 +msgid "Do Nothing Else Now" +msgstr "Больше ничего не делать" + +#: lib/remote_add.tcl:101 +msgid "Please supply a remote name." +msgstr "Укажите название внешнего репозитория." + +#: lib/remote_add.tcl:114 +#, tcl-format +msgid "'%s' is not an acceptable remote name." +msgstr "Недопустимое название внешнего репозитория '%s'." + +#: lib/remote_add.tcl:125 +#, tcl-format +msgid "Failed to add remote '%s' of location '%s'." +msgstr "Не удалось добавить '%s' из '%s'. " + +#: lib/remote_add.tcl:133 lib/transport.tcl:6 +#, tcl-format +msgid "fetch %s" +msgstr "получение %s" + +#: lib/remote_add.tcl:134 +#, tcl-format +msgid "Fetching the %s" +msgstr "Получение %s" + +#: lib/remote_add.tcl:157 +#, tcl-format +msgid "Do not know how to initialize repository at location '%s'." +msgstr "Невозможно инициалировать репозиторий в '%s'." + +#: lib/remote_add.tcl:163 lib/transport.tcl:25 lib/transport.tcl:63 +#: lib/transport.tcl:81 +#, tcl-format +msgid "push %s" +msgstr "отправить %s" + +#: lib/remote_add.tcl:164 +#, tcl-format +msgid "Setting up the %s (at %s)" +msgstr "Настройка %s (в %s)" + #: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34 -msgid "Delete Remote Branch" -msgstr "Удалить внешнюю ветвь" +msgid "Delete Branch Remotely" +msgstr "Удаление ветви во внешнем репозитории" #: lib/remote_branch_delete.tcl:47 msgid "From Repository" msgstr "Из репозитория" -#: lib/remote_branch_delete.tcl:50 lib/transport.tcl:123 +#: lib/remote_branch_delete.tcl:50 lib/transport.tcl:134 msgid "Remote:" msgstr "внешний:" -#: lib/remote_branch_delete.tcl:66 lib/transport.tcl:138 -msgid "Arbitrary URL:" -msgstr "по указанному URL:" +#: lib/remote_branch_delete.tcl:66 lib/transport.tcl:149 +msgid "Arbitrary Location:" +msgstr "Указаное положение:" #: lib/remote_branch_delete.tcl:84 msgid "Branches" @@ -1776,15 +2186,15 @@ msgstr "Удалить только в случае, если" #: lib/remote_branch_delete.tcl:111 msgid "Merged Into:" -msgstr "Объединено с:" +msgstr "Слияние с:" #: lib/remote_branch_delete.tcl:119 msgid "Always (Do not perform merge checks)" -msgstr "Всегда (не выполнять проверку объединений)" +msgstr "Всегда (не выполнять проверку на слияние)" #: lib/remote_branch_delete.tcl:152 msgid "A branch is required for 'Merged Into'." -msgstr "Для опции 'Объединено с' требуется указать ветвь." +msgstr "Для опции 'Слияние с' требуется указать ветвь." #: lib/remote_branch_delete.tcl:184 #, tcl-format @@ -1793,7 +2203,8 @@ msgid "" "\n" " - %s" msgstr "" -"Следующие ветви объединены с %s не полностью:\n" +"Следующие ветви могут быть объединены с %s при помощи операции слияния:\n" +"\n" " - %s" #: lib/remote_branch_delete.tcl:189 @@ -1802,7 +2213,7 @@ msgid "" "One or more of the merge tests failed because you have not fetched the " "necessary commits. Try fetching from %s first." msgstr "" -"Один или несколько тестов на объединение не прошли, потому что Вы не " +"Некоторые тесты на слияние не прошли, потому что Вы не " "получили необходимые состояния. Попытайтесь получить их из %s." #: lib/remote_branch_delete.tcl:207 @@ -1833,17 +2244,21 @@ msgstr "Не указан репозиторий." msgid "Scanning %s..." msgstr "Перечитывание %s... " -#: lib/remote.tcl:165 -msgid "Prune from" -msgstr "Чистка" +#: lib/search.tcl:21 +msgid "Find:" +msgstr "Поиск:" -#: lib/remote.tcl:170 -msgid "Fetch from" -msgstr "Получение из" +#: lib/search.tcl:23 +msgid "Next" +msgstr "Дальше" -#: lib/remote.tcl:213 -msgid "Push to" -msgstr "Отправить" +#: lib/search.tcl:24 +msgid "Prev" +msgstr "Обратно" + +#: lib/search.tcl:25 +msgid "Case-Sensitive" +msgstr "Игн. большие/маленькие" #: lib/shortcut.tcl:20 lib/shortcut.tcl:61 msgid "Cannot write shortcut:" @@ -1878,27 +2293,192 @@ msgstr "Программа проверки правописания не смо msgid "Unrecognized spell checker" msgstr "Нераспознаная программа проверки правописания" -#: lib/spellcheck.tcl:180 +#: lib/spellcheck.tcl:186 msgid "No Suggestions" msgstr "Исправлений не найдено" -#: lib/spellcheck.tcl:381 +#: lib/spellcheck.tcl:388 msgid "Unexpected EOF from spell checker" msgstr "Программа проверки правописания прервала передачу данных" -#: lib/spellcheck.tcl:385 +#: lib/spellcheck.tcl:392 msgid "Spell Checker Failed" msgstr "Ошибка проверки правописания" +#: lib/sshkey.tcl:31 +msgid "No keys found." +msgstr "Ключ не найден" + +#: lib/sshkey.tcl:34 +#, tcl-format +msgid "Found a public key in: %s" +msgstr "Публичный ключ из %s" + +#: lib/sshkey.tcl:40 +msgid "Generate Key" +msgstr "Создать ключ" + +#: lib/sshkey.tcl:56 +msgid "Copy To Clipboard" +msgstr "Скопировать в буфер обмена" + +#: lib/sshkey.tcl:70 +msgid "Your OpenSSH Public Key" +msgstr "Ваш публичный ключ OpenSSH" + +#: lib/sshkey.tcl:78 +msgid "Generating..." +msgstr "Создание..." + +#: lib/sshkey.tcl:84 +#, tcl-format +msgid "" +"Could not start ssh-keygen:\n" +"\n" +"%s" +msgstr "" +"Ошибка запуска ssh-keygen:\n" +"\n" +"%s" + +#: lib/sshkey.tcl:111 +msgid "Generation failed." +msgstr "Ключ не создан." + +#: lib/sshkey.tcl:118 +msgid "Generation succeded, but no keys found." +msgstr "Создание ключа завершилось, но результат не был найден" + +#: lib/sshkey.tcl:121 +#, tcl-format +msgid "Your key is in: %s" +msgstr "Ваш ключ находится в: %s" + #: lib/status_bar.tcl:83 #, tcl-format msgid "%s ... %*i of %*i %s (%3i%%)" msgstr "%s ... %*i из %*i %s (%3i%%)" -#: lib/transport.tcl:6 +#: lib/tools.tcl:75 #, tcl-format -msgid "fetch %s" -msgstr "получение %s" +msgid "Running %s requires a selected file." +msgstr "Запуск %s требует выбранного файла." + +#: lib/tools.tcl:90 +#, tcl-format +msgid "Are you sure you want to run %s?" +msgstr "Действительно запустить %s?" + +#: lib/tools.tcl:110 +#, tcl-format +msgid "Tool: %s" +msgstr "Вспомогательная операция: %s" + +#: lib/tools.tcl:111 +#, tcl-format +msgid "Running: %s" +msgstr "Выполнение: %s" + +#: lib/tools.tcl:149 +#, tcl-format +msgid "Tool completed succesfully: %s" +msgstr "Программа %s успешно завершилась." + +#: lib/tools.tcl:151 +#, tcl-format +msgid "Tool failed: %s" +msgstr "Ошибка выполнения программы: %s" + +#: lib/tools_dlg.tcl:22 +msgid "Add Tool" +msgstr "Добавить вспомогательную операцию" + +#: lib/tools_dlg.tcl:28 +msgid "Add New Tool Command" +msgstr "Новая вспомогательная операция" + +#: lib/tools_dlg.tcl:33 +msgid "Add globally" +msgstr "Добавить для всех репозиториев" + +#: lib/tools_dlg.tcl:45 +msgid "Tool Details" +msgstr "Описание вспомогательной операции" + +#: lib/tools_dlg.tcl:48 +msgid "Use '/' separators to create a submenu tree:" +msgstr "Испольуйте '/' для создания подменю" + +#: lib/tools_dlg.tcl:61 +msgid "Command:" +msgstr "Команда:" + +#: lib/tools_dlg.tcl:74 +msgid "Show a dialog before running" +msgstr "Показать диалог перед запуском" + +#: lib/tools_dlg.tcl:80 +msgid "Ask the user to select a revision (sets $REVISION)" +msgstr "Запрос на выбор версии (устанавливает $REVISION)" + +#: lib/tools_dlg.tcl:85 +msgid "Ask the user for additional arguments (sets $ARGS)" +msgstr "Запрос дополнительных аргументов (устанавливает $ARGS)" + +#: lib/tools_dlg.tcl:92 +msgid "Don't show the command output window" +msgstr "Не показывать окно вывода команды" + +#: lib/tools_dlg.tcl:97 +msgid "Run only if a diff is selected ($FILENAME not empty)" +msgstr "Запуск только если показан список изменений ($FILENAME не пусто)" + +#: lib/tools_dlg.tcl:121 +msgid "Please supply a name for the tool." +msgstr "Укажите название вспомогательной операции." + +#: lib/tools_dlg.tcl:129 +#, tcl-format +msgid "Tool '%s' already exists." +msgstr "Вспомогательная операция '%s' уже существует." + +#: lib/tools_dlg.tcl:151 +#, tcl-format +msgid "" +"Could not add tool:\n" +"%s" +msgstr "" +"Ошибка добавления программы:\n" +"%s" + +#: lib/tools_dlg.tcl:190 +msgid "Remove Tool" +msgstr "Удалить программу" + +#: lib/tools_dlg.tcl:196 +msgid "Remove Tool Commands" +msgstr "Удалить команды программы" + +#: lib/tools_dlg.tcl:200 +msgid "Remove" +msgstr "Удалить" + +#: lib/tools_dlg.tcl:236 +msgid "(Blue denotes repository-local tools)" +msgstr "(Синим выделены программы локальные репозиторию)" + +#: lib/tools_dlg.tcl:297 +#, tcl-format +msgid "Run Command: %s" +msgstr "Запуск команды: %s" + +#: lib/tools_dlg.tcl:311 +msgid "Arguments" +msgstr "Аргументы" + +#: lib/tools_dlg.tcl:348 +msgid "OK" +msgstr "OK" #: lib/transport.tcl:7 #, tcl-format @@ -1916,48 +2496,46 @@ msgstr "чистка внешнего %s" msgid "Pruning tracking branches deleted from %s" msgstr "Чистка ветвей слежения, удаленных из %s" -#: lib/transport.tcl:25 lib/transport.tcl:71 -#, tcl-format -msgid "push %s" -msgstr "отправить %s" - #: lib/transport.tcl:26 #, tcl-format msgid "Pushing changes to %s" msgstr "Отправка изменений в %s " -#: lib/transport.tcl:72 +#: lib/transport.tcl:64 +#, tcl-format +msgid "Mirroring to %s" +msgstr "Точное копирование в %s" + +#: lib/transport.tcl:82 #, tcl-format msgid "Pushing %s %s to %s" msgstr "Отправка %s %s в %s" -#: lib/transport.tcl:89 +#: lib/transport.tcl:100 msgid "Push Branches" msgstr "Отправить изменения в ветвях" -#: lib/transport.tcl:103 +#: lib/transport.tcl:114 msgid "Source Branches" msgstr "Исходные ветви" -#: lib/transport.tcl:120 +#: lib/transport.tcl:131 msgid "Destination Repository" msgstr "Репозиторий назначения" -#: lib/transport.tcl:158 +#: lib/transport.tcl:169 msgid "Transfer Options" msgstr "Настройки отправки" -#: lib/transport.tcl:160 +#: lib/transport.tcl:171 msgid "Force overwrite existing branch (may discard changes)" msgstr "Намеренно переписать существующую ветвь (возможна потеря изменений)" -#: lib/transport.tcl:164 +#: lib/transport.tcl:175 msgid "Use thin pack (for slow network connections)" msgstr "Использовать thin pack (для медленных сетевых подключений)" -#: lib/transport.tcl:168 +#: lib/transport.tcl:179 msgid "Include tags" -msgstr "Передать таги" +msgstr "Передать метки" -#~ msgid "Next >" -#~ msgstr "Дальше >" From 348df16679cf35b7bba7afea99638e7d81dc3d33 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <Johannes.Schindelin@gmx.de> Date: Tue, 28 Apr 2009 00:32:25 +0200 Subject: [PATCH 521/654] Rename core.unreliableHardlinks to core.createObject "Unreliable hardlinks" is a misleading description for what is happening. So rename it to something less misleading. Suggested by Linus Torvalds. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/config.txt | 12 ++++++++---- Makefile | 10 +++++----- cache.h | 7 ++++++- config.c | 9 +++++++-- environment.c | 6 +++--- sha1_file.c | 2 +- 6 files changed, 30 insertions(+), 16 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index d31adb6719..5dcad94f84 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -429,10 +429,14 @@ relatively high IO latencies. With this set to 'true', git will do the index comparison to the filesystem data in parallel, allowing overlapping IO's. -core.unreliableHardlinks:: - Some filesystem drivers cannot properly handle hardlinking a file - and deleting the source right away. In such a case, you need to - set this config variable to 'true'. +core.createObject:: + You can set this to 'link', in which case a hardlink followed by + a delete of the source are used to make sure that object creation + will not overwrite existing objects. ++ +On some file system/operating system combinations, this is unreliable. +Set this config setting to 'rename' there; However, This will remove the +check that makes sure that existing object files will not get overwritten. alias.*:: Command aliases for the linkgit:git[1] command wrapper - e.g. diff --git a/Makefile b/Makefile index 6b80f81d60..6e216436c3 100644 --- a/Makefile +++ b/Makefile @@ -172,8 +172,8 @@ all:: # information on a not yet closed file that lstat would return for the same # file after it was closed. # -# Define UNRELIABLE_HARDLINKS if your operating systems has problems when -# hardlinking a file to another name and unlinking the original file right +# Define OBJECT_CREATION_USES_RENAMES if your operating systems has problems +# when hardlinking a file to another name and unlinking the original file right # away (some NTFS drivers seem to zero the contents in that scenario). GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE @@ -837,7 +837,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_NSEC = YesPlease USE_WIN32_MMAP = YesPlease UNRELIABLE_FSTAT = UnfortunatelyYes - UNRELIABLE_HARDLINKS = UnfortunatelySometimes + OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" @@ -1021,8 +1021,8 @@ else COMPAT_OBJS += compat/win32mmap.o endif endif -ifdef UNRELIABLE_HARDLINKS - COMPAT_CFLAGS += -DUNRELIABLE_HARDLINKS=1 +ifdef OBJECT_CREATION_USES_RENAMES + COMPAT_CFLAGS += -DOBJECT_CREATION_MODE=1 endif ifdef NO_PREAD COMPAT_CFLAGS += -DNO_PREAD diff --git a/cache.h b/cache.h index ff9e145be0..d0d48b4c88 100644 --- a/cache.h +++ b/cache.h @@ -554,7 +554,12 @@ extern enum branch_track git_branch_track; extern enum rebase_setup_type autorebase; extern enum push_default_type push_default; -extern int unreliable_hardlinks; +enum object_creation_mode { + OBJECT_CREATION_USES_HARDLINKS = 0, + OBJECT_CREATION_USES_RENAMES = 1, +}; + +extern enum object_creation_mode object_creation_mode; #define GIT_REPO_VERSION 0 extern int repository_format_version; diff --git a/config.c b/config.c index 1750cfb85e..563a91594d 100644 --- a/config.c +++ b/config.c @@ -495,8 +495,13 @@ static int git_default_core_config(const char *var, const char *value) return 0; } - if (!strcmp(var, "core.unreliablehardlinks")) { - unreliable_hardlinks = git_config_bool(var, value); + if (!strcmp(var, "core.createobject")) { + if (!strcmp(value, "rename")) + object_creation_mode = OBJECT_CREATION_USES_RENAMES; + else if (!strcmp(value, "link")) + object_creation_mode = OBJECT_CREATION_USES_HARDLINKS; + else + die("Invalid mode for object creation: %s", value); return 0; } diff --git a/environment.c b/environment.c index 10578d24d7..801a005ef1 100644 --- a/environment.c +++ b/environment.c @@ -43,10 +43,10 @@ unsigned whitespace_rule_cfg = WS_DEFAULT_RULE; enum branch_track git_branch_track = BRANCH_TRACK_REMOTE; enum rebase_setup_type autorebase = AUTOREBASE_NEVER; enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED; -#ifndef UNRELIABLE_HARDLINKS -#define UNRELIABLE_HARDLINKS 0 +#ifndef OBJECT_CREATION_MODE +#define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS #endif -int unreliable_hardlinks = UNRELIABLE_HARDLINKS; +enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/sha1_file.c b/sha1_file.c index 11969fc161..f708cf4f67 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -2225,7 +2225,7 @@ int move_temp_to_file(const char *tmpfile, const char *filename) { int ret = 0; - if (unreliable_hardlinks) + if (object_creation_mode == OBJECT_CREATION_USES_RENAMES) goto try_rename; else if (link(tmpfile, filename)) ret = errno; From 2163e3f7786f56d5aaf9eadea6776bb0e38b30a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> Date: Tue, 28 Apr 2009 22:29:24 +0200 Subject: [PATCH 522/654] parseopt: fix documentation for --keep-dashdash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-rev-parse.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index fba30b12ed..52c353e674 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -26,7 +26,7 @@ OPTIONS --parseopt:: Use 'git-rev-parse' in option parsing mode (see PARSEOPT section below). ---keep-dash-dash:: +--keep-dashdash:: Only meaningful in `--parseopt` mode. Tells the option parser to echo out the first `--` met instead of skipping it. From d212ca1724b1a3708a3b4cb72c58b20ef442b24f Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Thu, 30 Apr 2009 01:49:47 +0300 Subject: [PATCH 523/654] git config: error when editing a repo config and not being in one Let's throw an error on this specific case. If the user specifies the config file, he must know what he is doing. Teemu Likonen pointed this out. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builtin-config.c b/builtin-config.c index d8da72cf20..a81bc8bbf0 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -390,6 +390,8 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } else if (actions == ACTION_EDIT) { check_argc(argc, 0, 0); + if (!config_exclusive_filename && nongit) + die("not in a git directory"); git_config(git_default_config, NULL); launch_editor(config_exclusive_filename ? config_exclusive_filename : git_path("config"), From 0c44c94309693d0582e91a6744edc2e8eba46ef8 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Wed, 29 Apr 2009 11:08:18 -0700 Subject: [PATCH 524/654] merge-recursive: do not die on a conflicting submodule We cannot represent the 3-way conflicted state in the work tree for these entries, but it is normal not to have commit objects for them in our repository. Just update the index and the life will be good. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- merge-recursive.c | 8 ++++++-- t/t7405-submodule-merge.sh | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index d6f0582238..a3721efcaf 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -520,8 +520,12 @@ static void update_file_flags(struct merge_options *o, unsigned long size; if (S_ISGITLINK(mode)) - die("cannot read object %s '%s': It is a submodule!", - sha1_to_hex(sha), path); + /* + * We may later decide to recursively descend into + * the submodule directory and update its index + * and/or work tree, but we do not do that now. + */ + goto update_index; buf = read_sha1_file(sha, &type, &size); if (!buf) diff --git a/t/t7405-submodule-merge.sh b/t/t7405-submodule-merge.sh index aa6c44ce4f..9a21f783d3 100755 --- a/t/t7405-submodule-merge.sh +++ b/t/t7405-submodule-merge.sh @@ -54,13 +54,13 @@ test_expect_success setup ' git merge -s ours a ' -test_expect_failure 'merging with modify/modify conflict' ' +test_expect_success 'merging with modify/modify conflict' ' git checkout -b test1 a && test_must_fail git merge b && test -f .git/MERGE_MSG && - git diff - + git diff && + test -n "$(git ls-files -u)" ' test_expect_success 'merging with a modify/modify conflict between merge bases' ' From 3e8a00ae1d529e61f38f36fdb504902064cf1f5d Mon Sep 17 00:00:00 2001 From: Benjamin Kramer <benny.kra@googlemail.com> Date: Mon, 27 Apr 2009 15:59:49 +0200 Subject: [PATCH 525/654] daemon.c: fix segfault on OS X On OS X (and maybe other unices), getaddrinfo(3) returns NULL in the ai_canonname field if it's called with an IP address for the hostname. We'll now use the IP address for the hostname if ai_canonname was NULL, this also matches the behaviour on Linux. steps to reproduce: $ git daemon --export-all $ git clone git://127.0.0.1/frotz => git daemon's fork (silently) segfaults. Remove the pointless loop while at it. There is only one iteration because of the break; on the last line and there are no continues. Signed-off-by: Benjamin Kramer <benny.kra@googlemail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- daemon.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/daemon.c b/daemon.c index 13401f1baf..daa4c8e8c9 100644 --- a/daemon.c +++ b/daemon.c @@ -444,27 +444,27 @@ static void parse_extra_args(char *extra_args, int buflen) if (hostname) { #ifndef NO_IPV6 struct addrinfo hints; - struct addrinfo *ai, *ai0; + struct addrinfo *ai; int gai; static char addrbuf[HOST_NAME_MAX + 1]; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_CANONNAME; - gai = getaddrinfo(hostname, 0, &hints, &ai0); + gai = getaddrinfo(hostname, 0, &hints, &ai); if (!gai) { - for (ai = ai0; ai; ai = ai->ai_next) { - struct sockaddr_in *sin_addr = (void *)ai->ai_addr; + struct sockaddr_in *sin_addr = (void *)ai->ai_addr; - inet_ntop(AF_INET, &sin_addr->sin_addr, - addrbuf, sizeof(addrbuf)); - free(canon_hostname); - canon_hostname = xstrdup(ai->ai_canonname); - free(ip_address); - ip_address = xstrdup(addrbuf); - break; - } - freeaddrinfo(ai0); + inet_ntop(AF_INET, &sin_addr->sin_addr, + addrbuf, sizeof(addrbuf)); + free(ip_address); + ip_address = xstrdup(addrbuf); + + free(canon_hostname); + canon_hostname = xstrdup(ai->ai_canonname ? + ai->ai_canonname : ip_address); + + freeaddrinfo(ai); } #else struct hostent *hent; From fc71db39e0d75e8a403f36f3fecf4450886cd165 Mon Sep 17 00:00:00 2001 From: Alex Riesen <raa.lkml@gmail.com> Date: Wed, 29 Apr 2009 23:21:46 +0200 Subject: [PATCH 526/654] Introduce an unlink(2) wrapper which gives warning if unlink failed This seem to be a very common pattern in the current code. The function prints a generic removal failure message, the file name which failed and readable errno presentation. The function preserves errno and always returns the value unlink(2) returned, but prints no message for ENOENT, as it was the most often filtered out in the code calling unlink. Besides, removing a file is anyway the purpose of calling unlink. Signed-off-by: Alex Riesen <raa.lkml@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-compat-util.h | 6 ++++++ wrapper.c | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/git-compat-util.h b/git-compat-util.h index 1ac16bde5a..c7cf2d5d9c 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -415,4 +415,10 @@ void git_qsort(void *base, size_t nmemb, size_t size, #define fstat_is_reliable() 1 #endif +/* + * Preserves errno, prints a message, but gives no warning for ENOENT. + * Always returns the return value of unlink(2). + */ +int unlink_or_warn(const char *path); + #endif diff --git a/wrapper.c b/wrapper.c index d8efb1365a..7eb3218ee9 100644 --- a/wrapper.c +++ b/wrapper.c @@ -289,3 +289,19 @@ int odb_pack_keep(char *name, size_t namesz, unsigned char *sha1) safe_create_leading_directories(name); return open(name, O_RDWR|O_CREAT|O_EXCL, 0600); } + +int unlink_or_warn(const char *file) +{ + int rc = unlink(file); + + if (rc < 0) { + int err = errno; + if (ENOENT != err) { + warning("unable to unlink %s: %s", + file, strerror(errno)); + errno = err; + } + } + return rc; +} + From 691f1a28bf57618d8b44a193b1d28013c858aba6 Mon Sep 17 00:00:00 2001 From: Alex Riesen <raa.lkml@gmail.com> Date: Wed, 29 Apr 2009 23:22:56 +0200 Subject: [PATCH 527/654] replace direct calls to unlink(2) with unlink_or_warn This helps to notice when something's going wrong, especially on systems which lock open files. I used the following criteria when selecting the code for replacement: - it was already printing a warning for the unlink failures - it is in a function which already printing something or is called from such a function - it is in a static function, returning void and the function is only called from a builtin main function (cmd_) - it is in a function which handles emergency exit (signal handlers) - it is in a function which is obvously cleaning up the lockfiles Signed-off-by: Alex Riesen <raa.lkml@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-apply.c | 4 ++-- builtin-fetch-pack.c | 2 +- builtin-prune-packed.c | 4 ++-- builtin-prune.c | 4 ++-- builtin-receive-pack.c | 2 +- builtin-remote.c | 4 ++-- builtin-rerere.c | 2 +- builtin-tag.c | 2 +- builtin-verify-tag.c | 2 +- diff.c | 2 +- entry.c | 2 +- fast-import.c | 4 ++-- http-push.c | 12 ++++++------ http-walker.c | 14 +++++++------- ll-merge.c | 2 +- lockfile.c | 4 ++-- pack-refs.c | 2 +- refs.c | 15 +++++---------- rerere.c | 2 +- server-info.c | 2 +- sha1_file.c | 2 +- transport.c | 2 +- unpack-trees.c | 2 +- 23 files changed, 44 insertions(+), 49 deletions(-) diff --git a/builtin-apply.c b/builtin-apply.c index 7b404ef660..8a3771e87e 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2781,7 +2781,7 @@ static void remove_file(struct patch *patch, int rmdir_empty) if (rmdir(patch->old_name)) warning("unable to remove submodule %s", patch->old_name); - } else if (!unlink(patch->old_name) && rmdir_empty) { + } else if (!unlink_or_warn(patch->old_name) && rmdir_empty) { remove_path(patch->old_name); } } @@ -2891,7 +2891,7 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned if (!try_create_file(newpath, mode, buf, size)) { if (!rename(newpath, path)) return; - unlink(newpath); + unlink_or_warn(newpath); break; } if (errno != EEXIST) diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 5d134be47c..bd97cfd9bf 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -814,7 +814,7 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args, fd = hold_lock_file_for_update(&lock, shallow, LOCK_DIE_ON_ERROR); if (!write_shallow_commits(fd, 0)) { - unlink(shallow); + unlink_or_warn(shallow); rollback_lock_file(&lock); } else { commit_lock_file(&lock); diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c index 4942892e9f..00590b1c3c 100644 --- a/builtin-prune-packed.c +++ b/builtin-prune-packed.c @@ -28,8 +28,8 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts) memcpy(pathname + len, de->d_name, 38); if (opts & DRY_RUN) printf("rm -f %s\n", pathname); - else if (unlink(pathname) < 0) - error("unable to unlink %s", pathname); + else + unlink_or_warn(pathname); display_progress(progress, i + 1); } pathname[len] = 0; diff --git a/builtin-prune.c b/builtin-prune.c index 545e9c1f94..145ba83651 100644 --- a/builtin-prune.c +++ b/builtin-prune.c @@ -27,7 +27,7 @@ static int prune_tmp_object(const char *path, const char *filename) } printf("Removing stale temporary file %s\n", fullpath); if (!show_only) - unlink(fullpath); + unlink_or_warn(fullpath); return 0; } @@ -47,7 +47,7 @@ static int prune_object(char *path, const char *filename, const unsigned char *s (type > 0) ? typename(type) : "unknown"); } if (!show_only) - unlink(fullpath); + unlink_or_warn(fullpath); return 0; } diff --git a/builtin-receive-pack.c b/builtin-receive-pack.c index a970b39505..035b723e50 100644 --- a/builtin-receive-pack.c +++ b/builtin-receive-pack.c @@ -702,7 +702,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) unpack_status = unpack(); execute_commands(unpack_status); if (pack_lockfile) - unlink(pack_lockfile); + unlink_or_warn(pack_lockfile); if (report_status) report(unpack_status); run_receive_hook(post_receive_hook); diff --git a/builtin-remote.c b/builtin-remote.c index 2ed752cbf1..71abf68404 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -525,8 +525,8 @@ static int migrate_file(struct remote *remote) path = git_path("remotes/%s", remote->name); else if (remote->origin == REMOTE_BRANCHES) path = git_path("branches/%s", remote->name); - if (path && unlink(path)) - warning("failed to remove '%s'", path); + if (path) + unlink_or_warn(path); return 0; } diff --git a/builtin-rerere.c b/builtin-rerere.c index 020af7377b..adfb7b5f48 100644 --- a/builtin-rerere.c +++ b/builtin-rerere.c @@ -116,7 +116,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix) if (!has_rerere_resolution(name)) unlink_rr_item(name); } - unlink(git_path("rr-cache/MERGE_RR")); + unlink_or_warn(git_path("rr-cache/MERGE_RR")); } else if (!strcmp(argv[1], "gc")) garbage_collect(&merge_rr); else if (!strcmp(argv[1], "status")) diff --git a/builtin-tag.c b/builtin-tag.c index 01e73747d0..e544430094 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -338,7 +338,7 @@ static void create_tag(const unsigned char *object, const char *tag, exit(128); } if (path) { - unlink(path); + unlink_or_warn(path); free(path); } } diff --git a/builtin-verify-tag.c b/builtin-verify-tag.c index 729a1593e6..7f7fda42f9 100644 --- a/builtin-verify-tag.c +++ b/builtin-verify-tag.c @@ -55,7 +55,7 @@ static int run_gpg_verify(const char *buf, unsigned long size, int verbose) close(gpg.in); ret = finish_command(&gpg); - unlink(path); + unlink_or_warn(path); return ret; } diff --git a/diff.c b/diff.c index 3ac71686eb..6802f5ac12 100644 --- a/diff.c +++ b/diff.c @@ -189,7 +189,7 @@ static void remove_tempfile(void) int i; for (i = 0; i < ARRAY_SIZE(diff_temp); i++) { if (diff_temp[i].name == diff_temp[i].tmp_path) - unlink(diff_temp[i].name); + unlink_or_warn(diff_temp[i].name); diff_temp[i].name = NULL; } } diff --git a/entry.c b/entry.c index 915514aa5c..cc841edf90 100644 --- a/entry.c +++ b/entry.c @@ -35,7 +35,7 @@ static void create_directories(const char *path, int path_len, */ if (mkdir(buf, 0777)) { if (errno == EEXIST && state->force && - !unlink(buf) && !mkdir(buf, 0777)) + !unlink_or_warn(buf) && !mkdir(buf, 0777)) continue; die("cannot create directory at %s", buf); } diff --git a/fast-import.c b/fast-import.c index 8d959af3b2..6a618e9163 100644 --- a/fast-import.c +++ b/fast-import.c @@ -931,7 +931,7 @@ static void unkeep_all_packs(void) struct packed_git *p = all_packs[k]; snprintf(name, sizeof(name), "%s/pack/pack-%s.keep", get_object_directory(), sha1_to_hex(p->sha1)); - unlink(name); + unlink_or_warn(name); } } @@ -981,7 +981,7 @@ static void end_packfile(void) } else { close(old_p->pack_fd); - unlink(old_p->pack_name); + unlink_or_warn(old_p->pack_name); } free(old_p); diff --git a/http-push.c b/http-push.c index 5138224cc3..29e8ebfebb 100644 --- a/http-push.c +++ b/http-push.c @@ -315,9 +315,9 @@ static void start_fetch_loose(struct transfer_request *request) "%s.temp", filename); snprintf(prevfile, sizeof(prevfile), "%s.prev", request->filename); - unlink(prevfile); + unlink_or_warn(prevfile); rename(request->tmpfile, prevfile); - unlink(request->tmpfile); + unlink_or_warn(request->tmpfile); if (request->local_fileno != -1) error("fd leakage in start: %d", request->local_fileno); @@ -372,7 +372,7 @@ static void start_fetch_loose(struct transfer_request *request) } while (prev_read > 0); close(prevlocal); } - unlink(prevfile); + unlink_or_warn(prevfile); /* Reset inflate/SHA1 if there was an error reading the previous temp file; also rewind to the beginning of the local file. */ @@ -784,7 +784,7 @@ static void finish_request(struct transfer_request *request) request->http_code != 416) { if (stat(request->tmpfile, &st) == 0) { if (st.st_size == 0) - unlink(request->tmpfile); + unlink_or_warn(request->tmpfile); } } else { if (request->http_code == 416) @@ -793,9 +793,9 @@ static void finish_request(struct transfer_request *request) git_inflate_end(&request->stream); git_SHA1_Final(request->real_sha1, &request->c); if (request->zret != Z_STREAM_END) { - unlink(request->tmpfile); + unlink_or_warn(request->tmpfile); } else if (hashcmp(request->obj->sha1, request->real_sha1)) { - unlink(request->tmpfile); + unlink_or_warn(request->tmpfile); } else { request->rename = move_temp_to_file( diff --git a/http-walker.c b/http-walker.c index c5a3ea3b31..7321ccc9fe 100644 --- a/http-walker.c +++ b/http-walker.c @@ -111,9 +111,9 @@ static void start_object_request(struct walker *walker, struct walker_data *data = walker->data; snprintf(prevfile, sizeof(prevfile), "%s.prev", obj_req->filename); - unlink(prevfile); + unlink_or_warn(prevfile); rename(obj_req->tmpfile, prevfile); - unlink(obj_req->tmpfile); + unlink_or_warn(obj_req->tmpfile); if (obj_req->local != -1) error("fd leakage in start: %d", obj_req->local); @@ -177,7 +177,7 @@ static void start_object_request(struct walker *walker, } while (prev_read > 0); close(prevlocal); } - unlink(prevfile); + unlink_or_warn(prevfile); /* Reset inflate/SHA1 if there was an error reading the previous temp file; also rewind to the beginning of the local file. */ @@ -238,18 +238,18 @@ static void finish_object_request(struct object_request *obj_req) } else if (obj_req->curl_result != CURLE_OK) { if (stat(obj_req->tmpfile, &st) == 0) if (st.st_size == 0) - unlink(obj_req->tmpfile); + unlink_or_warn(obj_req->tmpfile); return; } git_inflate_end(&obj_req->stream); git_SHA1_Final(obj_req->real_sha1, &obj_req->c); if (obj_req->zret != Z_STREAM_END) { - unlink(obj_req->tmpfile); + unlink_or_warn(obj_req->tmpfile); return; } if (hashcmp(obj_req->sha1, obj_req->real_sha1)) { - unlink(obj_req->tmpfile); + unlink_or_warn(obj_req->tmpfile); return; } obj_req->rename = @@ -809,7 +809,7 @@ static void abort_object_request(struct object_request *obj_req) close(obj_req->local); obj_req->local = -1; } - unlink(obj_req->tmpfile); + unlink_or_warn(obj_req->tmpfile); if (obj_req->slot) { release_active_slot(obj_req->slot); obj_req->slot = NULL; diff --git a/ll-merge.c b/ll-merge.c index fa2ca5250c..81c02ad053 100644 --- a/ll-merge.c +++ b/ll-merge.c @@ -219,7 +219,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn, close(fd); bad: for (i = 0; i < 3; i++) - unlink(temp[i]); + unlink_or_warn(temp[i]); strbuf_release(&cmd); return status; } diff --git a/lockfile.c b/lockfile.c index 3dbb2d1ff9..984eb320fc 100644 --- a/lockfile.c +++ b/lockfile.c @@ -16,7 +16,7 @@ static void remove_lock_file(void) lock_file_list->filename[0]) { if (lock_file_list->fd >= 0) close(lock_file_list->fd); - unlink(lock_file_list->filename); + unlink_or_warn(lock_file_list->filename); } lock_file_list = lock_file_list->next; } @@ -259,7 +259,7 @@ void rollback_lock_file(struct lock_file *lk) if (lk->filename[0]) { if (lk->fd >= 0) close(lk->fd); - unlink(lk->filename); + unlink_or_warn(lk->filename); } lk->filename[0] = 0; } diff --git a/pack-refs.c b/pack-refs.c index 2c76fb181f..301fc60eae 100644 --- a/pack-refs.c +++ b/pack-refs.c @@ -66,7 +66,7 @@ static void prune_ref(struct ref_to_prune *r) struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1); if (lock) { - unlink(git_path("%s", r->name)); + unlink_or_warn(git_path("%s", r->name)); unlock_ref(lock); } } diff --git a/refs.c b/refs.c index e65a3b4c4e..2b1f0f0e6e 100644 --- a/refs.c +++ b/refs.c @@ -1002,12 +1002,10 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt) } else { path = git_path("%s", refname); } - err = unlink(path); - if (err && errno != ENOENT) { + err = unlink_or_warn(path); + if (err && errno != ENOENT) ret = 1; - error("unlink(%s) failed: %s", - path, strerror(errno)); - } + if (!(delopt & REF_NODEREF)) lock->lk->filename[i] = '.'; } @@ -1017,10 +1015,7 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt) */ ret |= repack_without_ref(refname); - err = unlink(git_path("logs/%s", lock->ref_name)); - if (err && errno != ENOENT) - warning("unlink(%s) failed: %s", - git_path("logs/%s", lock->ref_name), strerror(errno)); + unlink_or_warn(git_path("logs/%s", lock->ref_name)); invalidate_cached_refs(); unlock_ref(lock); return ret; @@ -1381,7 +1376,7 @@ int create_symref(const char *ref_target, const char *refs_heads_master, if (adjust_shared_perm(git_HEAD)) { error("Unable to fix permissions on %s", lockpath); error_unlink_return: - unlink(lockpath); + unlink_or_warn(lockpath); error_free_return: free(git_HEAD); return -1; diff --git a/rerere.c b/rerere.c index 713c6e16ac..87360dc23e 100644 --- a/rerere.c +++ b/rerere.c @@ -173,7 +173,7 @@ static int handle_file(const char *path, git_SHA1_Final(sha1, &ctx); if (hunk != RR_CONTEXT) { if (output) - unlink(output); + unlink_or_warn(output); return error("Could not parse conflict hunks in %s", path); } if (wrerror) diff --git a/server-info.c b/server-info.c index 66b0d9d878..d096dc7718 100644 --- a/server-info.c +++ b/server-info.c @@ -246,7 +246,7 @@ int update_server_info(int force) errs = errs | update_info_packs(force); /* remove leftover rev-cache file if there is any */ - unlink(git_path("info/rev-cache")); + unlink_or_warn(git_path("info/rev-cache")); return errs; } diff --git a/sha1_file.c b/sha1_file.c index f708cf4f67..dd474116a8 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -2247,7 +2247,7 @@ int move_temp_to_file(const char *tmpfile, const char *filename) goto out; ret = errno; } - unlink(tmpfile); + unlink_or_warn(tmpfile); if (ret) { if (ret != EEXIST) { return error("unable to write sha1 filename %s: %s\n", filename, strerror(ret)); diff --git a/transport.c b/transport.c index 3dfb03c06e..efecb65258 100644 --- a/transport.c +++ b/transport.c @@ -1069,7 +1069,7 @@ int transport_fetch_refs(struct transport *transport, const struct ref *refs) void transport_unlock_pack(struct transport *transport) { if (transport->pack_lockfile) { - unlink(transport->pack_lockfile); + unlink_or_warn(transport->pack_lockfile); free(transport->pack_lockfile); transport->pack_lockfile = NULL; } diff --git a/unpack-trees.c b/unpack-trees.c index e4eb8fa3af..aaacaf1015 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -61,7 +61,7 @@ static void unlink_entry(struct cache_entry *ce) { if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce))) return; - if (unlink(ce->name)) + if (unlink_or_warn(ce->name)) return; schedule_dir_for_removal(ce->name, ce_namelen(ce)); } From f6a5f1bb509a3af182fe568135398f1f2be15e5d Mon Sep 17 00:00:00 2001 From: Alex Riesen <raa.lkml@gmail.com> Date: Wed, 29 Apr 2009 23:24:52 +0200 Subject: [PATCH 528/654] print unlink(2) errno in copy_or_link_directory Signed-off-by: Alex Riesen <raa.lkml@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-clone.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/builtin-clone.c b/builtin-clone.c index 880373f279..ba286e0160 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -228,7 +228,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest) } if (unlink(dest->buf) && errno != ENOENT) - die("failed to unlink %s", dest->buf); + die("failed to unlink %s: %s", + dest->buf, strerror(errno)); if (!option_no_hardlinks) { if (!link(src->buf, dest->buf)) continue; From 6ffd567bec439e7809ee0966556bd5e72fb78de4 Mon Sep 17 00:00:00 2001 From: Alex Riesen <raa.lkml@gmail.com> Date: Wed, 29 Apr 2009 23:27:54 +0200 Subject: [PATCH 529/654] improve error message in config.c Show errno if opening a lockfile fails. Signed-off-by: Alex Riesen <raa.lkml@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.c b/config.c index 563a91594d..f76a78311e 100644 --- a/config.c +++ b/config.c @@ -1001,7 +1001,7 @@ int git_config_set_multivar(const char* key, const char* value, lock = xcalloc(sizeof(struct lock_file), 1); fd = hold_lock_file_for_update(lock, config_filename, 0); if (fd < 0) { - error("could not lock config file %s", config_filename); + error("could not lock config file %s: %s", config_filename, strerror(errno)); free(store.key); ret = -1; goto out_free; From adfd55d51bff3bfcf17c3cd40d0689fb018c14cf Mon Sep 17 00:00:00 2001 From: Alex Riesen <raa.lkml@gmail.com> Date: Wed, 29 Apr 2009 23:40:50 +0200 Subject: [PATCH 530/654] Clarify kind of conflict in merge-one-file helper Not as verbose as the recursive merge driver, but better still. Signed-off-by: Alex Riesen <raa.lkml@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-merge-one-file.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh index e1eb963266..9c2c1b7202 100755 --- a/git-merge-one-file.sh +++ b/git-merge-one-file.sh @@ -113,6 +113,10 @@ case "${1:-.}${2:-.}${3:-.}" in src1=`git-unpack-file $2` git merge-file "$src1" "$orig" "$src2" ret=$? + msg= + if [ $ret -ne 0 ]; then + msg='content conflict' + fi # Create the working tree file, using "our tree" version from the # index, and then store the result of the merge. @@ -120,7 +124,10 @@ case "${1:-.}${2:-.}${3:-.}" in rm -f -- "$orig" "$src1" "$src2" if [ "$6" != "$7" ]; then - echo "ERROR: Permissions conflict: $5->$6,$7." + if [ -n "$msg" ]; then + msg="$msg, " + fi + msg="${msg}permissions conflict: $5->$6,$7" ret=1 fi if [ "$1" = '' ]; then @@ -128,7 +135,7 @@ case "${1:-.}${2:-.}${3:-.}" in fi if [ $ret -ne 0 ]; then - echo "ERROR: Merge conflict in $4" + echo "ERROR: $msg in $4" exit 1 fi exec git update-index -- "$4" From ad7ef5b88d5d8ce4434a7df7aa658b451867eec3 Mon Sep 17 00:00:00 2001 From: Alex Riesen <raa.lkml@gmail.com> Date: Mon, 27 Apr 2009 20:04:27 +0200 Subject: [PATCH 531/654] gitk: Add Russian translation Thanks go to Dmitry Potapov for proofreading and suggested translation of the word 'merge'. Signed-off-by: Alex Riesen <raa.lkml@gmail.com> Signed-off-by: Paul Mackerras <paulus@samba.org> --- po/ru.po | 1085 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1085 insertions(+) create mode 100644 po/ru.po diff --git a/po/ru.po b/po/ru.po new file mode 100644 index 0000000000..704eba8f9d --- /dev/null +++ b/po/ru.po @@ -0,0 +1,1085 @@ +# +# Translation of gitk to Russian. +# +msgid "" +msgstr "" +"Project-Id-Version: gitk\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-04-24 16:00+0200\n" +"PO-Revision-Date: 2009-04-24 16:00+0200\n" +"Last-Translator: Alex Riesen <raa.lkml@gmail.com>\n" +"Language-Team: Russian\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: gitk:113 +msgid "Couldn't get list of unmerged files:" +msgstr "" +"Невозможно получить список файлов незавершённой операции слияния:" + +#: gitk:268 +msgid "Error parsing revisions:" +msgstr "Ошибка в идентификаторе версии:" + +#: gitk:323 +msgid "Error executing --argscmd command:" +msgstr "Ошибка выполнения команды заданой --argscmd:" + +#: gitk:336 +msgid "No files selected: --merge specified but no files are unmerged." +msgstr "" +"Файлы не выбраны: указан --merge, но не было найдено ни одного файла " +"где эта операция должна быть завершена." + +#: gitk:339 +msgid "" +"No files selected: --merge specified but no unmerged files are within file " +"limit." +msgstr "" +"Файлы не выбраны: указан --merge, но в рамках указаного " +"ограничения на имена файлов нет ни одного " +"где эта операция должна быть завершена." + +#: gitk:361 gitk:508 +msgid "Error executing git log:" +msgstr "Ошибка запуска git log:" + +#: gitk:379 +msgid "Reading" +msgstr "Чтение" + +#: gitk:439 gitk:4021 +msgid "Reading commits..." +msgstr "Чтение версий..." + +#: gitk:442 gitk:1560 gitk:4024 +msgid "No commits selected" +msgstr "Ничего не выбрано" + +#: gitk:1436 +msgid "Can't parse git log output:" +msgstr "Ошибка обработки вывода команды git log:" + +#: gitk:1656 +msgid "No commit information available" +msgstr "Нет информации о состоянии" + +#: gitk:1791 gitk:1815 gitk:3814 gitk:8478 gitk:10014 gitk:10186 +msgid "OK" +msgstr "Ok" + +#: gitk:1817 gitk:3816 gitk:8078 gitk:8152 gitk:8259 gitk:8308 gitk:8480 +#: gitk:10015 gitk:10187 +msgid "Cancel" +msgstr "Отмена" + +#: gitk:1915 +msgid "Update" +msgstr "Обновить" + +#: gitk:1916 +msgid "Reload" +msgstr "Перечитать" + +#: gitk:1917 +msgid "Reread references" +msgstr "Обновить список ссылок" + +#: gitk:1918 +msgid "List references" +msgstr "Список ссылок" + +#: gitk:1920 +msgid "Start git gui" +msgstr "Запустить git gui" + +#: gitk:1922 +msgid "Quit" +msgstr "Завершить" + +#: gitk:1914 +msgid "File" +msgstr "Файл" + +#: gitk:1925 +msgid "Preferences" +msgstr "Настройки" + +#: gitk:1924 +msgid "Edit" +msgstr "Редактировать" + +#: gitk:1928 +msgid "New view..." +msgstr "Новое представление..." + +#: gitk:1929 +msgid "Edit view..." +msgstr "Редактировать представление..." + +#: gitk:1930 +msgid "Delete view" +msgstr "Удалить представление" + +#: gitk:1932 +msgid "All files" +msgstr "Все файлы" + +#: gitk:1927 gitk:3626 +msgid "View" +msgstr "Представление" + +#: gitk:1935 gitk:2609 +msgid "About gitk" +msgstr "О gitk" + +#: gitk:1936 +msgid "Key bindings" +msgstr "Назначения клавиатуры" + +#: gitk:1934 +msgid "Help" +msgstr "Подсказка" + +#: gitk:1994 +msgid "SHA1 ID: " +msgstr "SHA1:" + +#: gitk:2025 +msgid "Row" +msgstr "Строка" + +#: gitk:2056 +msgid "Find" +msgstr "Поиск" + +#: gitk:2057 +msgid "next" +msgstr "След." + +#: gitk:2058 +msgid "prev" +msgstr "Пред." + +#: gitk:2059 +msgid "commit" +msgstr "состояние" + +#: gitk:2062 gitk:2064 gitk:4179 gitk:4202 gitk:4226 gitk:6164 gitk:6236 +#: gitk:6320 +msgid "containing:" +msgstr "содержащее:" + +#: gitk:2065 gitk:3117 gitk:3122 gitk:4254 +msgid "touching paths:" +msgstr "касательно файлов:" + +#: gitk:2066 gitk:4259 +msgid "adding/removing string:" +msgstr "добавив/удалив строку:" + +#: gitk:2075 gitk:2077 +msgid "Exact" +msgstr "Точно" + +#: gitk:2077 gitk:4334 gitk:6132 +msgid "IgnCase" +msgstr "Игнорировать большие/маленькие" + +#: gitk:2077 gitk:4228 gitk:4332 gitk:6128 +msgid "Regexp" +msgstr "Регулярные выражения" + +#: gitk:2079 gitk:2080 gitk:4353 gitk:4383 gitk:4390 gitk:6256 gitk:6324 +msgid "All fields" +msgstr "Во всех полях" + +#: gitk:2080 gitk:4351 gitk:4383 gitk:6195 +msgid "Headline" +msgstr "Заголовок" + +#: gitk:2081 gitk:4351 gitk:6195 gitk:6324 gitk:6737 +msgid "Comments" +msgstr "Комментарии" + +#: gitk:2081 gitk:4351 gitk:4355 gitk:4390 gitk:6195 gitk:6672 gitk:7923 +#: gitk:7938 +msgid "Author" +msgstr "Автор" + +#: gitk:2081 gitk:4351 gitk:6195 gitk:6674 +msgid "Committer" +msgstr "Сохранивший состояние" + +#: gitk:2110 +msgid "Search" +msgstr "Найти" + +#: gitk:2117 +msgid "Diff" +msgstr "Сравнить" + +#: gitk:2119 +msgid "Old version" +msgstr "Старая версия" + +#: gitk:2121 +msgid "New version" +msgstr "Новая версия" + +#: gitk:2123 +msgid "Lines of context" +msgstr "Строк контекста" + +#: gitk:2133 +msgid "Ignore space change" +msgstr "Игнорировать пробелы" + +#: gitk:2191 +msgid "Patch" +msgstr "Патч" + +#: gitk:2193 +msgid "Tree" +msgstr "Файлы" + +#: gitk:2326 gitk:2339 +msgid "Diff this -> selected" +msgstr "Сравнить это состояние с выделеным" + +#: gitk:2327 gitk:2340 +msgid "Diff selected -> this" +msgstr "Сравнить выделеное с этим состоянием" + +#: gitk:2328 gitk:2341 +msgid "Make patch" +msgstr "Создать патч" + +#: gitk:2329 gitk:8136 +msgid "Create tag" +msgstr "Создать метку" + +#: gitk:2330 gitk:8239 +msgid "Write commit to file" +msgstr "Сохранить изменения в файл" + +#: gitk:2331 gitk:8296 +msgid "Create new branch" +msgstr "Создать ветвь" + +#: gitk:2332 +msgid "Cherry-pick this commit" +msgstr "Скопировать это состояние" + +#: gitk:2333 +msgid "Reset HEAD branch to here" +msgstr "Установить HEAD на это состояние" + +#: gitk:2347 +msgid "Check out this branch" +msgstr "Перейти на эту ветвь" + +#: gitk:2348 +msgid "Remove this branch" +msgstr "Удалить эту ветвь" + +#: gitk:2355 +msgid "Highlight this too" +msgstr "Подсветить этот тоже" + +#: gitk:2356 +msgid "Highlight this only" +msgstr "Подсветить только этот" + +#: gitk:2357 +msgid "External diff" +msgstr "Программа сравнения" + +#: gitk:2358 +msgid "Blame parent commit" +msgstr "Аннотировать родительское состояние" + +#: gitk:2365 +msgid "Show origin of this line" +msgstr "Показать источник этой строки" + +#: gitk:2366 +msgid "Run git gui blame on this line" +msgstr "Запустить git gui blame для этой строки" + +#: gitk:2611 +msgid "" +"\n" +"Gitk - a commit viewer for git\n" +"\n" +"Copyright © 2005-2008 Paul Mackerras\n" +"\n" +"Use and redistribute under the terms of the GNU General Public License" +msgstr "" +"\n" +"Gitk - программа просмотра истории репозиториев Git\n" +"\n" +"Copyright (c) 2005-2008 Paul Mackerras\n" +"\n" +"Использование и распространение согласно условиям GNU General Public License" + +#: gitk:2619 gitk:2681 gitk:8661 +msgid "Close" +msgstr "Закрыть" + +#: gitk:2638 +msgid "Gitk key bindings" +msgstr "Назначения клавиатуры в Gitk" + +#: gitk:2641 +msgid "Gitk key bindings:" +msgstr "Назначения клавиатуры в Gitk:" + +#: gitk:2643 +#, tcl-format +msgid "<%s-Q>\t\tQuit" +msgstr "<%s-Q>\t\tЗавершить" + +#: gitk:2644 +msgid "<Home>\t\tMove to first commit" +msgstr "<Home>\t\tПерейти к первому состоянию" + +#: gitk:2645 +msgid "<End>\t\tMove to last commit" +msgstr "<End>\t\tПерейти к последнему состоянию" + +#: gitk:2646 +msgid "<Up>, p, i\tMove up one commit" +msgstr "<Up>, p, i\tПерейти к следующему состоянию" + +#: gitk:2647 +msgid "<Down>, n, k\tMove down one commit" +msgstr "<Down>, n, k\tПерейти к предыдущему состоянию" + +#: gitk:2648 +msgid "<Left>, z, j\tGo back in history list" +msgstr "<Left>, z, j\tПоказать ранее посещённое состояние" + +#: gitk:2649 +msgid "<Right>, x, l\tGo forward in history list" +msgstr "<Right>, x, l\tПоказать следующее посещённое состояние" + +#: gitk:2650 +msgid "<PageUp>\tMove up one page in commit list" +msgstr "<PageUp>\tПерейти на страницу выше в списке состояний" + +#: gitk:2651 +msgid "<PageDown>\tMove down one page in commit list" +msgstr "<PageDown>\tПерейти на страницу ниже в списке состояний" + +#: gitk:2652 +#, tcl-format +msgid "<%s-Home>\tScroll to top of commit list" +msgstr "<%s-Home>\tПоказать начало списка состояний" + +#: gitk:2653 +#, tcl-format +msgid "<%s-End>\tScroll to bottom of commit list" +msgstr "<%s-End>\tПоказать конец списка состояний" + +#: gitk:2654 +#, tcl-format +msgid "<%s-Up>\tScroll commit list up one line" +msgstr "<%s-Up>\tПровернуть список состояний вверх" + +#: gitk:2655 +#, tcl-format +msgid "<%s-Down>\tScroll commit list down one line" +msgstr "<%s-Down>\tПровернуть список состояний вниз" + +#: gitk:2656 +#, tcl-format +msgid "<%s-PageUp>\tScroll commit list up one page" +msgstr "<%s-PageUp>\tПровернуть список состояний на страницу вверх" + +#: gitk:2657 +#, tcl-format +msgid "<%s-PageDown>\tScroll commit list down one page" +msgstr "<%s-PageDown>\tПровернуть список состояний на страницу вниз" + +#: gitk:2658 +msgid "<Shift-Up>\tFind backwards (upwards, later commits)" +msgstr "" +"<Shift-Up>\tПоиск в обратном порядке (вверх, среди новых состояний)" + +#: gitk:2659 +msgid "<Shift-Down>\tFind forwards (downwards, earlier commits)" +msgstr "<Shift-Down>\tПоиск (вниз, среди старых состояний)" + +#: gitk:2660 +msgid "<Delete>, b\tScroll diff view up one page" +msgstr "<Delete>, b\tПрокрутить список изменений на страницу выше" + +#: gitk:2661 +msgid "<Backspace>\tScroll diff view up one page" +msgstr "<Backspace>\tПрокрутить список изменений на страницу выше" + +#: gitk:2662 +msgid "<Space>\t\tScroll diff view down one page" +msgstr "<Leertaste>\t\tПрокрутить список изменений на страницу ниже" + +#: gitk:2663 +msgid "u\t\tScroll diff view up 18 lines" +msgstr "u\t\tПрокрутить список изменений на 18 строк вверх" + +#: gitk:2664 +msgid "d\t\tScroll diff view down 18 lines" +msgstr "d\t\tПрокрутить список изменений на 18 строк вниз" + +#: gitk:2665 +#, tcl-format +msgid "<%s-F>\t\tFind" +msgstr "<%s-F>\t\tПоиск" + +#: gitk:2666 +#, tcl-format +msgid "<%s-G>\t\tMove to next find hit" +msgstr "<%s-G>\t\tПерейти к следующему найденому состоянию" + +#: gitk:2667 +msgid "<Return>\tMove to next find hit" +msgstr "<Return>\tПерейти к следующему найденому состоянию" + +#: gitk:2668 +msgid "/\t\tFocus the search box" +msgstr "/\t\tПерейти к полю поиска" + +#: gitk:2669 +msgid "?\t\tMove to previous find hit" +msgstr "?\t\tПерейти к предыдущему найденому состоянию" + +#: gitk:2670 +msgid "f\t\tScroll diff view to next file" +msgstr "f\t\tПрокрутить список изменений к следующему файлу" + +#: gitk:2671 +#, tcl-format +msgid "<%s-S>\t\tSearch for next hit in diff view" +msgstr "<%s-S>\t\tПродолжить поиск в списке изменений" + +#: gitk:2672 +#, tcl-format +msgid "<%s-R>\t\tSearch for previous hit in diff view" +msgstr "<%s-R>\t\tПерейти к предыдущему найденому тексту в списке изменений" + +#: gitk:2673 +#, tcl-format +msgid "<%s-KP+>\tIncrease font size" +msgstr "<%s-KP+>\tУвеличить размер шрифта" + +#: gitk:2674 +#, tcl-format +msgid "<%s-plus>\tIncrease font size" +msgstr "<%s-plus>\tУвеличить размер шрифта" + +#: gitk:2675 +#, tcl-format +msgid "<%s-KP->\tDecrease font size" +msgstr "<%s-KP->\tУменьшить размер шрифта" + +#: gitk:2676 +#, tcl-format +msgid "<%s-minus>\tDecrease font size" +msgstr "<%s-minus>\tУменьшить размер шрифта" + +#: gitk:2677 +msgid "<F5>\t\tUpdate" +msgstr "<F5>\t\tОбновить" + +#: gitk:3132 +#, tcl-format +msgid "Error getting \"%s\" from %s:" +msgstr "Ошибка получения \"%s\" из %s:" + +#: gitk:3189 gitk:3198 +#, tcl-format +msgid "Error creating temporary directory %s:" +msgstr "Ошибка создания временного каталога %s:" + +#: gitk:3211 +msgid "command failed:" +msgstr "ошибка выполнения команды:" + +#: gitk:3357 +msgid "No such commit" +msgstr "Состояние не найдено" + +#: gitk:3371 +msgid "git gui blame: command failed:" +msgstr "git gui blame: ошибка выполнения команды:" + +#: gitk:3402 +#, tcl-format +msgid "Couldn't read merge head: %s" +msgstr "Ошибка чтения MERGE_HEAD: %s" + +#: gitk:3410 +#, tcl-format +msgid "Error reading index: %s" +msgstr "Ошибка чтения индекса: %s" + +#: gitk:3435 +#, tcl-format +msgid "Couldn't start git blame: %s" +msgstr "Ошибка запуска git blame: %s" + +#: gitk:3438 gitk:6163 +msgid "Searching" +msgstr "Поиск" + +#: gitk:3470 +#, tcl-format +msgid "Error running git blame: %s" +msgstr "Ошибка выполнения git blame: %s" + +#: gitk:3498 +#, tcl-format +msgid "That line comes from commit %s, which is not in this view" +msgstr "" +"Эта строка принадлежит состоянию %s, которое не показано в этом " +"представлении" + +#: gitk:3512 +msgid "External diff viewer failed:" +msgstr "Ошибка выполнения программы сравнения:" + +#: gitk:3630 +msgid "Gitk view definition" +msgstr "Gitk определение представлений" + +#: gitk:3634 +msgid "Remember this view" +msgstr "Запомнить представление" + +#: gitk:3635 +msgid "Commits to include (arguments to git log):" +msgstr "Включить состояния (аргументы для git-log):" + +#: gitk:3636 +msgid "Use all refs" +msgstr "Использовать все ветви" + +#: gitk:3637 +msgid "Strictly sort by date" +msgstr "Строгая сортировка по дате" + +#: gitk:3638 +msgid "Mark branch sides" +msgstr "Отметить стороны ветвей" + +#: gitk:3639 +msgid "Since date:" +msgstr "С даты:" + +#: gitk:3640 +msgid "Until date:" +msgstr "По дату:" + +#: gitk:3641 +msgid "Max count:" +msgstr "Макс. количество:" + +#: gitk:3642 +msgid "Skip:" +msgstr "Пропустить:" + +#: gitk:3643 +msgid "Limit to first parent" +msgstr "Ограничить первым предком" + +#: gitk:3644 +msgid "Command to generate more commits to include:" +msgstr "Дополнительная команда для списка состояний:" + +#: gitk:3753 +msgid "Name" +msgstr "Имя" + +#: gitk:3801 +msgid "Enter files and directories to include, one per line:" +msgstr "Файлы и каталоги для ограничения истории, по одному на строку:" + +#: gitk:3815 +msgid "Apply (F5)" +msgstr "Применить (F5)" + +#: gitk:3853 +msgid "Error in commit selection arguments:" +msgstr "Ошибка в параметрах выбора состояний:" + +#: gitk:3906 gitk:3958 gitk:4403 gitk:4417 gitk:5675 gitk:10867 gitk:10868 +msgid "None" +msgstr "Ни одного" + +#: gitk:4351 gitk:6195 gitk:7925 gitk:7940 +msgid "Date" +msgstr "Дата" + +#: gitk:4351 gitk:6195 +msgid "CDate" +msgstr "Дата ввода" + +#: gitk:4500 gitk:4505 +msgid "Descendant" +msgstr "Порождённое" + +#: gitk:4501 +msgid "Not descendant" +msgstr "Не порождённое" + +#: gitk:4508 gitk:4513 +msgid "Ancestor" +msgstr "Предок" + +#: gitk:4509 +msgid "Not ancestor" +msgstr "Не предок" + +#: gitk:4799 +msgid "Local changes checked in to index but not committed" +msgstr "Изменения зарегистрированные в индексе, но не сохранённые" + +#: gitk:4835 +msgid "Local uncommitted changes, not checked in to index" +msgstr "Изменения в рабочем каталоге, не зарегистрированные в индексе" + +#: gitk:6676 +msgid "Tags:" +msgstr "Таги:" + +#: gitk:6693 gitk:6699 gitk:7918 +msgid "Parent" +msgstr "Предок" + +#: gitk:6704 +msgid "Child" +msgstr "Потомок" + +#: gitk:6713 +msgid "Branch" +msgstr "Ветвь" + +#: gitk:6716 +msgid "Follows" +msgstr "Следует за" + +#: gitk:6719 +msgid "Precedes" +msgstr "Предшествует" + +#: gitk:7212 +#, tcl-format +msgid "Error getting diffs: %s" +msgstr "Ошибка получения изменений: %s" + +#: gitk:7751 +msgid "Goto:" +msgstr "Перейти к:" + +#: gitk:7753 +msgid "SHA1 ID:" +msgstr "SHA1 ID:" + +#: gitk:7772 +#, tcl-format +msgid "Short SHA1 id %s is ambiguous" +msgstr "Сокращённый SHA1 идентификатор %s неоднозначен" + +#: gitk:7784 +#, tcl-format +msgid "SHA1 id %s is not known" +msgstr "SHA1 идентификатор %s не найден" + +#: gitk:7786 +#, tcl-format +msgid "Tag/Head %s is not known" +msgstr "Метка или ветвь %s не найдена" + +#: gitk:7928 +msgid "Children" +msgstr "Потомки" + +#: gitk:7985 +#, tcl-format +msgid "Reset %s branch to here" +msgstr "Установить ветвь %s на это состояние" + +#: gitk:7987 +msgid "Detached head: can't reset" +msgstr "Состояние не принадлежит ни одной ветви, переход невозможен" + +#: gitk:8019 +msgid "Top" +msgstr "Верх" + +#: gitk:8020 +msgid "From" +msgstr "От" + +#: gitk:8025 +msgid "To" +msgstr "До" + +#: gitk:8049 +msgid "Generate patch" +msgstr "Создать патч" + +#: gitk:8051 +msgid "From:" +msgstr "От:" + +#: gitk:8060 +msgid "To:" +msgstr "До:" + +#: gitk:8069 +msgid "Reverse" +msgstr "В обратном порядке" + +#: gitk:8071 gitk:8253 +msgid "Output file:" +msgstr "Файл для сохранения:" + +#: gitk:8077 +msgid "Generate" +msgstr "Создать" + +#: gitk:8115 +msgid "Error creating patch:" +msgstr "Ошибка создания патча:" + +#: gitk:8138 gitk:8241 gitk:8298 +msgid "ID:" +msgstr "ID:" + +#: gitk:8147 +msgid "Tag name:" +msgstr "Имя метки:" + +#: gitk:8151 gitk:8307 +msgid "Create" +msgstr "Создать" + +#: gitk:8168 +msgid "No tag name specified" +msgstr "Не задано имя метки" + +#: gitk:8172 +#, tcl-format +msgid "Tag \"%s\" already exists" +msgstr "Метка \"%s\" уже существует" + +#: gitk:8178 +msgid "Error creating tag:" +msgstr "Ошибка создания метки:" + +#: gitk:8250 +msgid "Command:" +msgstr "Команда:" + +#: gitk:8258 +msgid "Write" +msgstr "Запись" + +#: gitk:8276 +msgid "Error writing commit:" +msgstr "Ошибка сохранения состояния:" + +#: gitk:8303 +msgid "Name:" +msgstr "Имя:" + +#: gitk:8326 +msgid "Please specify a name for the new branch" +msgstr "Укажите имя для новой ветви" + +#: gitk:8331 +#, tcl-format +msgid "Branch '%s' already exists. Overwrite?" +msgstr "Ветвь '%s' уже существует. Переписать?" + +#: gitk:8397 +#, tcl-format +msgid "Commit %s is already included in branch %s -- really re-apply it?" +msgstr "" +"Состояние %s уже принадлежит ветви %s. Продолжить операцию?" + +#: gitk:8402 +msgid "Cherry-picking" +msgstr "Копирование изменений" + +#: gitk:8411 +#, tcl-format +msgid "" +"Cherry-pick failed because of local changes to file '%s'.\n" +"Please commit, reset or stash your changes and try again." +msgstr "" +"Копирование невозможно из-за изменений в файле '%s'.\n" +"Сохраните или отмените изменения и повторите операцию." + +#: gitk:8417 +msgid "" +"Cherry-pick failed because of merge conflict.\n" +"Do you wish to run git citool to resolve it?" +msgstr "" +"Копирование изменений невозможно из-за незавершённой операции " +"слияния.\nЗапустить git citool для завершения этой операции?" + +#: gitk:8433 +msgid "No changes committed" +msgstr "Изменения не сохранены" + +#: gitk:8459 +msgid "Confirm reset" +msgstr "Подтвердите операцию перехода" + +#: gitk:8461 +#, tcl-format +msgid "Reset branch %s to %s?" +msgstr "Установить ветвь %s на состояние %s?" + +#: gitk:8465 +msgid "Reset type:" +msgstr "Тип операции перехода:" + +#: gitk:8469 +msgid "Soft: Leave working tree and index untouched" +msgstr "Лёгкий: оставить рабочий каталог и индекс неизменными" + +#: gitk:8472 +msgid "Mixed: Leave working tree untouched, reset index" +msgstr "" +"Смешаный: оставить рабочий каталог неизменным, установить индекс" + +#: gitk:8475 +msgid "" +"Hard: Reset working tree and index\n" +"(discard ALL local changes)" +msgstr "" +"Жесткий: переписать индекс и рабочий каталог\n" +"(все изменения в рабочем каталоги будут потеряны)" + +#: gitk:8492 +msgid "Resetting" +msgstr "Установка" + +#: gitk:8549 +msgid "Checking out" +msgstr "Переход" + +#: gitk:8602 +msgid "Cannot delete the currently checked-out branch" +msgstr "Активная ветвь не может быть удалена" + +#: gitk:8608 +#, tcl-format +msgid "" +"The commits on branch %s aren't on any other branch.\n" +"Really delete branch %s?" +msgstr "" +"Состояния ветви %s больше не принадлежат никакой другой ветви.\n" +"Действительно удалить ветвь %s?" + +#: gitk:8639 +#, tcl-format +msgid "Tags and heads: %s" +msgstr "Метки и ветви: %s" + +#: gitk:8654 +msgid "Filter" +msgstr "Фильтровать" + +#: gitk:8949 +msgid "" +"Error reading commit topology information; branch and preceding/following " +"tag information will be incomplete." +msgstr "" +"Ошибка чтения истории проекта; информация о ветвях и состояниях " +"вокруг меток (до/после) может быть неполной." + +#: gitk:9935 +msgid "Tag" +msgstr "Метка" + +#: gitk:9935 +msgid "Id" +msgstr "Id" + +#: gitk:9983 +msgid "Gitk font chooser" +msgstr "Шрифт Gitk" + +#: gitk:10000 +msgid "B" +msgstr "Ж" + +#: gitk:10003 +msgid "I" +msgstr "К" + +#: gitk:10098 +msgid "Gitk preferences" +msgstr "Настройки Gitk" + +#: gitk:10100 +msgid "Commit list display options" +msgstr "Параметры показа списка состояний" + +#: gitk:10103 +msgid "Maximum graph width (lines)" +msgstr "Макс. ширина графа (строк)" + +#: gitk:10107 +#, tcl-format +msgid "Maximum graph width (% of pane)" +msgstr "Макс. ширина графа (% ширины панели)" + +#: gitk:10111 +msgid "Show local changes" +msgstr "Показывать изменения в рабочем каталоге" + +#: gitk:10114 +msgid "Auto-select SHA1" +msgstr "Выделить SHA1" + +#: gitk:10118 +msgid "Diff display options" +msgstr "Параметры показа изменений" + +#: gitk:10120 +msgid "Tab spacing" +msgstr "Ширина табуляции" + +#: gitk:10123 +msgid "Display nearby tags" +msgstr "Показывать близкие метки" + +#: gitk:10126 +msgid "Limit diffs to listed paths" +msgstr "Ограничить показ изменений выбраными файлами" + +#: gitk:10129 +msgid "Support per-file encodings" +msgstr "Поддержка кодировок в отдельных файлах" + +#: gitk:10135 +msgid "External diff tool" +msgstr "Программа для показа изменений" + +#: gitk:10137 +msgid "Choose..." +msgstr "Выберите..." + +#: gitk:10142 +msgid "Colors: press to choose" +msgstr "Цвета: нажмите для выбора" + +#: gitk:10145 +msgid "Background" +msgstr "Фон" + +#: gitk:10146 gitk:10176 +msgid "background" +msgstr "фон" + +#: gitk:10149 +msgid "Foreground" +msgstr "Передний план" + +#: gitk:10150 +msgid "foreground" +msgstr "передний план" + +#: gitk:10153 +msgid "Diff: old lines" +msgstr "Изменения: старый текст" + +#: gitk:10154 +msgid "diff old lines" +msgstr "старый текст изменения" + +#: gitk:10158 +msgid "Diff: new lines" +msgstr "Изменения: новый текст" + +#: gitk:10159 +msgid "diff new lines" +msgstr "новый текст изменения" + +#: gitk:10163 +msgid "Diff: hunk header" +msgstr "Изменения: заголовок блока" + +#: gitk:10165 +msgid "diff hunk header" +msgstr "заголовок блока изменений" + +#: gitk:10169 +msgid "Marked line bg" +msgstr "Фон выбраной строки" + +#: gitk:10171 +msgid "marked line background" +msgstr "фон выбраной строки" + +#: gitk:10175 +msgid "Select bg" +msgstr "Выберите фон" + +#: gitk:10179 +msgid "Fonts: press to choose" +msgstr "Шрифт: нажмите для выбора" + +#: gitk:10181 +msgid "Main font" +msgstr "Основной шрифт" + +#: gitk:10182 +msgid "Diff display font" +msgstr "Шрифт показа изменений" + +#: gitk:10183 +msgid "User interface font" +msgstr "Шрифт интерфейса" + +#: gitk:10210 +#, tcl-format +msgid "Gitk: choose color for %s" +msgstr "Gitk: выберите цвет для %s" + +#: gitk:10656 +msgid "" +"Sorry, gitk cannot run with this version of Tcl/Tk.\n" +" Gitk requires at least Tcl/Tk 8.4." +msgstr "" +"К сожалению gitk не может работать с этой версий Tcl/Tk.\n" +"Требуется как минимум Tcl/Tk 8.4." + +#: gitk:10773 +msgid "Cannot find a git repository here." +msgstr "Git-репозитарий не найден в текущем каталоге." + +#: gitk:10777 +#, tcl-format +msgid "Cannot find the git directory \"%s\"." +msgstr "Git-репозитарий \"%s\" не найден." + +#: gitk:10824 +#, tcl-format +msgid "Ambiguous argument '%s': both revision and filename" +msgstr "Неоднозначный аргумент '%s': существует как версия и имя файла" + +#: gitk:10836 +msgid "Bad arguments to gitk:" +msgstr "Неправильные аргументы для gitk:" + +#: gitk:10896 +msgid "Command line" +msgstr "Командная строка" + From a91be3fcbe92c24e809b1ec85881a6da40a9a340 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" <das@users.sourceforge.net> Date: Sat, 16 Aug 2008 03:20:09 +0200 Subject: [PATCH 532/654] git-gui: Fixes for Mac OS X TkAqua - detect more Tk.framework variants - fix apple menu setup, use native preferences menu item - don't set menu font Signed-off-by: Daniel A. Steffen <das@users.sourceforge.net> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- Makefile | 7 +++++-- git-gui.sh | 34 +++++++++++++++++----------------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index 3ad8a21b30..b3580e9e48 100644 --- a/Makefile +++ b/Makefile @@ -105,8 +105,11 @@ endif ifeq ($(uname_S),Darwin) TKFRAMEWORK = /Library/Frameworks/Tk.framework/Resources/Wish.app - ifeq ($(shell expr "$(uname_R)" : '9\.'),2) - TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish\ Shell.app + ifeq ($(shell echo "$(uname_R)" | awk -F. '{if ($$1 >= 9) print "y"}')_$(shell test -d $(TKFRAMEWORK) || echo n),y_n) + TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish.app + ifeq ($(shell test -d $(TKFRAMEWORK) || echo n),n) + TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish\ Shell.app + endif endif TKEXECUTABLE = $(shell basename "$(TKFRAMEWORK)" .app) endif diff --git a/git-gui.sh b/git-gui.sh index c8f850d1ef..14b92ba786 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -663,10 +663,13 @@ font create font_diffbold font create font_diffitalic foreach class {Button Checkbutton Entry Label - Labelframe Listbox Menu Message + Labelframe Listbox Message Radiobutton Spinbox Text} { option add *$class.font font_ui } +if {![is_MacOSX]} { + option add *Menu.font font_ui +} unset class if {[is_Windows] || [is_MacOSX]} { @@ -2301,6 +2304,12 @@ set ui_comm {} # -- Menu Bar # menu .mbar -tearoff 0 +if {[is_MacOSX]} { + # -- Apple Menu (Mac OS X only) + # + .mbar add cascade -label Apple -menu .mbar.apple + menu .mbar.apple +} .mbar add cascade -label [mc Repository] -menu .mbar.repository .mbar add cascade -label [mc Edit] -menu .mbar.edit if {[is_enabled branch]} { @@ -2316,7 +2325,6 @@ if {[is_enabled transport]} { if {[is_enabled multicommit] || [is_enabled singlecommit]} { .mbar add cascade -label [mc Tools] -menu .mbar.tools } -. configure -menu .mbar # -- Repository Menu # @@ -2569,19 +2577,7 @@ if {[is_enabled transport]} { } if {[is_MacOSX]} { - # -- Apple Menu (Mac OS X only) - # - .mbar add cascade -label Apple -menu .mbar.apple - menu .mbar.apple - - .mbar.apple add command -label [mc "About %s" [appname]] \ - -command do_about - .mbar.apple add separator - .mbar.apple add command \ - -label [mc "Preferences..."] \ - -command do_options \ - -accelerator $M1T-, - bind . <$M1B-,> do_options + proc ::tk::mac::ShowPreferences {} {do_options} } else { # -- Edit Menu # @@ -2609,11 +2605,15 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} { .mbar add cascade -label [mc Help] -menu .mbar.help menu .mbar.help -if {![is_MacOSX]} { +if {[is_MacOSX]} { + .mbar.apple add command -label [mc "About %s" [appname]] \ + -command do_about + .mbar.apple add separator +} else { .mbar.help add command -label [mc "About %s" [appname]] \ -command do_about } - +. configure -menu .mbar set doc_path [githtmldir] if {$doc_path ne {}} { From 4b25d091ba53c758fae0096b8c0662371857b9d9 Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Fri, 1 May 2009 12:06:36 +0300 Subject: [PATCH 533/654] Fix a bunch of pointer declarations (codestyle) Essentially; s/type* /type */ as per the coding guidelines. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- alias.c | 4 +-- alloc.c | 2 +- attr.c | 4 +-- builtin-blame.c | 8 +++--- builtin-checkout-index.c | 4 +-- builtin-describe.c | 4 +-- builtin-fetch-pack.c | 2 +- builtin-help.c | 6 ++--- builtin-update-index.c | 6 ++--- cache.h | 2 +- combine-diff.c | 4 +-- compat/mingw.c | 2 +- config.c | 30 +++++++++++------------ contrib/convert-objects/convert-objects.c | 6 ++--- diff-no-index.c | 2 +- diff.c | 4 +-- dir.c | 2 +- fast-import.c | 14 +++++------ git.c | 8 +++--- lockfile.c | 2 +- reflog-walk.c | 2 +- run-command.c | 2 +- server-info.c | 4 +-- sha1_file.c | 2 +- wt-status.c | 2 +- 25 files changed, 64 insertions(+), 64 deletions(-) diff --git a/alias.c b/alias.c index ccb1108c94..e687fe54c1 100644 --- a/alias.c +++ b/alias.c @@ -27,7 +27,7 @@ int split_cmdline(char *cmdline, const char ***argv) int src, dst, count = 0, size = 16; char quoted = 0; - *argv = xmalloc(sizeof(char*) * size); + *argv = xmalloc(sizeof(char *) * size); /* split alias_string */ (*argv)[count++] = cmdline; @@ -40,7 +40,7 @@ int split_cmdline(char *cmdline, const char ***argv) ; /* skip */ if (count >= size) { size += 16; - *argv = xrealloc(*argv, sizeof(char*) * size); + *argv = xrealloc(*argv, sizeof(char *) * size); } (*argv)[count++] = cmdline + dst; } else if (!quoted && (c == '\'' || c == '"')) { diff --git a/alloc.c b/alloc.c index 216c23a6f8..6ef6753d18 100644 --- a/alloc.c +++ b/alloc.c @@ -57,7 +57,7 @@ DEFINE_ALLOCATOR(object, union any_object) #define SZ_FMT "%zu" #endif -static void report(const char* name, unsigned int count, size_t size) +static void report(const char *name, unsigned int count, size_t size) { fprintf(stderr, "%10s: %8u (" SZ_FMT " kB)\n", name, count, size); } diff --git a/attr.c b/attr.c index f1ca4f5859..98eb636f13 100644 --- a/attr.c +++ b/attr.c @@ -224,7 +224,7 @@ static struct match_attr *parse_attr_line(const char *line, const char *src, if (is_macro) res->u.attr = git_attr(name, namelen); else { - res->u.pattern = (char*)&(res->state[num_attr]); + res->u.pattern = (char *)&(res->state[num_attr]); memcpy(res->u.pattern, name, namelen); res->u.pattern[namelen] = 0; } @@ -275,7 +275,7 @@ static void free_attr_elem(struct attr_stack *e) setto == ATTR__UNKNOWN) ; else - free((char*) setto); + free((char *) setto); } free(a); } diff --git a/builtin-blame.c b/builtin-blame.c index 83141fc84e..cf74a92614 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -873,7 +873,7 @@ static void find_copy_in_blob(struct scoreboard *sb, * Prepare mmfile that contains only the lines in ent. */ cp = nth_line(sb, ent->lno); - file_o.ptr = (char*) cp; + file_o.ptr = (char *) cp; cnt = ent->num_lines; while (cnt && cp < sb->final_buf + sb->final_buf_size) { @@ -1704,7 +1704,7 @@ static int prepare_lines(struct scoreboard *sb) while (len--) { if (bol) { sb->lineno = xrealloc(sb->lineno, - sizeof(int* ) * (num + 1)); + sizeof(int *) * (num + 1)); sb->lineno[num] = buf - sb->final_buf; bol = 0; } @@ -1714,7 +1714,7 @@ static int prepare_lines(struct scoreboard *sb) } } sb->lineno = xrealloc(sb->lineno, - sizeof(int* ) * (num + incomplete + 1)); + sizeof(int *) * (num + incomplete + 1)); sb->lineno[num + incomplete] = buf - sb->final_buf; sb->num_lines = num + incomplete; return sb->num_lines; @@ -1889,7 +1889,7 @@ static const char *parse_loc(const char *spec, return spec; /* it could be a regexp of form /.../ */ - for (term = (char*) spec + 1; *term && *term != '/'; term++) { + for (term = (char *) spec + 1; *term && *term != '/'; term++) { if (*term == '\\') term++; } diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c index 0d534bc023..afe35e246c 100644 --- a/builtin-checkout-index.c +++ b/builtin-checkout-index.c @@ -124,7 +124,7 @@ static int checkout_file(const char *name, int prefix_length) static void checkout_all(const char *prefix, int prefix_length) { int i, errs = 0; - struct cache_entry* last_ce = NULL; + struct cache_entry *last_ce = NULL; for (i = 0; i < active_nr ; i++) { struct cache_entry *ce = active_cache[i]; @@ -278,7 +278,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) p = prefix_path(prefix, prefix_length, arg); checkout_file(p, prefix_length); if (p < arg || p > arg + strlen(arg)) - free((char*)p); + free((char *)p); } if (read_from_stdin) { diff --git a/builtin-describe.c b/builtin-describe.c index 3a007ed1ca..63c6a19da5 100644 --- a/builtin-describe.c +++ b/builtin-describe.c @@ -334,7 +334,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix) die("--long is incompatible with --abbrev=0"); if (contains) { - const char **args = xmalloc((7 + argc) * sizeof(char*)); + const char **args = xmalloc((7 + argc) * sizeof(char *)); int i = 0; args[i++] = "name-rev"; args[i++] = "--name-only"; @@ -349,7 +349,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix) args[i++] = s; } } - memcpy(args + i, argv, argc * sizeof(char*)); + memcpy(args + i, argv, argc * sizeof(char *)); args[i + argc] = NULL; return cmd_name_rev(i + argc, args, prefix); } diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 5d134be47c..cbe5f206f5 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -111,7 +111,7 @@ static void mark_common(struct commit *commit, Get the next rev to send, ignoring the common. */ -static const unsigned char* get_rev(void) +static const unsigned char *get_rev(void) { struct commit *commit = NULL; diff --git a/builtin-help.c b/builtin-help.c index e7fbe9af63..67dda3e6e6 100644 --- a/builtin-help.c +++ b/builtin-help.c @@ -114,7 +114,7 @@ static int check_emacsclient_version(void) return 0; } -static void exec_woman_emacs(const char* path, const char *page) +static void exec_woman_emacs(const char *path, const char *page) { if (!check_emacsclient_version()) { /* This works only with emacsclient version >= 22. */ @@ -128,7 +128,7 @@ static void exec_woman_emacs(const char* path, const char *page) } } -static void exec_man_konqueror(const char* path, const char *page) +static void exec_man_konqueror(const char *path, const char *page) { const char *display = getenv("DISPLAY"); if (display && *display) { @@ -156,7 +156,7 @@ static void exec_man_konqueror(const char* path, const char *page) } } -static void exec_man_man(const char* path, const char *page) +static void exec_man_man(const char *path, const char *page) { if (!path) path = "man"; diff --git a/builtin-update-index.c b/builtin-update-index.c index 1fde893cfa..92beaaf4b3 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -292,7 +292,7 @@ static void update_one(const char *path, const char *prefix, int prefix_length) report("add '%s'", path); free_return: if (p < path || p > path + strlen(path)) - free((char*)p); + free((char *)p); } static void read_index_info(int line_termination) @@ -509,7 +509,7 @@ static int do_unresolve(int ac, const char **av, const char *p = prefix_path(prefix, prefix_length, arg); err |= unresolve_one(p); if (p < arg || p > arg + strlen(arg)) - free((char*)p); + free((char *)p); } return err; } @@ -712,7 +712,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) if (set_executable_bit) chmod_path(set_executable_bit, p); if (p < path || p > path + strlen(path)) - free((char*)p); + free((char *)p); } if (read_from_stdin) { struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT; diff --git a/cache.h b/cache.h index d0d48b4c88..b8503ad91c 100644 --- a/cache.h +++ b/cache.h @@ -846,7 +846,7 @@ extern struct packed_git *find_sha1_pack(const unsigned char *sha1, extern void pack_report(void); extern int open_pack_index(struct packed_git *); -extern unsigned char* use_pack(struct packed_git *, struct pack_window **, off_t, unsigned int *); +extern unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned int *); extern void close_pack_windows(struct packed_git *); extern void unuse_pack(struct pack_window **); extern void free_pack_by_name(const char *); diff --git a/combine-diff.c b/combine-diff.c index d210656861..60d03676bb 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -24,7 +24,7 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, path = q->queue[i]->two->path; len = strlen(path); p = xmalloc(combine_diff_path_size(num_parent, len)); - p->path = (char*) &(p->parent[num_parent]); + p->path = (char *) &(p->parent[num_parent]); memcpy(p->path, path, len); p->path[len] = 0; p->len = len; @@ -1063,7 +1063,7 @@ void diff_tree_combined_merge(const unsigned char *sha1, for (parents = commit->parents, num_parent = 0; parents; parents = parents->next, num_parent++) - hashcpy((unsigned char*)(parent + num_parent), + hashcpy((unsigned char *)(parent + num_parent), parents->item->object.sha1); diff_tree_combined(sha1, parent, num_parent, dense, rev); } diff --git a/compat/mingw.c b/compat/mingw.c index 2a047019e8..cdeda1d985 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -562,7 +562,7 @@ static char **get_path_split(void) if (!n) return NULL; - path = xmalloc((n+1)*sizeof(char*)); + path = xmalloc((n+1)*sizeof(char *)); p = envpath; i = 0; do { diff --git a/config.c b/config.c index f76a78311e..1682273c12 100644 --- a/config.c +++ b/config.c @@ -724,16 +724,16 @@ int git_config(config_fn_t fn, void *data) static struct { int baselen; - char* key; + char *key; int do_not_match; - regex_t* value_regex; + regex_t *value_regex; int multi_replace; size_t offset[MAX_MATCHES]; enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state; int seen; } store; -static int matches(const char* key, const char* value) +static int matches(const char *key, const char *value) { return !strcmp(key, store.key) && (store.value_regex == NULL || @@ -741,7 +741,7 @@ static int matches(const char* key, const char* value) !regexec(store.value_regex, value, 0, NULL, 0))); } -static int store_aux(const char* key, const char* value, void *cb) +static int store_aux(const char *key, const char *value, void *cb) { const char *ep; size_t section_len; @@ -810,7 +810,7 @@ static int write_error(const char *filename) return 4; } -static int store_write_section(int fd, const char* key) +static int store_write_section(int fd, const char *key) { const char *dot; int i, success; @@ -835,7 +835,7 @@ static int store_write_section(int fd, const char* key) return success; } -static int store_write_pair(int fd, const char* key, const char* value) +static int store_write_pair(int fd, const char *key, const char *value) { int i, success; int length = strlen(key + store.baselen + 1); @@ -883,8 +883,8 @@ static int store_write_pair(int fd, const char* key, const char* value) return success; } -static ssize_t find_beginning_of_line(const char* contents, size_t size, - size_t offset_, int* found_bracket) +static ssize_t find_beginning_of_line(const char *contents, size_t size, + size_t offset_, int *found_bracket) { size_t equal_offset = size, bracket_offset = size; ssize_t offset; @@ -909,7 +909,7 @@ contline: return offset; } -int git_config_set(const char* key, const char* value) +int git_config_set(const char *key, const char *value) { return git_config_set_multivar(key, value, NULL, 0); } @@ -937,15 +937,15 @@ int git_config_set(const char* key, const char* value) * - the config file is removed and the lock file rename()d to it. * */ -int git_config_set_multivar(const char* key, const char* value, - const char* value_regex, int multi_replace) +int git_config_set_multivar(const char *key, const char *value, + const char *value_regex, int multi_replace) { int i, dot; int fd = -1, in_fd; int ret; - char* config_filename; + char *config_filename; struct lock_file *lock = NULL; - const char* last_dot = strrchr(key, '.'); + const char *last_dot = strrchr(key, '.'); if (config_exclusive_filename) config_filename = xstrdup(config_exclusive_filename); @@ -1026,13 +1026,13 @@ int git_config_set_multivar(const char* key, const char* value, goto out_free; } - store.key = (char*)key; + store.key = (char *)key; if (!store_write_section(fd, key) || !store_write_pair(fd, key, value)) goto write_err_out; } else { struct stat st; - char* contents; + char *contents; size_t contents_sz, copy_begin, copy_end; int i, new_line = 0; diff --git a/contrib/convert-objects/convert-objects.c b/contrib/convert-objects/convert-objects.c index 90e7900e6d..f3b57bf1d2 100644 --- a/contrib/convert-objects/convert-objects.c +++ b/contrib/convert-objects/convert-objects.c @@ -59,7 +59,7 @@ static void convert_ascii_sha1(void *buffer) struct entry *entry; if (get_sha1_hex(buffer, sha1)) - die("expected sha1, got '%s'", (char*) buffer); + die("expected sha1, got '%s'", (char *) buffer); entry = convert_entry(sha1); memcpy(buffer, sha1_to_hex(entry->new_sha1), 40); } @@ -100,7 +100,7 @@ static int write_subdirectory(void *buffer, unsigned long size, const char *base if (!slash) { newlen += sprintf(new + newlen, "%o %s", mode, path); new[newlen++] = '\0'; - hashcpy((unsigned char*)new + newlen, (unsigned char *) buffer + len - 20); + hashcpy((unsigned char *)new + newlen, (unsigned char *) buffer + len - 20); newlen += 20; used += len; @@ -271,7 +271,7 @@ static void convert_commit(void *buffer, unsigned long size, unsigned char *resu unsigned long orig_size = size; if (memcmp(buffer, "tree ", 5)) - die("Bad commit '%s'", (char*) buffer); + die("Bad commit '%s'", (char *) buffer); convert_ascii_sha1((char *) buffer + 5); buffer = (char *) buffer + 46; /* "tree " + "hex sha1" + "\n" */ while (!memcmp(buffer, "parent ", 7)) { diff --git a/diff-no-index.c b/diff-no-index.c index 42c1dd8ad3..4ebc1dbd87 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -233,7 +233,7 @@ void diff_no_index(struct rev_info *revs, if (prefix) { int len = strlen(prefix); - revs->diffopt.paths = xcalloc(2, sizeof(char*)); + revs->diffopt.paths = xcalloc(2, sizeof(char *)); for (i = 0; i < 2; i++) { const char *p = argv[argc - 2 + i]; /* diff --git a/diff.c b/diff.c index 3ac71686eb..363dcb9613 100644 --- a/diff.c +++ b/diff.c @@ -876,7 +876,7 @@ static void fill_print_name(struct diffstat_file *file) file->print_name = pname; } -static void show_stats(struct diffstat_t* data, struct diff_options *options) +static void show_stats(struct diffstat_t *data, struct diff_options *options) { int i, len, add, del, adds = 0, dels = 0; int max_change = 0, max_len = 0; @@ -1025,7 +1025,7 @@ static void show_shortstats(struct diffstat_t* data, struct diff_options *option total_files, adds, dels); } -static void show_numstat(struct diffstat_t* data, struct diff_options *options) +static void show_numstat(struct diffstat_t *data, struct diff_options *options) { int i; diff --git a/dir.c b/dir.c index c91ebfb46f..15677da47c 100644 --- a/dir.c +++ b/dir.c @@ -156,7 +156,7 @@ void add_exclude(const char *string, const char *base, if (len && string[len - 1] == '/') { char *s; x = xmalloc(sizeof(*x) + len); - s = (char*)(x+1); + s = (char *)(x+1); memcpy(s, string, len - 1); s[len - 1] = '\0'; string = s; diff --git a/fast-import.c b/fast-import.c index 8d959af3b2..e9d23ffb2f 100644 --- a/fast-import.c +++ b/fast-import.c @@ -212,7 +212,7 @@ struct tree_content; struct tree_entry { struct tree_content *tree; - struct atom_str* name; + struct atom_str *name; struct tree_entry_ms { uint16_t mode; @@ -313,7 +313,7 @@ static unsigned int object_entry_alloc = 5000; static struct object_entry_pool *blocks; static struct object_entry *object_table[1 << 16]; static struct mark_set *marks; -static const char* mark_file; +static const char *mark_file; /* Our last blob */ static struct last_object last_blob = { STRBUF_INIT, 0, 0, 0 }; @@ -672,7 +672,7 @@ static struct branch *lookup_branch(const char *name) static struct branch *new_branch(const char *name) { unsigned int hc = hc_str(name, strlen(name)) % branch_table_sz; - struct branch* b = lookup_branch(name); + struct branch *b = lookup_branch(name); if (b) die("Invalid attempt to create duplicate branch: %s", name); @@ -1035,7 +1035,7 @@ static int store_object( git_SHA_CTX c; z_stream s; - hdrlen = sprintf((char*)hdr,"%s %lu", typename(type), + hdrlen = sprintf((char *)hdr,"%s %lu", typename(type), (unsigned long)dat->len) + 1; git_SHA1_Init(&c); git_SHA1_Update(&c, hdr, hdrlen); @@ -1217,7 +1217,7 @@ static const char *get_mode(const char *str, uint16_t *modep) static void load_tree(struct tree_entry *root) { - unsigned char* sha1 = root->versions[1].sha1; + unsigned char *sha1 = root->versions[1].sha1; struct object_entry *myoe; struct tree_content *t; unsigned long size; @@ -1258,8 +1258,8 @@ static void load_tree(struct tree_entry *root) e->versions[0].mode = e->versions[1].mode; e->name = to_atom(c, strlen(c)); c += e->name->str_len + 1; - hashcpy(e->versions[0].sha1, (unsigned char*)c); - hashcpy(e->versions[1].sha1, (unsigned char*)c); + hashcpy(e->versions[0].sha1, (unsigned char *)c); + hashcpy(e->versions[1].sha1, (unsigned char *)c); c += 20; } free(buf); diff --git a/git.c b/git.c index cc5aaa76f1..5a00726d09 100644 --- a/git.c +++ b/git.c @@ -47,7 +47,7 @@ static void commit_pager_choice(void) { } } -static int handle_options(const char*** argv, int* argc, int* envchanged) +static int handle_options(const char ***argv, int *argc, int *envchanged) { int handled = 0; @@ -136,7 +136,7 @@ static int handle_alias(int *argcp, const char ***argv) int envchanged = 0, ret = 0, saved_errno = errno; const char *subdir; int count, option_count; - const char** new_argv; + const char **new_argv; const char *alias_command; char *alias_string; int unused_nongit; @@ -187,10 +187,10 @@ static int handle_alias(int *argcp, const char ***argv) "trace: alias expansion: %s =>", alias_command); - new_argv = xrealloc(new_argv, sizeof(char*) * + new_argv = xrealloc(new_argv, sizeof(char *) * (count + *argcp + 1)); /* insert after command name */ - memcpy(new_argv + count, *argv + 1, sizeof(char*) * *argcp); + memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp); new_argv[count+*argcp] = NULL; *argv = new_argv; diff --git a/lockfile.c b/lockfile.c index 3dbb2d1ff9..828d19f452 100644 --- a/lockfile.c +++ b/lockfile.c @@ -109,7 +109,7 @@ static char *resolve_symlink(char *p, size_t s) * link is a relative path, so I must replace the * last element of p with it. */ - char *r = (char*)last_path_elm(p); + char *r = (char *)last_path_elm(p); if (r - p + link_len < s) strcpy(r, link); else { diff --git a/reflog-walk.c b/reflog-walk.c index fd065f4e1a..5623ea6b48 100644 --- a/reflog-walk.c +++ b/reflog-walk.c @@ -241,7 +241,7 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit) commit->object.flags &= ~(ADDED | SEEN | SHOWN); } -void show_reflog_message(struct reflog_walk_info* info, int oneline, +void show_reflog_message(struct reflog_walk_info *info, int oneline, enum date_mode dmode) { if (info && info->last_commit_reflog) { diff --git a/run-command.c b/run-command.c index b05c734d05..eb2efc3307 100644 --- a/run-command.c +++ b/run-command.c @@ -106,7 +106,7 @@ int start_command(struct child_process *cmd) if (cmd->env) { for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) - putenv((char*)*cmd->env); + putenv((char *)*cmd->env); else unsetenv(*cmd->env); } diff --git a/server-info.c b/server-info.c index 66b0d9d878..906ce5b272 100644 --- a/server-info.c +++ b/server-info.c @@ -132,8 +132,8 @@ static int read_pack_info_file(const char *infofile) static int compare_info(const void *a_, const void *b_) { - struct pack_info * const* a = a_; - struct pack_info * const* b = b_; + struct pack_info *const *a = a_; + struct pack_info *const *b = b_; if (0 <= (*a)->old_num && 0 <= (*b)->old_num) /* Keep the order in the original */ diff --git a/sha1_file.c b/sha1_file.c index f708cf4f67..28bd9082fc 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -791,7 +791,7 @@ static int in_window(struct pack_window *win, off_t offset) && (offset + 20) <= (win_off + win->len); } -unsigned char* use_pack(struct packed_git *p, +unsigned char *use_pack(struct packed_git *p, struct pack_window **w_cursor, off_t offset, unsigned int *left) diff --git a/wt-status.c b/wt-status.c index 929b00f592..1b6df45450 100644 --- a/wt-status.c +++ b/wt-status.c @@ -40,7 +40,7 @@ static int parse_status_slot(const char *var, int offset) die("bad config variable '%s'", var); } -static const char* color(int slot) +static const char *color(int slot) { return wt_status_use_color > 0 ? wt_status_colors[slot] : ""; } From 1087aba86b4a687cabf03d4a060d4b51282819d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Fri, 1 May 2009 22:03:07 +0200 Subject: [PATCH 534/654] ctype.c: fix typo in comment Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- ctype.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ctype.c b/ctype.c index b90ec004f2..7ee64c7d77 100644 --- a/ctype.c +++ b/ctype.c @@ -10,7 +10,7 @@ enum { A = GIT_ALPHA, D = GIT_DIGIT, G = GIT_GLOB_SPECIAL, /* *, ?, [, \\ */ - R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | * */ + R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | */ }; unsigned char sane_ctype[256] = { From b74fce16fa51362d4a3875d46e488006c3ad5371 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre <nico@cam.org> Date: Fri, 1 May 2009 16:56:47 -0400 Subject: [PATCH 535/654] allow OFS_DELTA objects during a push The fetching of OFS_DELTA objects has been negotiated between both peers since git version 1.4.4. However, this was missing from the push side where every OFS_DELTA objects were always converted to REF_DELTA objects causing an increase in transferred data. To fix this, both the client and the server processes have to be modified: the former to invoke pack-objects with --delta-base-offset when the server provides the ofs-delta capability, and the later to send that capability when OFS_DELTA objects are allowed as already indicated by the repack.usedeltabaseoffset config variable which is TRUE by default since git v1.6.0. Signed-off-by: Nicolas Pitre <nico@cam.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-receive-pack.c | 22 +++++++++++++++------- builtin-send-pack.c | 8 +++++++- send-pack.h | 1 + 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/builtin-receive-pack.c b/builtin-receive-pack.c index a970b39505..4b9d9218d1 100644 --- a/builtin-receive-pack.c +++ b/builtin-receive-pack.c @@ -27,10 +27,9 @@ static int receive_unpack_limit = -1; static int transfer_unpack_limit = -1; static int unpack_limit = 100; static int report_status; +static int prefer_ofs_delta = 1; static const char *head_name; - -static char capabilities[] = " report-status delete-refs "; -static int capabilities_sent; +static char *capabilities_to_send; static enum deny_action parse_deny_action(const char *var, const char *value) { @@ -84,24 +83,29 @@ static int receive_pack_config(const char *var, const char *value, void *cb) return 0; } + if (strcmp(var, "repack.usedeltabaseoffset") == 0) { + prefer_ofs_delta = git_config_bool(var, value); + return 0; + } + return git_default_config(var, value, cb); } static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data) { - if (capabilities_sent) + if (!capabilities_to_send) packet_write(1, "%s %s\n", sha1_to_hex(sha1), path); else packet_write(1, "%s %s%c%s\n", - sha1_to_hex(sha1), path, 0, capabilities); - capabilities_sent = 1; + sha1_to_hex(sha1), path, 0, capabilities_to_send); + capabilities_to_send = NULL; return 0; } static void write_head_info(void) { for_each_ref(show_ref, NULL); - if (!capabilities_sent) + if (capabilities_to_send) show_ref("capabilities^{}", null_sha1, 0, NULL); } @@ -687,6 +691,10 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) else if (0 <= receive_unpack_limit) unpack_limit = receive_unpack_limit; + capabilities_to_send = (prefer_ofs_delta) ? + " report-status delete-refs ofs-delta " : + " report-status delete-refs "; + add_alternate_refs(); write_head_info(); clear_extra_refs(); diff --git a/builtin-send-pack.c b/builtin-send-pack.c index d5a1c48d0e..473a3de40c 100644 --- a/builtin-send-pack.c +++ b/builtin-send-pack.c @@ -43,12 +43,16 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext "--stdout", NULL, NULL, + NULL, }; struct child_process po; int i; + i = 4; if (args->use_thin_pack) - argv[4] = "--thin"; + argv[i++] = "--thin"; + if (args->use_ofs_delta) + argv[i++] = "--delta-base-offset"; memset(&po, 0, sizeof(po)); po.argv = argv; po.in = -1; @@ -315,6 +319,8 @@ int send_pack(struct send_pack_args *args, ask_for_status_report = 1; if (server_supports("delete-refs")) allow_deleting_refs = 1; + if (server_supports("ofs-delta")) + args->use_ofs_delta = 1; if (!remote_refs) { fprintf(stderr, "No refs in common and none specified; doing nothing.\n" diff --git a/send-pack.h b/send-pack.h index 83d76c7e35..1d7b1b3b4f 100644 --- a/send-pack.h +++ b/send-pack.h @@ -6,6 +6,7 @@ struct send_pack_args { send_mirror:1, force_update:1, use_thin_pack:1, + use_ofs_delta:1, dry_run:1; }; From 503f464090d835ad333f5a55662ca0880c7b1d44 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Fri, 1 May 2009 23:31:00 -0700 Subject: [PATCH 536/654] GIT 1.6.3-rc4 Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/RelNotes-1.6.3.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/RelNotes-1.6.3.txt b/Documentation/RelNotes-1.6.3.txt index 7270ef893b..33209fe7fd 100644 --- a/Documentation/RelNotes-1.6.3.txt +++ b/Documentation/RelNotes-1.6.3.txt @@ -37,6 +37,12 @@ Updates since v1.6.2 * various git-svn updates. +* git-gui updates, including an update to Russian translation, and a + fix to an infinite loop when showing an empty diff. + +* gitk updates, including an update to Russian translation and improved Windows + support. + (performance) * many uses of lstat(2) in the codepath for "git checkout" have been From 226b343cde7624e4f273a45d83009799447c914b Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Sun, 3 May 2009 23:25:31 -0700 Subject: [PATCH 537/654] completion: add missing configuration variables to _git_config() Signed-off-by: Stephen Boyd <bebarino@gmail.com> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 48 ++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 1a90cb87f5..28682a79be 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1393,6 +1393,7 @@ _git_config () ;; esac __gitcomp " + alias. apply.whitespace branch.autosetupmerge branch.autosetuprebase @@ -1410,6 +1411,9 @@ _git_config () color.diff.old color.diff.plain color.diff.whitespace + color.grep + color.grep.external + color.grep.match color.interactive color.interactive.header color.interactive.help @@ -1427,6 +1431,7 @@ _git_config () core.autocrlf core.bare core.compression + core.createObject core.deltaBaseCacheLimit core.editor core.excludesfile @@ -1457,11 +1462,20 @@ _git_config () diff.renameLimit diff.renameLimit. diff.renames + diff.suppressBlankEmpty + diff.tool + diff.wordRegex + difftool.prompt fetch.unpackLimit + format.attach + format.cc format.headers format.numbered format.pretty + format.signoff + format.subjectprefix format.suffix + format.thread gc.aggressiveWindow gc.auto gc.autopacklimit @@ -1472,6 +1486,7 @@ _git_config () gc.rerereresolved gc.rerereunresolved gitcvs.allbinary + gitcvs.commitmsgannotation gitcvs.dbTableNamePrefix gitcvs.dbdriver gitcvs.dbname @@ -1506,13 +1521,23 @@ _git_config () http.sslVerify i18n.commitEncoding i18n.logOutputEncoding + imap.folder + imap.host + imap.pass + imap.port + imap.preformattedHTML + imap.sslverify + imap.tunnel + imap.user instaweb.browser instaweb.httpd instaweb.local instaweb.modulepath instaweb.port + interactive.singlekey log.date log.showroot + mailmap.file man.viewer merge.conflictstyle merge.log @@ -1521,6 +1546,7 @@ _git_config () merge.tool merge.verbosity mergetool.keepBackup + mergetool.prompt pack.compression pack.deltaCacheLimit pack.deltaCacheSize @@ -1532,6 +1558,8 @@ _git_config () pack.windowMemory pull.octopus pull.twohead + push.default + rebase.stat receive.denyCurrentBranch receive.denyDeletes receive.denyNonFastForwards @@ -1540,6 +1568,26 @@ _git_config () repack.usedeltabaseoffset rerere.autoupdate rerere.enabled + sendemail.aliasesfile + sendemail.aliasesfiletype + sendemail.bcc + sendemail.cc + sendemail.cccmd + sendemail.chainreplyto + sendemail.confirm + sendemail.envelopesender + sendemail.multiedit + sendemail.signedoffbycc + sendemail.smtpencryption + sendemail.smtppass + sendemail.smtpserver + sendemail.smtpserverport + sendemail.smtpuser + sendemail.suppresscc + sendemail.suppressfrom + sendemail.thread + sendemail.to + sendemail.validate showbranch.default status.relativePaths status.showUntrackedFiles From 0aa62fd0414b0e8a6271d1d0dd80e5f640633473 Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Sun, 3 May 2009 23:25:32 -0700 Subject: [PATCH 538/654] completion: add {gui,diff,merge}tool, man, and pager config variables Signed-off-by: Stephen Boyd <bebarino@gmail.com> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 45 ++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 28682a79be..ec02b06cf2 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1376,6 +1376,39 @@ _git_config () __gitcomp "$(__git_heads)" "$pfx" "$cur" "." return ;; + guitool.*.*) + local pfx="${cur%.*}." + cur="${cur##*.}" + __gitcomp " + argprompt cmd confirm needsfile noconsole norescan + prompt revprompt revunmerged title + " "$pfx" "$cur" + return + ;; + difftool.*.*) + local pfx="${cur%.*}." + cur="${cur##*.}" + __gitcomp "cmd path" "$pfx" "$cur" + return + ;; + man.*.*) + local pfx="${cur%.*}." + cur="${cur##*.}" + __gitcomp "cmd path" "$pfx" "$cur" + return + ;; + mergetool.*.*) + local pfx="${cur%.*}." + cur="${cur##*.}" + __gitcomp "cmd path trustExitCode" "$pfx" "$cur" + return + ;; + pager.*) + local pfx="${cur%.*}." + cur="${cur#*.}" + __gitcomp "$(__git_all_commands)" "$pfx" "$cur" + return + ;; remote.*.*) local pfx="${cur%.*}." cur="${cur##*.}" @@ -1391,6 +1424,12 @@ _git_config () __gitcomp "$(__git_remotes)" "$pfx" "$cur" "." return ;; + url.*.*) + local pfx="${cur%.*}." + cur="${cur##*.}" + __gitcomp "insteadof" "$pfx" "$cur" + return + ;; esac __gitcomp " alias. @@ -1465,6 +1504,7 @@ _git_config () diff.suppressBlankEmpty diff.tool diff.wordRegex + difftool. difftool.prompt fetch.unpackLimit format.attach @@ -1495,6 +1535,7 @@ _git_config () gitcvs.enabled gitcvs.logfile gitcvs.usecrlfattr + guitool. gui.blamehistoryctx gui.commitmsgwidth gui.copyblamethreshold @@ -1538,6 +1579,7 @@ _git_config () log.date log.showroot mailmap.file + man. man.viewer merge.conflictstyle merge.log @@ -1545,6 +1587,7 @@ _git_config () merge.stat merge.tool merge.verbosity + mergetool. mergetool.keepBackup mergetool.prompt pack.compression @@ -1556,6 +1599,7 @@ _git_config () pack.threads pack.window pack.windowMemory + pager. pull.octopus pull.twohead push.default @@ -1593,6 +1637,7 @@ _git_config () status.showUntrackedFiles tar.umask transfer.unpackLimit + url. user.email user.name user.signingkey From 9b82d63b5a109112643843a8e6d1a201fdf2ec63 Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Sun, 3 May 2009 23:25:33 -0700 Subject: [PATCH 539/654] completion: complete values for help.format Signed-off-by: Stephen Boyd <bebarino@gmail.com> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index ec02b06cf2..023b0c9974 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1348,6 +1348,10 @@ _git_config () " return ;; + help.format) + __gitcomp "man info web html" + return + ;; *.*) COMPREPLY=() return From 672c68cbb90921a133ddf71d002342a448b6dd38 Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Sun, 3 May 2009 23:25:34 -0700 Subject: [PATCH 540/654] completion: complete values for log.date Add raw to the date formats too. Signed-off-by: Stephen Boyd <bebarino@gmail.com> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 023b0c9974..d67ffd9384 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1116,6 +1116,7 @@ __git_log_shortlog_options=" " __git_log_pretty_formats="oneline short medium full fuller email raw format:" +__git_log_date_formats="relative iso8601 rfc2822 short local default raw" _git_log () { @@ -1139,9 +1140,7 @@ _git_log () return ;; --date=*) - __gitcomp " - relative iso8601 rfc2822 short local default - " "" "${cur##--date=}" + __gitcomp "$__git_log_date_formats" "" "${cur##--date=}" return ;; --*) @@ -1352,6 +1351,10 @@ _git_config () __gitcomp "man info web html" return ;; + log.date) + __gitcomp "$__git_log_date_formats" + return + ;; *.*) COMPREPLY=() return From ae616de6d53ef14ba11d2aa32f366086c1435dfa Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Sun, 3 May 2009 23:25:35 -0700 Subject: [PATCH 541/654] completion: complete values for send-email Add completion for --confirm, --suppress-cc, and --smtp-encryption command line arguments. Add completion for aliasfiletype and confirm configuration variables. Since --smtp-ssl is deprecated, replace it with --smtp-encryption and the two options ssl and tls. Signed-off-by: Stephen Boyd <bebarino@gmail.com> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 39 ++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index d67ffd9384..1683e6d7b8 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1282,18 +1282,39 @@ _git_rebase () __gitcomp "$(__git_refs)" } +__git_send_email_confirm_options="always never auto cc compose" +__git_send_email_suppresscc_options="author self cc ccbody sob cccmd body all" + _git_send_email () { local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in + --confirm=*) + __gitcomp " + $__git_send_email_confirm_options + " "" "${cur##--confirm=}" + return + ;; + --suppress-cc=*) + __gitcomp " + $__git_send_email_suppresscc_options + " "" "${cur##--suppress-cc=}" + + return + ;; + --smtp-encryption=*) + __gitcomp "ssl tls" "" "${cur##--smtp-encryption=}" + return + ;; --*) __gitcomp "--annotate --bcc --cc --cc-cmd --chain-reply-to - --compose --dry-run --envelope-sender --from --identity + --compose --confirm= --dry-run --envelope-sender + --from --identity --in-reply-to --no-chain-reply-to --no-signed-off-by-cc --no-suppress-from --no-thread --quiet --signed-off-by-cc --smtp-pass --smtp-server - --smtp-server-port --smtp-ssl --smtp-user --subject - --suppress-cc --suppress-from --thread --to + --smtp-server-port --smtp-encryption= --smtp-user + --subject --suppress-cc= --suppress-from --thread --to --validate --no-validate" return ;; @@ -1355,6 +1376,18 @@ _git_config () __gitcomp "$__git_log_date_formats" return ;; + sendemail.aliasesfiletype) + __gitcomp "mutt mailrc pine elm gnus" + return + ;; + sendemail.confirm) + __gitcomp "$__git_send_email_confirm_options" + return + ;; + sendemail.suppresscc) + __gitcomp "$__git_send_email_suppresscc_options" + return + ;; *.*) COMPREPLY=() return From 6a260f53ad685a51ecf6cd875f44cb2c056d1d18 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Wed, 6 May 2009 10:48:26 -0700 Subject: [PATCH 542/654] git-clean doc: the command only affects paths under $(cwd) Fredrik Skolmli and Thomas Rast noticed that it was left unstated that "git clean" ran from a subdirectory will not affect anything outside it, with or without path limiters. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-clean.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt index 43b2de7db3..be894af39f 100644 --- a/Documentation/git-clean.txt +++ b/Documentation/git-clean.txt @@ -13,8 +13,8 @@ SYNOPSIS DESCRIPTION ----------- -This allows cleaning the working tree by removing files that are not -under version control. +Cleans the working tree by recursively removing files that are not +under version control, starting from the current directory. Normally, only files unknown to git are removed, but if the '-x' option is specified, ignored files are also removed. This can, for From 0b05dc2b7e929996afa3f325cce593585f3ec9b3 Mon Sep 17 00:00:00 2001 From: Brandon Casey <casey@nrlssc.navy.mil> Date: Wed, 6 May 2009 13:31:42 -0500 Subject: [PATCH 543/654] t8005: use egrep when extended regular expressions are required Not all versions of grep understand backslashed extended regular expressions. Possibly only gnu grep does. Signed-off-by: Brandon Casey <casey@nrlssc.navy.mil> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t8005-blame-i18n.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/t/t8005-blame-i18n.sh b/t/t8005-blame-i18n.sh index 4470a92bb2..fcd5c26675 100755 --- a/t/t8005-blame-i18n.sh +++ b/t/t8005-blame-i18n.sh @@ -36,7 +36,7 @@ EOF test_expect_success \ 'blame respects i18n.commitencoding' ' git blame --incremental file | \ - grep "^\(author\|summary\) " > actual && + egrep "^(author|summary) " > actual && test_cmp actual expected ' @@ -53,7 +53,7 @@ test_expect_success \ 'blame respects i18n.logoutputencoding' ' git config i18n.logoutputencoding cp1251 && git blame --incremental file | \ - grep "^\(author\|summary\) " > actual && + egrep "^(author|summary) " > actual && test_cmp actual expected ' @@ -69,7 +69,7 @@ EOF test_expect_success \ 'blame respects --encoding=utf-8' ' git blame --incremental --encoding=utf-8 file | \ - grep "^\(author\|summary\) " > actual && + egrep "^(author|summary) " > actual && test_cmp actual expected ' @@ -85,7 +85,7 @@ EOF test_expect_success \ 'blame respects --encoding=none' ' git blame --incremental --encoding=none file | \ - grep "^\(author\|summary\) " > actual && + egrep "^(author|summary) " > actual && test_cmp actual expected ' From 723570469f54449e54dcc8bbb8f1dcbaff29d535 Mon Sep 17 00:00:00 2001 From: Brandon Casey <casey@nrlssc.navy.mil> Date: Wed, 6 May 2009 13:29:14 -0500 Subject: [PATCH 544/654] t4118: add missing '&&' Signed-off-by: Brandon Casey <casey@nrlssc.navy.mil> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t4118-apply-empty-context.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t4118-apply-empty-context.sh b/t/t4118-apply-empty-context.sh index f92e259cc6..314bc6e68d 100755 --- a/t/t4118-apply-empty-context.sh +++ b/t/t4118-apply-empty-context.sh @@ -20,7 +20,7 @@ test_expect_success setup ' cat file1 && echo Q | tr -d "\\012" } >file2 && - cat file2 >file2.orig + cat file2 >file2.orig && git add file1 file2 && sed -e "/^B/d" <file1.orig >file1 && sed -e "/^[BQ]/d" <file2.orig >file2 && From 325fb151047d668133cd456e78953f1b1aa09114 Mon Sep 17 00:00:00 2001 From: Brandon Casey <casey@nrlssc.navy.mil> Date: Wed, 6 May 2009 13:29:15 -0500 Subject: [PATCH 545/654] t4118: avoid sed invocation on file without terminating newline Some versions of sed exit non-zero if the file they are supplied is not newline terminated. Solaris's /usr/xpg4/bin/sed is one such sed. In this case the sed invocation can be avoided entirely since the resulting file is equivalent to a previously created file. So, just copy that file into place instead. Signed-off-by: Brandon Casey <casey@nrlssc.navy.mil> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t4118-apply-empty-context.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t4118-apply-empty-context.sh b/t/t4118-apply-empty-context.sh index 314bc6e68d..65f2e4c3ef 100755 --- a/t/t4118-apply-empty-context.sh +++ b/t/t4118-apply-empty-context.sh @@ -23,7 +23,7 @@ test_expect_success setup ' cat file2 >file2.orig && git add file1 file2 && sed -e "/^B/d" <file1.orig >file1 && - sed -e "/^[BQ]/d" <file2.orig >file2 && + cat file1 > file2 && echo Q | tr -d "\\012" >>file2 && cat file1 >file1.mods && cat file2 >file2.mods && From d8b69ecb4c467c044c08e0435bb22ade16ea580f Mon Sep 17 00:00:00 2001 From: Brandon Casey <casey@nrlssc.navy.mil> Date: Wed, 6 May 2009 13:29:16 -0500 Subject: [PATCH 546/654] t/annotate-tests.sh: avoid passing a non-newline terminated file to sed Some versions of sed exit non-zero if the file they are supplied is not newline terminated. Solaris's /usr/xpg4/bin/sed is one such sed. So rework this test to avoid doing so. This affects tests t8001-annotate.sh and t8002-blame.sh. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/annotate-tests.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index cacb273aff..396b9653a3 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -114,7 +114,10 @@ test_expect_success \ test_expect_success \ 'some edit' \ 'mv file file.orig && - sed -e "s/^3A/99/" -e "/^1A/d" -e "/^incomplete/d" < file.orig > file && + { + cat file.orig && + echo + } | sed -e "s/^3A/99/" -e "/^1A/d" -e "/^incomplete/d" > file && echo "incomplete" | tr -d "\\012" >>file && GIT_AUTHOR_NAME="D" git commit -a -m "edit"' From 9eda0e980a43e6bf5167e1b35f457f970bec7b74 Mon Sep 17 00:00:00 2001 From: Brandon Casey <casey@nrlssc.navy.mil> Date: Wed, 6 May 2009 17:56:17 -0500 Subject: [PATCH 547/654] t4200: remove two unnecessary lines These two lines appear to be unnecessary. They set variables which are not used afterwards. The primary motivation to remove them is that the sed invocation exits non-zero for seds which require newline termination of input files. Signed-off-by: Brandon Casey <casey@nrlssc.navy.mil> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t4200-rerere.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh index b68ab11f29..504802c987 100755 --- a/t/t4200-rerere.sh +++ b/t/t4200-rerere.sh @@ -190,8 +190,6 @@ test_expect_success 'file2 added differently in two branches' ' git add file2 && git commit -m version2 && test_must_fail git merge fourth && - sha1=$(sed -e "s/ .*//" .git/MERGE_RR) && - rr=.git/rr-cache/$sha1 && echo Cello > file2 && git add file2 && git commit -m resolution From 5e16488edc3cf9d5c30d08fcd9b74525198d6184 Mon Sep 17 00:00:00 2001 From: Brandon Casey <casey@nrlssc.navy.mil> Date: Wed, 6 May 2009 17:56:18 -0500 Subject: [PATCH 548/654] t4200: convert sed expression which operates on non-text file to perl POSIX only requires sed to work on text files and MERGE_RR is not a text file. Some versions of sed complain that this file is not newline terminated, and exit non-zero. Use perl instead which does not have a problem with it. Signed-off-by: Brandon Casey <casey@nrlssc.navy.mil> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t4200-rerere.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh index 504802c987..a6bc028a57 100755 --- a/t/t4200-rerere.sh +++ b/t/t4200-rerere.sh @@ -57,7 +57,7 @@ test_expect_success 'conflicting merge' ' test_must_fail git merge first ' -sha1=$(sed -e 's/ .*//' .git/MERGE_RR) +sha1=$(perl -pe 's/ .*//' .git/MERGE_RR) rr=.git/rr-cache/$sha1 test_expect_success 'recorded preimage' "grep ^=======$ $rr/preimage" From c5ae7cb6d94f37deedd5dcf92a6608ca7d3ce081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= <pclouds@gmail.com> Date: Thu, 7 May 2009 00:33:34 +1000 Subject: [PATCH 549/654] t4029: use sh instead of bash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t4029-diff-trailing-space.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh index 9ddbbcde57..3ccc237a8d 100755 --- a/t/t4029-diff-trailing-space.sh +++ b/t/t4029-diff-trailing-space.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # Copyright (c) Jim Meyering # From f01f1099f40f24fe6f7802185340a6fa3a3d4f35 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Wed, 6 May 2009 17:13:27 -0700 Subject: [PATCH 550/654] GIT 1.6.3 Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/RelNotes-1.6.3.txt | 6 ------ Documentation/git.txt | 4 +++- GIT-VERSION-GEN | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Documentation/RelNotes-1.6.3.txt b/Documentation/RelNotes-1.6.3.txt index 33209fe7fd..418c685cf8 100644 --- a/Documentation/RelNotes-1.6.3.txt +++ b/Documentation/RelNotes-1.6.3.txt @@ -180,9 +180,3 @@ v1.6.2.X series. * git-gc spent excessive amount of time to decide if an object appears in a locally existing pack (if needed, backport by merging 69e020a). - ---- -exec >/var/tmp/1 -O=v1.6.3-rc2 -echo O=$(git describe master) -git shortlog --no-merges $O..master ^maint diff --git a/Documentation/git.txt b/Documentation/git.txt index 470fdc5ecd..9d8f236fe8 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,11 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.6.2.3/git.html[documentation for release 1.6.2.3] +* link:v1.6.3/git.html[documentation for release 1.6.3] * release notes for + link:RelNotes-1.6.2.5.txt[1.6.2.5], + link:RelNotes-1.6.2.4.txt[1.6.2.4], link:RelNotes-1.6.2.3.txt[1.6.2.3], link:RelNotes-1.6.2.2.txt[1.6.2.2], link:RelNotes-1.6.2.1.txt[1.6.2.1], diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 97fc1e0519..39cde784c9 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.6.2.GIT +DEF_VER=v1.6.3.GIT LF=' ' From 6207011ae3fe813159e92762e86f33c9bd42cd7f Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Fri, 8 May 2009 21:49:14 -0700 Subject: [PATCH 551/654] Start 1.6.3.1 maintenance series. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/RelNotes-1.6.3.1.txt | 12 ++++++++++++ RelNotes | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 Documentation/RelNotes-1.6.3.1.txt diff --git a/Documentation/RelNotes-1.6.3.1.txt b/Documentation/RelNotes-1.6.3.1.txt new file mode 100644 index 0000000000..98c02250bb --- /dev/null +++ b/Documentation/RelNotes-1.6.3.1.txt @@ -0,0 +1,12 @@ +GIT v1.6.3.1 Release Notes +========================== + +Fixes since v1.6.3 +------------------ + +-- +exec >/var/tmp/1 +O=v1.6.3 +echo O=$(git describe maint) +git shortlog $O..maint + diff --git a/RelNotes b/RelNotes index dd8bc4bb4a..0f6a588f1d 120000 --- a/RelNotes +++ b/RelNotes @@ -1 +1 @@ -Documentation/RelNotes-1.6.3.txt \ No newline at end of file +Documentation/RelNotes-1.6.3.1.txt \ No newline at end of file From 5a0e4a2a326966aabb566164a7571291e34adabd Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Fri, 8 May 2009 21:56:57 -0700 Subject: [PATCH 552/654] Start 1.6.4 development Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/RelNotes-1.6.4.txt | 59 ++++++++++++++++++++++++++++++++ RelNotes | 2 +- 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 Documentation/RelNotes-1.6.4.txt diff --git a/Documentation/RelNotes-1.6.4.txt b/Documentation/RelNotes-1.6.4.txt new file mode 100644 index 0000000000..b70ec11c26 --- /dev/null +++ b/Documentation/RelNotes-1.6.4.txt @@ -0,0 +1,59 @@ +GIT v1.6.4 Release Notes +======================== + +With the next major release, "git push" into a branch that is +currently checked out will be refused by default. You can choose +what should happen upon such a push by setting the configuration +variable receive.denyCurrentBranch in the receiving repository. + +To ease the transition plan, the receiving repository of such a +push running this release will issue a big warning when the +configuration variable is missing. Please refer to: + + http://git.or.cz/gitwiki/GitFaq#non-bare + http://thread.gmane.org/gmane.comp.version-control.git/107758/focus=108007 + +for more details on the reason why this change is needed and the +transition plan. + +For a similar reason, "git push $there :$killed" to delete the branch +$killed in a remote repository $there, if $killed branch is the current +branch pointed at by its HEAD, gets a large warning. You can choose what +should happen upon such a push by setting the configuration variable +receive.denyDeleteCurrent in the receiving repository. + +When the user does not tell "git push" what to push, it has always +pushed matching refs. For some people it is unexpected, and a new +configuration variable push.default has been introduced to allow +changing a different default behaviour. To advertise the new feature, +a big warning is issued if this is not configured and a git push without +arguments is attempted. + + +Updates since v1.6.3 +-------------------- + +(subsystems) + +(performance) + +(usability, bells and whistles) + +(developers) + + +Fixes since v1.6.3 +------------------ + +All of the fixes in v1.6.3.X maintenance series are included in this +release, unless otherwise noted. + +Here are fixes that this release has, but have not been backported to +v1.6.3.X series. + + +--- +exec >/var/tmp/1 +echo O=$(git describe master) +O=v1.6.3 +git shortlog --no-merges $O..master ^maint diff --git a/RelNotes b/RelNotes index 0f6a588f1d..f8e49a5070 120000 --- a/RelNotes +++ b/RelNotes @@ -1 +1 @@ -Documentation/RelNotes-1.6.3.1.txt \ No newline at end of file +Documentation/RelNotes-1.6.4.txt \ No newline at end of file From 3e1629f5a6c832941cc329c381de8b88ea775cb6 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Thu, 7 May 2009 01:08:19 -0700 Subject: [PATCH 553/654] archive-tar.c: squelch a type mismatch warning On some systems, giving a value of type time_t to printf "%lo" that expects an unsigned long would give a type mismatch warning. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- archive-tar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archive-tar.c b/archive-tar.c index ba890ebdec..cee06ce3cb 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -180,7 +180,7 @@ static int write_tar_entry(struct archiver_args *args, sprintf(header.mode, "%07o", mode & 07777); sprintf(header.size, "%011lo", S_ISREG(mode) ? size : 0); - sprintf(header.mtime, "%011lo", args->time); + sprintf(header.mtime, "%011lo", (unsigned long) args->time); sprintf(header.uid, "%07o", 0); sprintf(header.gid, "%07o", 0); From ac9f71cf766ab1affdfc4d4c4b58238bf9c76700 Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Thu, 7 May 2009 01:57:08 +0300 Subject: [PATCH 554/654] git config: clarify --add and --get-color Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-config.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index 7131ee3c66..f68b198205 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -69,7 +69,8 @@ OPTIONS --add:: Adds a new line to the option without altering any existing - values. This is the same as providing '^$' as the value_regex. + values. This is the same as providing '^$' as the value_regex + in `--replace-all`. --get:: Get the value for a given key (optionally filtered by a regex @@ -155,7 +156,7 @@ See also <<FILES>>. When the color setting for `name` is undefined, the command uses `color.ui` as fallback. ---get-color name default:: +--get-color name [default]:: Find the color configured for `name` (e.g. `color.diff.new`) and output it as the ANSI color escape sequence to the standard From 718135e3b6b5317f763477f5b0f408d888d79a8e Mon Sep 17 00:00:00 2001 From: Alex Riesen <raa.lkml@gmail.com> Date: Wed, 29 Apr 2009 23:40:50 +0200 Subject: [PATCH 555/654] Clarify kind of conflict in merge-one-file helper Not as verbose as the recursive merge driver, but better still. Signed-off-by: Alex Riesen <raa.lkml@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-merge-one-file.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh index e1eb963266..9c2c1b7202 100755 --- a/git-merge-one-file.sh +++ b/git-merge-one-file.sh @@ -113,6 +113,10 @@ case "${1:-.}${2:-.}${3:-.}" in src1=`git-unpack-file $2` git merge-file "$src1" "$orig" "$src2" ret=$? + msg= + if [ $ret -ne 0 ]; then + msg='content conflict' + fi # Create the working tree file, using "our tree" version from the # index, and then store the result of the merge. @@ -120,7 +124,10 @@ case "${1:-.}${2:-.}${3:-.}" in rm -f -- "$orig" "$src1" "$src2" if [ "$6" != "$7" ]; then - echo "ERROR: Permissions conflict: $5->$6,$7." + if [ -n "$msg" ]; then + msg="$msg, " + fi + msg="${msg}permissions conflict: $5->$6,$7" ret=1 fi if [ "$1" = '' ]; then @@ -128,7 +135,7 @@ case "${1:-.}${2:-.}${3:-.}" in fi if [ $ret -ne 0 ]; then - echo "ERROR: Merge conflict in $4" + echo "ERROR: $msg in $4" exit 1 fi exec git update-index -- "$4" From 2f4b97f91071f5060bf2da482cf8b0d70486d808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Thu, 7 May 2009 21:44:17 +0200 Subject: [PATCH 556/654] parseopt: add OPT_NEGBIT Add OPTION_NEGBIT and OPT_NEGBIT, mirroring OPTION_BIT and OPT_BIT. OPT_NEGBIT can be used together with OPT_BIT to define two options that cancel each other out. Note: this patch removes the reminder from the test script because it adds a test for --no-or4 and there already was one for --or4. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/technical/api-parse-options.txt | 4 +++ parse-options.c | 8 +++++ parse-options.h | 2 ++ t/t0040-parse-options.sh | 31 +++++++++++++++++-- test-parse-options.c | 1 + 5 files changed, 44 insertions(+), 2 deletions(-) diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt index e66ca9f70c..794194bad6 100644 --- a/Documentation/technical/api-parse-options.txt +++ b/Documentation/technical/api-parse-options.txt @@ -137,6 +137,10 @@ There are some macros to easily define options: Introduce a boolean option. If used, `int_var` is bitwise-ored with `mask`. +`OPT_NEGBIT(short, long, &int_var, description, mask)`:: + Introduce a boolean option. + If used, `int_var` is bitwise-anded with the inverted `mask`. + `OPT_SET_INT(short, long, &int_var, description, integer)`:: Introduce a boolean option. If used, set `int_var` to `integer`. diff --git a/parse-options.c b/parse-options.c index cf71bcffd2..a8c05e3dc2 100644 --- a/parse-options.c +++ b/parse-options.c @@ -50,6 +50,7 @@ static int get_value(struct parse_opt_ctx_t *p, /* FALLTHROUGH */ case OPTION_BOOLEAN: case OPTION_BIT: + case OPTION_NEGBIT: case OPTION_SET_INT: case OPTION_SET_PTR: return opterror(opt, "takes no value", flags); @@ -66,6 +67,13 @@ static int get_value(struct parse_opt_ctx_t *p, *(int *)opt->value |= opt->defval; return 0; + case OPTION_NEGBIT: + if (unset) + *(int *)opt->value |= opt->defval; + else + *(int *)opt->value &= ~opt->defval; + return 0; + case OPTION_BOOLEAN: *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1; return 0; diff --git a/parse-options.h b/parse-options.h index b54eec128b..f1e2452f69 100644 --- a/parse-options.h +++ b/parse-options.h @@ -8,6 +8,7 @@ enum parse_opt_type { OPTION_GROUP, /* options with no arguments */ OPTION_BIT, + OPTION_NEGBIT, OPTION_BOOLEAN, /* _INCR would have been a better name */ OPTION_SET_INT, OPTION_SET_PTR, @@ -93,6 +94,7 @@ struct option { #define OPT_ARGUMENT(l, h) { OPTION_ARGUMENT, 0, (l), NULL, NULL, (h) } #define OPT_GROUP(h) { OPTION_GROUP, 0, NULL, NULL, NULL, (h) } #define OPT_BIT(s, l, v, h, b) { OPTION_BIT, (s), (l), (v), NULL, (h), 0, NULL, (b) } +#define OPT_NEGBIT(s, l, v, h, b) { OPTION_NEGBIT, (s), (l), (v), NULL, (h), 0, NULL, (b) } #define OPT_BOOLEAN(s, l, v, h) { OPTION_BOOLEAN, (s), (l), (v), NULL, (h) } #define OPT_SET_INT(s, l, v, h, i) { OPTION_SET_INT, (s), (l), (v), NULL, (h), 0, NULL, (i) } #define OPT_SET_PTR(s, l, v, h, p) { OPTION_SET_PTR, (s), (l), (v), NULL, (h), 0, NULL, (p) } diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index e38241c80a..9054ed6030 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -12,6 +12,7 @@ usage: test-parse-options <options> -b, --boolean get a boolean -4, --or4 bitwise-or boolean with ...0100 + --neg-or4 same as --no-or4 -i, --integer <n> get a integer -j <n> get a integer, too @@ -245,7 +246,33 @@ test_expect_success 'OPT_BIT() and OPT_SET_INT() work' ' test_cmp expect output ' -# --or4 -# --no-or4 +test_expect_success 'OPT_NEGBIT() and OPT_SET_INT() work' ' + test-parse-options --set23 -bbbbb --neg-or4 > output 2> output.err && + test ! -s output.err && + test_cmp expect output +' + +cat > expect <<EOF +boolean: 6 +integer: 0 +timestamp: 0 +string: (not set) +abbrev: 7 +verbose: 0 +quiet: no +dry run: no +EOF + +test_expect_success 'OPT_BIT() works' ' + test-parse-options -bb --or4 > output 2> output.err && + test ! -s output.err && + test_cmp expect output +' + +test_expect_success 'OPT_NEGBIT() works' ' + test-parse-options -bb --no-neg-or4 > output 2> output.err && + test ! -s output.err && + test_cmp expect output +' test_done diff --git a/test-parse-options.c b/test-parse-options.c index 61d2c39814..eddc0267a2 100644 --- a/test-parse-options.c +++ b/test-parse-options.c @@ -29,6 +29,7 @@ int main(int argc, const char **argv) OPT_BOOLEAN('b', "boolean", &boolean, "get a boolean"), OPT_BIT('4', "or4", &boolean, "bitwise-or boolean with ...0100", 4), + OPT_NEGBIT(0, "neg-or4", &boolean, "same as --no-or4", 4), OPT_GROUP(""), OPT_INTEGER('i', "integer", &integer, "get a integer"), OPT_INTEGER('j', NULL, &integer, "get a integer, too"), From e9008b9a44f46e97f39c424240ade0a6e6429cab Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Fri, 8 May 2009 01:01:17 -0400 Subject: [PATCH 557/654] parseopt: add OPT_NEGBIT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Thu, May 07, 2009 at 09:44:17PM +0200, René Scharfe wrote: Subject: [PATCH] ls-files: make --no-empty-directory properly negatable This option was specified to parseopt as an OPT_BIT; however, we actually want to _set_ the bit on --no-empty-directory. Thus the existing implementation used --no-empty-directory, and required --no-no-empty-directory to negate it. Now that OPT_NEGBIT exists, we can properly support it as --empty-directory and --no-empty-directory (but of course still defaulting to showing empty directories). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-ls-files.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-ls-files.c b/builtin-ls-files.c index da2daf45ac..3d59b0e140 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -454,7 +454,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) OPT_BIT(0, "directory", &dir.flags, "show 'other' directories' name only", DIR_SHOW_OTHER_DIRECTORIES), - OPT_BIT(0, "no-empty-directory", &dir.flags, + OPT_NEGBIT(0, "empty-directory", &dir.flags, "don't show empty directories", DIR_HIDE_EMPTY_DIRECTORIES), OPT_BOOLEAN('u', "unmerged", &show_unmerged, From e0319ff5ed2b7927302389181449dcd029a26622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Thu, 7 May 2009 21:45:08 +0200 Subject: [PATCH 558/654] parseopt: add OPT_NUMBER_CALLBACK Add a way to recognize numerical options. The number is passed to a callback function as a string. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/technical/api-parse-options.txt | 8 ++++++ parse-options.c | 26 ++++++++++++++++++- parse-options.h | 4 +++ t/t0040-parse-options.sh | 18 +++++++++++++ test-parse-options.c | 8 ++++++ 5 files changed, 63 insertions(+), 1 deletion(-) diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt index 794194bad6..beca98d754 100644 --- a/Documentation/technical/api-parse-options.txt +++ b/Documentation/technical/api-parse-options.txt @@ -170,6 +170,14 @@ There are some macros to easily define options: `OPT_ARGUMENT(long, description)`:: Introduce a long-option argument that will be kept in `argv[]`. +`OPT_NUMBER_CALLBACK(&var, description, func_ptr)`:: + Recognize numerical options like -123 and feed the integer as + if it was an argument to the function given by `func_ptr`. + The result will be put into `var`. There can be only one such + option definition. It cannot be negated and it takes no + arguments. Short options that happen to be digits take + precedence over it. + The last element of the array must be `OPT_END()`. diff --git a/parse-options.c b/parse-options.c index a8c05e3dc2..aaa218d191 100644 --- a/parse-options.c +++ b/parse-options.c @@ -129,11 +129,33 @@ static int get_value(struct parse_opt_ctx_t *p, static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options) { + const struct option *numopt = NULL; + for (; options->type != OPTION_END; options++) { if (options->short_name == *p->opt) { p->opt = p->opt[1] ? p->opt + 1 : NULL; return get_value(p, options, OPT_SHORT); } + + /* + * Handle the numerical option later, explicit one-digit + * options take precedence over it. + */ + if (options->type == OPTION_NUMBER) + numopt = options; + } + if (numopt && isdigit(*p->opt)) { + size_t len = 1; + char *arg; + int rc; + + while (isdigit(p->opt[len])) + len++; + arg = xmemdupz(p->opt, len); + p->opt = p->opt[len] ? p->opt + len : NULL; + rc = (*numopt->callback)(numopt, arg, 0) ? (-1) : 0; + free(arg); + return rc; } return -2; } @@ -411,6 +433,8 @@ int usage_with_options_internal(const char * const *usagestr, pos += fprintf(stderr, ", "); if (opts->long_name) pos += fprintf(stderr, "--%s", opts->long_name); + if (opts->type == OPTION_NUMBER) + pos += fprintf(stderr, "-NUM"); switch (opts->type) { case OPTION_ARGUMENT: @@ -447,7 +471,7 @@ int usage_with_options_internal(const char * const *usagestr, pos += fprintf(stderr, " ..."); } break; - default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */ + default: /* OPTION_{BIT,BOOLEAN,NUMBER,SET_INT,SET_PTR} */ break; } diff --git a/parse-options.h b/parse-options.h index f1e2452f69..77919a77fb 100644 --- a/parse-options.h +++ b/parse-options.h @@ -6,6 +6,7 @@ enum parse_opt_type { OPTION_END, OPTION_ARGUMENT, OPTION_GROUP, + OPTION_NUMBER, /* options with no arguments */ OPTION_BIT, OPTION_NEGBIT, @@ -105,6 +106,9 @@ struct option { parse_opt_approxidate_cb } #define OPT_CALLBACK(s, l, v, a, h, f) \ { OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) } +#define OPT_NUMBER_CALLBACK(v, h, f) \ + { OPTION_NUMBER, 0, NULL, (v), NULL, (h), \ + PARSE_OPT_NOARG | PARSE_OPT_NONEG, (f) } /* parse_options() will filter out the processed options and leave the * non-option arguments in argv[]. diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index 9054ed6030..8ca62ef453 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -30,6 +30,7 @@ String options Magic arguments --quux means --quux + -NUM set integer to NUM Standard options --abbrev[=<n>] use <n> digits to display SHA-1s @@ -275,4 +276,21 @@ test_expect_success 'OPT_NEGBIT() works' ' test_cmp expect output ' +cat > expect <<EOF +boolean: 0 +integer: 12345 +timestamp: 0 +string: (not set) +abbrev: 7 +verbose: 0 +quiet: no +dry run: no +EOF + +test_expect_success 'OPT_NUMBER_CALLBACK() works' ' + test-parse-options -12345 > output 2> output.err && + test ! -s output.err && + test_cmp expect output +' + test_done diff --git a/test-parse-options.c b/test-parse-options.c index eddc0267a2..d46eac21b1 100644 --- a/test-parse-options.c +++ b/test-parse-options.c @@ -19,6 +19,12 @@ int length_callback(const struct option *opt, const char *arg, int unset) return 0; } +int number_callback(const struct option *opt, const char *arg, int unset) +{ + *(int *)opt->value = strtol(arg, NULL, 10); + return 0; +} + int main(int argc, const char **argv) { const char *usage[] = { @@ -46,6 +52,8 @@ int main(int argc, const char **argv) "set string to default", (unsigned long)"default"), OPT_GROUP("Magic arguments"), OPT_ARGUMENT("quux", "means --quux"), + OPT_NUMBER_CALLBACK(&integer, "set integer to NUM", + number_callback), OPT_GROUP("Standard options"), OPT__ABBREV(&abbrev), OPT__VERBOSE(&verbose), From 51a9949eda7421a2dd9cb45b2110d6571ba09bbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Thu, 7 May 2009 21:45:42 +0200 Subject: [PATCH 559/654] parseopt: add PARSE_OPT_NODASH Add support for options that don't start with a dash. Initially, they don't accept arguments and can only be short options, i.e. consist of a single character. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- parse-options.c | 29 +++++++++++++++++++++++++++-- parse-options.h | 8 ++++++-- t/t0040-parse-options.sh | 7 +++++++ test-parse-options.c | 2 ++ 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/parse-options.c b/parse-options.c index aaa218d191..c52b8ccf59 100644 --- a/parse-options.c +++ b/parse-options.c @@ -245,6 +245,25 @@ is_abbreviated: return -2; } +static int parse_nodash_opt(struct parse_opt_ctx_t *p, const char *arg, + const struct option *options) +{ + for (; options->type != OPTION_END; options++) { + if (!(options->flags & PARSE_OPT_NODASH)) + continue; + if ((options->flags & PARSE_OPT_OPTARG) || + !(options->flags & PARSE_OPT_NOARG)) + die("BUG: dashless options don't support arguments"); + if (!(options->flags & PARSE_OPT_NONEG)) + die("BUG: dashless options don't support negation"); + if (options->long_name) + die("BUG: dashless options can't be long"); + if (options->short_name == arg[0] && arg[1] == '\0') + return get_value(p, options, OPT_SHORT); + } + return -2; +} + static void check_typos(const char *arg, const struct option *options) { if (strlen(arg) < 3) @@ -295,6 +314,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, const char *arg = ctx->argv[0]; if (*arg != '-' || !arg[1]) { + if (parse_nodash_opt(ctx, arg, options) == 0) + continue; if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION) break; ctx->out[ctx->cpidx++] = ctx->argv[0]; @@ -427,8 +448,12 @@ int usage_with_options_internal(const char * const *usagestr, continue; pos = fprintf(stderr, " "); - if (opts->short_name) - pos += fprintf(stderr, "-%c", opts->short_name); + if (opts->short_name) { + if (opts->flags & PARSE_OPT_NODASH) + pos += fprintf(stderr, "%c", opts->short_name); + else + pos += fprintf(stderr, "-%c", opts->short_name); + } if (opts->long_name && opts->short_name) pos += fprintf(stderr, ", "); if (opts->long_name) diff --git a/parse-options.h b/parse-options.h index 77919a77fb..919b9b441f 100644 --- a/parse-options.h +++ b/parse-options.h @@ -33,6 +33,7 @@ enum parse_opt_option_flags { PARSE_OPT_NONEG = 4, PARSE_OPT_HIDDEN = 8, PARSE_OPT_LASTARG_DEFAULT = 16, + PARSE_OPT_NODASH = 32, }; struct option; @@ -66,8 +67,11 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset); * PARSE_OPT_OPTARG: says that the argument is optional (not for BOOLEANs) * PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs * PARSE_OPT_NONEG: says that this option cannot be negated - * PARSE_OPT_HIDDEN this option is skipped in the default usage, showed in - * the long one. + * PARSE_OPT_HIDDEN: this option is skipped in the default usage, and + * shown only in the full usage. + * PARSE_OPT_LASTARG_DEFAULT: if no argument is given, the default value + * is used. + * PARSE_OPT_NODASH: this option doesn't start with a dash. * * `callback`:: * pointer to the callback to use for OPTION_CALLBACK. diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index 8ca62ef453..a40c1236c0 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -31,6 +31,7 @@ String options Magic arguments --quux means --quux -NUM set integer to NUM + + same as -b Standard options --abbrev[=<n>] use <n> digits to display SHA-1s @@ -276,6 +277,12 @@ test_expect_success 'OPT_NEGBIT() works' ' test_cmp expect output ' +test_expect_success 'OPT_BOOLEAN() with PARSE_OPT_NODASH works' ' + test-parse-options + + + + + + > output 2> output.err && + test ! -s output.err && + test_cmp expect output +' + cat > expect <<EOF boolean: 0 integer: 12345 diff --git a/test-parse-options.c b/test-parse-options.c index d46eac21b1..e0669dcb41 100644 --- a/test-parse-options.c +++ b/test-parse-options.c @@ -54,6 +54,8 @@ int main(int argc, const char **argv) OPT_ARGUMENT("quux", "means --quux"), OPT_NUMBER_CALLBACK(&integer, "set integer to NUM", number_callback), + { OPTION_BOOLEAN, '+', NULL, &boolean, NULL, "same as -b", + PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH }, OPT_GROUP("Standard options"), OPT__ABBREV(&abbrev), OPT__VERBOSE(&verbose), From 1b5fb44ad1131112fcc2b2b082fda61260e31570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Thu, 7 May 2009 21:46:17 +0200 Subject: [PATCH 560/654] grep: remove global variable builtin_grep Replace the only global variable in builtin-grep.c, builtin_grep, by a local one and a function parameter with reversed meaning. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-grep.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/builtin-grep.c b/builtin-grep.c index f88a912ace..620399f9ab 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -20,8 +20,6 @@ #endif #endif -static int builtin_grep; - static int grep_config(const char *var, const char *value, void *cb) { struct grep_opt *opt = cb; @@ -432,7 +430,8 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached) } #endif -static int grep_cache(struct grep_opt *opt, const char **paths, int cached) +static int grep_cache(struct grep_opt *opt, const char **paths, int cached, + int external_grep_allowed) { int hit = 0; int nr; @@ -444,7 +443,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) * we grep through the checked-out files. It tends to * be a lot more optimized */ - if (!cached && !builtin_grep) { + if (!cached && external_grep_allowed) { hit = external_grep(opt, paths, cached); if (hit >= 0) return hit; @@ -574,6 +573,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) { int hit = 0; int cached = 0; + int external_grep_allowed = 1; int seen_dashdash = 0; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; @@ -612,7 +612,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) continue; } if (!strcmp("--no-ext-grep", arg)) { - builtin_grep = 1; + external_grep_allowed = 0; continue; } if (!strcmp("-a", arg) || @@ -823,7 +823,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (opt.color && !opt.color_external) - builtin_grep = 1; + external_grep_allowed = 0; if (!opt.pattern_list) die("no pattern given."); if ((opt.regflags != REG_NEWLINE) && opt.fixed) @@ -874,7 +874,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (!list.nr) { if (!cached) setup_work_tree(); - return !grep_cache(&opt, paths, cached); + return !grep_cache(&opt, paths, cached, external_grep_allowed); } if (cached) From 3e230fa1b2ba3aa1a207c4399a1b93e41b103dfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Thu, 7 May 2009 21:46:48 +0200 Subject: [PATCH 561/654] grep: use parseopt Convert git-grep to parseopt. The bitfields in struct grep_opt are converted to full ints, increasing its size. This shouldn't be a problem as there is only a single instance in memory. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-grep.c | 404 ++++++++++++++++++++++--------------------------- grep.h | 28 ++-- 2 files changed, 193 insertions(+), 239 deletions(-) diff --git a/builtin-grep.c b/builtin-grep.c index 620399f9ab..169a91c17e 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -10,6 +10,7 @@ #include "tag.h" #include "tree-walk.h" #include "builtin.h" +#include "parse-options.h" #include "grep.h" #ifndef NO_EXTERNAL_GREP @@ -20,6 +21,11 @@ #endif #endif +static char const * const grep_usage[] = { + "git grep [options] [-e] <pattern> [<rev>...] [[--] path...]", + NULL +}; + static int grep_config(const char *var, const char *value, void *cb) { struct grep_opt *opt = cb; @@ -559,15 +565,86 @@ static int grep_object(struct grep_opt *opt, const char **paths, die("unable to grep from object of type %s", typename(obj->type)); } -static const char builtin_grep_usage[] = -"git grep <option>* [-e] <pattern> <rev>* [[--] <path>...]"; +int context_callback(const struct option *opt, const char *arg, int unset) +{ + struct grep_opt *grep_opt = opt->value; + int value; + const char *endp; -static const char emsg_invalid_context_len[] = -"%s: invalid context length argument"; -static const char emsg_missing_context_len[] = -"missing context length argument"; -static const char emsg_missing_argument[] = -"option requires an argument -%s"; + if (unset) { + grep_opt->pre_context = grep_opt->post_context = 0; + return 0; + } + value = strtol(arg, (char **)&endp, 10); + if (*endp) { + return error("switch `%c' expects a numerical value", + opt->short_name); + } + grep_opt->pre_context = grep_opt->post_context = value; + return 0; +} + +int file_callback(const struct option *opt, const char *arg, int unset) +{ + struct grep_opt *grep_opt = opt->value; + FILE *patterns; + int lno = 0; + struct strbuf sb; + + patterns = fopen(arg, "r"); + if (!patterns) + die("'%s': %s", arg, strerror(errno)); + while (strbuf_getline(&sb, patterns, '\n') == 0) { + /* ignore empty line like grep does */ + if (sb.len == 0) + continue; + append_grep_pattern(grep_opt, strbuf_detach(&sb, NULL), arg, + ++lno, GREP_PATTERN); + } + fclose(patterns); + strbuf_release(&sb); + return 0; +} + +int not_callback(const struct option *opt, const char *arg, int unset) +{ + struct grep_opt *grep_opt = opt->value; + append_grep_pattern(grep_opt, "--not", "command line", 0, GREP_NOT); + return 0; +} + +int and_callback(const struct option *opt, const char *arg, int unset) +{ + struct grep_opt *grep_opt = opt->value; + append_grep_pattern(grep_opt, "--and", "command line", 0, GREP_AND); + return 0; +} + +int open_callback(const struct option *opt, const char *arg, int unset) +{ + struct grep_opt *grep_opt = opt->value; + append_grep_pattern(grep_opt, "(", "command line", 0, GREP_OPEN_PAREN); + return 0; +} + +int close_callback(const struct option *opt, const char *arg, int unset) +{ + struct grep_opt *grep_opt = opt->value; + append_grep_pattern(grep_opt, ")", "command line", 0, GREP_CLOSE_PAREN); + return 0; +} + +int pattern_callback(const struct option *opt, const char *arg, int unset) +{ + struct grep_opt *grep_opt = opt->value; + append_grep_pattern(grep_opt, arg, "-e option", 0, GREP_PATTERN); + return 0; +} + +int help_callback(const struct option *opt, const char *arg, int unset) +{ + return -1; +} int cmd_grep(int argc, const char **argv, const char *prefix) { @@ -579,6 +656,89 @@ int cmd_grep(int argc, const char **argv, const char *prefix) struct object_array list = { 0, 0, NULL }; const char **paths = NULL; int i; + int dummy; + struct option options[] = { + OPT_BOOLEAN(0, "cached", &cached, + "search in index instead of in the work tree"), + OPT_GROUP(""), + OPT_BOOLEAN('v', "invert-match", &opt.invert, + "show non-matching lines"), + OPT_BIT('i', "ignore-case", &opt.regflags, + "case insensitive matching", REG_ICASE), + OPT_BOOLEAN('w', "word-regexp", &opt.word_regexp, + "match patterns only at word boundaries"), + OPT_SET_INT('a', "text", &opt.binary, + "process binary files as text", GREP_BINARY_TEXT), + OPT_SET_INT('I', NULL, &opt.binary, + "don't match patterns in binary files", + GREP_BINARY_NOMATCH), + OPT_GROUP(""), + OPT_BIT('E', "extended-regexp", &opt.regflags, + "use extended POSIX regular expressions", REG_EXTENDED), + OPT_NEGBIT('G', "basic-regexp", &opt.regflags, + "use basic POSIX regular expressions (default)", + REG_EXTENDED), + OPT_BOOLEAN('F', "fixed-strings", &opt.fixed, + "interpret patterns as fixed strings"), + OPT_GROUP(""), + OPT_BOOLEAN('n', NULL, &opt.linenum, "show line numbers"), + OPT_NEGBIT('h', NULL, &opt.pathname, "don't show filenames", 1), + OPT_BIT('H', NULL, &opt.pathname, "show filenames", 1), + OPT_NEGBIT(0, "full-name", &opt.relative, + "show filenames relative to top directory", 1), + OPT_BOOLEAN('l', "files-with-matches", &opt.name_only, + "show only filenames instead of matching lines"), + OPT_BOOLEAN(0, "name-only", &opt.name_only, + "synonym for --files-with-matches"), + OPT_BOOLEAN('L', "files-without-match", + &opt.unmatch_name_only, + "show only the names of files without match"), + OPT_BOOLEAN('z', "null", &opt.null_following_name, + "print NUL after filenames"), + OPT_BOOLEAN('c', "count", &opt.count, + "show the number of matches instead of matching lines"), + OPT_SET_INT(0, "color", &opt.color, "highlight matches", 1), + OPT_GROUP(""), + OPT_CALLBACK('C', NULL, &opt, "n", + "show <n> context lines before and after matches", + context_callback), + OPT_INTEGER('B', NULL, &opt.pre_context, + "show <n> context lines before matches"), + OPT_INTEGER('A', NULL, &opt.post_context, + "show <n> context lines after matches"), + OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM", + context_callback), + OPT_GROUP(""), + OPT_CALLBACK('f', NULL, &opt, "file", + "read patterns from file", file_callback), + { OPTION_CALLBACK, 'e', NULL, &opt, "pattern", + "match <pattern>", PARSE_OPT_NONEG, pattern_callback }, + { OPTION_CALLBACK, 0, "and", &opt, NULL, + "combine patterns specified with -e", + PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback }, + OPT_BOOLEAN(0, "or", &dummy, ""), + { OPTION_CALLBACK, 0, "not", &opt, NULL, "", + PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback }, + { OPTION_CALLBACK, '(', NULL, &opt, NULL, "", + PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH, + open_callback }, + { OPTION_CALLBACK, ')', NULL, &opt, NULL, "", + PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH, + close_callback }, + OPT_BOOLEAN(0, "all-match", &opt.all_match, + "show only matches from files that match all patterns"), + OPT_GROUP(""), +#if NO_EXTERNAL_GREP + OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed, + "allow calling of grep(1) (ignored by this build)"), +#else + OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed, + "allow calling of grep(1) (default)"), +#endif + { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", + PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback }, + OPT_END() + }; memset(&opt, 0, sizeof(opt)); opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0; @@ -603,223 +763,17 @@ int cmd_grep(int argc, const char **argv, const char *prefix) * unrecognized non option is the beginning of the refs list * that continues up to the -- (if exists), and then paths. */ + argc = parse_options(argc, argv, options, grep_usage, + PARSE_OPT_KEEP_DASHDASH | + PARSE_OPT_STOP_AT_NON_OPTION | + PARSE_OPT_NO_INTERNAL_HELP); - while (1 < argc) { - const char *arg = argv[1]; - argc--; argv++; - if (!strcmp("--cached", arg)) { - cached = 1; - continue; - } - if (!strcmp("--no-ext-grep", arg)) { - external_grep_allowed = 0; - continue; - } - if (!strcmp("-a", arg) || - !strcmp("--text", arg)) { - opt.binary = GREP_BINARY_TEXT; - continue; - } - if (!strcmp("-i", arg) || - !strcmp("--ignore-case", arg)) { - opt.regflags |= REG_ICASE; - continue; - } - if (!strcmp("-I", arg)) { - opt.binary = GREP_BINARY_NOMATCH; - continue; - } - if (!strcmp("-v", arg) || - !strcmp("--invert-match", arg)) { - opt.invert = 1; - continue; - } - if (!strcmp("-E", arg) || - !strcmp("--extended-regexp", arg)) { - opt.regflags |= REG_EXTENDED; - continue; - } - if (!strcmp("-F", arg) || - !strcmp("--fixed-strings", arg)) { - opt.fixed = 1; - continue; - } - if (!strcmp("-G", arg) || - !strcmp("--basic-regexp", arg)) { - opt.regflags &= ~REG_EXTENDED; - continue; - } - if (!strcmp("-n", arg)) { - opt.linenum = 1; - continue; - } - if (!strcmp("-h", arg)) { - opt.pathname = 0; - continue; - } - if (!strcmp("-H", arg)) { - opt.pathname = 1; - continue; - } - if (!strcmp("-l", arg) || - !strcmp("--name-only", arg) || - !strcmp("--files-with-matches", arg)) { - opt.name_only = 1; - continue; - } - if (!strcmp("-L", arg) || - !strcmp("--files-without-match", arg)) { - opt.unmatch_name_only = 1; - continue; - } - if (!strcmp("-z", arg) || - !strcmp("--null", arg)) { - opt.null_following_name = 1; - continue; - } - if (!strcmp("-c", arg) || - !strcmp("--count", arg)) { - opt.count = 1; - continue; - } - if (!strcmp("-w", arg) || - !strcmp("--word-regexp", arg)) { - opt.word_regexp = 1; - continue; - } - if (!prefixcmp(arg, "-A") || - !prefixcmp(arg, "-B") || - !prefixcmp(arg, "-C") || - (arg[0] == '-' && '1' <= arg[1] && arg[1] <= '9')) { - unsigned num; - const char *scan; - switch (arg[1]) { - case 'A': case 'B': case 'C': - if (!arg[2]) { - if (argc <= 1) - die(emsg_missing_context_len); - scan = *++argv; - argc--; - } - else - scan = arg + 2; - break; - default: - scan = arg + 1; - break; - } - if (strtoul_ui(scan, 10, &num)) - die(emsg_invalid_context_len, scan); - switch (arg[1]) { - case 'A': - opt.post_context = num; - break; - default: - case 'C': - opt.post_context = num; - case 'B': - opt.pre_context = num; - break; - } - continue; - } - if (!strcmp("-f", arg)) { - FILE *patterns; - int lno = 0; - char buf[1024]; - if (argc <= 1) - die(emsg_missing_argument, arg); - patterns = fopen(argv[1], "r"); - if (!patterns) - die("'%s': %s", argv[1], strerror(errno)); - while (fgets(buf, sizeof(buf), patterns)) { - int len = strlen(buf); - if (len && buf[len-1] == '\n') - buf[len-1] = 0; - /* ignore empty line like grep does */ - if (!buf[0]) - continue; - append_grep_pattern(&opt, xstrdup(buf), - argv[1], ++lno, - GREP_PATTERN); - } - fclose(patterns); - argv++; - argc--; - continue; - } - if (!strcmp("--not", arg)) { - append_grep_pattern(&opt, arg, "command line", 0, - GREP_NOT); - continue; - } - if (!strcmp("--and", arg)) { - append_grep_pattern(&opt, arg, "command line", 0, - GREP_AND); - continue; - } - if (!strcmp("--or", arg)) - continue; /* no-op */ - if (!strcmp("(", arg)) { - append_grep_pattern(&opt, arg, "command line", 0, - GREP_OPEN_PAREN); - continue; - } - if (!strcmp(")", arg)) { - append_grep_pattern(&opt, arg, "command line", 0, - GREP_CLOSE_PAREN); - continue; - } - if (!strcmp("--all-match", arg)) { - opt.all_match = 1; - continue; - } - if (!strcmp("-e", arg)) { - if (1 < argc) { - append_grep_pattern(&opt, argv[1], - "-e option", 0, - GREP_PATTERN); - argv++; - argc--; - continue; - } - die(emsg_missing_argument, arg); - } - if (!strcmp("--full-name", arg)) { - opt.relative = 0; - continue; - } - if (!strcmp("--color", arg)) { - opt.color = 1; - continue; - } - if (!strcmp("--no-color", arg)) { - opt.color = 0; - continue; - } - if (!strcmp("--", arg)) { - /* later processing wants to have this at argv[1] */ - argv--; - argc++; - break; - } - if (*arg == '-') - usage(builtin_grep_usage); - - /* First unrecognized non-option token */ - if (!opt.pattern_list) { - append_grep_pattern(&opt, arg, "command line", 0, - GREP_PATTERN); - break; - } - else { - /* We are looking at the first path or rev; - * it is found at argv[1] after leaving the - * loop. - */ - argc++; argv--; - break; - } + /* First unrecognized non-option token */ + if (argc > 0 && !opt.pattern_list) { + append_grep_pattern(&opt, argv[0], "command line", 0, + GREP_PATTERN); + argv++; + argc--; } if (opt.color && !opt.color_external) @@ -831,7 +785,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) compile_grep_patterns(&opt); /* Check revs and then paths */ - for (i = 1; i < argc; i++) { + for (i = 0; i < argc; i++) { const char *arg = argv[i]; unsigned char sha1[20]; /* Is it a rev? */ diff --git a/grep.h b/grep.h index a67005de62..464e272edf 100644 --- a/grep.h +++ b/grep.h @@ -61,23 +61,23 @@ struct grep_opt { struct grep_expr *pattern_expression; int prefix_length; regex_t regexp; - unsigned linenum:1; - unsigned invert:1; - unsigned status_only:1; - unsigned name_only:1; - unsigned unmatch_name_only:1; - unsigned count:1; - unsigned word_regexp:1; - unsigned fixed:1; - unsigned all_match:1; + int linenum; + int invert; + int status_only; + int name_only; + int unmatch_name_only; + int count; + int word_regexp; + int fixed; + int all_match; #define GREP_BINARY_DEFAULT 0 #define GREP_BINARY_NOMATCH 1 #define GREP_BINARY_TEXT 2 - unsigned binary:2; - unsigned extended:1; - unsigned relative:1; - unsigned pathname:1; - unsigned null_following_name:1; + int binary; + int extended; + int relative; + int pathname; + int null_following_name; int color; char color_match[COLOR_MAXLEN]; const char *color_external; From 7742c65ba5d74f9cbb426f206a88ae04be3f46cd Mon Sep 17 00:00:00 2001 From: Heiko Voigt <hvoigt@hvoigt.net> Date: Fri, 8 May 2009 17:22:30 +0200 Subject: [PATCH 562/654] Extend sample update hook, disable modifying of existing tags Because no special rule for this existed it was allowed by default Signed-off-by: Heiko Voigt <heiko.voigt@mahr.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- templates/hooks--update.sample | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/templates/hooks--update.sample b/templates/hooks--update.sample index f8bf490cff..fd63b2d662 100755 --- a/templates/hooks--update.sample +++ b/templates/hooks--update.sample @@ -13,6 +13,9 @@ # hooks.allowdeletetag # This boolean sets whether deleting tags will be allowed in the # repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. # hooks.allowdeletebranch # This boolean sets whether deleting branches will be allowed in the # repository. By default they won't be. @@ -44,6 +47,7 @@ allowunannotated=$(git config --bool hooks.allowunannotated) allowdeletebranch=$(git config --bool hooks.allowdeletebranch) denycreatebranch=$(git config --bool hooks.denycreatebranch) allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) # check for no description projectdesc=$(sed -e '1q' "$GIT_DIR/description") @@ -82,6 +86,12 @@ case "$refname","$newrev_type" in ;; refs/tags/*,tag) # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi ;; refs/heads/*,commit) # branch From ec00d6e0038e030cf73182374e21025c2776cb23 Mon Sep 17 00:00:00 2001 From: Alexander Potashev <aspotashev@gmail.com> Date: Thu, 7 May 2009 16:04:08 +0400 Subject: [PATCH 563/654] Documentation: cloning to empty directory is allowed Cloning into an existing empty directory is now allowed: commit 55892d23981917aefdb387ad7d0429f90cbd446a ("Allow cloning to an existing empty directory") Signed-off-by: Alexander Potashev <aspotashev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-clone.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index 4072f40d7a..b14de6c407 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -149,7 +149,7 @@ then the cloned repository will become corrupt. part of the source repository is used if no directory is explicitly given ("repo" for "/path/to/repo.git" and "foo" for "host.xz:foo/.git"). Cloning into an existing directory - is not allowed. + is only allowed if the directory is empty. :git-clone: 1 include::urls.txt[] From 74fd8728e2abd46a6276f6d48bfc6c9f01d74570 Mon Sep 17 00:00:00 2001 From: Jakub Narebski <jnareb@gmail.com> Date: Thu, 7 May 2009 19:11:29 +0200 Subject: [PATCH 564/654] gitweb: Remove function prototypes (cleanup) Use of function prototypes is considered bad practice in Perl. The ones used here didn't accomplish anything anyhow, so they've been removed. >From perlsub(1): [...] the intent of this feature [prototypes] is primarily to let you define subroutines that work like built-in functions [...] you can generate new syntax with it [...] We don't want to have subroutines behaving exactly like built-in functions, we don't want to define new syntax / syntactic sugar, so prototypes in gitweb are not needed... and they can have unintended consequences. Signed-off-by: Jakub Narebski <jnareb@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- gitweb/gitweb.perl | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 3f99361ed0..06e91608fa 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -838,7 +838,7 @@ exit; ## ====================================================================== ## action links -sub href (%) { +sub href { my %params = @_; # default is to use -absolute url() i.e. $my_uri my $href = $params{-full} ? $my_url : $my_uri; @@ -1036,7 +1036,7 @@ sub esc_url { } # replace invalid utf8 character with SUBSTITUTION sequence -sub esc_html ($;%) { +sub esc_html { my $str = shift; my %opts = @_; @@ -1296,7 +1296,7 @@ use constant { }; # submodule/subproject, a commit object reference -sub S_ISGITLINK($) { +sub S_ISGITLINK { my $mode = shift; return (($mode & S_IFMT) == S_IFGITLINK) @@ -2615,7 +2615,7 @@ sub parsed_difftree_line { } # parse line of git-ls-tree output -sub parse_ls_tree_line ($;%) { +sub parse_ls_tree_line { my $line = shift; my %opts = @_; my %res; @@ -3213,7 +3213,6 @@ sub git_print_header_div { "\n</div>\n"; } -#sub git_print_authorship (\%) { sub git_print_authorship { my $co = shift; @@ -3269,8 +3268,7 @@ sub git_print_page_path { print "<br/></div>\n"; } -# sub git_print_log (\@;%) { -sub git_print_log ($;%) { +sub git_print_log { my $log = shift; my %opts = @_; From a4c2e69936df8dd0b071b85664c6cc6a4870dd84 Mon Sep 17 00:00:00 2001 From: Robin Rosenberg <robin.rosenberg@dewire.com> Date: Fri, 8 May 2009 07:32:37 +0200 Subject: [PATCH 565/654] Disallow '\' in ref names This is asking for trouble since '\' is a directory separator in Windows and thus may produce unpredictable results. Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-check-ref-format.txt | 2 ++ refs.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt index c1ce26884e..bf43454415 100644 --- a/Documentation/git-check-ref-format.txt +++ b/Documentation/git-check-ref-format.txt @@ -38,6 +38,8 @@ imposes the following rules on how references are named: . They cannot contain a sequence `@{`. +- They cannot contain a `\\`. + These rules make it easy for shell script based tools to parse reference names, pathname expansion by the shell when a reference name is used unquoted (by mistake), and also avoids ambiguities in certain diff --git a/refs.c b/refs.c index e65a3b4c4e..fc33bc6ac4 100644 --- a/refs.c +++ b/refs.c @@ -682,12 +682,13 @@ int for_each_rawref(each_ref_fn fn, void *cb_data) * - it has ASCII control character, "~", "^", ":" or SP, anywhere, or * - it ends with a "/". * - it ends with ".lock" + * - it contains a "\" (backslash) */ static inline int bad_ref_char(int ch) { if (((unsigned) ch) <= ' ' || - ch == '~' || ch == '^' || ch == ':') + ch == '~' || ch == '^' || ch == ':' || ch == '\\') return 1; /* 2.13 Pattern Matching Notation */ if (ch == '?' || ch == '[') /* Unsupported */ From 27d5438d9f4eb2cefc2a989c68f9b42b529b2a12 Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Fri, 8 May 2009 05:06:15 -0400 Subject: [PATCH 566/654] fix GIT_TRACE segfault with shell-quoted aliases The alias argv comes from the split_cmdline function, which splits the config text for the alias into an array of strings. It returns the number of elements in the array, but does not actually put a NULL at the end of the array. Later, the trace function tries to print this argv and assumes that it has the trailing NULL. The split_cmdline function is probably at fault, since argv lists almost always end with a NULL signal. This patch adds one, in addition to the returned count; this doesn't hurt the other callers at all, since they were presumably using the count already (and will never look at the NULL). While we're there and using ALLOC_GROW, let's clean up the other manual grow. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- alias.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/alias.c b/alias.c index ccb1108c94..4f4d0141cd 100644 --- a/alias.c +++ b/alias.c @@ -38,10 +38,7 @@ int split_cmdline(char *cmdline, const char ***argv) while (cmdline[++src] && isspace(cmdline[src])) ; /* skip */ - if (count >= size) { - size += 16; - *argv = xrealloc(*argv, sizeof(char*) * size); - } + ALLOC_GROW(*argv, count+1, size); (*argv)[count++] = cmdline + dst; } else if (!quoted && (c == '\'' || c == '"')) { quoted = c; @@ -72,6 +69,9 @@ int split_cmdline(char *cmdline, const char ***argv) return error("unclosed quote"); } + ALLOC_GROW(*argv, count+1, size); + (*argv)[count] = NULL; + return count; } From ca6b91d29b7ea937b71f62bf00ba7750f3e594ce Mon Sep 17 00:00:00 2001 From: Jim Meyering <jim@meyering.net> Date: Sat, 9 May 2009 10:12:01 +0200 Subject: [PATCH 567/654] format-patch let -k override a config-specified format.numbered Let a command-line --keep-subject (-k) override a config-specified format.numbered (--numbered (-n)), rather than provoking the "-n and -k are mutually exclusive" failure. * t4021-format-patch-numbered.sh: Test for the above Signed-off-by: Jim Meyering <meyering@redhat.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-log.c | 14 +++++++++++++- t/t4021-format-patch-numbered.sh | 7 +++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/builtin-log.c b/builtin-log.c index 5eaec5d24e..f10cfebdbb 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -755,6 +755,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) int cover_letter = 0; int boundary_count = 0; int no_binary_diff = 0; + int numbered_cmdline_opt = 0; struct commit *origin = NULL, *head = NULL; const char *in_reply_to = NULL; struct patch_ids ids; @@ -786,8 +787,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (!strcmp(argv[i], "--stdout")) use_stdout = 1; else if (!strcmp(argv[i], "-n") || - !strcmp(argv[i], "--numbered")) + !strcmp(argv[i], "--numbered")) { numbered = 1; + numbered_cmdline_opt = 1; + } else if (!strcmp(argv[i], "-N") || !strcmp(argv[i], "--no-numbered")) { numbered = 0; @@ -918,6 +921,15 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (start_number < 0) start_number = 1; + + /* + * If numbered is set solely due to format.numbered in config, + * and it would conflict with --keep-subject (-k) from the + * command line, reset "numbered". + */ + if (numbered && keep_subject && !numbered_cmdline_opt) + numbered = 0; + if (numbered && keep_subject) die ("-n and -k are mutually exclusive."); if (keep_subject && subject_prefix) diff --git a/t/t4021-format-patch-numbered.sh b/t/t4021-format-patch-numbered.sh index 390af2389f..9b6e1be8b2 100755 --- a/t/t4021-format-patch-numbered.sh +++ b/t/t4021-format-patch-numbered.sh @@ -86,6 +86,13 @@ test_expect_success 'format.numbered && --no-numbered' ' ' +test_expect_success 'format.numbered && --keep-subject' ' + + git format-patch --keep-subject --stdout HEAD^ >patch4a && + grep "^Subject: Third" patch4a + +' + test_expect_success 'format.numbered = auto' ' git config format.numbered auto From 4481ff048df4c86021d783de6f099909495f04ff Mon Sep 17 00:00:00 2001 From: David Aguilar <davvid@gmail.com> Date: Sat, 2 May 2009 01:57:21 -0700 Subject: [PATCH 568/654] mergetool--lib: specialize diff options for emerge and ecmerge The ecmerge documentation mentions the following form: ecmerge --mode=diff2 $1 $2 Since git-difftool is about diffing, we should use that instead of --mode=merge2. Likewise, this drops the $MERGED argument to emerge, as discussed on the git list ($gmane/117930). Signed-off-by: David Aguilar <davvid@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-mergetool--lib.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh index a16a2795d7..8b5e6a8c64 100644 --- a/git-mergetool--lib.sh +++ b/git-mergetool--lib.sh @@ -228,8 +228,8 @@ run_merge_tool () { fi check_unchanged else - "$merge_tool_path" "$LOCAL" "$REMOTE" \ - --default --mode=merge2 --to="$MERGED" + "$merge_tool_path" --default --mode=diff2 \ + "$LOCAL" "$REMOTE" fi ;; emerge) @@ -248,7 +248,7 @@ run_merge_tool () { status=$? else "$merge_tool_path" -f emerge-files-command \ - "$LOCAL" "$REMOTE" "$(basename "$MERGED")" + "$LOCAL" "$REMOTE" fi ;; tortoisemerge) From da159c7759418bb14af655968dfa7a98bdcb8661 Mon Sep 17 00:00:00 2001 From: Frank Lichtenheld <flichtenheld@astaro.com> Date: Thu, 7 May 2009 15:41:27 +0200 Subject: [PATCH 569/654] Git.pm: Set GIT_WORK_TREE if we set GIT_DIR Otherwise git will use the current directory as work tree which will lead to unexpected results if we operate in sub directory of the work tree. Signed-off-by: Frank Lichtenheld <flichtenheld@astaro.com> Acked-by: Petr Baudis <pasky@suse.cz> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- perl/Git.pm | 2 ++ t/t9700-perl-git.sh | 4 ++++ t/t9700/test.pl | 13 +++++++++++++ 3 files changed, 19 insertions(+) diff --git a/perl/Git.pm b/perl/Git.pm index 291ff5b53c..4313db75b5 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -1280,6 +1280,8 @@ sub _cmd_exec { my ($self, @args) = @_; if ($self) { $self->repo_path() and $ENV{'GIT_DIR'} = $self->repo_path(); + $self->repo_path() and $self->wc_path() + and $ENV{'GIT_WORK_TREE'} = $self->wc_path(); $self->wc_path() and chdir($self->wc_path()); $self->wc_subdir() and chdir($self->wc_subdir()); } diff --git a/t/t9700-perl-git.sh b/t/t9700-perl-git.sh index b4ca244626..4eb7d3f7f0 100755 --- a/t/t9700-perl-git.sh +++ b/t/t9700-perl-git.sh @@ -29,6 +29,10 @@ test_expect_success \ git add . && git commit -m "first commit" && + echo "new file in subdir 2" > directory2/file2 && + git add . && + git commit -m "commit in directory2" && + echo "changed file 1" > file1 && git commit -a -m "second commit" && diff --git a/t/t9700/test.pl b/t/t9700/test.pl index 697daf3ffd..d9b29eab22 100755 --- a/t/t9700/test.pl +++ b/t/t9700/test.pl @@ -98,3 +98,16 @@ TODO: { todo_skip 'config after wc_chdir', 1; is($r->config("color.string"), "value", "config after wc_chdir"); } + +# Object generation in sub directory +chdir("directory2"); +my $r2 = Git->repository(); +is($r2->repo_path, $abs_repo_dir . "/.git", "repo_path (2)"); +is($r2->wc_path, $abs_repo_dir . "/", "wc_path (2)"); +is($r2->wc_subdir, "directory2/", "wc_subdir initial (2)"); + +# commands in sub directory +my $last_commit = $r2->command_oneline(qw(rev-parse --verify HEAD)); +like($last_commit, qr/^[0-9a-fA-F]{40}$/, 'rev-parse returned hash'); +my $dir_commit = $r2->command_oneline('log', '-n1', '--pretty=format:%H', '.'); +isnt($last_commit, $dir_commit, 'log . does not show last commit'); From fe53bbc9bebb853f97f0da3f63f7fca5774e3f95 Mon Sep 17 00:00:00 2001 From: Frank Lichtenheld <flichtenheld@astaro.com> Date: Thu, 7 May 2009 15:41:28 +0200 Subject: [PATCH 570/654] Git.pm: Always set Repository to absolute path if autodetecting So far we only set it to absolute paths in some cases which lead to problems like wc_chdir not working. Signed-off-by: Frank Lichtenheld <flichtenheld@astaro.com> Acked-by: Petr Baudis <pasky@suse.cz> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- perl/Git.pm | 2 +- t/t9700/test.pl | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/perl/Git.pm b/perl/Git.pm index 4313db75b5..e8df55d2f2 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -185,7 +185,7 @@ sub repository { if ($dir) { $dir =~ m#^/# or $dir = $opts{Directory} . '/' . $dir; - $opts{Repository} = $dir; + $opts{Repository} = abs_path($dir); # If --git-dir went ok, this shouldn't die either. my $prefix = $search->command_oneline('rev-parse', '--show-prefix'); diff --git a/t/t9700/test.pl b/t/t9700/test.pl index d9b29eab22..6c70aec020 100755 --- a/t/t9700/test.pl +++ b/t/t9700/test.pl @@ -86,18 +86,12 @@ close TEMPFILE; unlink $tmpfile; # paths -is($r->repo_path, "./.git", "repo_path"); +is($r->repo_path, $abs_repo_dir . "/.git", "repo_path"); is($r->wc_path, $abs_repo_dir . "/", "wc_path"); is($r->wc_subdir, "", "wc_subdir initial"); $r->wc_chdir("directory1"); is($r->wc_subdir, "directory1", "wc_subdir after wc_chdir"); -TODO: { - local $TODO = "commands do not work after wc_chdir"; - # Failure output is active even in non-verbose mode and thus - # annoying. Hence we skip these tests as long as they fail. - todo_skip 'config after wc_chdir', 1; - is($r->config("color.string"), "value", "config after wc_chdir"); -} +is($r->config("test.string"), "value", "config after wc_chdir"); # Object generation in sub directory chdir("directory2"); From 07d7bedda8d18ffbfe5960ce27b73a24c01cac1a Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Tue, 28 Apr 2009 23:21:01 -0400 Subject: [PATCH 571/654] add: don't complain when adding empty project root We try to warn the user if one of their pathspecs caused no matches, as it may have been a typo. However, we disable the warning if the pathspec points to an existing file, since that means it is not a typo but simply an empty directory. Unfortunately, the file_exists() test was broken for one special case: the pathspec of the project root is just "". This patch detects this special case and acts as if the file exists (which it must, since it is the project root). The user-visible effect is that this: $ mkdir repo && cd repo && git init && git add . used to complain like: fatal: pathspec '' did not match any files but now is a silent no-op. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-add.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-add.c b/builtin-add.c index cb67d2c17e..ad889aac5b 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -61,7 +61,7 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p fill_pathspec_matches(pathspec, seen, specs); for (i = 0; i < specs; i++) { - if (!seen[i] && !file_exists(pathspec[i])) + if (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i])) die("pathspec '%s' did not match any files", pathspec[i]); } From d92a39590d1126e195f1bbccf182a2cdb79218e7 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" <mst@redhat.com> Date: Mon, 4 May 2009 22:30:01 +0300 Subject: [PATCH 572/654] Add --reference option to git submodule. This adds --reference option to git submodule add and git submodule update commands, which is passed to git clone. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-submodule.txt | 14 +++++- git-submodule.sh | 38 ++++++++++++++-- t/t7406-submodule-reference.sh | 81 +++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 6 deletions(-) create mode 100755 t/t7406-submodule-reference.sh diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index 3b8df44673..14256c695b 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -9,10 +9,12 @@ git-submodule - Initialize, update or inspect submodules SYNOPSIS -------- [verse] -'git submodule' [--quiet] add [-b branch] [--] <repository> <path> +'git submodule' [--quiet] add [-b branch] + [--reference <repository>] [--] <repository> <path> 'git submodule' [--quiet] status [--cached] [--] [<path>...] 'git submodule' [--quiet] init [--] [<path>...] -'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--] [<path>...] +'git submodule' [--quiet] update [--init] [-N|--no-fetch] + [--reference <repository>] [--] [<path>...] 'git submodule' [--quiet] summary [--summary-limit <n>] [commit] [--] [<path>...] 'git submodule' [--quiet] foreach <command> 'git submodule' [--quiet] sync [--] [<path>...] @@ -177,6 +179,14 @@ OPTIONS This option is only valid for the update command. Don't fetch new objects from the remote site. +--reference <repository>:: + This option is only valid for add and update commands. These + commands sometimes need to clone a remote repository. In this case, + this option will be passed to the linkgit:git-clone[1] command. ++ +*NOTE*: Do *not* use this option unless you have read the note +for linkgit:git-clone[1]'s --reference and --shared options carefully. + <path>...:: Paths to submodule(s). When specified this will restrict the command to only operate on the submodules found at the specified paths. diff --git a/git-submodule.sh b/git-submodule.sh index 8e234a4028..ab1ed02a66 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -15,6 +15,7 @@ require_work_tree command= branch= quiet= +reference= cached= nofetch= @@ -91,6 +92,7 @@ module_clone() { path=$1 url=$2 + reference="$3" # If there already is a directory at the submodule path, # expect it to be empty (since that is the default checkout @@ -106,7 +108,12 @@ module_clone() test -e "$path" && die "A file already exist at path '$path'" - git-clone -n "$url" "$path" || + if test -n "$reference" + then + git-clone "$reference" -n "$url" "$path" + else + git-clone -n "$url" "$path" + fi || die "Clone of '$url' into submodule path '$path' failed" } @@ -131,6 +138,15 @@ cmd_add() -q|--quiet) quiet=1 ;; + --reference) + case "$2" in '') usage ;; esac + reference="--reference=$2" + shift + ;; + --reference=*) + reference="$1" + shift + ;; --) shift break @@ -203,7 +219,7 @@ cmd_add() git config submodule."$path".url "$url" else - module_clone "$path" "$realrepo" || exit + module_clone "$path" "$realrepo" "$reference" || exit ( unset GIT_DIR cd "$path" && @@ -314,13 +330,22 @@ cmd_update() quiet=1 ;; -i|--init) + init=1 shift - cmd_init "$@" || return ;; -N|--no-fetch) shift nofetch=1 ;; + --reference) + case "$2" in '') usage ;; esac + reference="--reference=$2" + shift 2 + ;; + --reference=*) + reference="$1" + shift + ;; --) shift break @@ -334,6 +359,11 @@ cmd_update() esac done + if test -n "$init" + then + cmd_init "--" "$@" || return + fi + module_list "$@" | while read mode sha1 stage path do @@ -351,7 +381,7 @@ cmd_update() if ! test -d "$path"/.git -o -f "$path"/.git then - module_clone "$path" "$url" || exit + module_clone "$path" "$url" "$reference"|| exit subsha1= else subsha1=$(unset GIT_DIR; cd "$path" && diff --git a/t/t7406-submodule-reference.sh b/t/t7406-submodule-reference.sh new file mode 100755 index 0000000000..cc16d3f05d --- /dev/null +++ b/t/t7406-submodule-reference.sh @@ -0,0 +1,81 @@ +#!/bin/sh +# +# Copyright (c) 2009, Red Hat Inc, Author: Michael S. Tsirkin (mst@redhat.com) +# + +test_description='test clone --reference' +. ./test-lib.sh + +base_dir=`pwd` + +U=$base_dir/UPLOAD_LOG + +test_expect_success 'preparing first repository' \ +'test_create_repo A && cd A && +echo first > file1 && +git add file1 && +git commit -m A-initial' + +cd "$base_dir" + +test_expect_success 'preparing second repository' \ +'git clone A B && cd B && +echo second > file2 && +git add file2 && +git commit -m B-addition && +git repack -a -d && +git prune' + +cd "$base_dir" + +test_expect_success 'preparing supermodule' \ +'test_create_repo super && cd super && +echo file > file && +git add file && +git commit -m B-super-initial' + +cd "$base_dir" + +test_expect_success 'submodule add --reference' \ +'cd super && git submodule add --reference ../B "file://$base_dir/A" sub && +git commit -m B-super-added' + +cd "$base_dir" + +test_expect_success 'after add: existence of info/alternates' \ +'test `wc -l <super/sub/.git/objects/info/alternates` = 1' + +cd "$base_dir" + +test_expect_success 'that reference gets used with add' \ +'cd super/sub && +echo "0 objects, 0 kilobytes" > expected && +git count-objects > current && +diff expected current' + +cd "$base_dir" + +test_expect_success 'cloning supermodule' \ +'git clone super super-clone' + +cd "$base_dir" + +test_expect_success 'update with reference' \ +'cd super-clone && git submodule update --init --reference ../B' + +cd "$base_dir" + +test_expect_success 'after update: existence of info/alternates' \ +'test `wc -l <super-clone/sub/.git/objects/info/alternates` = 1' + +cd "$base_dir" + +test_expect_success 'that reference gets used with update' \ +'cd super-clone/sub && +echo "0 objects, 0 kilobytes" > expected && +git count-objects > current && +diff expected current' + +cd "$base_dir" + +test_done From be427d758b53343d31debb520c0bc251a62013a9 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty <sitaramc@gmail.com> Date: Tue, 28 Apr 2009 20:51:20 +0530 Subject: [PATCH 573/654] allow -t abbreviation for --track in git branch also makes it consistent with git-checkout Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-branch.txt | 1 + builtin-branch.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index cbd4275871..ae201deb7a 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -111,6 +111,7 @@ OPTIONS --no-abbrev:: Display the full sha1s in the output listing rather than abbreviating them. +-t:: --track:: When creating a new branch, set up configuration to mark the start-point branch as "upstream" from the new branch. This diff --git a/builtin-branch.c b/builtin-branch.c index 91098ca9b1..6aaa708473 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -547,7 +547,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) struct option options[] = { OPT_GROUP("Generic options"), OPT__VERBOSE(&verbose), - OPT_SET_INT( 0 , "track", &track, "set up tracking mode (see git-pull(1))", + OPT_SET_INT('t', "track", &track, "set up tracking mode (see git-pull(1))", BRANCH_TRACK_EXPLICIT), OPT_BOOLEAN( 0 , "color", &branch_use_color, "use colored output"), OPT_SET_INT('r', NULL, &kinds, "act on remote-tracking branches", From 658dd48c8572d0db49719cbef6605d384621d87c Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@linux-foundation.org> Date: Sat, 9 May 2009 14:57:30 -0700 Subject: [PATCH 574/654] Avoid unnecessary 'lstat()' calls in 'get_stat_data()' When we ask get_stat_data() to get the mode and size of an index entry, we can avoid the lstat() call if we have marked the index entry as being uptodate due to earlier lstat() calls. This avoids a lot of unnecessary lstat() calls in eg 'git checkout', where the last phase shows the differences to the working tree (requiring a diff), but earlier phases have already verified the index. On the kernel repo (with a fast machine and everything cached), this changes timings of a nul 'git checkout' from - Before (best of ten): 0.14user 0.05system 0:00.19elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+13237minor)pagefaults 0swaps - After 0.11user 0.03system 0:00.15elapsed 98%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+13235minor)pagefaults 0swaps so it can obviously be noticeable, although equally obviously it's not a show-stopper on this particular machine. The difference is likely larger on slower machines, or with operating systems that don't do as good a job of name caching. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- diff-lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diff-lib.c b/diff-lib.c index ae96c64ca2..d230efc146 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -222,7 +222,7 @@ static int get_stat_data(struct cache_entry *ce, const unsigned char *sha1 = ce->sha1; unsigned int mode = ce->ce_mode; - if (!cached) { + if (!cached && !ce_uptodate(ce)) { int changed; struct stat st; changed = check_removed(ce, &st); From 53996fe5397ff37c5934bb5e9b23ef5985b3d152 Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@linux-foundation.org> Date: Sat, 9 May 2009 15:11:17 -0700 Subject: [PATCH 575/654] Teach 'git checkout' to preload the index contents This makes git checkout know to use the threaded index preloading if it is enabled in the config file. You need to have [core] preloadindex = true in your config file to see it, and for that feature to make sense your filesystem needs to be able to do concurrent 'lstat()' lookups, but when that is the case (especially NFS over a high-latency network), this can be a noticeable performance win. But with a low-latency network and at least older Linux NFS clients, this will clearly potentially cause a lot of lock contention. It may still speed up the uncached case, but the threading and locking overhead will result in the cached case likely slowing down. That was almost certainly fixed by Linux commit fc0f684c2 ("NFS: Remove BKL from NFS lookup code"), but that one got merged into 2.6.27-rc1, so older kernel versions than 2.6.27 will not scale very well. But regardless, it's the right thing to do. If your filesystem doesn't scale, don't enable index preloading. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-checkout.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin-checkout.c b/builtin-checkout.c index b5dd9c07b4..f1342abd02 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -228,7 +228,7 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec, struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); newfd = hold_locked_index(lock_file, 1); - if (read_cache() < 0) + if (read_cache_preload(pathspec) < 0) return error("corrupt index file"); if (source_tree) @@ -373,7 +373,7 @@ static int merge_working_tree(struct checkout_opts *opts, struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); int newfd = hold_locked_index(lock_file, 1); - if (read_cache() < 0) + if (read_cache_preload(NULL) < 0) return error("corrupt index file"); if (opts->force) { From bf74106a5b4577fd695d15a28ad51537ae7470d8 Mon Sep 17 00:00:00 2001 From: Dave Olszewski <cxreg@pobox.com> Date: Sat, 9 May 2009 14:49:59 -0700 Subject: [PATCH 576/654] merge-recursive: never leave index unmerged while recursing When you are trying to come up with the final result (i.e. depth=0), you want to record how the conflict arose by registering the state of the common ancestor, your branch and the other branch in the index, hence you want to do update_stages(). When you are merging with positive depth, that is because of a criss-cross merge situation. In such a case, you would need to record the tentative result, with conflict markers and all, as if the merge went cleanly, even if there are conflicts, in order to write it out as a tree object later to be used as a common ancestor tree. update_file() calls update_file_flags() with update_cache=1 to signal that the result needs to be written to the index at stage #0 (i.e. merged), and the code should not clobber the index further by calling update_stages(). The codepath to deal with rename/delete conflict in a recursive merge however left the index unmerged. Signed-off-by: Dave Olszewski <cxreg@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- merge-recursive.c | 11 +++-- t/t3031-merge-criscross.sh | 95 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 5 deletions(-) create mode 100755 t/t3031-merge-criscross.sh diff --git a/merge-recursive.c b/merge-recursive.c index 9bf5cc7175..2f1025c2aa 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -934,11 +934,12 @@ static int process_renames(struct merge_options *o, ren1_src, ren1_dst, branch1, branch2); update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, ren1_dst); - update_stages(ren1_dst, NULL, - branch1 == o->branch1 ? - ren1->pair->two : NULL, - branch1 == o->branch1 ? - NULL : ren1->pair->two, 1); + if (!o->call_depth) + update_stages(ren1_dst, NULL, + branch1 == o->branch1 ? + ren1->pair->two : NULL, + branch1 == o->branch1 ? + NULL : ren1->pair->two, 1); } else if (!sha_eq(dst_other.sha1, null_sha1)) { const char *new_path; clean_merge = 0; diff --git a/t/t3031-merge-criscross.sh b/t/t3031-merge-criscross.sh new file mode 100755 index 0000000000..7f41607c56 --- /dev/null +++ b/t/t3031-merge-criscross.sh @@ -0,0 +1,95 @@ +#!/bin/sh + +test_description='merge-recursive backend test' + +. ./test-lib.sh + +# A <- create some files +# / \ +# B C <- cause rename/delete conflicts between B and C +# / \ +# |\ /| +# | D E | +# | \ / | +# | X | +# | / \ | +# | / \ | +# |/ \| +# F G <- merge E into B, D into C +# \ / +# \ / +# \ / +# H <- recursive merge crashes +# + +# initialize +test_expect_success 'setup repo with criss-cross history' ' + mkdir data && + + # create a bunch of files + n=1 && + while test $n -le 10 + do + echo $n > data/$n && + n=$(($n+1)) || + break + done && + + # check them in + git add data && + git commit -m A && + git branch A && + + # a file in one branch + git checkout -b B A && + git rm data/9 && + git add data && + git commit -m B && + + # with a branch off of it + git branch D && + + # put some commits on D + git checkout D && + echo testD > data/testD && + git add data && + git commit -m D && + + # back up to the top, create another branch and cause + # a rename conflict with the file we deleted earlier + git checkout -b C A && + git mv data/9 data/new-9 && + git add data && + git commit -m C && + + # with a branch off of it + git branch E && + + # put a commit on E + git checkout E && + echo testE > data/testE && + git add data && + git commit -m E && + + # now, merge E into B + git checkout B && + test_must_fail git merge E && + # force-resolve + git add data && + git commit -m F && + git branch F && + + # and merge D into C + git checkout C && + test_must_fail git merge D && + # force-resolve + git add data && + git commit -m G && + git branch G +' + +test_expect_success 'recursive merge between F and G, causes segfault' ' + git merge F +' + +test_done From 1c876546bda5dde35d4ae887ad6d24ed16ec953a Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sun, 19 Apr 2009 11:55:38 +0200 Subject: [PATCH 577/654] rev-list: make "estimate_bisect_steps" non static Because it will be used from "bisect.c" too. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.h | 2 ++ builtin-rev-list.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bisect.h b/bisect.h index fdba913877..cb37ddfac0 100644 --- a/bisect.h +++ b/bisect.h @@ -26,4 +26,6 @@ extern int show_bisect_vars(struct rev_list_info *info, int reaches, int all); extern int bisect_next_vars(const char *prefix); +extern int estimate_bisect_steps(int all); + #endif diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 38a8f234de..4c5f5eec0e 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -211,7 +211,7 @@ static inline int exp2i(int n) * * and P(2^n + x) < 0.5 means 2^n < 3x */ -static int estimate_bisect_steps(int all) +int estimate_bisect_steps(int all) { int n, x, e; From 280e65cbd83a867437cef3543d445013ecbfe29a Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sun, 19 Apr 2009 11:55:43 +0200 Subject: [PATCH 578/654] rev-list: refactor printing bisect vars This simplifies the code, and while at it we create the "print_commit_list" function that will be reused later. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.h | 4 +++ builtin-rev-list.c | 61 +++++++++++++++++++++++++--------------------- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/bisect.h b/bisect.h index cb37ddfac0..89aa6cb0b3 100644 --- a/bisect.h +++ b/bisect.h @@ -9,6 +9,10 @@ extern struct commit_list *filter_skipped(struct commit_list *list, struct commit_list **tried, int show_all); +extern void print_commit_list(struct commit_list *list, + const char *format_cur, + const char *format_last); + /* bisect_show_flags flags in struct rev_list_info */ #define BISECT_SHOW_ALL (1<<0) #define BISECT_SHOW_TRIED (1<<1) diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 4c5f5eec0e..35f88ca425 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -225,20 +225,37 @@ int estimate_bisect_steps(int all) return (e < 3 * x) ? n : n - 1; } +void print_commit_list(struct commit_list *list, + const char *format_cur, + const char *format_last) +{ + for ( ; list; list = list->next) { + const char *format = list->next ? format_cur : format_last; + printf(format, sha1_to_hex(list->item->object.sha1)); + } +} + static void show_tried_revs(struct commit_list *tried, int stringed) { printf("bisect_tried='"); - for (;tried; tried = tried->next) { - char *format = tried->next ? "%s|" : "%s"; - printf(format, sha1_to_hex(tried->item->object.sha1)); - } + print_commit_list(tried, "%s|", "%s"); printf(stringed ? "' &&\n" : "'\n"); } +static void print_var_str(const char *var, const char *val, int stringed) +{ + printf("%s='%s'%s\n", var, val, stringed ? " &&" : ""); +} + +static void print_var_int(const char *var, int val, int stringed) +{ + printf("%s=%d%s\n", var, val, stringed ? " &&" : ""); +} + int show_bisect_vars(struct rev_list_info *info, int reaches, int all) { - int cnt, flags = info->bisect_show_flags; - char hex[41] = "", *format; + int cnt, stringed, flags = info->bisect_show_flags; + char hex[41] = ""; struct commit_list *tried; struct rev_info *revs = info->revs; @@ -268,29 +285,17 @@ int show_bisect_vars(struct rev_list_info *info, int reaches, int all) printf("------\n"); } + stringed = flags & BISECT_SHOW_STRINGED; + if (flags & BISECT_SHOW_TRIED) - show_tried_revs(tried, flags & BISECT_SHOW_STRINGED); - format = (flags & BISECT_SHOW_STRINGED) ? - "bisect_rev=%s &&\n" - "bisect_nr=%d &&\n" - "bisect_good=%d &&\n" - "bisect_bad=%d &&\n" - "bisect_all=%d &&\n" - "bisect_steps=%d\n" - : - "bisect_rev=%s\n" - "bisect_nr=%d\n" - "bisect_good=%d\n" - "bisect_bad=%d\n" - "bisect_all=%d\n" - "bisect_steps=%d\n"; - printf(format, - hex, - cnt - 1, - all - reaches - 1, - reaches - 1, - all, - estimate_bisect_steps(all)); + show_tried_revs(tried, stringed); + + print_var_str("bisect_rev", hex, stringed); + print_var_int("bisect_nr", cnt - 1, stringed); + print_var_int("bisect_good", all - reaches - 1, stringed); + print_var_int("bisect_bad", reaches - 1, stringed); + print_var_int("bisect_all", all, stringed); + print_var_int("bisect_steps", estimate_bisect_steps(all), 0); return 0; } From 2ace9727be2b04ce9fbc5939466da38be7fd8496 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sun, 19 Apr 2009 11:55:57 +0200 Subject: [PATCH 579/654] bisect: move common bisect functionality to "bisect_common" So we can easily reuse the code in a later patch. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/bisect.c b/bisect.c index 58f7e6f773..0448eae3f8 100644 --- a/bisect.c +++ b/bisect.c @@ -532,6 +532,20 @@ static void bisect_rev_setup(struct rev_info *revs, const char *prefix) revs->limited = 1; } +static void bisect_common(struct rev_info *revs, const char *prefix, + int *reaches, int *all) +{ + bisect_rev_setup(revs, prefix); + + if (prepare_revision_walk(revs)) + die("revision walk setup failed"); + if (revs->tree_objects) + mark_edges_uninteresting(revs->commits, revs, NULL); + + revs->commits = find_bisection(revs->commits, reaches, all, + !!skipped_sha1_nr); +} + int bisect_next_vars(const char *prefix) { struct rev_info revs; @@ -542,15 +556,7 @@ int bisect_next_vars(const char *prefix) info.revs = &revs; info.bisect_show_flags = BISECT_SHOW_TRIED | BISECT_SHOW_STRINGED; - bisect_rev_setup(&revs, prefix); - - if (prepare_revision_walk(&revs)) - die("revision walk setup failed"); - if (revs.tree_objects) - mark_edges_uninteresting(revs.commits, &revs, NULL); - - revs.commits = find_bisection(revs.commits, &reaches, &all, - !!skipped_sha1_nr); + bisect_common(&revs, prefix, &reaches, &all); return show_bisect_vars(&info, reaches, all); } From ef24c7ca055f03c673c2b67a3a7c92bcc32f62f0 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sun, 19 Apr 2009 11:56:07 +0200 Subject: [PATCH 580/654] bisect--helper: add "--next-exit" to output bisect results The goal of this patch is to port more shell code from the "bisect_next" function in "git-bisect.sh" to C code in "builtin-bisect--helper.c". So we port the code that interprets the bisection result and stops or continues (by checking out the next revision) the bisection process. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 105 +++++++++++++++++++++++++++++++++++++++ bisect.h | 1 + builtin-bisect--helper.c | 12 +++-- 3 files changed, 115 insertions(+), 3 deletions(-) diff --git a/bisect.c b/bisect.c index 0448eae3f8..5902e83fac 100644 --- a/bisect.c +++ b/bisect.c @@ -6,6 +6,7 @@ #include "list-objects.h" #include "quote.h" #include "sha1-lookup.h" +#include "run-command.h" #include "bisect.h" static unsigned char (*skipped_sha1)[20]; @@ -16,6 +17,12 @@ static const char **rev_argv; static int rev_argv_nr; static int rev_argv_alloc; +static const unsigned char *current_bad_sha1; + +static const char *argv_diff_tree[] = {"diff-tree", "--pretty", NULL, NULL}; +static const char *argv_checkout[] = {"checkout", "-q", NULL, "--", NULL}; +static const char *argv_show_branch[] = {"show-branch", NULL, NULL}; + /* bits #0-15 in revision.h */ #define COUNTED (1u<<16) @@ -403,6 +410,7 @@ static int register_ref(const char *refname, const unsigned char *sha1, { if (!strcmp(refname, "bad")) { ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); + current_bad_sha1 = sha1; rev_argv[rev_argv_nr++] = xstrdup(sha1_to_hex(sha1)); } else if (!prefixcmp(refname, "good-")) { const char *hex = sha1_to_hex(sha1); @@ -560,3 +568,100 @@ int bisect_next_vars(const char *prefix) return show_bisect_vars(&info, reaches, all); } + +static void exit_if_skipped_commits(struct commit_list *tried, + const unsigned char *bad) +{ + if (!tried) + return; + + printf("There are only 'skip'ped commits left to test.\n" + "The first bad commit could be any of:\n"); + print_commit_list(tried, "%s\n", "%s\n"); + if (bad) + printf("%s\n", sha1_to_hex(bad)); + printf("We cannot bisect more!\n"); + exit(2); +} + +static void mark_expected_rev(char *bisect_rev_hex) +{ + int len = strlen(bisect_rev_hex); + const char *filename = git_path("BISECT_EXPECTED_REV"); + int fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600); + + if (fd < 0) + die("could not create file '%s': %s", + filename, strerror(errno)); + + bisect_rev_hex[len] = '\n'; + write_or_die(fd, bisect_rev_hex, len + 1); + bisect_rev_hex[len] = '\0'; + + if (close(fd) < 0) + die("closing file %s: %s", filename, strerror(errno)); +} + +static int bisect_checkout(char *bisect_rev_hex) +{ + int res; + + mark_expected_rev(bisect_rev_hex); + + argv_checkout[2] = bisect_rev_hex; + res = run_command_v_opt(argv_checkout, RUN_GIT_CMD); + if (res) + exit(res); + + argv_show_branch[1] = bisect_rev_hex; + return run_command_v_opt(argv_show_branch, RUN_GIT_CMD); +} + +/* + * We use the convention that exiting with an exit code 10 means that + * the bisection process finished successfully. + * In this case the calling shell script should exit 0. + */ +int bisect_next_exit(const char *prefix) +{ + struct rev_info revs; + struct commit_list *tried; + int reaches = 0, all = 0, nr; + const unsigned char *bisect_rev; + char bisect_rev_hex[41]; + + bisect_common(&revs, prefix, &reaches, &all); + + revs.commits = filter_skipped(revs.commits, &tried, 0); + + if (!revs.commits) { + /* + * We should exit here only if the "bad" + * commit is also a "skip" commit. + */ + exit_if_skipped_commits(tried, NULL); + + printf("%s was both good and bad\n", + sha1_to_hex(current_bad_sha1)); + exit(1); + } + + bisect_rev = revs.commits->item->object.sha1; + memcpy(bisect_rev_hex, sha1_to_hex(bisect_rev), 41); + + if (!hashcmp(bisect_rev, current_bad_sha1)) { + exit_if_skipped_commits(tried, current_bad_sha1); + printf("%s is first bad commit\n", bisect_rev_hex); + argv_diff_tree[2] = bisect_rev_hex; + run_command_v_opt(argv_diff_tree, RUN_GIT_CMD); + /* This means the bisection process succeeded. */ + exit(10); + } + + nr = all - reaches - 1; + printf("Bisecting: %d revisions left to test after this " + "(roughly %d steps)\n", nr, estimate_bisect_steps(all)); + + return bisect_checkout(bisect_rev_hex); +} + diff --git a/bisect.h b/bisect.h index 89aa6cb0b3..028eb85220 100644 --- a/bisect.h +++ b/bisect.h @@ -29,6 +29,7 @@ struct rev_list_info { extern int show_bisect_vars(struct rev_list_info *info, int reaches, int all); extern int bisect_next_vars(const char *prefix); +extern int bisect_next_exit(const char *prefix); extern int estimate_bisect_steps(int all); diff --git a/builtin-bisect--helper.c b/builtin-bisect--helper.c index 8fe778766a..cb86a9a9e0 100644 --- a/builtin-bisect--helper.c +++ b/builtin-bisect--helper.c @@ -5,23 +5,29 @@ static const char * const git_bisect_helper_usage[] = { "git bisect--helper --next-vars", + "git bisect--helper --next-exit", NULL }; int cmd_bisect__helper(int argc, const char **argv, const char *prefix) { int next_vars = 0; + int next_exit = 0; struct option options[] = { OPT_BOOLEAN(0, "next-vars", &next_vars, "output next bisect step variables"), + OPT_BOOLEAN(0, "next-exit", &next_exit, + "output bisect result and exit instuctions"), OPT_END() }; argc = parse_options(argc, argv, options, git_bisect_helper_usage, 0); - if (!next_vars) + if ((next_vars && next_exit) || (!next_vars && !next_exit)) usage_with_options(git_bisect_helper_usage, options); - /* next-vars */ - return bisect_next_vars(prefix); + if (next_vars) + return bisect_next_vars(prefix); + else /* next-exit */ + return bisect_next_exit(prefix); } From 5a1d31c7e43a54c3a5275266745488de7208d871 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sun, 19 Apr 2009 11:56:16 +0200 Subject: [PATCH 581/654] bisect: use "git bisect--helper --next-exit" in "git-bisect.sh" instead of "git bisect--helper --next-vars". Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-bisect.sh | 39 +++++++++------------------------------ 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/git-bisect.sh b/git-bisect.sh index 24712ff304..e1f300bed1 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -279,19 +279,6 @@ bisect_auto_next() { bisect_next_check && bisect_next || : } -exit_if_skipped_commits () { - _tried=$1 - _bad=$2 - if test -n "$_tried" ; then - echo "There are only 'skip'ped commit left to test." - echo "The first bad commit could be any of:" - echo "$_tried" | tr '[|]' '[\012]' - test -n "$_bad" && echo "$_bad" - echo "We cannot bisect more!" - exit 2 - fi -} - bisect_checkout() { _rev="$1" _msg="$2" @@ -416,25 +403,17 @@ bisect_next() { # Return now if a checkout has already been done test "$?" -eq "1" && return - # Get bisection information - eval=$(eval "git bisect--helper --next-vars") && - eval "$eval" || exit + # Perform bisection computation, display and checkout + git bisect--helper --next-exit + res=$? - if [ -z "$bisect_rev" ]; then - # We should exit here only if the "bad" - # commit is also a "skip" commit (see above). - exit_if_skipped_commits "$bisect_tried" - echo "$bad was both good and bad" - exit 1 - fi - if [ "$bisect_rev" = "$bad" ]; then - exit_if_skipped_commits "$bisect_tried" "$bad" - echo "$bisect_rev is first bad commit" - git diff-tree --pretty $bisect_rev - exit 0 - fi + # Check if we should exit because bisection is finished + test $res -eq 10 && exit 0 - bisect_checkout "$bisect_rev" "$bisect_nr revisions left to test after this (roughly $bisect_steps steps)" + # Check for an error in the bisection process + test $res -ne 0 && exit $res + + return 0 } bisect_visualize() { From c99f069de2f06b7abe0406c2ff1b46621dbc9398 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Tue, 21 Apr 2009 07:54:09 +0200 Subject: [PATCH 582/654] bisect--helper: remove "--next-vars" option as it is now useless Because it has been replaced by "--next-exit". Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 15 --------------- bisect.h | 1 - builtin-bisect--helper.c | 12 +++--------- 3 files changed, 3 insertions(+), 25 deletions(-) diff --git a/bisect.c b/bisect.c index 5902e83fac..4796aa9198 100644 --- a/bisect.c +++ b/bisect.c @@ -554,21 +554,6 @@ static void bisect_common(struct rev_info *revs, const char *prefix, !!skipped_sha1_nr); } -int bisect_next_vars(const char *prefix) -{ - struct rev_info revs; - struct rev_list_info info; - int reaches = 0, all = 0; - - memset(&info, 0, sizeof(info)); - info.revs = &revs; - info.bisect_show_flags = BISECT_SHOW_TRIED | BISECT_SHOW_STRINGED; - - bisect_common(&revs, prefix, &reaches, &all); - - return show_bisect_vars(&info, reaches, all); -} - static void exit_if_skipped_commits(struct commit_list *tried, const unsigned char *bad) { diff --git a/bisect.h b/bisect.h index 028eb85220..908e362f8b 100644 --- a/bisect.h +++ b/bisect.h @@ -28,7 +28,6 @@ struct rev_list_info { extern int show_bisect_vars(struct rev_list_info *info, int reaches, int all); -extern int bisect_next_vars(const char *prefix); extern int bisect_next_exit(const char *prefix); extern int estimate_bisect_steps(int all); diff --git a/builtin-bisect--helper.c b/builtin-bisect--helper.c index cb86a9a9e0..aca7018d83 100644 --- a/builtin-bisect--helper.c +++ b/builtin-bisect--helper.c @@ -4,18 +4,14 @@ #include "bisect.h" static const char * const git_bisect_helper_usage[] = { - "git bisect--helper --next-vars", "git bisect--helper --next-exit", NULL }; int cmd_bisect__helper(int argc, const char **argv, const char *prefix) { - int next_vars = 0; int next_exit = 0; struct option options[] = { - OPT_BOOLEAN(0, "next-vars", &next_vars, - "output next bisect step variables"), OPT_BOOLEAN(0, "next-exit", &next_exit, "output bisect result and exit instuctions"), OPT_END() @@ -23,11 +19,9 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, options, git_bisect_helper_usage, 0); - if ((next_vars && next_exit) || (!next_vars && !next_exit)) + if (!next_exit) usage_with_options(git_bisect_helper_usage, options); - if (next_vars) - return bisect_next_vars(prefix); - else /* next-exit */ - return bisect_next_exit(prefix); + /* next-exit */ + return bisect_next_exit(prefix); } From 38ef7507d1dce87d68f177a6209d716339fee854 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Tue, 21 Apr 2009 07:54:10 +0200 Subject: [PATCH 583/654] rev-list: remove stringed output flag from "show_bisect_vars" Because it was used only by "git bisect--helper --next-vars" but the "--next-vars" option has been removed. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.h | 1 - builtin-rev-list.c | 30 ++++++++++++++---------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/bisect.h b/bisect.h index 908e362f8b..0b5d122a7b 100644 --- a/bisect.h +++ b/bisect.h @@ -16,7 +16,6 @@ extern void print_commit_list(struct commit_list *list, /* bisect_show_flags flags in struct rev_list_info */ #define BISECT_SHOW_ALL (1<<0) #define BISECT_SHOW_TRIED (1<<1) -#define BISECT_SHOW_STRINGED (1<<2) struct rev_list_info { struct rev_info *revs; diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 35f88ca425..31ea5f4aac 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -235,26 +235,26 @@ void print_commit_list(struct commit_list *list, } } -static void show_tried_revs(struct commit_list *tried, int stringed) +static void show_tried_revs(struct commit_list *tried) { printf("bisect_tried='"); print_commit_list(tried, "%s|", "%s"); - printf(stringed ? "' &&\n" : "'\n"); + printf("'\n"); } -static void print_var_str(const char *var, const char *val, int stringed) +static void print_var_str(const char *var, const char *val) { - printf("%s='%s'%s\n", var, val, stringed ? " &&" : ""); + printf("%s='%s'\n", var, val); } -static void print_var_int(const char *var, int val, int stringed) +static void print_var_int(const char *var, int val) { - printf("%s=%d%s\n", var, val, stringed ? " &&" : ""); + printf("%s=%d\n", var, val); } int show_bisect_vars(struct rev_list_info *info, int reaches, int all) { - int cnt, stringed, flags = info->bisect_show_flags; + int cnt, flags = info->bisect_show_flags; char hex[41] = ""; struct commit_list *tried; struct rev_info *revs = info->revs; @@ -285,17 +285,15 @@ int show_bisect_vars(struct rev_list_info *info, int reaches, int all) printf("------\n"); } - stringed = flags & BISECT_SHOW_STRINGED; - if (flags & BISECT_SHOW_TRIED) - show_tried_revs(tried, stringed); + show_tried_revs(tried); - print_var_str("bisect_rev", hex, stringed); - print_var_int("bisect_nr", cnt - 1, stringed); - print_var_int("bisect_good", all - reaches - 1, stringed); - print_var_int("bisect_bad", reaches - 1, stringed); - print_var_int("bisect_all", all, stringed); - print_var_int("bisect_steps", estimate_bisect_steps(all), 0); + print_var_str("bisect_rev", hex); + print_var_int("bisect_nr", cnt - 1); + print_var_int("bisect_good", all - reaches - 1); + print_var_int("bisect_bad", reaches - 1); + print_var_int("bisect_all", all); + print_var_int("bisect_steps", estimate_bisect_steps(all)); return 0; } From 503253771e93fd9f29c9f0773223d456677452c4 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sat, 25 Apr 2009 06:55:26 +0200 Subject: [PATCH 584/654] rev-parse: add --sq-quote to shell quote arguments Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-rev-parse.txt | 35 ++++++++++++++++++++++++++++++++- builtin-rev-parse.c | 15 ++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index 52c353e674..4bbdd056da 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. +--sq-quote:: + Use 'git-rev-parse' in shell quoting mode (see SQ-QUOTE + section below). In contrast to the `--sq` option below, this + mode does only quoting. Nothing else is done to command input. + --revs-only:: Do not output flags and parameters not meant for 'git-rev-list' command. @@ -64,7 +69,8 @@ OPTIONS properly quoted for consumption by shell. Useful when you expect your parameter to contain whitespaces and newlines (e.g. when using pickaxe `-S` with - 'git-diff-\*'). + 'git-diff-\*'). In contrast to the `--sq-quote` option, + the command input is still interpreted as usual. --not:: When showing object names, prefix them with '{caret}' and @@ -406,6 +412,33 @@ C? option C with an optional argument" eval `echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?` ------------ +SQ-QUOTE +-------- + +In `--sq-quote` mode, 'git-rev-parse' echoes on the standard output a +single line suitable for `sh(1)` `eval`. This line is made by +normalizing the arguments following `--sq-quote`. Nothing other than +quoting the arguments is done. + +If you want command input to still be interpreted as usual by +'git-rev-parse' before the output is shell quoted, see the `--sq` +option. + +Example +~~~~~~~ + +------------ +$ cat >your-git-script.sh <<\EOF +#!/bin/sh +args=$(git rev-parse --sq-quote "$@") # quote user-supplied arguments +command="git frotz -n24 $args" # and use it inside a handcrafted + # command line +eval "$command" +EOF + +$ sh your-git-script.sh "a b'c" +------------ + EXAMPLES -------- diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c index 22c6d6ad16..c5b3d6e31b 100644 --- a/builtin-rev-parse.c +++ b/builtin-rev-parse.c @@ -402,6 +402,18 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix) return 0; } +static int cmd_sq_quote(int argc, const char **argv) +{ + struct strbuf buf = STRBUF_INIT; + + if (argc) + sq_quote_argv(&buf, argv, 0); + printf("%s\n", buf.buf); + strbuf_release(&buf); + + return 0; +} + static void die_no_single_rev(int quiet) { if (quiet) @@ -419,6 +431,9 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) if (argc > 1 && !strcmp("--parseopt", argv[1])) return cmd_parseopt(argc - 1, argv + 1, prefix); + if (argc > 1 && !strcmp("--sq-quote", argv[1])) + return cmd_sq_quote(argc - 2, argv + 2); + prefix = setup_git_directory(); git_config(git_default_config, NULL); for (i = 1; i < argc; i++) { From de52f5a806f58c6b73b2e24768530213fab5a635 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Fri, 24 Apr 2009 08:29:00 +0200 Subject: [PATCH 585/654] bisect: use "git rev-parse --sq-quote" instead of a custom "sq" function As the "sq" function was the only place using Perl in "git-bisect.sh", this removes the Perl dependency in this script. While at it, we also remove the sed instruction in the Makefile that substituted @@PERL@@ with the Perl path in shell scripts, as this is not needed anymore. (It is now only needed in "git-instaweb.sh" but this command is dealt with separately in the Makefile.) Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 1 - git-bisect.sh | 16 +++------------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index 6e216436c3..274d97c836 100644 --- a/Makefile +++ b/Makefile @@ -1248,7 +1248,6 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh $(QUIET_GEN)$(RM) $@ $@+ && \ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \ - -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ $@.sh >$@+ && \ diff --git a/git-bisect.sh b/git-bisect.sh index e1f300bed1..786b7b9110 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -33,16 +33,6 @@ require_work_tree _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" -sq() { - @@PERL@@ -e ' - for (@ARGV) { - s/'\''/'\'\\\\\'\''/g; - print " '\''$_'\''"; - } - print "\n"; - ' "$@" -} - bisect_autostart() { test -s "$GIT_DIR/BISECT_START" || { echo >&2 'You need to start by "git bisect start"' @@ -107,7 +97,7 @@ bisect_start() { for arg; do case "$arg" in --) has_double_dash=1; break ;; esac done - orig_args=$(sq "$@") + orig_args=$(git rev-parse --sq-quote "$@") bad_seen=0 eval='' while [ $# -gt 0 ]; do @@ -147,7 +137,7 @@ bisect_start() { # Write new start state. # echo "$start_head" >"$GIT_DIR/BISECT_START" && - sq "$@" >"$GIT_DIR/BISECT_NAMES" && + git rev-parse --sq-quote "$@" >"$GIT_DIR/BISECT_NAMES" && eval "$eval" && echo "git bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit # @@ -199,7 +189,7 @@ bisect_skip() { *..*) revs=$(git rev-list "$arg") || die "Bad rev input: $arg" ;; *) - revs=$(sq "$arg") ;; + revs=$(git rev-parse --sq-quote "$arg") ;; esac all="$all $revs" done From 47c9739e5e02484de618ca70a592ecd25c05fd1a Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Fri, 24 Apr 2009 08:29:01 +0200 Subject: [PATCH 586/654] am: simplify "sq" function by using "git rev-parse --sq-quote" Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-am.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/git-am.sh b/git-am.sh index 6d1848b6cc..578780be13 100755 --- a/git-am.sh +++ b/git-am.sh @@ -44,11 +44,7 @@ else fi sq () { - for sqarg - do - printf "%s" "$sqarg" | - sed -e 's/'\''/'\''\\'\'''\''/g' -e 's/.*/ '\''&'\''/' - done + git rev-parse --sq-quote "$@" } stop_here () { From 6212b1aae9dcc0de1dca1553298c6668579dd184 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sat, 9 May 2009 17:55:38 +0200 Subject: [PATCH 587/654] bisect: use "sha1_array" to store skipped revisions This patch creates a "struct sha1_array" to store skipped revisions, so that the same struct can be reused in a later patch for good revisions. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/bisect.c b/bisect.c index 4796aa9198..12df855cfa 100644 --- a/bisect.c +++ b/bisect.c @@ -9,9 +9,13 @@ #include "run-command.h" #include "bisect.h" -static unsigned char (*skipped_sha1)[20]; -static int skipped_sha1_nr; -static int skipped_sha1_alloc; +struct sha1_array { + unsigned char (*sha1)[20]; + int sha1_nr; + int sha1_alloc; +}; + +static struct sha1_array skipped_revs; static const char **rev_argv; static int rev_argv_nr; @@ -420,9 +424,9 @@ static int register_ref(const char *refname, const unsigned char *sha1, ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); rev_argv[rev_argv_nr++] = good; } else if (!prefixcmp(refname, "skip-")) { - ALLOC_GROW(skipped_sha1, skipped_sha1_nr + 1, - skipped_sha1_alloc); - hashcpy(skipped_sha1[skipped_sha1_nr++], sha1); + ALLOC_GROW(skipped_revs.sha1, skipped_revs.sha1_nr + 1, + skipped_revs.sha1_alloc); + hashcpy(skipped_revs.sha1[skipped_revs.sha1_nr++], sha1); } return 0; @@ -466,7 +470,8 @@ static int skipcmp(const void *a, const void *b) static void prepare_skipped(void) { - qsort(skipped_sha1, skipped_sha1_nr, sizeof(*skipped_sha1), skipcmp); + qsort(skipped_revs.sha1, skipped_revs.sha1_nr, + sizeof(*skipped_revs.sha1), skipcmp); } static const unsigned char *skipped_sha1_access(size_t index, void *table) @@ -477,7 +482,7 @@ static const unsigned char *skipped_sha1_access(size_t index, void *table) static int lookup_skipped(unsigned char *sha1) { - return sha1_pos(sha1, skipped_sha1, skipped_sha1_nr, + return sha1_pos(sha1, skipped_revs.sha1, skipped_revs.sha1_nr, skipped_sha1_access); } @@ -489,7 +494,7 @@ struct commit_list *filter_skipped(struct commit_list *list, *tried = NULL; - if (!skipped_sha1_nr) + if (!skipped_revs.sha1_nr) return list; prepare_skipped(); @@ -551,7 +556,7 @@ static void bisect_common(struct rev_info *revs, const char *prefix, mark_edges_uninteresting(revs->commits, revs, NULL); revs->commits = find_bisection(revs->commits, reaches, all, - !!skipped_sha1_nr); + !!skipped_revs.sha1_nr); } static void exit_if_skipped_commits(struct commit_list *tried, From 3755ccdb65a3bcaa1d55a6b4ec9c47eab0501baa Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sat, 9 May 2009 17:55:39 +0200 Subject: [PATCH 588/654] bisect: implement "rev_argv_push" to fill an argv with revs This patch is a minor clean up right now, but the new function will evolve and be used more later. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/bisect.c b/bisect.c index 12df855cfa..f99637d9cf 100644 --- a/bisect.c +++ b/bisect.c @@ -409,20 +409,23 @@ struct commit_list *find_bisection(struct commit_list *list, return best; } +static void rev_argv_push(const unsigned char *sha1, const char *format) +{ + struct strbuf buf = STRBUF_INIT; + + strbuf_addf(&buf, format, sha1_to_hex(sha1)); + ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); + rev_argv[rev_argv_nr++] = strbuf_detach(&buf, NULL); +} + static int register_ref(const char *refname, const unsigned char *sha1, int flags, void *cb_data) { if (!strcmp(refname, "bad")) { - ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); current_bad_sha1 = sha1; - rev_argv[rev_argv_nr++] = xstrdup(sha1_to_hex(sha1)); + rev_argv_push(sha1, "%s"); } else if (!prefixcmp(refname, "good-")) { - const char *hex = sha1_to_hex(sha1); - char *good = xmalloc(strlen(hex) + 2); - *good = '^'; - memcpy(good + 1, hex, strlen(hex) + 1); - ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); - rev_argv[rev_argv_nr++] = good; + rev_argv_push(sha1, "^%s"); } else if (!prefixcmp(refname, "skip-")) { ALLOC_GROW(skipped_revs.sha1, skipped_revs.sha1_nr + 1, skipped_revs.sha1_alloc); From fad2d31d62277eced9aa7fc187ae3b97e72895bb Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sat, 9 May 2009 17:55:40 +0200 Subject: [PATCH 589/654] bisect: store good revisions in a "sha1_array" This will make it easier to use good revisions for checking merge bases later. To simplify the code, a new "sha1_array_push" function is also introduced. And while at it we move the earlier part of the code to fill the argv that is passed to "setup_revisions", so that all this code is now completely after "read_bisect_refs". Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/bisect.c b/bisect.c index f99637d9cf..7976cbfcd7 100644 --- a/bisect.c +++ b/bisect.c @@ -15,6 +15,7 @@ struct sha1_array { int sha1_alloc; }; +static struct sha1_array good_revs; static struct sha1_array skipped_revs; static const char **rev_argv; @@ -418,18 +419,22 @@ static void rev_argv_push(const unsigned char *sha1, const char *format) rev_argv[rev_argv_nr++] = strbuf_detach(&buf, NULL); } +static void sha1_array_push(struct sha1_array *array, + const unsigned char *sha1) +{ + ALLOC_GROW(array->sha1, array->sha1_nr + 1, array->sha1_alloc); + hashcpy(array->sha1[array->sha1_nr++], sha1); +} + static int register_ref(const char *refname, const unsigned char *sha1, int flags, void *cb_data) { if (!strcmp(refname, "bad")) { current_bad_sha1 = sha1; - rev_argv_push(sha1, "%s"); } else if (!prefixcmp(refname, "good-")) { - rev_argv_push(sha1, "^%s"); + sha1_array_push(&good_revs, sha1); } else if (!prefixcmp(refname, "skip-")) { - ALLOC_GROW(skipped_revs.sha1, skipped_revs.sha1_nr + 1, - skipped_revs.sha1_alloc); - hashcpy(skipped_revs.sha1[skipped_revs.sha1_nr++], sha1); + sha1_array_push(&skipped_revs, sha1); } return 0; @@ -524,16 +529,23 @@ struct commit_list *filter_skipped(struct commit_list *list, static void bisect_rev_setup(struct rev_info *revs, const char *prefix) { + int i; + init_revisions(revs, prefix); revs->abbrev = 0; revs->commit_format = CMIT_FMT_UNSPECIFIED; + if (read_bisect_refs()) + die("reading bisect refs failed"); + /* argv[0] will be ignored by setup_revisions */ ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); rev_argv[rev_argv_nr++] = xstrdup("bisect_rev_setup"); - if (read_bisect_refs()) - die("reading bisect refs failed"); + rev_argv_push(current_bad_sha1, "%s"); + + for (i = 0; i < good_revs.sha1_nr; i++) + rev_argv_push(good_revs.sha1[i], "^%s"); ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); rev_argv[rev_argv_nr++] = xstrdup("--"); From 1c953a1f46340a9ca0fc84345e826c9372dee42a Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sat, 9 May 2009 17:55:41 +0200 Subject: [PATCH 590/654] bisect: use new "struct argv_array" to prepare argv for "setup_revisions" Because we will use other instances of this struct. The "rev_argv_push" function is changed into 2 functions "argv_array_push" and "argv_array_push_sha1" that take a "struct argv_array *" as first argument. And these functions are used to simplify "bisect_rev_setup". Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 57 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/bisect.c b/bisect.c index 7976cbfcd7..8e34186f95 100644 --- a/bisect.c +++ b/bisect.c @@ -18,12 +18,16 @@ struct sha1_array { static struct sha1_array good_revs; static struct sha1_array skipped_revs; -static const char **rev_argv; -static int rev_argv_nr; -static int rev_argv_alloc; - static const unsigned char *current_bad_sha1; +struct argv_array { + const char **argv; + int argv_nr; + int argv_alloc; +}; + +struct argv_array rev_argv; + static const char *argv_diff_tree[] = {"diff-tree", "--pretty", NULL, NULL}; static const char *argv_checkout[] = {"checkout", "-q", NULL, "--", NULL}; static const char *argv_show_branch[] = {"show-branch", NULL, NULL}; @@ -410,13 +414,19 @@ struct commit_list *find_bisection(struct commit_list *list, return best; } -static void rev_argv_push(const unsigned char *sha1, const char *format) +static void argv_array_push(struct argv_array *array, const char *string) +{ + ALLOC_GROW(array->argv, array->argv_nr + 1, array->argv_alloc); + array->argv[array->argv_nr++] = string; +} + +static void argv_array_push_sha1(struct argv_array *array, + const unsigned char *sha1, + const char *format) { struct strbuf buf = STRBUF_INIT; - strbuf_addf(&buf, format, sha1_to_hex(sha1)); - ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); - rev_argv[rev_argv_nr++] = strbuf_detach(&buf, NULL); + argv_array_push(array, strbuf_detach(&buf, NULL)); } static void sha1_array_push(struct sha1_array *array, @@ -445,7 +455,7 @@ static int read_bisect_refs(void) return for_each_ref_in("refs/bisect/", register_ref, NULL); } -void read_bisect_paths(void) +void read_bisect_paths(struct argv_array *array) { struct strbuf str = STRBUF_INIT; const char *filename = git_path("BISECT_NAMES"); @@ -460,8 +470,8 @@ void read_bisect_paths(void) strbuf_trim(&str); quoted = strbuf_detach(&str, NULL); - res = sq_dequote_to_argv(quoted, &rev_argv, - &rev_argv_nr, &rev_argv_alloc); + res = sq_dequote_to_argv(quoted, &array->argv, + &array->argv_nr, &array->argv_alloc); if (res) die("Badly quoted content in file '%s': %s", filename, quoted); @@ -538,25 +548,16 @@ static void bisect_rev_setup(struct rev_info *revs, const char *prefix) if (read_bisect_refs()) die("reading bisect refs failed"); - /* argv[0] will be ignored by setup_revisions */ - ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); - rev_argv[rev_argv_nr++] = xstrdup("bisect_rev_setup"); - - rev_argv_push(current_bad_sha1, "%s"); - + /* rev_argv.argv[0] will be ignored by setup_revisions */ + argv_array_push(&rev_argv, xstrdup("bisect_rev_setup")); + argv_array_push_sha1(&rev_argv, current_bad_sha1, "%s"); for (i = 0; i < good_revs.sha1_nr; i++) - rev_argv_push(good_revs.sha1[i], "^%s"); - - ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); - rev_argv[rev_argv_nr++] = xstrdup("--"); - - read_bisect_paths(); - - ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); - rev_argv[rev_argv_nr++] = NULL; - - setup_revisions(rev_argv_nr, rev_argv, revs, NULL); + argv_array_push_sha1(&rev_argv, good_revs.sha1[i], "^%s"); + argv_array_push(&rev_argv, xstrdup("--")); + read_bisect_paths(&rev_argv); + argv_array_push(&rev_argv, NULL); + setup_revisions(rev_argv.argv_nr, rev_argv.argv, revs, NULL); revs->limited = 1; } From 2b020695e4db8dbaee7997090aec08760903291b Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sat, 9 May 2009 17:55:42 +0200 Subject: [PATCH 591/654] bisect: remove too much function nesting This patch moves some function calls into "bisect_next_exit" so that functions are nesting less. The call to "bisect_rev_setup" is moved from "bisect_common" into "bisect_next_exit" and the call to "read_bisect_refs" from "bisect_rev_setup" into "bisect_next_exit". While at it, "rev_argv" is moved into "bisect_rev_setup". This will make it easier and cleaner to implement checking merge bases. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/bisect.c b/bisect.c index 8e34186f95..9e01b9e0ef 100644 --- a/bisect.c +++ b/bisect.c @@ -26,8 +26,6 @@ struct argv_array { int argv_alloc; }; -struct argv_array rev_argv; - static const char *argv_diff_tree[] = {"diff-tree", "--pretty", NULL, NULL}; static const char *argv_checkout[] = {"checkout", "-q", NULL, "--", NULL}; static const char *argv_show_branch[] = {"show-branch", NULL, NULL}; @@ -539,15 +537,13 @@ struct commit_list *filter_skipped(struct commit_list *list, static void bisect_rev_setup(struct rev_info *revs, const char *prefix) { + struct argv_array rev_argv = { NULL, 0, 0 }; int i; init_revisions(revs, prefix); revs->abbrev = 0; revs->commit_format = CMIT_FMT_UNSPECIFIED; - if (read_bisect_refs()) - die("reading bisect refs failed"); - /* rev_argv.argv[0] will be ignored by setup_revisions */ argv_array_push(&rev_argv, xstrdup("bisect_rev_setup")); argv_array_push_sha1(&rev_argv, current_bad_sha1, "%s"); @@ -561,11 +557,8 @@ static void bisect_rev_setup(struct rev_info *revs, const char *prefix) revs->limited = 1; } -static void bisect_common(struct rev_info *revs, const char *prefix, - int *reaches, int *all) +static void bisect_common(struct rev_info *revs, int *reaches, int *all) { - bisect_rev_setup(revs, prefix); - if (prepare_revision_walk(revs)) die("revision walk setup failed"); if (revs->tree_objects) @@ -636,7 +629,12 @@ int bisect_next_exit(const char *prefix) const unsigned char *bisect_rev; char bisect_rev_hex[41]; - bisect_common(&revs, prefix, &reaches, &all); + if (read_bisect_refs()) + die("reading bisect refs failed"); + + bisect_rev_setup(&revs, prefix); + + bisect_common(&revs, &reaches, &all); revs.commits = filter_skipped(revs.commits, &tried, 0); From aaaff9e2d29a68c23a416bcc5f3f382504770bf8 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sat, 9 May 2009 17:55:43 +0200 Subject: [PATCH 592/654] bisect: make skipped array functions more generic So they can be used on the good array too. This is done by renaming many functions and some variables to remove "skip" in the name, and by adding a "struct sha1_array *array" argument where needed. While at it, make the second argument to "lookup_sha1_array" const. It becomes "const unsigned char *sha1". Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/bisect.c b/bisect.c index 9e01b9e0ef..77edecaaec 100644 --- a/bisect.c +++ b/bisect.c @@ -479,27 +479,26 @@ void read_bisect_paths(struct argv_array *array) fclose(fp); } -static int skipcmp(const void *a, const void *b) +static int array_cmp(const void *a, const void *b) { return hashcmp(a, b); } -static void prepare_skipped(void) +static void sort_sha1_array(struct sha1_array *array) { - qsort(skipped_revs.sha1, skipped_revs.sha1_nr, - sizeof(*skipped_revs.sha1), skipcmp); + qsort(array->sha1, array->sha1_nr, sizeof(*array->sha1), array_cmp); } -static const unsigned char *skipped_sha1_access(size_t index, void *table) +static const unsigned char *sha1_access(size_t index, void *table) { - unsigned char (*skipped)[20] = table; - return skipped[index]; + unsigned char (*array)[20] = table; + return array[index]; } -static int lookup_skipped(unsigned char *sha1) +static int lookup_sha1_array(struct sha1_array *array, + const unsigned char *sha1) { - return sha1_pos(sha1, skipped_revs.sha1, skipped_revs.sha1_nr, - skipped_sha1_access); + return sha1_pos(sha1, array->sha1, array->sha1_nr, sha1_access); } struct commit_list *filter_skipped(struct commit_list *list, @@ -513,12 +512,13 @@ struct commit_list *filter_skipped(struct commit_list *list, if (!skipped_revs.sha1_nr) return list; - prepare_skipped(); + sort_sha1_array(&skipped_revs); while (list) { struct commit_list *next = list->next; list->next = NULL; - if (0 <= lookup_skipped(list->item->object.sha1)) { + if (0 <= lookup_sha1_array(&skipped_revs, + list->item->object.sha1)) { /* Move current to tried list */ *tried = list; tried = &list->next; From 1da8c4fc2c85ed99e23d640bddedd8119150a1b8 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sat, 9 May 2009 17:55:44 +0200 Subject: [PATCH 593/654] bisect: automatically sort sha1_array if needed when looking it up This makes sha1_array easier to use, so later patches will be simpler. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bisect.c b/bisect.c index 77edecaaec..d2a34d1e51 100644 --- a/bisect.c +++ b/bisect.c @@ -13,6 +13,7 @@ struct sha1_array { unsigned char (*sha1)[20]; int sha1_nr; int sha1_alloc; + int sorted; }; static struct sha1_array good_revs; @@ -487,6 +488,8 @@ static int array_cmp(const void *a, const void *b) static void sort_sha1_array(struct sha1_array *array) { qsort(array->sha1, array->sha1_nr, sizeof(*array->sha1), array_cmp); + + array->sorted = 1; } static const unsigned char *sha1_access(size_t index, void *table) @@ -498,6 +501,9 @@ static const unsigned char *sha1_access(size_t index, void *table) static int lookup_sha1_array(struct sha1_array *array, const unsigned char *sha1) { + if (!array->sorted) + sort_sha1_array(array); + return sha1_pos(sha1, array->sha1, array->sha1_nr, sha1_access); } @@ -512,8 +518,6 @@ struct commit_list *filter_skipped(struct commit_list *list, if (!skipped_revs.sha1_nr) return list; - sort_sha1_array(&skipped_revs); - while (list) { struct commit_list *next = list->next; list->next = NULL; From c0537662806f4b3d3ba883d05a48fdf9120893f0 Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sat, 9 May 2009 17:55:45 +0200 Subject: [PATCH 594/654] bisect: implement the "check_merge_bases" function And all functions needed to make it work. This is a port from the shell function with the same name "git-bisect.sh". This function is not used yet but it will be used later. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/bisect.c b/bisect.c index d2a34d1e51..b24ee78ba9 100644 --- a/bisect.c +++ b/bisect.c @@ -507,6 +507,20 @@ static int lookup_sha1_array(struct sha1_array *array, return sha1_pos(sha1, array->sha1, array->sha1_nr, sha1_access); } +static char *join_sha1_array_hex(struct sha1_array *array, char delim) +{ + struct strbuf joined_hexs = STRBUF_INIT; + int i; + + for (i = 0; i < array->sha1_nr; i++) { + strbuf_addstr(&joined_hexs, sha1_to_hex(array->sha1[i])); + if (i + 1 < array->sha1_nr) + strbuf_addch(&joined_hexs, delim); + } + + return strbuf_detach(&joined_hexs, NULL); +} + struct commit_list *filter_skipped(struct commit_list *list, struct commit_list **tried, int show_all) @@ -587,6 +601,30 @@ static void exit_if_skipped_commits(struct commit_list *tried, exit(2); } +static int is_expected_rev(const unsigned char *sha1) +{ + const char *filename = git_path("BISECT_EXPECTED_REV"); + struct stat st; + struct strbuf str = STRBUF_INIT; + FILE *fp; + int res = 0; + + if (stat(filename, &st) || !S_ISREG(st.st_mode)) + return 0; + + fp = fopen(filename, "r"); + if (!fp) + return 0; + + if (strbuf_getline(&str, fp, '\n') != EOF) + res = !strcmp(str.buf, sha1_to_hex(sha1)); + + strbuf_release(&str); + fclose(fp); + + return res; +} + static void mark_expected_rev(char *bisect_rev_hex) { int len = strlen(bisect_rev_hex); @@ -620,6 +658,98 @@ static int bisect_checkout(char *bisect_rev_hex) return run_command_v_opt(argv_show_branch, RUN_GIT_CMD); } +static struct commit *get_commit_reference(const unsigned char *sha1) +{ + struct commit *r = lookup_commit_reference(sha1); + if (!r) + die("Not a valid commit name %s", sha1_to_hex(sha1)); + return r; +} + +static struct commit **get_bad_and_good_commits(int *rev_nr) +{ + int len = 1 + good_revs.sha1_nr; + struct commit **rev = xmalloc(len * sizeof(*rev)); + int i, n = 0; + + rev[n++] = get_commit_reference(current_bad_sha1); + for (i = 0; i < good_revs.sha1_nr; i++) + rev[n++] = get_commit_reference(good_revs.sha1[i]); + *rev_nr = n; + + return rev; +} + +static void handle_bad_merge_base(void) +{ + if (is_expected_rev(current_bad_sha1)) { + char *bad_hex = sha1_to_hex(current_bad_sha1); + char *good_hex = join_sha1_array_hex(&good_revs, ' '); + + fprintf(stderr, "The merge base %s is bad.\n" + "This means the bug has been fixed " + "between %s and [%s].\n", + bad_hex, bad_hex, good_hex); + + exit(3); + } + + fprintf(stderr, "Some good revs are not ancestor of the bad rev.\n" + "git bisect cannot work properly in this case.\n" + "Maybe you mistake good and bad revs?\n"); + exit(1); +} + +void handle_skipped_merge_base(const unsigned char *mb) +{ + char *mb_hex = sha1_to_hex(mb); + char *bad_hex = sha1_to_hex(current_bad_sha1); + char *good_hex = join_sha1_array_hex(&good_revs, ' '); + + fprintf(stderr, "Warning: the merge base between %s and [%s] " + "must be skipped.\n" + "So we cannot be sure the first bad commit is " + "between %s and %s.\n" + "We continue anyway.\n", + bad_hex, good_hex, mb_hex, bad_hex); + free(good_hex); +} + +/* + * "check_merge_bases" checks that merge bases are not "bad". + * + * - If one is "bad", it means the user assumed something wrong + * and we must exit with a non 0 error code. + * - If one is "good", that's good, we have nothing to do. + * - If one is "skipped", we can't know but we should warn. + * - If we don't know, we should check it out and ask the user to test. + */ +static void check_merge_bases(void) +{ + struct commit_list *result; + int rev_nr; + struct commit **rev = get_bad_and_good_commits(&rev_nr); + + result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1, 0); + + for (; result; result = result->next) { + const unsigned char *mb = result->item->object.sha1; + if (!hashcmp(mb, current_bad_sha1)) { + handle_bad_merge_base(); + } else if (0 <= lookup_sha1_array(&good_revs, mb)) { + continue; + } else if (0 <= lookup_sha1_array(&skipped_revs, mb)) { + handle_skipped_merge_base(mb); + } else { + printf("Bisecting: a merge base must be tested\n"); + exit(bisect_checkout(sha1_to_hex(mb))); + } + } + + free(rev); + free_commit_list(result); +} + /* * We use the convention that exiting with an exit code 10 means that * the bisection process finished successfully. From d937d4aca1f10b9202b620a89dc6a5972e9605eb Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sat, 9 May 2009 17:55:46 +0200 Subject: [PATCH 595/654] bisect: add "check_good_are_ancestors_of_bad" function This is a port of the function with the same name that is in "git-bisect.sh". The new function is not used yet but will be in a later patch. We also implement an helper "check_ancestors" function that use "start_command" and "finish_command" to launch "git rev-list $good ^$bad". Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/bisect.c b/bisect.c index b24ee78ba9..09102daba8 100644 --- a/bisect.c +++ b/bisect.c @@ -750,6 +750,81 @@ static void check_merge_bases(void) free_commit_list(result); } +/* + * This function runs the command "git rev-list $_good ^$_bad" + * and returns 1 if it produces some output, 0 otherwise. + */ +static int check_ancestors(void) +{ + struct argv_array rev_argv = { NULL, 0, 0 }; + struct strbuf str = STRBUF_INIT; + int i, result = 0; + struct child_process rls; + FILE *rls_fout; + + argv_array_push(&rev_argv, xstrdup("rev-list")); + argv_array_push_sha1(&rev_argv, current_bad_sha1, "^%s"); + for (i = 0; i < good_revs.sha1_nr; i++) + argv_array_push_sha1(&rev_argv, good_revs.sha1[i], "%s"); + argv_array_push(&rev_argv, NULL); + + memset(&rls, 0, sizeof(rls)); + rls.argv = rev_argv.argv; + rls.out = -1; + rls.git_cmd = 1; + if (start_command(&rls)) + die("Could not launch 'git rev-list' command."); + rls_fout = fdopen(rls.out, "r"); + while (strbuf_getline(&str, rls_fout, '\n') != EOF) { + strbuf_trim(&str); + if (*str.buf) { + result = 1; + break; + } + } + fclose(rls_fout); + finish_command(&rls); + + return result; +} + +/* + * "check_good_are_ancestors_of_bad" checks that all "good" revs are + * ancestor of the "bad" rev. + * + * If that's not the case, we need to check the merge bases. + * If a merge base must be tested by the user, its source code will be + * checked out to be tested by the user and we will exit. + */ +static void check_good_are_ancestors_of_bad(const char *prefix) +{ + const char *filename = git_path("BISECT_ANCESTORS_OK"); + struct stat st; + int fd; + + if (!current_bad_sha1) + die("a bad revision is needed"); + + /* Check if file BISECT_ANCESTORS_OK exists. */ + if (!stat(filename, &st) && S_ISREG(st.st_mode)) + return; + + /* Bisecting with no good rev is ok. */ + if (good_revs.sha1_nr == 0) + return; + + if (check_ancestors()) + check_merge_bases(); + + /* Create file BISECT_ANCESTORS_OK. */ + fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600); + if (fd < 0) + warning("could not create file '%s': %s", + filename, strerror(errno)); + else + close(fd); +} + /* * We use the convention that exiting with an exit code 10 means that * the bisection process finished successfully. From 0871984d304c9201b85897743eae583cd165106d Mon Sep 17 00:00:00 2001 From: Christian Couder <chriscool@tuxfamily.org> Date: Sat, 9 May 2009 17:55:47 +0200 Subject: [PATCH 596/654] bisect: make "git bisect" use new "--next-all" bisect-helper function This patch replace the "--next-exit" option of "git bisect--helper" with a "--next-all" option that does merge base checking using the "check_good_are_ancestors_of_bad" function implemented in "bisect.c" in a former patch. The new "--next-all" option is then used in "git-bisect.sh" instead of the "--next-exit" option, and all the shell functions in "git-bisect.sh" that are now unused are removed. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bisect.c | 4 +- bisect.h | 2 +- builtin-bisect--helper.c | 14 ++--- git-bisect.sh | 127 +-------------------------------------- 4 files changed, 13 insertions(+), 134 deletions(-) diff --git a/bisect.c b/bisect.c index 09102daba8..f57b62cddd 100644 --- a/bisect.c +++ b/bisect.c @@ -830,7 +830,7 @@ static void check_good_are_ancestors_of_bad(const char *prefix) * the bisection process finished successfully. * In this case the calling shell script should exit 0. */ -int bisect_next_exit(const char *prefix) +int bisect_next_all(const char *prefix) { struct rev_info revs; struct commit_list *tried; @@ -841,6 +841,8 @@ int bisect_next_exit(const char *prefix) if (read_bisect_refs()) die("reading bisect refs failed"); + check_good_are_ancestors_of_bad(prefix); + bisect_rev_setup(&revs, prefix); bisect_common(&revs, &reaches, &all); diff --git a/bisect.h b/bisect.h index 0b5d122a7b..fb744fdb79 100644 --- a/bisect.h +++ b/bisect.h @@ -27,7 +27,7 @@ struct rev_list_info { extern int show_bisect_vars(struct rev_list_info *info, int reaches, int all); -extern int bisect_next_exit(const char *prefix); +extern int bisect_next_all(const char *prefix); extern int estimate_bisect_steps(int all); diff --git a/builtin-bisect--helper.c b/builtin-bisect--helper.c index aca7018d83..cb3e155116 100644 --- a/builtin-bisect--helper.c +++ b/builtin-bisect--helper.c @@ -4,24 +4,24 @@ #include "bisect.h" static const char * const git_bisect_helper_usage[] = { - "git bisect--helper --next-exit", + "git bisect--helper --next-all", NULL }; int cmd_bisect__helper(int argc, const char **argv, const char *prefix) { - int next_exit = 0; + int next_all = 0; struct option options[] = { - OPT_BOOLEAN(0, "next-exit", &next_exit, - "output bisect result and exit instuctions"), + OPT_BOOLEAN(0, "next-all", &next_all, + "perform 'git bisect next'"), OPT_END() }; argc = parse_options(argc, argv, options, git_bisect_helper_usage, 0); - if (!next_exit) + if (!next_all) usage_with_options(git_bisect_helper_usage, options); - /* next-exit */ - return bisect_next_exit(prefix); + /* next-all */ + return bisect_next_all(prefix); } diff --git a/git-bisect.sh b/git-bisect.sh index 786b7b9110..8969553658 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -167,10 +167,6 @@ is_expected_rev() { test "$1" = $(cat "$GIT_DIR/BISECT_EXPECTED_REV") } -mark_expected_rev() { - echo "$1" > "$GIT_DIR/BISECT_EXPECTED_REV" -} - check_expected_revs() { for _rev in "$@"; do if ! is_expected_rev "$_rev"; then @@ -269,132 +265,13 @@ bisect_auto_next() { bisect_next_check && bisect_next || : } -bisect_checkout() { - _rev="$1" - _msg="$2" - echo "Bisecting: $_msg" - mark_expected_rev "$_rev" - git checkout -q "$_rev" -- || exit - git show-branch "$_rev" -} - -is_among() { - _rev="$1" - _list="$2" - case "$_list" in *$_rev*) return 0 ;; esac - return 1 -} - -handle_bad_merge_base() { - _badmb="$1" - _good="$2" - if is_expected_rev "$_badmb"; then - cat >&2 <<EOF -The merge base $_badmb is bad. -This means the bug has been fixed between $_badmb and [$_good]. -EOF - exit 3 - else - cat >&2 <<EOF -Some good revs are not ancestor of the bad rev. -git bisect cannot work properly in this case. -Maybe you mistake good and bad revs? -EOF - exit 1 - fi -} - -handle_skipped_merge_base() { - _mb="$1" - _bad="$2" - _good="$3" - cat >&2 <<EOF -Warning: the merge base between $_bad and [$_good] must be skipped. -So we cannot be sure the first bad commit is between $_mb and $_bad. -We continue anyway. -EOF -} - -# -# "check_merge_bases" checks that merge bases are not "bad". -# -# - If one is "good", that's good, we have nothing to do. -# - If one is "bad", it means the user assumed something wrong -# and we must exit. -# - If one is "skipped", we can't know but we should warn. -# - If we don't know, we should check it out and ask the user to test. -# -# In the last case we will return 1, and otherwise 0. -# -check_merge_bases() { - _bad="$1" - _good="$2" - _skip="$3" - for _mb in $(git merge-base --all $_bad $_good) - do - if is_among "$_mb" "$_good"; then - continue - elif test "$_mb" = "$_bad"; then - handle_bad_merge_base "$_bad" "$_good" - elif is_among "$_mb" "$_skip"; then - handle_skipped_merge_base "$_mb" "$_bad" "$_good" - else - bisect_checkout "$_mb" "a merge base must be tested" - return 1 - fi - done - return 0 -} - -# -# "check_good_are_ancestors_of_bad" checks that all "good" revs are -# ancestor of the "bad" rev. -# -# If that's not the case, we need to check the merge bases. -# If a merge base must be tested by the user we return 1 and -# otherwise 0. -# -check_good_are_ancestors_of_bad() { - test -f "$GIT_DIR/BISECT_ANCESTORS_OK" && - return - - _bad="$1" - _good=$(echo $2 | sed -e 's/\^//g') - _skip="$3" - - # Bisecting with no good rev is ok - test -z "$_good" && return - - _side=$(git rev-list $_good ^$_bad) - if test -n "$_side"; then - # Return if a checkout was done - check_merge_bases "$_bad" "$_good" "$_skip" || return - fi - - : > "$GIT_DIR/BISECT_ANCESTORS_OK" - - return 0 -} - bisect_next() { case "$#" in 0) ;; *) usage ;; esac bisect_autostart bisect_next_check good - # Get bad, good and skipped revs - bad=$(git rev-parse --verify refs/bisect/bad) && - good=$(git for-each-ref --format='^%(objectname)' \ - "refs/bisect/good-*" | tr '\012' ' ') && - skip=$(git for-each-ref --format='%(objectname)' \ - "refs/bisect/skip-*" | tr '\012' ' ') || exit - - # Maybe some merge bases must be tested first - check_good_are_ancestors_of_bad "$bad" "$good" "$skip" - # Return now if a checkout has already been done - test "$?" -eq "1" && return - - # Perform bisection computation, display and checkout - git bisect--helper --next-exit + # Perform all bisection computation, display and checkout + git bisect--helper --next-all res=$? # Check if we should exit because bisection is finished From ad87e4f6f19e78b3f2d7dde3d3ed403db4f79a03 Mon Sep 17 00:00:00 2001 From: Jakub Narebski <jnareb@gmail.com> Date: Mon, 11 May 2009 03:21:06 +0200 Subject: [PATCH 597/654] gitweb: Do not use bareword filehandles gitweb: Do not use bareword filehandles The script was using bareword filehandles. This is considered a bad practice so they have been changed to indirect filehandles. Changes touch git_get_project_ctags and mimetype_guess_file; while at it rename local variable from $mime to $mimetype (in mimetype_guess_file) to better reflect its value (its contents). Signed-off-by: Jakub Narebski <jnareb@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- gitweb/gitweb.perl | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 06e91608fa..584644cbee 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2065,18 +2065,17 @@ sub git_get_project_ctags { my $ctags = {}; $git_dir = "$projectroot/$path"; - unless (opendir D, "$git_dir/ctags") { - return $ctags; - } - foreach (grep { -f $_ } map { "$git_dir/ctags/$_" } readdir(D)) { - open CT, $_ or next; - my $val = <CT>; + opendir my $dh, "$git_dir/ctags" + or return $ctags; + foreach (grep { -f $_ } map { "$git_dir/ctags/$_" } readdir($dh)) { + open my $ct, $_ or next; + my $val = <$ct>; chomp $val; - close CT; + close $ct; my $ctag = $_; $ctag =~ s#.*/##; $ctags->{$ctag} = $val; } - closedir D; + closedir $dh; $ctags; } @@ -2804,18 +2803,18 @@ sub mimetype_guess_file { -r $mimemap or return undef; my %mimemap; - open(MIME, $mimemap) or return undef; - while (<MIME>) { + open(my $mh, $mimemap) or return undef; + while (<$mh>) { next if m/^#/; # skip comments - my ($mime, $exts) = split(/\t+/); + my ($mimetype, $exts) = split(/\t+/); if (defined $exts) { my @exts = split(/\s+/, $exts); foreach my $ext (@exts) { - $mimemap{$ext} = $mime; + $mimemap{$ext} = $mimetype; } } } - close(MIME); + close($mh); $filename =~ /\.([^.]*)$/; return $mimemap{$1}; From dff2b6d4842eef0a03a3c8b3761f72e2b55b609e Mon Sep 17 00:00:00 2001 From: Jakub Narebski <jnareb@gmail.com> Date: Sun, 10 May 2009 02:38:34 +0200 Subject: [PATCH 598/654] gitweb: Always use three argument form of open In most cases (except insert_file() subroutine) we used old two argument form of 'open' to open files for reading. This can cause subtle bugs when $projectroot or $projects_list file starts with mode characters ('>', '<', '+<', '|', etc.) or with leading whitespace; and also when $projects_list file or $mimetypes_file or ctags files end with trailing whitespace or '|'. Additionally it is also more clear to explicitly state that we open those files for reading. Signed-off-by: Jakub Narebski <jnareb@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- gitweb/gitweb.perl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 584644cbee..e7cab9020f 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2050,7 +2050,7 @@ sub git_get_project_description { my $path = shift; $git_dir = "$projectroot/$path"; - open my $fd, "$git_dir/description" + open my $fd, '<', "$git_dir/description" or return git_get_project_config('description'); my $descr = <$fd>; close $fd; @@ -2068,7 +2068,7 @@ sub git_get_project_ctags { opendir my $dh, "$git_dir/ctags" or return $ctags; foreach (grep { -f $_ } map { "$git_dir/ctags/$_" } readdir($dh)) { - open my $ct, $_ or next; + open my $ct, '<', $_ or next; my $val = <$ct>; chomp $val; close $ct; @@ -2128,7 +2128,7 @@ sub git_get_project_url_list { my $path = shift; $git_dir = "$projectroot/$path"; - open my $fd, "$git_dir/cloneurl" + open my $fd, '<', "$git_dir/cloneurl" or return wantarray ? @{ config_to_multi(git_get_project_config('url')) } : config_to_multi(git_get_project_config('url')); @@ -2186,7 +2186,7 @@ sub git_get_projects_list { # 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin' # 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman' my %paths; - open my ($fd), $projects_list or return; + open my $fd, '<', $projects_list or return; PROJECT: while (my $line = <$fd>) { chomp $line; @@ -2249,7 +2249,7 @@ sub git_get_project_list_from_file { # 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin' # 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman' if (-f $projects_list) { - open (my $fd , $projects_list); + open(my $fd, '<', $projects_list); while (my $line = <$fd>) { chomp $line; my ($pr, $ow) = split ' ', $line; @@ -2803,7 +2803,7 @@ sub mimetype_guess_file { -r $mimemap or return undef; my %mimemap; - open(my $mh, $mimemap) or return undef; + open(my $mh, '<', $mimemap) or return undef; while (<$mh>) { next if m/^#/; # skip comments my ($mimetype, $exts) = split(/\t+/); From 34122b57eca747022336f5a3dc1aa80377d1ce56 Mon Sep 17 00:00:00 2001 From: Jakub Narebski <jnareb@gmail.com> Date: Mon, 11 May 2009 03:29:40 +0200 Subject: [PATCH 599/654] gitweb: Always use three argument form of open From 94638fb6edf3ea693228c680a6a30271ccd77522 Mon Sep 17 00:00:00 2001 From: Jakub Narebski <jnareb@gmail.com> Date: Mon, 11 May 2009 03:25:55 +0200 Subject: [PATCH] gitweb: Localize magic variable $/ Instead of undefining and then restoring magic variable $/ (input record separator) for 'slurp mode', localize it. While at it, state explicitely that "local $/;" makes it undefined, by using explicit "local $/ = undef;". Signed-off-by: Jakub Narebski <jnareb@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- gitweb/gitweb.perl | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index e7cab9020f..4efeeedccf 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3325,7 +3325,7 @@ sub git_get_link_target { open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash or return; { - local $/; + local $/ = undef; $link_target = <$fd>; } close $fd @@ -4800,11 +4800,10 @@ sub git_blob_plain { -content_disposition => ($sandbox ? 'attachment' : 'inline') . '; filename="' . $save_as . '"'); - undef $/; + local $/ = undef; binmode STDOUT, ':raw'; print <$fd>; binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi - $/ = "\n"; close $fd; } @@ -4906,12 +4905,16 @@ sub git_tree { } } die_error(404, "No such tree") unless defined($hash); - $/ = "\0"; - open my $fd, "-|", git_cmd(), "ls-tree", '-z', $hash - or die_error(500, "Open git-ls-tree failed"); - my @entries = map { chomp; $_ } <$fd>; - close $fd or die_error(404, "Reading tree failed"); - $/ = "\n"; + + my @entries = (); + { + local $/ = "\0"; + open my $fd, "-|", git_cmd(), "ls-tree", '-z', $hash + or die_error(500, "Open git-ls-tree failed"); + @entries = map { chomp; $_ } <$fd>; + close $fd + or die_error(404, "Reading tree failed"); + } my $refs = git_get_references(); my $ref = format_ref_marker($refs, $hash_base); @@ -5806,7 +5809,7 @@ sub git_search { print "<table class=\"pickaxe search\">\n"; my $alternate = 1; - $/ = "\n"; + local $/ = "\n"; open my $fd, '-|', git_cmd(), '--no-pager', 'log', @diff_opts, '--pretty=format:%H', '--no-abbrev', '--raw', "-S$searchtext", ($search_use_regexp ? '--pickaxe-regex' : ()); @@ -5876,7 +5879,7 @@ sub git_search { print "<table class=\"grep_search\">\n"; my $alternate = 1; my $matches = 0; - $/ = "\n"; + local $/ = "\n"; open my $fd, "-|", git_cmd(), 'grep', '-n', $search_use_regexp ? ('-E', '-i') : '-F', $searchtext, $co{'tree'}; From 68cedb1fea0bbcd5f7c32ce10e3c346bc6db38c5 Mon Sep 17 00:00:00 2001 From: Jakub Narebski <jnareb@gmail.com> Date: Sun, 10 May 2009 02:40:37 +0200 Subject: [PATCH 600/654] gitweb: Use block form of map/grep in a few cases more Use block form of 'grep' i.e. 'grep {BLOCK} LIST' rather than 'grep(EXPR, LIST)' in filter_snapshot_fmts subroutine. This makes code more readable, as expression is rather long, and statement above there is 'map' with very similar expression also in the block form. Remove unnecessary and misleading parentheses around block form 'map' arguments in quote_command subroutine. The inner "map" in format_snapshot_links was left alone, as it is not clear whether adding parentheses or changing it into block form would improve readibility and clarity of this code. Signed-off-by: Jakub Narebski <jnareb@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- gitweb/gitweb.perl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 4efeeedccf..8c51f3e79e 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -458,8 +458,8 @@ sub filter_snapshot_fmts { @fmts = map { exists $known_snapshot_format_aliases{$_} ? $known_snapshot_format_aliases{$_} : $_} @fmts; - @fmts = grep(exists $known_snapshot_formats{$_}, @fmts); - + @fmts = grep { + exists $known_snapshot_formats{$_} } @fmts; } our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++"; @@ -1838,7 +1838,7 @@ sub git_cmd { # Try to avoid using this function wherever possible. sub quote_command { return join(' ', - map( { my $a = $_; $a =~ s/(['!])/'\\$1'/g; "'$a'" } @_ )); + map { my $a = $_; $a =~ s/(['!])/'\\$1'/g; "'$a'" } @_ ); } # get HEAD ref of given project as hash From eb127887faa8771f2cf11d6809abfc51eb661e6e Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Tue, 12 May 2009 02:01:51 -0700 Subject: [PATCH 601/654] t3900: ISO-2022-JP has more than one popular variants When converting from other encodings (e.g. EUC-JP or UTF-8), there are subtly different variants of ISO-2022-JP, all of which are valid. At the end of line or when a run of string switches to 1-byte sequence, ESC ( B can be used to switch to ASCII or ESC ( J can be used to switch to ISO 646:JP (JIS X 0201) but they essentially are the same character set and are used interchangeably. Similarly the set ESC $ @ switches to (JIS X 0208-1978) and ESC $ B switches to (JIS X 0208-1983) are in practice used interchangeably. Depending on the iconv library and the locale definition on the system, a program that converts from another encoding to ISO-2022-JP can produce different byte sequence, and GIT_TEST_CMP (aka "diff -u") will report the difference as a failure. Fix this by converting the expected and the actual output to UTF-8 before comparing when the end result is ISO-2022-JP. The test vector string in t3900/ISO-2022-JP.txt is expressed with ASCII and JIS X 0208-1983, but it can be expressed with any other possible variant, and when converted back to UTF-8, these variants produce identical byte sequences. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t3900-i18n-commit.sh | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index 784c31aec9..5dbbcb6345 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -9,7 +9,15 @@ test_description='commit and log output encodings' compare_with () { git show -s $1 | sed -e '1,/^$/d' -e 's/^ //' >current && - test_cmp current "$2" + case "$3" in + '') + test_cmp "$2" current ;; + ?*) + iconv -f "$3" -t utf8 >current.utf8 <current && + iconv -f "$3" -t utf8 >expect.utf8 <"$2" && + test_cmp expect.utf8 current.utf8 + ;; + esac } test_expect_success setup ' @@ -103,11 +111,17 @@ done for J in EUCJP ISO-2022-JP do + if test "$J" = ISO-2022-JP + then + ICONV=$J + else + ICONV= + fi git config i18n.logoutputencoding $J for H in EUCJP ISO-2022-JP do test_expect_success "$H should be shown in $J now" ' - compare_with '$H' "$TEST_DIRECTORY"/t3900/'$J'.txt + compare_with '$H' "$TEST_DIRECTORY"/t3900/'$J'.txt $ICONV ' done done From 4774780ab196ff4ace780445c06c8e5bfffffc49 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Tue, 12 May 2009 22:28:22 -0700 Subject: [PATCH 602/654] GIT 1.6.3.1 Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/RelNotes-1.6.3.1.txt | 10 ++++------ GIT-VERSION-GEN | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Documentation/RelNotes-1.6.3.1.txt b/Documentation/RelNotes-1.6.3.1.txt index 98c02250bb..2400b72ef7 100644 --- a/Documentation/RelNotes-1.6.3.1.txt +++ b/Documentation/RelNotes-1.6.3.1.txt @@ -4,9 +4,7 @@ GIT v1.6.3.1 Release Notes Fixes since v1.6.3 ------------------ --- -exec >/var/tmp/1 -O=v1.6.3 -echo O=$(git describe maint) -git shortlog $O..maint - +* "git checkout -b new-branch" with a staged change in the index + incorrectly primed the in-index cache-tree, resulting a wrong tree + object to be written out of the index. This is a grave regression + since the last 1.6.2.X maintenance release. diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 39cde784c9..d292e3a2d3 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.6.3.GIT +DEF_VER=v1.6.3.1 LF=' ' From 3278fbc5ce39e0f7bf095ce99912dccbc347b4d7 Mon Sep 17 00:00:00 2001 From: Jakub Narebski <jnareb@gmail.com> Date: Mon, 11 May 2009 19:37:28 +0200 Subject: [PATCH 603/654] gitweb: Replace wrongly added tabs with spaces In two places there was hard tab character instead of space. Fix this. Signed-off-by: Jakub Narebski <jnareb@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- gitweb/gitweb.perl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 8c51f3e79e..beb79eebd5 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3990,7 +3990,7 @@ sub fill_project_list_info { ($pname !~ /\/$/) && (-d "$projectroot/$pname")) { $pr->{'forks'} = "-d $projectroot/$pname"; - } else { + } else { $pr->{'forks'} = 0; } } @@ -6282,7 +6282,7 @@ XML # end of feed if ($format eq 'rss') { print "</channel>\n</rss>\n"; - } elsif ($format eq 'atom') { + } elsif ($format eq 'atom') { print "</feed>\n"; } } From e8bb4b38dfcbd5ff02ceb5e925d53c1460887df5 Mon Sep 17 00:00:00 2001 From: Jakub Narebski <jnareb@gmail.com> Date: Mon, 11 May 2009 19:39:43 +0200 Subject: [PATCH 604/654] gitweb: Use capturing parentheses only when you intend to capture Non-capturing groups are useful because they have better runtime performance and do not copy strings to the magic global capture variables. Signed-off-by: Jakub Narebski <jnareb@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- gitweb/gitweb.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index beb79eebd5..097bd18be5 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -828,7 +828,7 @@ if (!defined $action) { if (!defined($actions{$action})) { die_error(400, "Unknown action"); } -if ($action !~ m/^(opml|project_list|project_index)$/ && +if ($action !~ m/^(?:opml|project_list|project_index)$/ && !$project) { die_error(400, "Project needed"); } From 095e914281395f6c0529ce39939d804eb2ccec02 Mon Sep 17 00:00:00 2001 From: Jakub Narebski <jnareb@gmail.com> Date: Mon, 11 May 2009 19:42:47 +0200 Subject: [PATCH 605/654] gitweb: Simplify snapshot format detection logic in evaluate_path_info This issue was caught by perlcritic in harsh severity level noticing that catch variable was used outside conditional thanks to the Perl::Critic::Policy::RegularExpressions::ProhibitCaptureWithoutTest policy. See "Perl Best Practices", chapter 12. Regular Expressions, section 12.15. Captured Values: Pattern matches that fail never assign anything to $1, $2, etc., nor do they leave those variables undefined. After an unsuccessful pattern match, the numeric capture variables remain exactly as they were before the match was attempted. New version is in my opinion much easier to understand; previous version worked correctly due to the fact that we returned from loop on first found match. Signed-off-by: Jakub Narebski <jnareb@gmail.com> Acked-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- gitweb/gitweb.perl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 097bd18be5..c72ae10ef1 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -690,9 +690,10 @@ sub evaluate_path_info { # format key itself, with a prepended dot while (my ($fmt, $opt) = each %known_snapshot_formats) { my $hash = $refname; - my $sfx; - $hash =~ s/(\Q$opt->{'suffix'}\E|\Q.$fmt\E)$//; - next unless $sfx = $1; + unless ($hash =~ s/(\Q$opt->{'suffix'}\E|\Q.$fmt\E)$//) { + next; + } + my $sfx = $1; # a valid suffix was found, so set the snapshot format # and reset the hash parameter $input_params{'snapshot_format'} = $fmt; From 15c54fe7aa9376de2e03045122723ebde09bfeeb Mon Sep 17 00:00:00 2001 From: Jakub Narebski <jnareb@gmail.com> Date: Mon, 11 May 2009 19:45:11 +0200 Subject: [PATCH 606/654] gitweb: Remove unused $hash_base parameter from normalize_link_target ...since it was decided for normalize_link_target to only mangle pathname, and do not try to check if target is present in $hash_base tree, for performance reasons. Signed-off-by: Jakub Narebski <jnareb@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- gitweb/gitweb.perl | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index c72ae10ef1..05702e4070 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3339,10 +3339,7 @@ sub git_get_link_target { # return target of link relative to top directory (top tree); # return undef if it is not possible (including absolute links). sub normalize_link_target { - my ($link_target, $basedir, $hash_base) = @_; - - # we can normalize symlink target only if $hash_base is provided - return unless $hash_base; + my ($link_target, $basedir) = @_; # absolute symlinks (beginning with '/') cannot be normalized return if (substr($link_target, 0, 1) eq '/'); @@ -3398,7 +3395,7 @@ sub git_print_tree_entry { if (S_ISLNK(oct $t->{'mode'})) { my $link_target = git_get_link_target($t->{'hash'}); if ($link_target) { - my $norm_target = normalize_link_target($link_target, $basedir, $hash_base); + my $norm_target = normalize_link_target($link_target, $basedir); if (defined $norm_target) { print " -> " . $cgi->a({-href => href(action=>"object", hash_base=>$hash_base, From 00652369ff285f84e440f5d41d708283e30825d7 Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Fri, 8 May 2009 18:23:32 -0700 Subject: [PATCH 607/654] bash completion: complete variable names for "git config" with options This makes it easier for users to get and unset their configuration variables without having to open documentation or dig through their configuration file. __git_config_get_set_variables() retrieves the set configuration variables from the appropriate configuration file. For example, if the user has previously specified --global only the global variables are returned. The same applies for --system, and --file. If no location has been specified, all set variables are returned. Signed-off-by: Stephen Boyd <bebarino@gmail.com> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 33 ++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 1683e6d7b8..ad26b7c5ae 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1322,6 +1322,35 @@ _git_send_email () COMPREPLY=() } +__git_config_get_set_variables () +{ + local prevword word config_file= c=$COMP_CWORD + while [ $c -gt 1 ]; do + word="${COMP_WORDS[c]}" + case "$word" in + --global|--system|--file=*) + config_file="$word" + break + ;; + -f|--file) + config_file="$word $prevword" + break + ;; + esac + prevword=$word + c=$((--c)) + done + + for i in $(git --git-dir="$(__gitdir)" config $config_file --list \ + 2>/dev/null); do + case "$i" in + *.*) + echo "${i/=*/}" + ;; + esac + done +} + _git_config () { local cur="${COMP_WORDS[COMP_CWORD]}" @@ -1388,6 +1417,10 @@ _git_config () __gitcomp "$__git_send_email_suppresscc_options" return ;; + --get|--get-all|--unset|--unset-all) + __gitcomp "$(__git_config_get_set_variables)" + return + ;; *.*) COMPREPLY=() return From 1a2872595409fbdd5d448730953884ef8d8c6613 Mon Sep 17 00:00:00 2001 From: Michael J Gruber <git@drmicha.warpmail.net> Date: Wed, 13 May 2009 17:43:06 +0200 Subject: [PATCH 608/654] Documentation: clarify / requirement in 'git check-ref-format' 'git check-ref-format' checks for the presence of at least one '/', the idea being that there should be no refs directly below 'refs/', so there should be a category like 'heads/' or 'tags/' in a refname. Try and make this clearer in the man page. Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-check-ref-format.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt index c1ce26884e..0873e60f7f 100644 --- a/Documentation/git-check-ref-format.txt +++ b/Documentation/git-check-ref-format.txt @@ -25,6 +25,10 @@ imposes the following rules on how references are named: grouping, but no slash-separated component can begin with a dot `.`. +. They must contain at least one `/`. This enforces the presence of a + category like `heads/`, `tags/` etc. but the actual names are not + restricted. + . They cannot have two consecutive dots `..` anywhere. . They cannot have ASCII control characters (i.e. bytes whose From 95405ba6cf7adeaa4a066e8a3a1b76b73f7b9341 Mon Sep 17 00:00:00 2001 From: Alex Riesen <raa.lkml@gmail.com> Date: Wed, 13 May 2009 20:08:53 +0200 Subject: [PATCH 609/654] Quote LF in urls git fetch saves in FETCH_HEAD The fmt-merge-msg does a strong syntax checking of its input and fails with if it is incorrect. The LF character is the only character important for fmt-merge-msg. As the url in FETCH_HEAD plays only informational role, a quoted representation of the url should be good and true enough. The url often comes from either user-editable config or command line, so it is reasonable to expect all kinds of characters in it, including the characters which the format of FETCH_HEAD considers special (line separator in this case). Noticed and reported by Hugo Mildenberger. Signed-off-by: Alex Riesen <raa.lkml@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-fetch.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/builtin-fetch.c b/builtin-fetch.c index 3c998ea740..ec75df0900 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -353,12 +353,18 @@ static int store_updated_refs(const char *url, const char *remote_name, kind); note_len += sprintf(note + note_len, "'%s' of ", what); } - note_len += sprintf(note + note_len, "%.*s", url_len, url); - fprintf(fp, "%s\t%s\t%s\n", + note[note_len] = '\0'; + fprintf(fp, "%s\t%s\t%s", sha1_to_hex(commit ? commit->object.sha1 : rm->old_sha1), rm->merge ? "" : "not-for-merge", note); + for (i = 0; i < url_len; ++i) + if ('\n' == url[i]) + fputs("\\n", fp); + else + fputc(url[i], fp); + fputc('\n', fp); if (ref) rc |= update_local_ref(ref, what, note); From 1be570f4ebb5f3c4e0a56341db166a760829782a Mon Sep 17 00:00:00 2001 From: Michael J Gruber <git@drmicha.warpmail.net> Date: Mon, 11 May 2009 16:42:53 +0200 Subject: [PATCH 610/654] Test tracking of non-commit upstreams git-checkout and git-branch allow setting up an arbitrary committish as the upstream reference for --track. In particular, tags are allowed. But they and git-status barf on non-commit upstreams as soon as they are asked for trackings stats. Expose this shortcoming by adding two tests: annotated tags are affected but lightweight tags are OK. Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t6040-tracking-info.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh index ba9060190d..4b89ac71f5 100755 --- a/t/t6040-tracking-info.sh +++ b/t/t6040-tracking-info.sh @@ -66,5 +66,19 @@ test_expect_success 'status' ' grep "have 1 and 1 different" actual ' +test_expect_success 'status when tracking lightweight tags' ' + git checkout master && + git tag light && + git branch --track lighttrack light >actual && + grep "set up to track" actual && + git checkout lighttrack +' +test_expect_failure 'status when tracking annotated tags' ' + git checkout master && + git tag -m heavy heavy && + git branch --track heavytrack heavy >actual && + grep "set up to track" actual && + git checkout heavytrack +' test_done From 3426e34feddf97085615e619d39f8173ff3f9fb4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <Johannes.Schindelin@gmx.de> Date: Mon, 11 May 2009 13:02:18 +0200 Subject: [PATCH 611/654] Add NO_CROSS_DIRECTORY_HARDLINKS support to the Makefile When the installed programs are tar'ed up and installed on a system where bin/ and libexec/git-core/ live on different file systems, we do not want libexec/git-core/git-* to be hardlinks to bin/git. Noticed by Cedric Staniewski. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 0675c43e73..2b8ce48c0c 100644 --- a/Makefile +++ b/Makefile @@ -159,6 +159,9 @@ all:: # Define NO_EXTERNAL_GREP if you don't want "git grep" to ever call # your external grep (e.g., if your system lacks grep, if its grep is # broken, or spawning external process is slower than built-in grep git has). +# +# Define NO_CROSS_DIRECTORY_HARDLINKS if you plan to distribute the installed +# programs as a tar, where bin/ and libexec/ might be on different file systems. GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE @$(SHELL_PATH) ./GIT-VERSION-GEN @@ -1468,6 +1471,7 @@ endif bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \ execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \ { $(RM) "$$execdir/git-add$X" && \ + test -z "$(NO_CROSS_DIRECTORY_HARDLINKS)" && \ ln "$$bindir/git$X" "$$execdir/git-add$X" 2>/dev/null || \ cp "$$bindir/git$X" "$$execdir/git-add$X"; } && \ { for p in $(filter-out git-add$X,$(BUILT_INS)); do \ From 09caa24facae88e19cce1c12f21dac935cbf0909 Mon Sep 17 00:00:00 2001 From: Trent Piepho <xyzzy@speakeasy.org> Date: Tue, 12 May 2009 15:48:56 -0700 Subject: [PATCH 612/654] send-email: Add config option for sender address The sender address, as specified with the '--from' command line option, couldn't be set in the config file. So add a new config option, 'sendemail.from', which sets it. One can use 'sendemail.<identity>.from' as well of course, which is likely the more useful case. The sender address would default to GIT_AUTHOR_IDENT, which is usually the right thing, but this doesn't allow switching based on the identity selected. It's possible to switch the SMTP server and envelope sender by using the '--identity' option, in which case one probably wants to use a different from address as well, but this had to be manually specified. The documentation for 'from' is also corrected somewhat. If '--from' is specified (or the new sendemail.from option is used) then the user isn't prompted. The default with no '--from' option (or sendemail.from option) is GIT_AUTHOR_IDENT first then GIT_COMMITTER_IDENT, not just GIT_COMMITTER_IDENT. Signed-off-by: Trent Piepho <xyzzy@speakeasy.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-send-email.txt | 9 ++++++--- git-send-email.perl | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index 794224b1b3..f940770279 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -69,9 +69,12 @@ and In-Reply-To headers will be used unless they are removed. Missing From or In-Reply-To headers will be prompted for. --from=<address>:: - Specify the sender of the emails. This will default to - the value GIT_COMMITTER_IDENT, as returned by "git var -l". - The user will still be prompted to confirm this entry. + Specify the sender of the emails. If not specified on the command line, + the value of the 'sendemail.from' configuration option is used. If + neither the command line option nor 'sendemail.from' are set, then the + user will be prompted for the value. The default for the prompt will be + the value of GIT_AUTHOR_IDENT, or GIT_COMMITTER_IDENT if that is not + set, as returned by "git var -l". --in-reply-to=<identifier>:: Specify the contents of the first In-Reply-To header. diff --git a/git-send-email.perl b/git-send-email.perl index cccbf4517a..d9c7f32aa3 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -210,6 +210,7 @@ my %config_settings = ( "envelopesender" => \$envelope_sender, "multiedit" => \$multiedit, "confirm" => \$confirm, + "from" => \$sender, ); # Handle Uncouth Termination From 4577e483648f50dd80faa401dc1d3eb33ffb627b Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Thu, 14 May 2009 00:22:04 +0300 Subject: [PATCH 613/654] Change prettify_ref to prettify_refname In preparation to be used when the ref object is not available Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Acked-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-fetch.c | 2 +- builtin-send-pack.c | 4 ++-- refs.c | 3 +-- refs.h | 2 +- transport.c | 4 ++-- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/builtin-fetch.c b/builtin-fetch.c index 3c998ea740..ebd0c08788 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -197,7 +197,7 @@ static int update_local_ref(struct ref *ref, struct commit *current = NULL, *updated; enum object_type type; struct branch *current_branch = branch_get(NULL); - const char *pretty_ref = prettify_ref(ref); + const char *pretty_ref = prettify_refname(ref->name); *display = 0; type = sha1_object_info(ref->new_sha1, NULL); diff --git a/builtin-send-pack.c b/builtin-send-pack.c index d5a1c48d0e..b2279b0d29 100644 --- a/builtin-send-pack.c +++ b/builtin-send-pack.c @@ -174,9 +174,9 @@ static void print_ref_status(char flag, const char *summary, struct ref *to, str { fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary); if (from) - fprintf(stderr, "%s -> %s", prettify_ref(from), prettify_ref(to)); + fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name)); else - fputs(prettify_ref(to), stderr); + fputs(prettify_refname(to->name), stderr); if (msg) { fputs(" (", stderr); fputs(msg, stderr); diff --git a/refs.c b/refs.c index e65a3b4c4e..e74461eaaf 100644 --- a/refs.c +++ b/refs.c @@ -750,9 +750,8 @@ int check_ref_format(const char *ref) } } -const char *prettify_ref(const struct ref *ref) +const char *prettify_refname(const char *name) { - const char *name = ref->name; return name + ( !prefixcmp(name, "refs/heads/") ? 11 : !prefixcmp(name, "refs/tags/") ? 10 : diff --git a/refs.h b/refs.h index 29d17a48e4..c11f6a6d58 100644 --- a/refs.h +++ b/refs.h @@ -80,7 +80,7 @@ extern int for_each_reflog(each_ref_fn, void *); #define CHECK_REF_FORMAT_WILDCARD (-3) extern int check_ref_format(const char *target); -extern const char *prettify_ref(const struct ref *ref); +extern const char *prettify_refname(const char *refname); extern char *shorten_unambiguous_ref(const char *ref, int strict); /** rename ref, return 0 on success **/ diff --git a/transport.c b/transport.c index 3dfb03c06e..38c7f578e5 100644 --- a/transport.c +++ b/transport.c @@ -732,9 +732,9 @@ static void print_ref_status(char flag, const char *summary, struct ref *to, str { fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary); if (from) - fprintf(stderr, "%s -> %s", prettify_ref(from), prettify_ref(to)); + fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name)); else - fputs(prettify_ref(to), stderr); + fputs(prettify_refname(to->name), stderr); if (msg) { fputs(" (", stderr); fputs(msg, stderr); From de435ac0f633b1f68dba2970cb7fa019171e40fe Mon Sep 17 00:00:00 2001 From: Felipe Contreras <felipe.contreras@gmail.com> Date: Thu, 14 May 2009 00:32:53 +0300 Subject: [PATCH 614/654] Prettify log decorations even more "tag: v1.6.2.5" looks much better than "tag: refs/tags/v1.6.2.5". Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Acked-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- log-tree.c | 1 + t/t4013/diff.log_--decorate_--all | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/log-tree.c b/log-tree.c index 5bd29e6994..59d63eb67e 100644 --- a/log-tree.c +++ b/log-tree.c @@ -25,6 +25,7 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in struct object *obj = parse_object(sha1); if (!obj) return 0; + refname = prettify_refname(refname); add_name_decoration("", refname, obj); while (obj->type == OBJ_TAG) { obj = ((struct tag *)obj)->tagged; diff --git a/t/t4013/diff.log_--decorate_--all b/t/t4013/diff.log_--decorate_--all index 12da8ac07d..954210ea90 100644 --- a/t/t4013/diff.log_--decorate_--all +++ b/t/t4013/diff.log_--decorate_--all @@ -1,12 +1,12 @@ $ git log --decorate --all -commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (refs/heads/master) +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (master) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 Merge branch 'side' -commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (refs/heads/side) +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (side) Author: A U Thor <author@example.com> Date: Mon Jun 26 00:03:00 2006 +0000 @@ -26,7 +26,7 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. -commit 444ac553ac7612cc88969031b02b3767fb8a353a (refs/heads/initial) +commit 444ac553ac7612cc88969031b02b3767fb8a353a (initial) Author: A U Thor <author@example.com> Date: Mon Jun 26 00:00:00 2006 +0000 From 57ffc5f85a17416a718d4e7baf71d8356c9c7808 Mon Sep 17 00:00:00 2001 From: Michael J Gruber <git@drmicha.warpmail.net> Date: Mon, 11 May 2009 16:42:54 +0200 Subject: [PATCH 615/654] Fix behavior with non-commit upstream references stat_tracking_info() assumes that upstream references (as specified by --track or set up automatically) are commits. By calling lookup_commit() on them, create_objects() creates objects for them with type commit no matter what their real type is; this disturbs lookup_tag() later on in the call sequence, leading to git status, git branch -v and git checkout erroring out. Fix this by using lookup_commit_reference() instead so that (annotated) tags can be used as upstream references. Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- remote.c | 4 ++-- t/t6040-tracking-info.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/remote.c b/remote.c index d7079c6dd8..36c995d364 100644 --- a/remote.c +++ b/remote.c @@ -1296,13 +1296,13 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs) base = branch->merge[0]->dst; if (!resolve_ref(base, sha1, 1, NULL)) return 0; - theirs = lookup_commit(sha1); + theirs = lookup_commit_reference(sha1); if (!theirs) return 0; if (!resolve_ref(branch->refname, sha1, 1, NULL)) return 0; - ours = lookup_commit(sha1); + ours = lookup_commit_reference(sha1); if (!ours) return 0; diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh index 4b89ac71f5..5211e244b8 100755 --- a/t/t6040-tracking-info.sh +++ b/t/t6040-tracking-info.sh @@ -74,7 +74,7 @@ test_expect_success 'status when tracking lightweight tags' ' git checkout lighttrack ' -test_expect_failure 'status when tracking annotated tags' ' +test_expect_success 'status when tracking annotated tags' ' git checkout master && git tag -m heavy heavy && git branch --track heavytrack heavy >actual && From 90f2e6526b3b800af4d10b900167a508b3774b98 Mon Sep 17 00:00:00 2001 From: Tony Kemp <Tony.Kemp@newcastle.edu.au> Date: Thu, 14 May 2009 16:47:41 +1000 Subject: [PATCH 616/654] Turn on USE_ST_TIMESPEC for OpenBSD Like Darwin, OpenBSD's stat struct uses st_ctimespec and st_mtimestruct rather than st_ctim and st_mtim. Signed-off-by: Tony Kemp <tony.kemp@newcastle.edu.au> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 6e216436c3..26d180cc54 100644 --- a/Makefile +++ b/Makefile @@ -749,6 +749,7 @@ endif ifeq ($(uname_S),OpenBSD) NO_STRCASESTR = YesPlease NO_MEMMEM = YesPlease + USE_ST_TIMESPEC = YesPlease NEEDS_LIBICONV = YesPlease BASIC_CFLAGS += -I/usr/local/include BASIC_LDFLAGS += -L/usr/local/lib From ca156cfcc2dee5a1cee4f96023bb2f8c15a2c48c Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Sat, 16 May 2009 02:24:44 -0700 Subject: [PATCH 617/654] api-parse-options.txt: use 'func' instead of 'funct' Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/technical/api-parse-options.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt index e66ca9f70c..e30c602f47 100644 --- a/Documentation/technical/api-parse-options.txt +++ b/Documentation/technical/api-parse-options.txt @@ -198,7 +198,7 @@ The function must be defined in this form: The callback mechanism is as follows: -* Inside `funct`, the only interesting member of the structure +* Inside `func`, the only interesting member of the structure given by `opt` is the void pointer `opt->value`. `\*opt->value` will be the value that is saved into `var`, if you use `OPT_CALLBACK()`. From f044fe2de6f7bbace158853c075a4065f3722265 Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Sat, 16 May 2009 02:24:45 -0700 Subject: [PATCH 618/654] tests: Add tests for missing format-patch long options Exercise format-patch's --signoff, --in-reply-to and --start-number long options. Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t4014-format-patch.sh | 11 +++++++++++ t/t4021-format-patch-numbered.sh | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 11061ddd5b..922a8941ed 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -505,4 +505,15 @@ test_expect_success 'format-patch from a subdirectory (3)' ' test -f "$basename" ' +test_expect_success 'format-patch --in-reply-to' ' + git format-patch -1 --stdout --in-reply-to "baz@foo.bar" > patch8 && + grep "^In-Reply-To: <baz@foo.bar>" patch8 && + grep "^References: <baz@foo.bar>" patch8 +' + +test_expect_success 'format-patch --signoff' ' + git format-patch -1 --signoff --stdout | + grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" +' + test_done diff --git a/t/t4021-format-patch-numbered.sh b/t/t4021-format-patch-numbered.sh index 390af2389f..3c27f0dc19 100755 --- a/t/t4021-format-patch-numbered.sh +++ b/t/t4021-format-patch-numbered.sh @@ -108,4 +108,10 @@ test_expect_success 'format.numbered = auto && --no-numbered' ' ' +test_expect_success '--start-number && --numbered' ' + + git format-patch --start-number 3 --numbered --stdout HEAD~1 > patch8 && + grep "^Subject: \[PATCH 3/3\]" patch8 +' + test_done From c646217e1366b0397552fad8c32acb47fbe8977d Mon Sep 17 00:00:00 2001 From: Jim Meyering <jim@meyering.net> Date: Sat, 16 May 2009 12:21:50 +0200 Subject: [PATCH 619/654] pre-commit.sample: don't print incidental SHA1 Make the sample pre-commit hook script discard all git-rev-parse output, not just stderr. Otherwise, it would print an SHA1. Signed-off-by: Jim Meyering <meyering@redhat.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- templates/hooks--pre-commit.sample | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/hooks--pre-commit.sample b/templates/hooks--pre-commit.sample index 0e49279c7f..0ba62076fb 100755 --- a/templates/hooks--pre-commit.sample +++ b/templates/hooks--pre-commit.sample @@ -7,7 +7,7 @@ # # To enable this hook, rename this file to "pre-commit". -if git-rev-parse --verify HEAD 2>/dev/null +if git-rev-parse --verify HEAD >/dev/null 2>&1 then against=HEAD else From 77ebd56dc3d2efaeac87edc990cc1b99f331527c Mon Sep 17 00:00:00 2001 From: Daniel Cordero <theappleman@gmail.com> Date: Sat, 16 May 2009 10:54:45 -0700 Subject: [PATCH 620/654] builtin-checkout: Don't tell user that HEAD has moved before it has Previously, checkout would tell the user this message before moving HEAD, without regard to whether the upcoming move will result in success. If the move failed, this causes confusion. Show the message after the move, unless the move failed. Signed-off-by: Daniel Cordero <theappleman@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-checkout.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/builtin-checkout.c b/builtin-checkout.c index dc4bfb5fc0..f2d7ef01b0 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -541,14 +541,6 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new) parse_commit(new->commit); } - /* - * If we were on a detached HEAD, but we are now moving to - * a new commit, we want to mention the old commit once more - * to remind the user that it might be lost. - */ - if (!opts->quiet && !old.path && old.commit && new->commit != old.commit) - describe_detached_head("Previous HEAD position was", old.commit); - if (!old.commit && !opts->force) { if (!opts->quiet) { warning("You appear to be on a branch yet to be born."); @@ -561,6 +553,14 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new) if (ret) return ret; + /* + * If we were on a detached HEAD, but have now moved to + * a new commit, we want to mention the old commit once more + * to remind the user that it might be lost. + */ + if (!opts->quiet && !old.path && old.commit && new->commit != old.commit) + describe_detached_head("Previous HEAD position was", old.commit); + update_refs_for_switch(opts, &old, new); ret = post_checkout_hook(old.commit, new->commit, 1); From 39d404d13774fac5ce4b7b180d2b8988eb6fd6c7 Mon Sep 17 00:00:00 2001 From: Alex Riesen <raa.lkml@gmail.com> Date: Thu, 14 May 2009 14:55:54 +0200 Subject: [PATCH 621/654] Use UTF-8 instead of utf8 for backward compatibility An old iconv (GNU libiconv 1.11) does not know about utf8, it does know UTF-8 though, which is also understood by all newer iconv implementations. Signed-off-by: Alex Riesen <raa.lkml@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t3900-i18n-commit.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index 5dbbcb6345..b4ec2b53de 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -13,8 +13,8 @@ compare_with () { '') test_cmp "$2" current ;; ?*) - iconv -f "$3" -t utf8 >current.utf8 <current && - iconv -f "$3" -t utf8 >expect.utf8 <"$2" && + iconv -f "$3" -t UTF-8 >current.utf8 <current && + iconv -f "$3" -t UTF-8 >expect.utf8 <"$2" && test_cmp expect.utf8 current.utf8 ;; esac From 8a94bc7bdc54db0d77058e63baf173ff932cba7c Mon Sep 17 00:00:00 2001 From: Alex Riesen <raa.lkml@gmail.com> Date: Wed, 13 May 2009 18:32:06 +0200 Subject: [PATCH 622/654] Improve the naming of guessed target repository for git clone Strip leading and trailing spaces off guessed target directory, and replace sequences of whitespace and 'control' characters with one space character. User still can have any name by specifying it explicitely after url. Signed-off-by: Alex Riesen <raa.lkml@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-clone.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/builtin-clone.c b/builtin-clone.c index 880373f279..d068b7e0d8 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -104,11 +104,12 @@ static char *get_repo_path(const char *repo, int *is_bundle) static char *guess_dir_name(const char *repo, int is_bundle, int is_bare) { const char *end = repo + strlen(repo), *start; + char *dir; /* - * Strip trailing slashes and /.git + * Strip trailing spaces, slashes and /.git */ - while (repo < end && is_dir_sep(end[-1])) + while (repo < end && (is_dir_sep(end[-1]) || isspace(end[-1]))) end--; if (end - repo > 5 && is_dir_sep(end[-5]) && !strncmp(end - 4, ".git", 4)) { @@ -140,10 +141,33 @@ static char *guess_dir_name(const char *repo, int is_bundle, int is_bare) if (is_bare) { struct strbuf result = STRBUF_INIT; strbuf_addf(&result, "%.*s.git", (int)(end - start), start); - return strbuf_detach(&result, 0); + dir = strbuf_detach(&result, 0); + } else + dir = xstrndup(start, end - start); + /* + * Replace sequences of 'control' characters and whitespace + * with one ascii space, remove leading and trailing spaces. + */ + if (*dir) { + char *out = dir; + int prev_space = 1 /* strip leading whitespace */; + for (end = dir; *end; ++end) { + char ch = *end; + if ((unsigned char)ch < '\x20') + ch = '\x20'; + if (isspace(ch)) { + if (prev_space) + continue; + prev_space = 1; + } else + prev_space = 0; + *out++ = ch; + } + *out = '\0'; + if (out > dir && prev_space) + out[-1] = '\0'; } - - return xstrndup(start, end - start); + return dir; } static void strip_trailing_slashes(char *dir) From 8763dbb1b24c260243f69130c734c13563a16db6 Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Sat, 16 May 2009 11:46:22 -0700 Subject: [PATCH 623/654] completion: fix PS1 display during a merge on detached HEAD If your merge stops in a conflict while on a detached HEAD, recent completion code fails to show anything. This was because various cases added to support the operation-in-progress markers (e.g. REBASE, MERGING) forgot that they need to set the variable "b" to something for the result they computed to be displayed at all. Probably not many people make trial merges on a detached HEAD (which is tremendously useful feature of git, by the way), and that may be why this was not noticed for a long time. Acked-By: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 1683e6d7b8..c2f8ea3444 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -99,10 +99,10 @@ __git_ps1 () elif [ -d "$g/rebase-merge" ]; then r="|REBASE-m" b="$(cat "$g/rebase-merge/head-name")" - elif [ -f "$g/MERGE_HEAD" ]; then - r="|MERGING" - b="$(git symbolic-ref HEAD 2>/dev/null)" else + if [ -f "$g/MERGE_HEAD" ]; then + r="|MERGING" + fi if [ -f "$g/BISECT_LOG" ]; then r="|BISECTING" fi From ff790b6a4bb7fa3bbccd5ea23cefd89da900aa2e Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Sun, 10 May 2009 01:53:19 -0700 Subject: [PATCH 624/654] completion: simplify "current branch" in __git_ps1() As I very often work on a detached HEAD, I found it pretty confusing when __git_ps1() said 'some-name'. Did I create a branch with that name by mistake, or do I happen to be on a commit with that exact tag? This patch fixes the issue by enclosing non branch names in a pair of parentheses when used to substitute %s token in __git_ps1() argument. It also fixes a small bug where the branch part is left empty when .git/HEAD is unreadable for whatever reason. The output now says "(unknown)". Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index c2f8ea3444..be591468db 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -106,13 +106,14 @@ __git_ps1 () if [ -f "$g/BISECT_LOG" ]; then r="|BISECTING" fi - if ! b="$(git symbolic-ref HEAD 2>/dev/null)"; then - if ! b="$(git describe --exact-match HEAD 2>/dev/null)"; then - if [ -r "$g/HEAD" ]; then - b="$(cut -c1-7 "$g/HEAD")..." - fi - fi - fi + + b="$(git symbolic-ref HEAD 2>/dev/null)" || { + b="$(git describe --exact-match HEAD 2>/dev/null)" || + b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." || + b="unknown" + + b="($b)" + } fi local w From dd42c2f015102626562da05bb290f47862ea06fb Mon Sep 17 00:00:00 2001 From: Junio C Hamano <gitster@pobox.com> Date: Sun, 10 May 2009 01:56:21 -0700 Subject: [PATCH 625/654] completion: enhance "current branch" display Introduce GIT_PS1_DESCRIBE option you can set to "contains", "branch", or "describe" to tweak the way how a detached HEAD is described. The default behaviour is to describe only exact match with some tag (otherwise use the first 7 hexdigits) as before. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index be591468db..dd6cd250e3 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -108,10 +108,21 @@ __git_ps1 () fi b="$(git symbolic-ref HEAD 2>/dev/null)" || { - b="$(git describe --exact-match HEAD 2>/dev/null)" || + + b="$( + case "${GIT_PS1_DESCRIBE_STYLE-}" in + (contains) + git describe --contains HEAD ;; + (branch) + git describe --contains --all HEAD ;; + (describe) + git describe HEAD ;; + (* | default) + git describe --exact-match HEAD ;; + esac 2>/dev/null)" || + b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." || b="unknown" - b="($b)" } fi From e4b09dad9f65395fd4bb8ab165012a3a6698a75b Mon Sep 17 00:00:00 2001 From: Nanako Shiraishi <nanako3@lavabit.com> Date: Sun, 17 May 2009 11:43:08 +0900 Subject: [PATCH 626/654] test: checkout shouldn't say that HEAD has moved if it didn't MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: しらいしななこ <nanako3@lavabit.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t7201-co.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/t/t7201-co.sh b/t/t7201-co.sh index bdb808af1a..ebfd34df36 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -534,4 +534,12 @@ test_expect_success 'failing checkout -b should not break working tree' ' ' +test_expect_success 'switch out of non-branch' ' + git reset --hard master && + git checkout master^0 && + echo modified >one && + test_must_fail git checkout renamer 2>error.log && + ! grep "^Previous HEAD" error.log +' + test_done From b867d324ceb7e5c4f14a04c6b55d69498812d24b Mon Sep 17 00:00:00 2001 From: Dan McGee <dpmcgee@gmail.com> Date: Mon, 11 May 2009 20:17:38 -0500 Subject: [PATCH 627/654] Fix type-punning issues In these two places we are casting part of our unsigned char sha1 array into an unsigned int, which violates GCCs strict-aliasing rules (and probably other compilers). Signed-off-by: Dan McGee <dpmcgee@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- decorate.c | 4 +++- object.c | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/decorate.c b/decorate.c index 82d9e221ea..e6fd8a7441 100644 --- a/decorate.c +++ b/decorate.c @@ -8,7 +8,9 @@ static unsigned int hash_obj(const struct object *obj, unsigned int n) { - unsigned int hash = *(unsigned int *)obj->sha1; + unsigned int hash; + + memcpy(&hash, obj->sha1, sizeof(unsigned int)); return hash % n; } diff --git a/object.c b/object.c index 7e6a92c88e..e1feef9c33 100644 --- a/object.c +++ b/object.c @@ -45,7 +45,8 @@ int type_from_string(const char *str) static unsigned int hash_obj(struct object *obj, unsigned int n) { - unsigned int hash = *(unsigned int *)obj->sha1; + unsigned int hash; + memcpy(&hash, obj->sha1, sizeof(unsigned int)); return hash % n; } From da4b3e8c28b1dc2b856d2555ac7bb47ab712598c Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@linux-foundation.org> Date: Thu, 14 May 2009 13:05:03 -0700 Subject: [PATCH 628/654] dir.c: clean up handling of 'path' parameter in read_directory_recursive() Right now we pass two different pathnames ('path' and 'base') down to read_directory_recursive(), and the only real reason for that is that we want to allow an empty 'base' parameter, but when we do so, we need the pathname to "opendir()" to be "." rather than the empty string. And rather than handle that confusion in the caller, we can just fix read_directory_recursive() to handle the case of an empty path itself, by just passing opendir() a "." ourselves if the path is empty. This would allow us to then drop one of the pathnames entirely from the calling convention, but rather than do that, we'll start separating them out as a "filesystem pathname" (the one we use for filesystem accesses) and a "git internal base name" (which is the name that we use for git internally). That will eventually allow us to do things like handle different encodings (eg the filesystem pathnames might be Latin1, while git itself would use UTF-8 for filename information). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dir.c b/dir.c index 6aae09a22e..0e6b752cd5 100644 --- a/dir.c +++ b/dir.c @@ -576,7 +576,7 @@ static int get_dtype(struct dirent *de, const char *path) */ static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen, int check_only, const struct path_simplify *simplify) { - DIR *fdir = opendir(path); + DIR *fdir = opendir(*path ? path : "."); int contents = 0; if (fdir) { From 076c32370d8a6ac2fb57b2a55c674942e106f8ab Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Sat, 16 May 2009 20:42:43 -0700 Subject: [PATCH 629/654] completion: add missing options to show-branch and show Add --oneline and --abbrev-commit to show and --sparse to show-branch. Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index dd6cd250e3..a0c5794828 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1804,7 +1804,7 @@ _git_show () return ;; --*) - __gitcomp "--pretty= --format= + __gitcomp "--pretty= --format= --abbrev-commit --oneline $__git_diff_common_options " return @@ -1821,7 +1821,7 @@ _git_show_branch () __gitcomp " --all --remotes --topo-order --current --more= --list --independent --merge-base --no-name - --sha1-name --topics --reflog + --sha1-name --sparse --topics --reflog " return ;; From 5acb3e5012966cc11e54f50e0592b3639bade02c Mon Sep 17 00:00:00 2001 From: Stephen Boyd <bebarino@gmail.com> Date: Sun, 17 May 2009 03:47:02 -0700 Subject: [PATCH 630/654] show-branch: Fix die message in parse_reflog_param() Commit 76a44c5 (show-branch --reflog: show the reflog message at the top, 2007-01-19) introduced parse_reflog_param(). The die() call was incorrectly passed arg + 9, when it should have been passed arg. Signed-off-by: Stephen Boyd <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-show-branch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-show-branch.c b/builtin-show-branch.c index 828e6f86de..c3afabbe91 100644 --- a/builtin-show-branch.c +++ b/builtin-show-branch.c @@ -576,7 +576,7 @@ static void parse_reflog_param(const char *arg, int *cnt, const char **base) if (*ep == ',') *base = ep + 1; else if (*ep) - die("unrecognized reflog param '%s'", arg + 9); + die("unrecognized reflog param '%s'", arg); else *base = NULL; if (*cnt <= 0) From 91fe2f909154c5cda3b40c68e72c3172a7f137f6 Mon Sep 17 00:00:00 2001 From: Dan McGee <dpmcgee@gmail.com> Date: Mon, 18 May 2009 23:34:02 -0500 Subject: [PATCH 631/654] Unify signedness in hashing calls Our hash_obj and hashtable_index calls and functions were doing a lot of funny things with signedness. Unify all of it to 'unsigned int'. Signed-off-by: Dan McGee <dpmcgee@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- decorate.c | 4 ++-- object.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/decorate.c b/decorate.c index e6fd8a7441..2f8a63e388 100644 --- a/decorate.c +++ b/decorate.c @@ -18,7 +18,7 @@ static void *insert_decoration(struct decoration *n, const struct object *base, { int size = n->size; struct object_decoration *hash = n->hash; - int j = hash_obj(base, size); + unsigned int j = hash_obj(base, size); while (hash[j].base) { if (hash[j].base == base) { @@ -70,7 +70,7 @@ void *add_decoration(struct decoration *n, const struct object *obj, /* Lookup a decoration pointer */ void *lookup_decoration(struct decoration *n, const struct object *obj) { - int j; + unsigned int j; /* nothing to lookup */ if (!n->size) diff --git a/object.c b/object.c index e1feef9c33..a6ef439192 100644 --- a/object.c +++ b/object.c @@ -52,7 +52,7 @@ static unsigned int hash_obj(struct object *obj, unsigned int n) static void insert_obj_hash(struct object *obj, struct object **hash, unsigned int size) { - int j = hash_obj(obj, size); + unsigned int j = hash_obj(obj, size); while (hash[j]) { j++; @@ -62,16 +62,16 @@ static void insert_obj_hash(struct object *obj, struct object **hash, unsigned i hash[j] = obj; } -static int hashtable_index(const unsigned char *sha1) +static unsigned int hashtable_index(const unsigned char *sha1) { unsigned int i; memcpy(&i, sha1, sizeof(unsigned int)); - return (int)(i % obj_hash_size); + return i % obj_hash_size; } struct object *lookup_object(const unsigned char *sha1) { - int i; + unsigned int i; struct object *obj; if (!obj_hash) From d00e364de99d51bb76e437820e23cfa820417ec5 Mon Sep 17 00:00:00 2001 From: Heiko Voigt <hvoigt@hvoigt.net> Date: Tue, 19 May 2009 22:01:54 +0200 Subject: [PATCH 632/654] Extend sample pre-commit hook to check for non ascii filenames At the moment non-ascii encodings of filenames are not portably converted between different filesystems by git. This will most likely change in the future but to allow repositories to be portable among different file/operating systems this check is enabled by default. Signed-off-by: Heiko Voigt <hvoigt@hvoigt.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- templates/hooks--pre-commit.sample | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/templates/hooks--pre-commit.sample b/templates/hooks--pre-commit.sample index 0ba62076fb..b11ad6a6fb 100755 --- a/templates/hooks--pre-commit.sample +++ b/templates/hooks--pre-commit.sample @@ -7,6 +7,31 @@ # # To enable this hook, rename this file to "pre-commit". +# If you want to allow non-ascii filenames set this variable to true. +allownonascii=$(git config hooks.allownonascii) + +# Cross platform projects tend to avoid non-ascii filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + test "$(git diff --cached --name-only --diff-filter=A -z | + LC_ALL=C tr -d '[ -~]\0')" +then + echo "Error: Attempt to add a non-ascii filename." + echo + echo "This can cause problems if you want to work together" + echo "with people on other platforms than you." + echo + echo "To be portable it is adviseable to rename the file ..." + echo + echo "If you know what you are doing you can disable this" + echo "check using:" + echo + echo " git config hooks.allownonascii true" + echo + exit 1 +fi + if git-rev-parse --verify HEAD >/dev/null 2>&1 then against=HEAD From e64c1b0053f2dc4fc5b434a9806b90318bac9592 Mon Sep 17 00:00:00 2001 From: Jeff King <peff@peff.net> Date: Mon, 18 May 2009 13:58:11 -0400 Subject: [PATCH 633/654] for-each-ref: fix segfault in copy_email You can trigger a segfault in git.git by doing: git for-each-ref --format='%(taggeremail)' refs/tags/v0.99 The v0.99 tag is special in that it contains no "tagger" header. The bug is obvious in copy_email, which carefully checks to make sure the result of a strchr is non-NULL, but only after already having used it to perform other work. The fix is to move the check up. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-for-each-ref.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index 91e8f95fd2..d091e04af9 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -339,8 +339,11 @@ static const char *copy_name(const char *buf) static const char *copy_email(const char *buf) { const char *email = strchr(buf, '<'); - const char *eoemail = strchr(email, '>'); - if (!email || !eoemail) + const char *eoemail; + if (!email) + return ""; + eoemail = strchr(email, '>'); + if (!eoemail) return ""; return xmemdupz(email, eoemail + 1 - email); } From ff3c7f9a264da41a2cd7b7a28a27f8ad935b81a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Thu, 21 May 2009 00:05:22 +0200 Subject: [PATCH 634/654] grep: make callback functions static Suggested by Stephen Boyd: make the callback functions used for option parsing static. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-grep.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/builtin-grep.c b/builtin-grep.c index 169a91c17e..5308b346e6 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -565,7 +565,8 @@ static int grep_object(struct grep_opt *opt, const char **paths, die("unable to grep from object of type %s", typename(obj->type)); } -int context_callback(const struct option *opt, const char *arg, int unset) +static int context_callback(const struct option *opt, const char *arg, + int unset) { struct grep_opt *grep_opt = opt->value; int value; @@ -584,7 +585,7 @@ int context_callback(const struct option *opt, const char *arg, int unset) return 0; } -int file_callback(const struct option *opt, const char *arg, int unset) +static int file_callback(const struct option *opt, const char *arg, int unset) { struct grep_opt *grep_opt = opt->value; FILE *patterns; @@ -606,42 +607,43 @@ int file_callback(const struct option *opt, const char *arg, int unset) return 0; } -int not_callback(const struct option *opt, const char *arg, int unset) +static int not_callback(const struct option *opt, const char *arg, int unset) { struct grep_opt *grep_opt = opt->value; append_grep_pattern(grep_opt, "--not", "command line", 0, GREP_NOT); return 0; } -int and_callback(const struct option *opt, const char *arg, int unset) +static int and_callback(const struct option *opt, const char *arg, int unset) { struct grep_opt *grep_opt = opt->value; append_grep_pattern(grep_opt, "--and", "command line", 0, GREP_AND); return 0; } -int open_callback(const struct option *opt, const char *arg, int unset) +static int open_callback(const struct option *opt, const char *arg, int unset) { struct grep_opt *grep_opt = opt->value; append_grep_pattern(grep_opt, "(", "command line", 0, GREP_OPEN_PAREN); return 0; } -int close_callback(const struct option *opt, const char *arg, int unset) +static int close_callback(const struct option *opt, const char *arg, int unset) { struct grep_opt *grep_opt = opt->value; append_grep_pattern(grep_opt, ")", "command line", 0, GREP_CLOSE_PAREN); return 0; } -int pattern_callback(const struct option *opt, const char *arg, int unset) +static int pattern_callback(const struct option *opt, const char *arg, + int unset) { struct grep_opt *grep_opt = opt->value; append_grep_pattern(grep_opt, arg, "-e option", 0, GREP_PATTERN); return 0; } -int help_callback(const struct option *opt, const char *arg, int unset) +static int help_callback(const struct option *opt, const char *arg, int unset) { return -1; } From fd73ccf27956f24dc0db9acd4ff7d9dcd5e41bfb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <Johannes.Schindelin@gmx.de> Date: Fri, 15 May 2009 20:52:47 +0200 Subject: [PATCH 635/654] Cope better with a _lot_ of packs You might end up with a situation where you have tons of pack files, e.g. when using hg2git. In this situation, all kinds of operations may end up with a "too many files open" error. Let's recover gracefully from that. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Looks-right-to-me-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- sha1_file.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sha1_file.c b/sha1_file.c index 28bd9082fc..bd5edd8e65 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -720,6 +720,8 @@ static int open_packed_git_1(struct packed_git *p) return error("packfile %s index unavailable", p->pack_name); p->pack_fd = open(p->pack_name, O_RDONLY); + while (p->pack_fd < 0 && errno == EMFILE && unuse_one_window(p, -1)) + p->pack_fd = open(p->pack_name, O_RDONLY); if (p->pack_fd < 0 || fstat(p->pack_fd, &st)) return -1; @@ -937,6 +939,8 @@ static void prepare_packed_git_one(char *objdir, int local) sprintf(path, "%s/pack", objdir); len = strlen(path); dir = opendir(path); + while (!dir && errno == EMFILE && unuse_one_window(packed_git, -1)) + dir = opendir(path); if (!dir) { if (errno != ENOENT) error("unable to open object pack directory: %s: %s", @@ -2339,6 +2343,8 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen, filename = sha1_file_name(sha1); fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename); + while (fd < 0 && errno == EMFILE && unuse_one_window(packed_git, -1)) + fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename); if (fd < 0) { if (errno == EACCES) return error("insufficient permission for adding an object to repository database %s\n", get_object_directory()); From 8dfb17e1fd7dec1d3a1978eb46743964c481cd08 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta <giuseppe.bilotta@gmail.com> Date: Mon, 18 May 2009 18:24:30 +0200 Subject: [PATCH 636/654] completion: use git rev-parse to detect bare repos Its check is more robust than a config check for core.bare Trivially-Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/completion/git-completion.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index a0c5794828..f44152c433 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -132,7 +132,7 @@ __git_ps1 () local c if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then - if [ "true" = "$(git config --bool core.bare 2>/dev/null)" ]; then + if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then c="BARE:" else b="GIT_DIR!" From e701fadb9e0e51a6811690d95a53bd1f5b6fad86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= <rene.scharfe@lsrfire.ath.cx> Date: Wed, 20 May 2009 23:31:53 +0200 Subject: [PATCH 637/654] grep: fix word-regexp colouring As noticed by Dmitry Gryazin: When a pattern is found but it doesn't start and end at word boundaries, bol is forwarded to after the match and the pattern is searched again. When a pattern is finally found between word boundaries, the match offsets are off by the number of characters that have been skipped. This patch corrects the offsets to be relative to the value of bol as passed to match_one_pattern() by its caller. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- grep.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/grep.c b/grep.c index 04c777a20c..a649f063cf 100644 --- a/grep.c +++ b/grep.c @@ -305,6 +305,7 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol, { int hit = 0; int saved_ch = 0; + const char *start = bol; if ((p->token != GREP_PATTERN) && ((p->token == GREP_PATTERN_HEAD) != (ctx == GREP_CONTEXT_HEAD))) @@ -365,6 +366,10 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol, } if (p->token == GREP_PATTERN_HEAD && saved_ch) *eol = saved_ch; + if (hit) { + pmatch[0].rm_so += bol - start; + pmatch[0].rm_eo += bol - start; + } return hit; } From da083d688e41f9a4328fab262f315f9e4fe52a32 Mon Sep 17 00:00:00 2001 From: Eygene Ryabinkin <rea-git@codelabs.ru> Date: Fri, 8 May 2009 12:06:16 +0400 Subject: [PATCH 638/654] git-svn testsuite: use standard configuration for Subversion tools I have tweaked configuration in my ~/.subversion directory, namely I am running auto-properties and automatically adding '$Id$' expansion to every file. This choke the last test named 'proplist' from t9101-git-svn-props.sh, because one more property, svn:keywords is automatically added. I had just wrapped svn invocation with the svn_cmd that specifies empty directory via --config-dir argument. Since the latter is the global option, it should be recognized by all svn subcommands, so no regressions will be introduced. Now svn_cmd is used everywhere, not just in the failed test module: this should guard us from the future clashes with user-defined configuration tweaks. Signed-off-by: Eygene Ryabinkin <rea-git@codelabs.ru> Acked-by: Eric Wong <normalperson@yhbt.net> --- t/lib-git-svn.sh | 15 +++++++ t/t9100-git-svn-basic.sh | 14 +++--- t/t9101-git-svn-props.sh | 38 ++++++++-------- t/t9102-git-svn-deep-rmdir.sh | 4 +- t/t9103-git-svn-tracked-directory-removed.sh | 8 ++-- t/t9104-git-svn-follow-parent.sh | 40 ++++++++--------- t/t9105-git-svn-commit-diff.sh | 8 ++-- t/t9106-git-svn-commit-diff-clobber.sh | 14 +++--- t/t9107-git-svn-migrate.sh | 2 +- t/t9108-git-svn-glob.sh | 26 +++++------ t/t9109-git-svn-multi-glob.sh | 44 +++++++++---------- t/t9113-git-svn-dcommit-new-file.sh | 2 +- t/t9114-git-svn-dcommit-merge.sh | 6 +-- t/t9116-git-svn-log.sh | 2 +- t/t9117-git-svn-init-clone.sh | 2 +- t/t9118-git-svn-funky-branch-names.sh | 8 ++-- t/t9119-git-svn-info.sh | 30 ++++++------- t/t9120-git-svn-clone-with-percent-escapes.sh | 2 +- t/t9122-git-svn-author.sh | 12 ++--- t/t9123-git-svn-rebuild-with-rewriteroot.sh | 2 +- t/t9124-git-svn-dcommit-auto-props.sh | 30 ++++++------- t/t9125-git-svn-multi-glob-branch-names.sh | 6 +-- t/t9127-git-svn-partial-rebuild.sh | 14 +++--- t/t9128-git-svn-cmd-branch.sh | 18 ++++---- t/t9129-git-svn-i18n-commitencoding.sh | 2 +- t/t9130-git-svn-authors-file.sh | 6 +-- t/t9133-git-svn-nested-git-repo.sh | 32 +++++++------- t/t9134-git-svn-ignore-paths.sh | 32 +++++++------- t/t9137-git-svn-dcommit-clobber-series.sh | 8 ++-- 29 files changed, 221 insertions(+), 206 deletions(-) diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh index 773d47cf3c..5654962343 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -26,6 +26,8 @@ fi svnrepo=$PWD/svnrepo export svnrepo +svnconf=$PWD/svnconf +export svnconf perl -w -e " use SVN::Core; @@ -54,6 +56,19 @@ poke() { test-chmtime +1 "$1" } +# We need this, because we should pass empty configuration directory to +# the 'svn commit' to avoid automated property changes and other stuff +# that could be set from user's configuration files in ~/.subversion. +svn_cmd () { + [ -d "$svnconf" ] || mkdir "$svnconf" + orig_svncmd="$1"; shift + if [ -z "$orig_svncmd" ]; then + svn + return + fi + svn "$orig_svncmd" --config-dir "$svnconf" "$@" +} + for d in \ "$SVN_HTTPD_PATH" \ /usr/sbin/apache2 \ diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh index 4eee2e9fa6..64aa7e2f10 100755 --- a/t/t9100-git-svn-basic.sh +++ b/t/t9100-git-svn-basic.sh @@ -31,7 +31,7 @@ test_expect_success \ echo "zzz" > bar/zzz && echo "#!/bin/sh" > exec.sh && chmod +x exec.sh && - svn import -m "import for git svn" . "$svnrepo" >/dev/null && + svn_cmd import -m "import for git svn" . "$svnrepo" >/dev/null && cd .. && rm -rf import && git svn init "$svnrepo"' @@ -51,7 +51,7 @@ test_expect_success "$name" ' git commit -m "$name" && git svn set-tree --find-copies-harder --rmdir \ ${remotes_git_svn}..mybranch && - svn up "$SVN_TREE" && + svn_cmd up "$SVN_TREE" && test -d "$SVN_TREE"/dir && test ! -d "$SVN_TREE"/dir/a' @@ -118,7 +118,7 @@ test_expect_success "$name" ' git commit -m "$name" && git svn set-tree --find-copies-harder --rmdir \ ${remotes_git_svn}..mybranch5 && - svn up "$SVN_TREE" && + svn_cmd up "$SVN_TREE" && test ! -x "$SVN_TREE"/exec.sh' @@ -129,7 +129,7 @@ test_expect_success "$name" ' git commit -m "$name" && git svn set-tree --find-copies-harder --rmdir \ ${remotes_git_svn}..mybranch5 && - svn up "$SVN_TREE" && + svn_cmd up "$SVN_TREE" && test -x "$SVN_TREE"/exec.sh' @@ -141,7 +141,7 @@ test_expect_success "$name" ' git commit -m "$name" && git svn set-tree --find-copies-harder --rmdir \ ${remotes_git_svn}..mybranch5 && - svn up "$SVN_TREE" && + svn_cmd up "$SVN_TREE" && test -L "$SVN_TREE"/exec.sh' name='new symlink is added to a file that was also just made executable' @@ -153,7 +153,7 @@ test_expect_success "$name" ' git commit -m "$name" && git svn set-tree --find-copies-harder --rmdir \ ${remotes_git_svn}..mybranch5 && - svn up "$SVN_TREE" && + svn_cmd up "$SVN_TREE" && test -x "$SVN_TREE"/bar/zzz && test -L "$SVN_TREE"/exec-2.sh' @@ -166,7 +166,7 @@ test_expect_success "$name" ' git commit -m "$name" && git svn set-tree --find-copies-harder --rmdir \ ${remotes_git_svn}..mybranch5 && - svn up "$SVN_TREE" && + svn_cmd up "$SVN_TREE" && test -f "$SVN_TREE"/exec-2.sh && test ! -L "$SVN_TREE"/exec-2.sh && test_cmp help "$SVN_TREE"/exec-2.sh' diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh index 1e31d6ea72..9da4178c94 100755 --- a/t/t9101-git-svn-props.sh +++ b/t/t9101-git-svn-props.sh @@ -48,7 +48,7 @@ EOF printf "\r\n" > empty_crlf a_empty_crlf=`git hash-object -w empty_crlf` - svn import --no-auto-props -m 'import for git svn' . "$svnrepo" >/dev/null + svn_cmd import --no-auto-props -m 'import for git svn' . "$svnrepo" >/dev/null cd .. rm -rf import @@ -57,13 +57,13 @@ test_expect_success 'setup some commits to svn' \ 'cd test_wc && echo Greetings >> kw.c && poke kw.c && - svn commit -m "Not yet an Id" && + svn_cmd commit -m "Not yet an Id" && echo Hello world >> kw.c && poke kw.c && - svn commit -m "Modified file, but still not yet an Id" && - svn propset svn:keywords Id kw.c && + svn_cmd commit -m "Modified file, but still not yet an Id" && + svn_cmd propset svn:keywords Id kw.c && poke kw.c && - svn commit -m "Propset Id" && + svn_cmd commit -m "Propset Id" && cd ..' test_expect_success 'initialize git svn' 'git svn init "$svnrepo"' @@ -83,16 +83,16 @@ test_expect_success 'raw $Id$ found in kw.c' "test '$expect' = '$got'" test_expect_success "propset CR on crlf files" \ 'cd test_wc && - svn propset svn:eol-style CR empty && - svn propset svn:eol-style CR crlf && - svn propset svn:eol-style CR ne_crlf && - svn commit -m "propset CR on crlf files" && + svn_cmd propset svn:eol-style CR empty && + svn_cmd propset svn:eol-style CR crlf && + svn_cmd propset svn:eol-style CR ne_crlf && + svn_cmd commit -m "propset CR on crlf files" && cd ..' test_expect_success 'fetch and pull latest from svn and checkout a new wc' \ 'git svn fetch && git pull . ${remotes_git_svn} && - svn co "$svnrepo" new_wc' + svn_cmd co "$svnrepo" new_wc' for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf do @@ -106,11 +106,11 @@ cd test_wc a_cr=`printf '$Id$\r\nHello\r\nWorld\r\n' | git hash-object --stdin` a_ne_cr=`printf '$Id$\r\nHello\r\nWorld' | git hash-object --stdin` test_expect_success 'Set CRLF on cr files' \ - 'svn propset svn:eol-style CRLF cr && - svn propset svn:eol-style CRLF ne_cr && - svn propset svn:keywords Id cr && - svn propset svn:keywords Id ne_cr && - svn commit -m "propset CRLF on cr files"' + 'svn_cmd propset svn:eol-style CRLF cr && + svn_cmd propset svn:eol-style CRLF ne_cr && + svn_cmd propset svn:keywords Id cr && + svn_cmd propset svn:keywords Id ne_cr && + svn_cmd commit -m "propset CRLF on cr files"' cd .. test_expect_success 'fetch and pull latest from svn' \ 'git svn fetch && git pull . ${remotes_git_svn}' @@ -140,10 +140,10 @@ test_expect_success 'test show-ignore' " cd test_wc && mkdir -p deeply/nested/directory && touch deeply/nested/directory/.keep && - svn add deeply && - svn up && - svn propset -R svn:ignore 'no-such-file*' . - svn commit -m 'propset svn:ignore' + svn_cmd add deeply && + svn_cmd up && + svn_cmd propset -R svn:ignore 'no-such-file*' . + svn_cmd commit -m 'propset svn:ignore' cd .. && git svn show-ignore > show-ignore.got && cmp show-ignore.expect show-ignore.got diff --git a/t/t9102-git-svn-deep-rmdir.sh b/t/t9102-git-svn-deep-rmdir.sh index e223218015..028fb19e09 100755 --- a/t/t9102-git-svn-deep-rmdir.sh +++ b/t/t9102-git-svn-deep-rmdir.sh @@ -9,7 +9,7 @@ test_expect_success 'initialize repo' ' mkdir -p deeply/nested/directory/number/2 && echo foo > deeply/nested/directory/number/1/file && echo foo > deeply/nested/directory/number/2/another && - svn import -m "import for git svn" . "$svnrepo" && + svn_cmd import -m "import for git svn" . "$svnrepo" && cd .. ' @@ -23,7 +23,7 @@ test_expect_success 'Try a commit on rmdir' ' git rm -f deeply/nested/directory/number/2/another && git commit -a -m "remove another" && git svn set-tree --rmdir HEAD && - svn ls -R "$svnrepo" | grep ^deeply/nested/directory/number/1 + svn_cmd ls -R "$svnrepo" | grep ^deeply/nested/directory/number/1 ' diff --git a/t/t9103-git-svn-tracked-directory-removed.sh b/t/t9103-git-svn-tracked-directory-removed.sh index 963dd95e4a..3413164cb1 100755 --- a/t/t9103-git-svn-tracked-directory-removed.sh +++ b/t/t9103-git-svn-tracked-directory-removed.sh @@ -10,15 +10,15 @@ test_expect_success 'make history for tracking' ' mkdir import && mkdir import/trunk && echo hello >> import/trunk/README && - svn import -m initial import "$svnrepo" && + svn_cmd import -m initial import "$svnrepo" && rm -rf import && - svn co "$svnrepo"/trunk trunk && + svn_cmd co "$svnrepo"/trunk trunk && echo bye bye >> trunk/README && - svn rm -m "gone" "$svnrepo"/trunk && + svn_cmd rm -m "gone" "$svnrepo"/trunk && rm -rf trunk && mkdir trunk && echo "new" > trunk/FOLLOWME && - svn import -m "new trunk" trunk "$svnrepo"/trunk + svn_cmd import -m "new trunk" trunk "$svnrepo"/trunk ' test_expect_success 'clone repo with git' ' diff --git a/t/t9104-git-svn-follow-parent.sh b/t/t9104-git-svn-follow-parent.sh index ab9fa32220..78610b61e6 100755 --- a/t/t9104-git-svn-follow-parent.sh +++ b/t/t9104-git-svn-follow-parent.sh @@ -11,18 +11,18 @@ test_expect_success 'initialize repo' ' cd import && mkdir -p trunk && echo hello > trunk/readme && - svn import -m "initial" . "$svnrepo" && + svn_cmd import -m "initial" . "$svnrepo" && cd .. && - svn co "$svnrepo" wc && + svn_cmd co "$svnrepo" wc && cd wc && echo world >> trunk/readme && poke trunk/readme && - svn commit -m "another commit" && - svn up && - svn mv trunk thunk && + svn_cmd commit -m "another commit" && + svn_cmd up && + svn_cmd mv trunk thunk && echo goodbye >> thunk/readme && poke thunk/readme && - svn commit -m "bye now" && + svn_cmd commit -m "bye now" && cd .. ' @@ -51,7 +51,7 @@ test_expect_success 'init and fetch from one svn-remote' ' ' test_expect_success 'follow deleted parent' ' - (svn cp -m "resurrecting trunk as junk" \ + (svn_cmd cp -m "resurrecting trunk as junk" \ "$svnrepo"/trunk@2 "$svnrepo"/junk || svn cp -m "resurrecting trunk as junk" \ -r2 "$svnrepo"/trunk "$svnrepo"/junk) && @@ -97,8 +97,8 @@ test_expect_success 'follow higher-level parent' ' ' test_expect_success 'follow deleted directory' ' - svn mv -m "bye!" "$svnrepo"/glob/blob/hi "$svnrepo"/glob/blob/bye && - svn rm -m "remove glob" "$svnrepo"/glob && + svn_cmd mv -m "bye!" "$svnrepo"/glob/blob/hi "$svnrepo"/glob/blob/bye && + svn_cmd rm -m "remove glob" "$svnrepo"/glob && git svn init --minimize-url -i glob "$svnrepo"/glob && git svn fetch -i glob && test "`git cat-file blob refs/remotes/glob:blob/bye`" = hi && @@ -120,7 +120,7 @@ test_expect_success 'follow-parent avoids deleting relevant info' ' cd import && svn import -m "r9270 test" . "$svnrepo"/r9270 && cd .. && - svn co "$svnrepo"/r9270/trunk/subversion/bindings/swig/perl r9270 && + svn_cmd co "$svnrepo"/r9270/trunk/subversion/bindings/swig/perl r9270 && cd r9270 && svn mkdir native && svn mv t native/t && @@ -138,7 +138,7 @@ test_expect_success 'follow-parent avoids deleting relevant info' ' ' test_expect_success "track initial change if it was only made to parent" ' - svn cp -m "wheee!" "$svnrepo"/r9270/trunk "$svnrepo"/r9270/drunk && + svn_cmd cp -m "wheee!" "$svnrepo"/r9270/trunk "$svnrepo"/r9270/drunk && git svn init --minimize-url -i r9270-d \ "$svnrepo"/r9270/drunk/subversion/bindings/swig/perl/native/t && git svn fetch -i r9270-d && @@ -152,20 +152,20 @@ test_expect_success "track initial change if it was only made to parent" ' test_expect_success "follow-parent is atomic" ' ( cd wc && - svn up && - svn mkdir stunk && + svn_cmd up && + svn_cmd mkdir stunk && echo "trunk stunk" > stunk/readme && - svn add stunk/readme && - svn ci -m "trunk stunk" && + svn_cmd add stunk/readme && + svn_cmd ci -m "trunk stunk" && echo "stunk like junk" >> stunk/readme && - svn ci -m "really stunk" && + svn_cmd ci -m "really stunk" && echo "stink stank stunk" >> stunk/readme && - svn ci -m "even the grinch agrees" + svn_cmd ci -m "even the grinch agrees" ) && - svn copy -m "stunk flunked" "$svnrepo"/stunk "$svnrepo"/flunk && + svn_cmd copy -m "stunk flunked" "$svnrepo"/stunk "$svnrepo"/flunk && { svn cp -m "early stunk flunked too" \ "$svnrepo"/stunk@17 "$svnrepo"/flunked || - svn cp -m "early stunk flunked too" \ + svn_cmd cp -m "early stunk flunked too" \ -r17 "$svnrepo"/stunk "$svnrepo"/flunked; } && git svn init --minimize-url -i stunk "$svnrepo"/stunk && git svn fetch -i stunk && @@ -192,7 +192,7 @@ test_expect_success "follow-parent is atomic" ' ' test_expect_success "track multi-parent paths" ' - svn cp -m "resurrect /glob" "$svnrepo"/r9270 "$svnrepo"/glob && + svn_cmd cp -m "resurrect /glob" "$svnrepo"/r9270 "$svnrepo"/glob && git svn multi-fetch && test `git cat-file commit refs/remotes/glob | \ grep "^parent " | wc -l` -eq 2 diff --git a/t/t9105-git-svn-commit-diff.sh b/t/t9105-git-svn-commit-diff.sh index ba99abb6d9..dd48e9cba8 100755 --- a/t/t9105-git-svn-commit-diff.sh +++ b/t/t9105-git-svn-commit-diff.sh @@ -8,7 +8,7 @@ test_expect_success 'initialize repo' ' mkdir import && cd import && echo hello > readme && - svn import -m "initial" . "$svnrepo" && + svn_cmd import -m "initial" . "$svnrepo" && cd .. && echo hello > readme && git update-index --add readme && @@ -27,16 +27,16 @@ prev=`git rev-parse --verify HEAD^1` test_expect_success 'test the commit-diff command' ' test -n "$prev" && test -n "$head" && git svn commit-diff -r1 "$prev" "$head" "$svnrepo" && - svn co "$svnrepo" wc && + svn_cmd co "$svnrepo" wc && cmp readme wc/readme ' test_expect_success 'commit-diff to a sub-directory (with git svn config)' ' - svn import -m "sub-directory" import "$svnrepo"/subdir && + svn_cmd import -m "sub-directory" import "$svnrepo"/subdir && git svn init --minimize-url "$svnrepo"/subdir && git svn fetch && git svn commit-diff -r3 "$prev" "$head" && - svn cat "$svnrepo"/subdir/readme > readme.2 && + svn_cmd cat "$svnrepo"/subdir/readme > readme.2 && cmp readme readme.2 ' diff --git a/t/t9106-git-svn-commit-diff-clobber.sh b/t/t9106-git-svn-commit-diff-clobber.sh index 6eb0fd85c8..12f21b700e 100755 --- a/t/t9106-git-svn-commit-diff-clobber.sh +++ b/t/t9106-git-svn-commit-diff-clobber.sh @@ -8,18 +8,18 @@ test_expect_success 'initialize repo' ' mkdir import && cd import && echo initial > file && - svn import -m "initial" . "$svnrepo" && + svn_cmd import -m "initial" . "$svnrepo" && cd .. && echo initial > file && git update-index --add file && git commit -a -m "initial" ' test_expect_success 'commit change from svn side' ' - svn co "$svnrepo" t.svn && + svn_cmd co "$svnrepo" t.svn && cd t.svn && echo second line from svn >> file && poke file && - svn commit -m "second line from svn" && + svn_cmd commit -m "second line from svn" && cd .. && rm -rf t.svn ' @@ -43,11 +43,11 @@ test_expect_success 'dcommit fails to commit because of conflict' ' git svn init "$svnrepo" && git svn fetch && git reset --hard refs/${remotes_git_svn} && - svn co "$svnrepo" t.svn && + svn_cmd co "$svnrepo" t.svn && cd t.svn && echo fourth line from svn >> file && poke file && - svn commit -m "fourth line from svn" && + svn_cmd commit -m "fourth line from svn" && cd .. && rm -rf t.svn && echo "fourth line from git" >> file && @@ -67,11 +67,11 @@ test_expect_success 'dcommit does the svn equivalent of an index merge' " " test_expect_success 'commit another change from svn side' ' - svn co "$svnrepo" t.svn && + svn_cmd co "$svnrepo" t.svn && cd t.svn && echo third line from svn >> file && poke file && - svn commit -m "third line from svn" && + svn_cmd commit -m "third line from svn" && cd .. && rm -rf t.svn ' diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh index acad16a6f0..3a9e07768d 100755 --- a/t/t9107-git-svn-migrate.sh +++ b/t/t9107-git-svn-migrate.sh @@ -12,7 +12,7 @@ test_expect_success 'setup old-looking metadata' ' mkdir -p $i && \ echo hello >> $i/README || exit 1 done && \ - svn import -m test . "$svnrepo" + svn_cmd import -m test . "$svnrepo" cd .. && git svn init "$svnrepo" && git svn fetch && diff --git a/t/t9108-git-svn-glob.sh b/t/t9108-git-svn-glob.sh index d8582b1aa5..d732d31302 100755 --- a/t/t9108-git-svn-glob.sh +++ b/t/t9108-git-svn-glob.sh @@ -14,30 +14,30 @@ test_expect_success 'test refspec globbing' ' mkdir -p trunk/src/a trunk/src/b trunk/doc && echo "hello world" > trunk/src/a/readme && echo "goodbye world" > trunk/src/b/readme && - svn import -m "initial" trunk "$svnrepo"/trunk && - svn co "$svnrepo" tmp && + svn_cmd import -m "initial" trunk "$svnrepo"/trunk && + svn_cmd co "$svnrepo" tmp && ( cd tmp && mkdir branches tags && - svn add branches tags && - svn cp trunk branches/start && - svn commit -m "start a new branch" && - svn up && + svn_cmd add branches tags && + svn_cmd cp trunk branches/start && + svn_cmd commit -m "start a new branch" && + svn_cmd up && echo "hi" >> branches/start/src/b/readme && poke branches/start/src/b/readme && echo "hey" >> branches/start/src/a/readme && poke branches/start/src/a/readme && - svn commit -m "hi" && - svn up && - svn cp branches/start tags/end && + svn_cmd commit -m "hi" && + svn_cmd up && + svn_cmd cp branches/start tags/end && echo "bye" >> tags/end/src/b/readme && poke tags/end/src/b/readme && echo "aye" >> tags/end/src/a/readme && poke tags/end/src/a/readme && - svn commit -m "the end" && + svn_cmd commit -m "the end" && echo "byebye" >> tags/end/src/b/readme && poke tags/end/src/b/readme && - svn commit -m "nothing to see here" + svn_cmd commit -m "nothing to see here" ) && git config --add svn-remote.svn.url "$svnrepo" && git config --add svn-remote.svn.fetch \ @@ -72,7 +72,7 @@ test_expect_success 'test left-hand-side only globbing' ' cd tmp && echo "try try" >> tags/end/src/b/readme && poke tags/end/src/b/readme && - svn commit -m "try to try" + svn_cmd commit -m "try to try" ) && git svn fetch two && test `git rev-list refs/remotes/two/tags/end | wc -l` -eq 6 && @@ -102,7 +102,7 @@ test_expect_success 'test disallow multi-globs' ' cd tmp && echo "try try" >> tags/end/src/b/readme && poke tags/end/src/b/readme && - svn commit -m "try to try" + svn_cmd commit -m "try to try" ) && test_must_fail git svn fetch three 2> stderr.three && test_cmp expect.three stderr.three diff --git a/t/t9109-git-svn-multi-glob.sh b/t/t9109-git-svn-multi-glob.sh index 8f79c3f251..c318f9f946 100755 --- a/t/t9109-git-svn-multi-glob.sh +++ b/t/t9109-git-svn-multi-glob.sh @@ -14,30 +14,30 @@ test_expect_success 'test refspec globbing' ' mkdir -p trunk/src/a trunk/src/b trunk/doc && echo "hello world" > trunk/src/a/readme && echo "goodbye world" > trunk/src/b/readme && - svn import -m "initial" trunk "$svnrepo"/trunk && - svn co "$svnrepo" tmp && + svn_cmd import -m "initial" trunk "$svnrepo"/trunk && + svn_cmd co "$svnrepo" tmp && ( cd tmp && mkdir branches branches/v1 tags && - svn add branches tags && - svn cp trunk branches/v1/start && - svn commit -m "start a new branch" && - svn up && + svn_cmd add branches tags && + svn_cmd cp trunk branches/v1/start && + svn_cmd commit -m "start a new branch" && + svn_cmd up && echo "hi" >> branches/v1/start/src/b/readme && poke branches/v1/start/src/b/readme && echo "hey" >> branches/v1/start/src/a/readme && poke branches/v1/start/src/a/readme && - svn commit -m "hi" && - svn up && - svn cp branches/v1/start tags/end && + svn_cmd commit -m "hi" && + svn_cmd up && + svn_cmd cp branches/v1/start tags/end && echo "bye" >> tags/end/src/b/readme && poke tags/end/src/b/readme && echo "aye" >> tags/end/src/a/readme && poke tags/end/src/a/readme && - svn commit -m "the end" && + svn_cmd commit -m "the end" && echo "byebye" >> tags/end/src/b/readme && poke tags/end/src/b/readme && - svn commit -m "nothing to see here" + svn_cmd commit -m "nothing to see here" ) && git config --add svn-remote.svn.url "$svnrepo" && git config --add svn-remote.svn.fetch \ @@ -72,7 +72,7 @@ test_expect_success 'test left-hand-side only globbing' ' cd tmp && echo "try try" >> tags/end/src/b/readme && poke tags/end/src/b/readme && - svn commit -m "try to try" + svn_cmd commit -m "try to try" ) && git svn fetch two && test `git rev-list refs/remotes/two/tags/end | wc -l` -eq 6 && @@ -97,25 +97,25 @@ test_expect_success 'test another branch' ' ( cd tmp && mkdir branches/v2 && - svn add branches/v2 && - svn cp trunk branches/v2/start && - svn commit -m "Another versioned branch" && - svn up && + svn_cmd add branches/v2 && + svn_cmd cp trunk branches/v2/start && + svn_cmd commit -m "Another versioned branch" && + svn_cmd up && echo "hello" >> branches/v2/start/src/b/readme && poke branches/v2/start/src/b/readme && echo "howdy" >> branches/v2/start/src/a/readme && poke branches/v2/start/src/a/readme && - svn commit -m "Changed 2 in v2/start" && - svn up && - svn cp branches/v2/start tags/next && + svn_cmd commit -m "Changed 2 in v2/start" && + svn_cmd up && + svn_cmd cp branches/v2/start tags/next && echo "bye" >> tags/next/src/b/readme && poke tags/next/src/b/readme && echo "aye" >> tags/next/src/a/readme && poke tags/next/src/a/readme && - svn commit -m "adding more" && + svn_cmd commit -m "adding more" && echo "byebye" >> tags/next/src/b/readme && poke tags/next/src/b/readme && - svn commit -m "adios" + svn_cmd commit -m "adios" ) && git config --add svn-remote.four.url "$svnrepo" && git config --add svn-remote.four.fetch trunk:refs/remotes/four/trunk && @@ -151,7 +151,7 @@ test_expect_success 'test disallow multiple globs' ' cd tmp && echo "try try" >> tags/end/src/b/readme && poke tags/end/src/b/readme && - svn commit -m "try to try" + svn_cmd commit -m "try to try" ) && test_must_fail git svn fetch three 2> stderr.three && test_cmp expect.three stderr.three diff --git a/t/t9113-git-svn-dcommit-new-file.sh b/t/t9113-git-svn-dcommit-new-file.sh index e9b6128b3f..e8479cec7a 100755 --- a/t/t9113-git-svn-dcommit-new-file.sh +++ b/t/t9113-git-svn-dcommit-new-file.sh @@ -15,7 +15,7 @@ test_description='git svn dcommit new files over svn:// test' require_svnserve test_expect_success 'start tracking an empty repo' ' - svn mkdir -m "empty dir" "$svnrepo"/empty-dir && + svn_cmd mkdir -m "empty dir" "$svnrepo"/empty-dir && echo "[general]" > "$rawsvnrepo"/conf/svnserve.conf && echo anon-access = write >> "$rawsvnrepo"/conf/svnserve.conf && start_svnserve && diff --git a/t/t9114-git-svn-dcommit-merge.sh b/t/t9114-git-svn-dcommit-merge.sh index 17b2855c4f..84f7c9b4bb 100755 --- a/t/t9114-git-svn-dcommit-merge.sh +++ b/t/t9114-git-svn-dcommit-merge.sh @@ -35,12 +35,12 @@ EOF } test_expect_success 'setup svn repository' ' - svn co "$svnrepo" mysvnwork && + svn_cmd co "$svnrepo" mysvnwork && mkdir -p mysvnwork/trunk && cd mysvnwork && big_text_block >> trunk/README && - svn add trunk && - svn ci -m "first commit" trunk && + svn_cmd add trunk && + svn_cmd ci -m "first commit" trunk && cd .. ' diff --git a/t/t9116-git-svn-log.sh b/t/t9116-git-svn-log.sh index fd6d1d2046..0374a7476b 100755 --- a/t/t9116-git-svn-log.sh +++ b/t/t9116-git-svn-log.sh @@ -14,7 +14,7 @@ test_expect_success 'setup repository and import' ' mkdir -p $i && \ echo hello >> $i/README || exit 1 done && \ - svn import -m test . "$svnrepo" + svn_cmd import -m test . "$svnrepo" cd .. && git svn init "$svnrepo" -T trunk -b branches -t tags && git svn fetch && diff --git a/t/t9117-git-svn-init-clone.sh b/t/t9117-git-svn-init-clone.sh index dde46cd92f..b7ef9e2589 100755 --- a/t/t9117-git-svn-init-clone.sh +++ b/t/t9117-git-svn-init-clone.sh @@ -16,7 +16,7 @@ cd tmp test_expect_success 'setup svnrepo' ' mkdir project project/trunk project/branches project/tags && echo foo > project/trunk/foo && - svn import -m "$test_description" project "$svnrepo"/project && + svn_cmd import -m "$test_description" project "$svnrepo"/project && rm -rf project ' diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh index 7a7c128687..ac52bff0ef 100755 --- a/t/t9118-git-svn-funky-branch-names.sh +++ b/t/t9118-git-svn-funky-branch-names.sh @@ -13,13 +13,13 @@ scary_ref='Abo-Uebernahme%20(Bug%20#994)' test_expect_success 'setup svnrepo' ' mkdir project project/trunk project/branches project/tags && echo foo > project/trunk/foo && - svn import -m "$test_description" project "$svnrepo/pr ject" && + svn_cmd import -m "$test_description" project "$svnrepo/pr ject" && rm -rf project && - svn cp -m "fun" "$svnrepo/pr ject/trunk" \ + svn_cmd cp -m "fun" "$svnrepo/pr ject/trunk" \ "$svnrepo/pr ject/branches/fun plugin" && - svn cp -m "more fun!" "$svnrepo/pr ject/branches/fun plugin" \ + svn_cmd cp -m "more fun!" "$svnrepo/pr ject/branches/fun plugin" \ "$svnrepo/pr ject/branches/more fun plugin!" && - svn cp -m "scary" "$svnrepo/pr ject/branches/fun plugin" \ + svn_cmd cp -m "scary" "$svnrepo/pr ject/branches/fun plugin" \ "$svnrepo/pr ject/branches/$scary_uri" && start_httpd ' diff --git a/t/t9119-git-svn-info.sh b/t/t9119-git-svn-info.sh index 27dd7c273a..95741cbbac 100755 --- a/t/t9119-git-svn-info.sh +++ b/t/t9119-git-svn-info.sh @@ -7,7 +7,7 @@ test_description='git svn info' . ./lib-git-svn.sh # Tested with: svn, version 1.4.4 (r25188) -v=`svn --version | sed -n -e 's/^svn, version \(1\.[0-9]*\.[0-9]*\).*$/\1/p'` +v=`svn_cmd --version | sed -n -e 's/^svn, version \(1\.[0-9]*\.[0-9]*\).*$/\1/p'` case $v in 1.[45].*) ;; @@ -31,7 +31,7 @@ ptouch() { my $atime = $mtime; utime $atime, $mtime, $git_file; } - ' "`svn info $2 | grep '^Text Last Updated:'`" "$1" + ' "`svn_cmd info $2 | grep '^Text Last Updated:'`" "$1" } quoted_svnrepo="$(echo $svnrepo | sed 's/ /%20/')" @@ -45,14 +45,14 @@ test_expect_success 'setup repository and import' ' mkdir directory && touch directory/.placeholder && ln -s directory symlink-directory && - svn import -m "initial" . "$svnrepo" && + svn_cmd import -m "initial" . "$svnrepo" && cd .. && - svn co "$svnrepo" svnwc && + svn_cmd co "$svnrepo" svnwc && cd svnwc && echo foo > foo && - svn add foo && - svn commit -m "change outside directory" && - svn update && + svn_cmd add foo && + svn_cmd commit -m "change outside directory" && + svn_cmd update && cd .. && mkdir gitwc && cd gitwc && @@ -143,7 +143,7 @@ test_expect_success 'info added-file' " cp gitwc/added-file svnwc/added-file && ptouch gitwc/added-file svnwc/added-file && cd svnwc && - svn add added-file > /dev/null && + svn_cmd add added-file > /dev/null && cd .. && (cd svnwc; svn info added-file) > expected.info-added-file && (cd gitwc; git svn info added-file) > actual.info-added-file && @@ -160,7 +160,7 @@ test_expect_success 'info added-directory' " ptouch gitwc/added-directory svnwc/added-directory && touch gitwc/added-directory/.placeholder && cd svnwc && - svn add added-directory > /dev/null && + svn_cmd add added-directory > /dev/null && cd .. && cd gitwc && git add added-directory && @@ -184,7 +184,7 @@ test_expect_success 'info added-symlink-file' " cd .. && cd svnwc && ln -s added-file added-symlink-file && - svn add added-symlink-file > /dev/null && + svn_cmd add added-symlink-file > /dev/null && cd .. && ptouch gitwc/added-symlink-file svnwc/added-symlink-file && (cd svnwc; svn info added-symlink-file) \ @@ -207,7 +207,7 @@ test_expect_success 'info added-symlink-directory' " cd .. && cd svnwc && ln -s added-directory added-symlink-directory && - svn add added-symlink-directory > /dev/null && + svn_cmd add added-symlink-directory > /dev/null && cd .. && ptouch gitwc/added-symlink-directory svnwc/added-symlink-directory && (cd svnwc; svn info added-symlink-directory) \ @@ -233,7 +233,7 @@ test_expect_success 'info deleted-file' " git rm -f file > /dev/null && cd .. && cd svnwc && - svn rm --force file > /dev/null && + svn_cmd rm --force file > /dev/null && cd .. && (cd svnwc; svn info file) | sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \ @@ -254,7 +254,7 @@ test_expect_success 'info deleted-directory' " git rm -r -f directory > /dev/null && cd .. && cd svnwc && - svn rm --force directory > /dev/null && + svn_cmd rm --force directory > /dev/null && cd .. && (cd svnwc; svn info directory) | sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \ @@ -275,7 +275,7 @@ test_expect_success 'info deleted-symlink-file' " git rm -f symlink-file > /dev/null && cd .. && cd svnwc && - svn rm --force symlink-file > /dev/null && + svn_cmd rm --force symlink-file > /dev/null && cd .. && (cd svnwc; svn info symlink-file) | sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \ @@ -297,7 +297,7 @@ test_expect_success 'info deleted-symlink-directory' " git rm -f symlink-directory > /dev/null && cd .. && cd svnwc && - svn rm --force symlink-directory > /dev/null && + svn_cmd rm --force symlink-directory > /dev/null && cd .. && (cd svnwc; svn info symlink-directory) | sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \ diff --git a/t/t9120-git-svn-clone-with-percent-escapes.sh b/t/t9120-git-svn-clone-with-percent-escapes.sh index ef2c0523cd..555a0189a7 100755 --- a/t/t9120-git-svn-clone-with-percent-escapes.sh +++ b/t/t9120-git-svn-clone-with-percent-escapes.sh @@ -9,7 +9,7 @@ test_description='git svn clone with percent escapes' test_expect_success 'setup svnrepo' ' mkdir project project/trunk project/branches project/tags && echo foo > project/trunk/foo && - svn import -m "$test_description" project "$svnrepo/pr ject" && + svn_cmd import -m "$test_description" project "$svnrepo/pr ject" && rm -rf project && start_httpd ' diff --git a/t/t9122-git-svn-author.sh b/t/t9122-git-svn-author.sh index 1b1cf47281..30013b7bb9 100755 --- a/t/t9122-git-svn-author.sh +++ b/t/t9122-git-svn-author.sh @@ -4,12 +4,12 @@ test_description='git svn authorship' . ./lib-git-svn.sh test_expect_success 'setup svn repository' ' - svn checkout "$svnrepo" work.svn && + svn_cmd checkout "$svnrepo" work.svn && ( cd work.svn && echo >file - svn add file - svn commit -m "first commit" file + svn_cmd add file + svn_cmd commit -m "first commit" file ) ' @@ -74,10 +74,10 @@ test_expect_success 'interact with it via git svn' ' # Make sure there are no svn commit messages with excess blank lines ( cd work.svn && - svn up && + svn_cmd up && - test $(svn log -r2:2 | wc -l) = 5 && - test $(svn log -r4:4 | wc -l) = 7 + test $(svn_cmd log -r2:2 | wc -l) = 5 && + test $(svn_cmd log -r4:4 | wc -l) = 7 ) ' diff --git a/t/t9123-git-svn-rebuild-with-rewriteroot.sh b/t/t9123-git-svn-rebuild-with-rewriteroot.sh index cf0415274c..045521615c 100755 --- a/t/t9123-git-svn-rebuild-with-rewriteroot.sh +++ b/t/t9123-git-svn-rebuild-with-rewriteroot.sh @@ -10,7 +10,7 @@ test_description='git svn respects rewriteRoot during rebuild' mkdir import cd import touch foo - svn import -m 'import for git svn' . "$svnrepo" >/dev/null + svn_cmd import -m 'import for git svn' . "$svnrepo" >/dev/null cd .. rm -rf import diff --git a/t/t9124-git-svn-dcommit-auto-props.sh b/t/t9124-git-svn-dcommit-auto-props.sh index 263dbf5fc2..d6b076f6b7 100755 --- a/t/t9124-git-svn-dcommit-auto-props.sh +++ b/t/t9124-git-svn-dcommit-auto-props.sh @@ -21,7 +21,7 @@ test_expect_success 'initialize git svn' ' ( cd import && echo foo >foo && - svn import -m "import for git svn" . "$svnrepo" + svn_cmd import -m "import for git svn" . "$svnrepo" ) && rm -rf import && git svn init "$svnrepo" @@ -61,23 +61,23 @@ test_expect_success 'check resulting svn repository' ' ( mkdir work && cd work && - svn co "$svnrepo" && + svn_cmd co "$svnrepo" && cd svnrepo && # Check properties from first commit. - test "x$(svn propget svn:executable exec1.sh)" = "x*" && - test "x$(svn propget svn:mime-type exec1.sh)" = \ + test "x$(svn_cmd propget svn:executable exec1.sh)" = "x*" && + test "x$(svn_cmd propget svn:mime-type exec1.sh)" = \ "xapplication/x-shellscript" && - test "x$(svn propget svn:mime-type hello.txt)" = "xtext/plain" && - test "x$(svn propget svn:eol-style hello.txt)" = "xnative" && - test "x$(svn propget svn:mime-type bar)" = "x" && + test "x$(svn_cmd propget svn:mime-type hello.txt)" = "xtext/plain" && + test "x$(svn_cmd propget svn:eol-style hello.txt)" = "xnative" && + test "x$(svn_cmd propget svn:mime-type bar)" = "x" && # Check properties from second commit. - test "x$(svn propget svn:executable exec2.sh)" = "x*" && - test "x$(svn propget svn:mime-type exec2.sh)" = "x" && - test "x$(svn propget svn:mime-type world.txt)" = "x" && - test "x$(svn propget svn:eol-style world.txt)" = "x" && - test "x$(svn propget svn:mime-type zot)" = "x" + test "x$(svn_cmd propget svn:executable exec2.sh)" = "x*" && + test "x$(svn_cmd propget svn:mime-type exec2.sh)" = "x" && + test "x$(svn_cmd propget svn:mime-type world.txt)" = "x" && + test "x$(svn_cmd propget svn:eol-style world.txt)" = "x" && + test "x$(svn_cmd propget svn:mime-type zot)" = "x" ) ' @@ -89,12 +89,12 @@ test_expect_success 'check renamed file' ' git svn dcommit --config-dir=user && ( cd work/svnrepo && - svn up && + svn_cmd up && test ! -e foo && test -e foo.sh && - test "x$(svn propget svn:mime-type foo.sh)" = \ + test "x$(svn_cmd propget svn:mime-type foo.sh)" = \ "xapplication/x-shellscript" && - test "x$(svn propget svn:eol-style foo.sh)" = "xLF" + test "x$(svn_cmd propget svn:eol-style foo.sh)" = "xLF" ) ' diff --git a/t/t9125-git-svn-multi-glob-branch-names.sh b/t/t9125-git-svn-multi-glob-branch-names.sh index 475c751c1c..c19418614f 100755 --- a/t/t9125-git-svn-multi-glob-branch-names.sh +++ b/t/t9125-git-svn-multi-glob-branch-names.sh @@ -8,11 +8,11 @@ test_expect_success 'setup svnrepo' ' mkdir project project/trunk project/branches \ project/branches/v14.1 project/tags && echo foo > project/trunk/foo && - svn import -m "$test_description" project "$svnrepo/project" && + svn_cmd import -m "$test_description" project "$svnrepo/project" && rm -rf project && - svn cp -m "fun" "$svnrepo/project/trunk" \ + svn_cmd cp -m "fun" "$svnrepo/project/trunk" \ "$svnrepo/project/branches/v14.1/beta" && - svn cp -m "more fun!" "$svnrepo/project/branches/v14.1/beta" \ + svn_cmd cp -m "more fun!" "$svnrepo/project/branches/v14.1/beta" \ "$svnrepo/project/branches/v14.1/gold" ' diff --git a/t/t9127-git-svn-partial-rebuild.sh b/t/t9127-git-svn-partial-rebuild.sh index 87696a92dc..4aab8ecc14 100755 --- a/t/t9127-git-svn-partial-rebuild.sh +++ b/t/t9127-git-svn-partial-rebuild.sh @@ -14,21 +14,21 @@ test_expect_success 'initialize svnrepo' ' cd trunk && echo foo > foo && cd .. && - svn import -m "import for git-svn" . "$svnrepo" >/dev/null && - svn copy "$svnrepo"/trunk "$svnrepo"/branches/a \ + svn_cmd import -m "import for git-svn" . "$svnrepo" >/dev/null && + svn_cmd copy "$svnrepo"/trunk "$svnrepo"/branches/a \ -m "created branch a" && cd .. && rm -rf import && - svn co "$svnrepo"/trunk trunk && + svn_cmd co "$svnrepo"/trunk trunk && cd trunk && echo bar >> foo && - svn ci -m "updated trunk" && + svn_cmd ci -m "updated trunk" && cd .. && - svn co "$svnrepo"/branches/a a && + svn_cmd co "$svnrepo"/branches/a a && cd a && echo baz >> a && - svn add a && - svn ci -m "updated a" && + svn_cmd add a && + svn_cmd ci -m "updated a" && cd .. && git svn init --stdlayout "$svnrepo" ) diff --git a/t/t9128-git-svn-cmd-branch.sh b/t/t9128-git-svn-cmd-branch.sh index 252daa7e1a..807e494a3a 100755 --- a/t/t9128-git-svn-cmd-branch.sh +++ b/t/t9128-git-svn-cmd-branch.sh @@ -14,13 +14,13 @@ test_expect_success 'initialize svnrepo' ' cd trunk && echo foo > foo && cd .. && - svn import -m "import for git-svn" . "$svnrepo" >/dev/null && + svn_cmd import -m "import for git-svn" . "$svnrepo" >/dev/null && cd .. && rm -rf import && - svn co "$svnrepo"/trunk trunk && + svn_cmd co "$svnrepo"/trunk trunk && cd trunk && echo bar >> foo && - svn ci -m "updated trunk" && + svn_cmd ci -m "updated trunk" && cd .. && rm -rf trunk ) @@ -57,14 +57,14 @@ test_expect_success 'git svn branch tests' ' ' test_expect_success 'branch uses correct svn-remote' ' - (svn co "$svnrepo" svn && + (svn_cmd co "$svnrepo" svn && cd svn && mkdir mirror && - svn add mirror && - svn copy trunk mirror/ && - svn copy tags mirror/ && - svn copy branches mirror/ && - svn ci -m "made mirror" ) && + svn_cmd add mirror && + svn_cmd copy trunk mirror/ && + svn_cmd copy tags mirror/ && + svn_cmd copy branches mirror/ && + svn_cmd ci -m "made mirror" ) && rm -rf svn && git svn init -s -R mirror --prefix=mirror/ "$svnrepo"/mirror && git svn fetch -R mirror && diff --git a/t/t9129-git-svn-i18n-commitencoding.sh b/t/t9129-git-svn-i18n-commitencoding.sh index 3200ab38ef..d45fb73016 100755 --- a/t/t9129-git-svn-i18n-commitencoding.sh +++ b/t/t9129-git-svn-i18n-commitencoding.sh @@ -33,7 +33,7 @@ for H in ISO-8859-1 EUCJP ISO-2022-JP do test_expect_success "$H setup" ' mkdir $H && - svn import -m "$H test" $H "$svnrepo"/$H && + svn_cmd import -m "$H test" $H "$svnrepo"/$H && git svn clone "$svnrepo"/$H $H ' done diff --git a/t/t9130-git-svn-authors-file.sh b/t/t9130-git-svn-authors-file.sh index b8fb277562..f5abdb3c7f 100755 --- a/t/t9130-git-svn-authors-file.sh +++ b/t/t9130-git-svn-authors-file.sh @@ -15,7 +15,7 @@ EOF test_expect_success 'setup svnrepo' ' for i in aa bb cc dd do - svn mkdir -m $i --username $i "$svnrepo"/$i + svn_cmd mkdir -m $i --username $i "$svnrepo"/$i done ' @@ -52,13 +52,13 @@ test_expect_success 'continues to import once authors have been added' ' ' test_expect_success 'authors-file against globs' ' - svn mkdir -m globs --username aa \ + svn_cmd mkdir -m globs --username aa \ "$svnrepo"/aa/trunk "$svnrepo"/aa/branches "$svnrepo"/aa/tags && git svn clone --authors-file=svn-authors -s "$svnrepo"/aa aa-work && for i in bb ee cc do branch="aa/branches/$i" - svn mkdir -m "$branch" --username $i "$svnrepo/$branch" + svn_cmd mkdir -m "$branch" --username $i "$svnrepo/$branch" done ' diff --git a/t/t9133-git-svn-nested-git-repo.sh b/t/t9133-git-svn-nested-git-repo.sh index 893f57ef73..f3c30e63b7 100755 --- a/t/t9133-git-svn-nested-git-repo.sh +++ b/t/t9133-git-svn-nested-git-repo.sh @@ -7,19 +7,19 @@ test_description='git svn property tests' . ./lib-git-svn.sh test_expect_success 'setup repo with a git repo inside it' ' - svn co "$svnrepo" s && + svn_cmd co "$svnrepo" s && ( cd s && git init && test -f .git/HEAD && > .git/a && echo a > a && - svn add .git a && - svn commit -m "create a nested git repo" && - svn up && + svn_cmd add .git a && + svn_cmd commit -m "create a nested git repo" && + svn_cmd up && echo hi >> .git/a && - svn commit -m "modify .git/a" && - svn up + svn_cmd commit -m "modify .git/a" && + svn_cmd up ) ' @@ -33,9 +33,9 @@ test_expect_success 'SVN-side change outside of .git' ' ( cd s && echo b >> a && - svn commit -m "SVN-side change outside of .git" && - svn up && - svn log -v | fgrep "SVN-side change outside of .git" + svn_cmd commit -m "SVN-side change outside of .git" && + svn_cmd up && + svn_cmd log -v | fgrep "SVN-side change outside of .git" ) ' @@ -56,10 +56,10 @@ test_expect_success 'SVN-side change inside of .git' ' git add a && git commit -m "add a inside an SVN repo" && git log && - svn add --force .git && - svn commit -m "SVN-side change inside of .git" && - svn up && - svn log -v | fgrep "SVN-side change inside of .git" + svn_cmd add --force .git && + svn_cmd commit -m "SVN-side change inside of .git" && + svn_cmd up && + svn_cmd log -v | fgrep "SVN-side change inside of .git" ) ' @@ -80,9 +80,9 @@ test_expect_success 'SVN-side change in and out of .git' ' echo c >> a && git add a && git commit -m "add a inside an SVN repo" && - svn commit -m "SVN-side change in and out of .git" && - svn up && - svn log -v | fgrep "SVN-side change in and out of .git" + svn_cmd commit -m "SVN-side change in and out of .git" && + svn_cmd up && + svn_cmd log -v | fgrep "SVN-side change in and out of .git" ) ' diff --git a/t/t9134-git-svn-ignore-paths.sh b/t/t9134-git-svn-ignore-paths.sh index 71fdc4a69d..09ff10cd9b 100755 --- a/t/t9134-git-svn-ignore-paths.sh +++ b/t/t9134-git-svn-ignore-paths.sh @@ -8,19 +8,19 @@ test_description='git svn property tests' . ./lib-git-svn.sh test_expect_success 'setup test repository' ' - svn co "$svnrepo" s && + svn_cmd co "$svnrepo" s && ( cd s && mkdir qqq www && echo test_qqq > qqq/test_qqq.txt && echo test_www > www/test_www.txt && - svn add qqq && - svn add www && - svn commit -m "create some files" && - svn up && + svn_cmd add qqq && + svn_cmd add www && + svn_cmd commit -m "create some files" && + svn_cmd up && echo hi >> www/test_www.txt && - svn commit -m "modify www/test_www.txt" && - svn up + svn_cmd commit -m "modify www/test_www.txt" && + svn_cmd up ) ' @@ -51,9 +51,9 @@ test_expect_success 'SVN-side change outside of www' ' ( cd s && echo b >> qqq/test_qqq.txt && - svn commit -m "SVN-side change outside of www" && - svn up && - svn log -v | fgrep "SVN-side change outside of www" + svn_cmd commit -m "SVN-side change outside of www" && + svn_cmd up && + svn_cmd log -v | fgrep "SVN-side change outside of www" ) ' @@ -83,9 +83,9 @@ test_expect_success 'SVN-side change inside of ignored www' ' ( cd s && echo zaq >> www/test_www.txt - svn commit -m "SVN-side change inside of www/test_www.txt" && - svn up && - svn log -v | fgrep "SVN-side change inside of www/test_www.txt" + svn_cmd commit -m "SVN-side change inside of www/test_www.txt" && + svn_cmd up && + svn_cmd log -v | fgrep "SVN-side change inside of www/test_www.txt" ) ' @@ -116,9 +116,9 @@ test_expect_success 'SVN-side change in and out of ignored www' ' cd s && echo cvf >> www/test_www.txt echo ygg >> qqq/test_qqq.txt - svn commit -m "SVN-side change in and out of ignored www" && - svn up && - svn log -v | fgrep "SVN-side change in and out of ignored www" + svn_cmd commit -m "SVN-side change in and out of ignored www" && + svn_cmd up && + svn_cmd log -v | fgrep "SVN-side change in and out of ignored www" ) ' diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh index fd185011b7..636ca0abb9 100755 --- a/t/t9137-git-svn-dcommit-clobber-series.sh +++ b/t/t9137-git-svn-dcommit-clobber-series.sh @@ -8,7 +8,7 @@ test_expect_success 'initialize repo' ' mkdir import && cd import && awk "BEGIN { for (i = 1; i < 64; i++) { print i } }" > file - svn import -m "initial" . "$svnrepo" && + svn_cmd import -m "initial" . "$svnrepo" && cd .. && git svn init "$svnrepo" && git svn fetch && @@ -18,14 +18,14 @@ test_expect_success 'initialize repo' ' test_expect_success '(supposedly) non-conflicting change from SVN' ' test x"`sed -n -e 58p < file`" = x58 && test x"`sed -n -e 61p < file`" = x61 && - svn co "$svnrepo" tmp && + svn_cmd co "$svnrepo" tmp && cd tmp && perl -i.bak -p -e "s/^58$/5588/" file && perl -i.bak -p -e "s/^61$/6611/" file && poke file && test x"`sed -n -e 58p < file`" = x5588 && test x"`sed -n -e 61p < file`" = x6611 && - svn commit -m "58 => 5588, 61 => 6611" && + svn_cmd commit -m "58 => 5588, 61 => 6611" && cd .. ' @@ -46,7 +46,7 @@ test_expect_success 'change file but in unrelated area' " test x\"\`sed -n -e 7p < file\`\" = x7777 && git commit -m '4 => 4444, 7 => 7777' file && git svn dcommit && - svn up tmp && + svn_cmd up tmp && cd tmp && test x\"\`sed -n -e 4p < file\`\" = x4444 && test x\"\`sed -n -e 7p < file\`\" = x7777 && From c69700fe042ad2ecf2904a8b7d8eddc6d52b790b Mon Sep 17 00:00:00 2001 From: Alex Vandiver <alexmv@MIT.EDU> Date: Wed, 6 May 2009 16:18:52 -0400 Subject: [PATCH 639/654] git-svn: Fix for svn paths removed > log-window-size revisions ago Instead of trying to find the end of the commit history only in the last window, track if we have seen commits yet, and use that to judge if we need to backtrack and look for a tail. Otherwise, conversion can silently lose up to 100 revisions of a branch if it was deleted >100 revisions ago. Signed-off-by: Alex Vandiver <alexmv@mit.edu> Acked-by: Eric Wong <normalperson@yhbt.net> --- git-svn.perl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/git-svn.perl b/git-svn.perl index ef1d30db38..5836ddec8a 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -4438,6 +4438,7 @@ sub gs_fetch_loop_common { my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc); my $longest_path = longest_common_path($gsv, $globs); my $ra_url = $self->{url}; + my $find_trailing_edge; while (1) { my %revs; my $err; @@ -4455,8 +4456,10 @@ sub gs_fetch_loop_common { sub { $revs{$_[1]} = _cb(@_) }); if ($err) { print "Checked through r$max\r"; + } else { + $find_trailing_edge = 1; } - if ($err && $max >= $head) { + if ($err and $find_trailing_edge) { print STDERR "Path '$longest_path' ", "was probably deleted:\n", $err->expanded_message, @@ -4475,6 +4478,7 @@ sub gs_fetch_loop_common { last; } } + $find_trailing_edge = 0; } $SVN::Error::handler = $err_handler; From b6c61778d4fa57904d5b818e0ca04292aa1d0335 Mon Sep 17 00:00:00 2001 From: Alex Vandiver <alexmv@MIT.EDU> Date: Wed, 6 May 2009 16:18:53 -0400 Subject: [PATCH 640/654] git-svn: Correctly report max revision when following deleted paths Report the maximum found revision in the range, instead of the minimum changed revision. Signed-off-by: Alex Vandiver <alexmv@mit.edu> Acked-by: Eric Wong <normalperson@yhbt.net> --- git-svn.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-svn.perl b/git-svn.perl index 5836ddec8a..eebcf0f20e 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -4471,7 +4471,7 @@ sub gs_fetch_loop_common { my $ok; $self->get_log([$longest_path], $min, $hi, 0, 1, 1, sub { - $ok ||= $_[1]; + $ok = $_[1]; $revs{$_[1]} = _cb(@_) }); if ($ok) { print STDERR "r$min .. r$ok OK\n"; From 42a5da1806fd6891d4fcc0ad9c0e550c12f75df5 Mon Sep 17 00:00:00 2001 From: Alex Vandiver <alexmv@MIT.EDU> Date: Wed, 6 May 2009 16:19:45 -0400 Subject: [PATCH 641/654] git-svn: Set svn.authorsfile if it is passed to git svn clone Signed-off-by: Alex Vandiver <alexmv@mit.edu> Acked-by: Eric Wong <normalperson@yhbt.net> --- git-svn.perl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-svn.perl b/git-svn.perl index eebcf0f20e..e927965ac4 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -361,6 +361,7 @@ sub cmd_clone { $path = basename($url) if !defined $path || !length $path; cmd_init($url, $path); Git::SVN::fetch_all($Git::SVN::default_repo_id); + command_oneline('config', 'svn.authorsfile', $_authors) if $_authors; } sub cmd_init { From 36db1eddf972c88edf402b99e2366ad533635ab8 Mon Sep 17 00:00:00 2001 From: Mark Lodato <lodatom@gmail.com> Date: Thu, 14 May 2009 21:27:15 -0400 Subject: [PATCH 642/654] git-svn: add --authors-prog option Add a new option, --authors-prog, to git-svn that allows a more flexible alternative (or supplement) to --authors-file. This allows more advanced username operations than the authors file will allow. For example, one may look up Subversion users via LDAP, or may generate the name and email address from the Subversion username. Notes: * If both --authors-name and --authors-prog are given, the former is tried first, falling back to the later. * The program is called once per unique SVN username, and the result is cached. * The command-line argument must be the path to a program, not a generic shell command line. The absolute path to this program is taken at startup since the git-svn script changes directory during operation. * The option is not enabled for `git svn log'. [ew: fixed case where neither --authors-(name|prog) were defined] Signed-off-by: Mark Lodato <lodatom@gmail.com> Acked-by: Eric Wong <normalperson@yhbt.net> --- Documentation/git-svn.txt | 8 ++++ git-svn.perl | 32 +++++++++++++-- t/t9138-git-svn-authors-prog.sh | 69 +++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 3 deletions(-) create mode 100755 t/t9138-git-svn-authors-prog.sh diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index 1c40894669..ca3fc3de1f 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -398,6 +398,14 @@ after the authors-file is modified should continue operation. config key: svn.authorsfile +--authors-prog=<filename>:: + +If this option is specified, for each SVN committer name that does not +exist in the authors file, the given file is executed with the committer +name as the first argument. The program is expected to return a single +line of the form "Name <email>", which will be treated as if included in +the authors file. + -q:: --quiet:: Make 'git-svn' less verbose. Specify a second time to make it diff --git a/git-svn.perl b/git-svn.perl index e927965ac4..a70c7d7b2c 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -5,7 +5,7 @@ use warnings; use strict; use vars qw/ $AUTHOR $VERSION $sha1 $sha1_short $_revision $_repository - $_q $_authors %users/; + $_q $_authors $_authors_prog %users/; $AUTHOR = 'Eric Wong <normalperson@yhbt.net>'; $VERSION = '@@GIT_VERSION@@'; @@ -39,6 +39,7 @@ use Digest::MD5; use IO::File qw//; use File::Basename qw/dirname basename/; use File::Path qw/mkpath/; +use File::Spec; use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/; use IPC::Open3; use Git; @@ -76,6 +77,7 @@ my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username, 'ignore-paths=s' => \$SVN::Git::Fetcher::_ignore_regex ); my %fc_opts = ( 'follow-parent|follow!' => \$Git::SVN::_follow_parent, 'authors-file|A=s' => \$_authors, + 'authors-prog=s' => \$_authors_prog, 'repack:i' => \$Git::SVN::_repack, 'noMetadata' => \$Git::SVN::_no_metadata, 'useSvmProps' => \$Git::SVN::_use_svm_props, @@ -263,6 +265,9 @@ usage(0) if $_help; version() if $_version; usage(1) unless defined $cmd; load_authors() if $_authors; +if (defined $_authors_prog) { + $_authors_prog = "'" . File::Spec->rel2abs($_authors_prog) . "'"; +} unless ($cmd =~ /^(?:clone|init|multi-init|commit-diff)$/) { Git::SVN::Migration::migration_check(); @@ -2664,12 +2669,33 @@ sub other_gs { $gs } +sub call_authors_prog { + my ($orig_author) = @_; + my $author = `$::_authors_prog $orig_author`; + if ($? != 0) { + die "$::_authors_prog failed with exit code $?\n" + } + if ($author =~ /^\s*(.+?)\s*<(.*)>\s*$/) { + my ($name, $email) = ($1, $2); + $email = undef if length $2 == 0; + return [$name, $email]; + } else { + die "Author: $orig_author: $::_authors_prog returned " + . "invalid author format: $author\n"; + } +} + sub check_author { my ($author) = @_; if (!defined $author || length $author == 0) { $author = '(no author)'; - } elsif (defined $::_authors && ! defined $::users{$author}) { - die "Author: $author not defined in $::_authors file\n"; + } + if (!defined $::users{$author}) { + if (defined $::_authors_prog) { + $::users{$author} = call_authors_prog($author); + } elsif (defined $::_authors) { + die "Author: $author not defined in $::_authors file\n"; + } } $author; } diff --git a/t/t9138-git-svn-authors-prog.sh b/t/t9138-git-svn-authors-prog.sh new file mode 100755 index 0000000000..a4b00f2a3f --- /dev/null +++ b/t/t9138-git-svn-authors-prog.sh @@ -0,0 +1,69 @@ +#!/bin/sh +# +# Copyright (c) 2009 Eric Wong, Mark Lodato +# + +test_description='git svn authors prog tests' + +. ./lib-git-svn.sh + +cat > svn-authors-prog <<'EOF' +#!/usr/bin/perl +$_ = shift; +if (s/-sub$//) { + print "$_ <$_\@sub.example.com>\n"; +} +else { + print "$_ <$_\@example.com>\n"; +} +EOF +chmod +x svn-authors-prog + +cat > svn-authors <<'EOF' +ff = FFFFFFF FFFFFFF <fFf@other.example.com> +EOF + +test_expect_success 'setup svnrepo' ' + for i in aa bb cc-sub dd-sub ee-foo ff + do + svn mkdir -m $i --username $i "$svnrepo"/$i + done + ' + +test_expect_success 'import authors with prog and file' ' + git svn clone --authors-prog=./svn-authors-prog \ + --authors-file=svn-authors "$svnrepo" x + ' + +test_expect_success 'imported 6 revisions successfully' ' + ( + cd x + test "`git rev-list refs/remotes/git-svn | wc -l`" -eq 6 + ) + ' + +test_expect_success 'authors-prog ran correctly' ' + ( + cd x + git rev-list -1 --pretty=raw refs/remotes/git-svn~1 | \ + grep "^author ee-foo <ee-foo@example\.com> " && + git rev-list -1 --pretty=raw refs/remotes/git-svn~2 | \ + grep "^author dd <dd@sub\.example\.com> " && + git rev-list -1 --pretty=raw refs/remotes/git-svn~3 | \ + grep "^author cc <cc@sub\.example\.com> " && + git rev-list -1 --pretty=raw refs/remotes/git-svn~4 | \ + grep "^author bb <bb@example\.com> " && + git rev-list -1 --pretty=raw refs/remotes/git-svn~5 | \ + grep "^author aa <aa@example\.com> " + ) + ' + +test_expect_success 'authors-file overrode authors-prog' ' + ( + cd x + git rev-list -1 --pretty=raw refs/remotes/git-svn | \ + grep "^author FFFFFFF FFFFFFF <fFf@other\.example\.com> " + ) + ' + +test_done From fe87c92138d91e2002c46b06f8389814436de1cf Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" <ebiederm@xmission.com> Date: Wed, 20 May 2009 19:45:53 -0700 Subject: [PATCH 643/654] git-send-email: Handle quotes when parsing .mailrc files It is legal and not uncommon to use quotes in a .mailrc file so you can include a persons fullname as well as their email alias. Handle this by using quotewords instead of split when parsing .mailrc files. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index cccbf4517a..e3408d513f 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -409,7 +409,7 @@ my %parse_alias = ( mailrc => sub { my $fh = shift; while (<$fh>) { if (/^alias\s+(\S+)\s+(.*)$/) { # spaces delimit multiple addresses - $aliases{$1} = [ split(/\s+/, $2) ]; + $aliases{$1} = [ quotewords('\s+', 0, $2) ]; }}}, pine => sub { my $fh = shift; my $f='\t[^\t]*'; for (my $x = ''; defined($x); $x = $_) { From 06f391906a69e410c9a6ca5e13774529a091385d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= <pclouds@gmail.com> Date: Thu, 21 May 2009 19:47:07 +1000 Subject: [PATCH 644/654] doc/git-rebase.txt: remove mention of multiple strategies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-rebase.sh does not seem to support this. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Documentation/git-rebase.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 3d5a066c31..26f3b7b2b0 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -231,8 +231,7 @@ OPTIONS -s <strategy>:: --strategy=<strategy>:: - Use the given merge strategy; can be supplied more than - once to specify them in the order they should be tried. + Use the given merge strategy. If there is no `-s` option, a built-in list of strategies is used instead ('git-merge-recursive' when merging a single head, 'git-merge-octopus' otherwise). This implies --merge. From a80aad7b85fc560451e07792d64ab6cb15a39914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= <pclouds@gmail.com> Date: Thu, 21 May 2009 19:32:44 +1000 Subject: [PATCH 645/654] Terminate argv with NULL before calling setup_revisions() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is convention that argv should be terminated with NULL, even if argc is used to specify the size of argv. setup_revisions() requires this and may segfault otherwise. This patch makes sure that all argv (that I can find) is NULL terminated. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- bundle.c | 2 +- http-push.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/bundle.c b/bundle.c index d0dd818b31..e4b2aa9c4a 100644 --- a/bundle.c +++ b/bundle.c @@ -98,7 +98,7 @@ int verify_bundle(struct bundle_header *header, int verbose) */ struct ref_list *p = &header->prerequisites; struct rev_info revs; - const char *argv[] = {NULL, "--all"}; + const char *argv[] = {NULL, "--all", NULL}; struct object_array refs; struct commit *commit; int i, ret = 0, req_nr; diff --git a/http-push.c b/http-push.c index 29e8ebfebb..dac2c6e052 100644 --- a/http-push.c +++ b/http-push.c @@ -2326,7 +2326,7 @@ int main(int argc, char **argv) new_refs = 0; for (ref = remote_refs; ref; ref = ref->next) { char old_hex[60], *new_hex; - const char *commit_argv[4]; + const char *commit_argv[5]; int commit_argc; char *new_sha1_hex, *old_sha1_hex; @@ -2406,6 +2406,7 @@ int main(int argc, char **argv) commit_argv[3] = old_sha1_hex; commit_argc++; } + commit_argv[commit_argc] = NULL; init_revisions(&revs, setup_git_directory()); setup_revisions(commit_argc, commit_argv, &revs, NULL); revs.edge_hint = 0; /* just in case */ From 14afe77486281e411bfadd131e5c8ffc44e22a26 Mon Sep 17 00:00:00 2001 From: Jakub Narebski <jnareb@gmail.com> Date: Fri, 22 May 2009 17:35:46 +0200 Subject: [PATCH 646/654] gitweb: Sanitize title attribute in format_subject_html Replace control characters with question mark '?' (like in chop_and_esc_str). A little background: some web browsers turn on strict (and unforgiving) XML validating mode for XHTML documents served using application/xhtml+xml content type. This means among others that control characters are forbidden to appear in gitweb output. CGI.pm does by default slight escaping (using simple_escape subroutine from CGI::Util) of all _attribute_ values (depending on the value of autoEscape, by default on). This escaping, at least in CGI.pm version 3.10 (most current version at CPAN is 3.43), is minimal: only '"', '&', '<' and '>' are escaped using named HTML entity references (", &, < and > respectively). But simple_escape does not do escaping of control characters such as ^X which are invalid in XHTML (in strict mode). If by some accident commit message do contain some control character in first 50 characters (more or less) of first line of commit message, and this line is longer than 50 characters (so gitweb shortens it for display), then gitweb would put this control character in title attribute (and CGI.pm would not remove them). The tag _contents_ is safe because it is escaped using esc_html() explicitly, and it replaces control characters by their printable representation. While at it: chop_and_escape_str doesn't need capturing group. Noticed-by: Paul Gortmaker <paul.gortmaker@windriver.com> Signed-off-by: Jakub Narebski <jnareb@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- gitweb/gitweb.perl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 06e91608fa..d143829c5d 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1235,7 +1235,7 @@ sub chop_and_escape_str { if ($chopped eq $str) { return esc_html($chopped); } else { - $str =~ s/([[:cntrl:]])/?/g; + $str =~ s/[[:cntrl:]]/?/g; return $cgi->span({-title=>$str}, esc_html($chopped)); } } @@ -1458,6 +1458,7 @@ sub format_subject_html { $extra = '' unless defined($extra); if (length($short) < length($long)) { + $long =~ s/[[:cntrl:]]/?/g; return $cgi->a({-href => $href, -class => "list subject", -title => to_utf8($long)}, esc_html($short) . $extra); From bedc4279a833dc7f17ea7d1730d9f3e4ff018729 Mon Sep 17 00:00:00 2001 From: Peter Harris <git@peter.is-a-geek.org> Date: Sat, 23 May 2009 10:04:47 +0200 Subject: [PATCH 647/654] MinGW: Scan for \r in addition to \n when reading shbang lines \r is common on Windows, so we should handle it gracefully. Signed-off-by: Steffen Prohaska <prohaska@zib.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index cdeda1d985..b723c4dfd6 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -525,8 +525,8 @@ static const char *parse_interpreter(const char *cmd) if (buf[0] != '#' || buf[1] != '!') return NULL; buf[n] = '\0'; - p = strchr(buf, '\n'); - if (!p) + p = buf + strcspn(buf, "\r\n"); + if (!*p) return NULL; *p = '\0'; From 352c81114ca436b9e06255f24bf8a7d2fd0a4029 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Sat, 23 May 2009 10:04:48 +0200 Subject: [PATCH 648/654] MinGW: the path separator to split GITPERLLIB is ';' on Win32 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Steffen Prohaska <prohaska@zib.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index fdb39fa439..eaae45db7c 100644 --- a/Makefile +++ b/Makefile @@ -228,6 +228,7 @@ ETC_GITCONFIG = etc/gitconfig endif lib = lib # DESTDIR= +pathsep = : # default configuration for gitweb GITWEB_CONFIG = gitweb_config.perl @@ -816,6 +817,7 @@ ifneq (,$(findstring CYGWIN,$(uname_S))) UNRELIABLE_FSTAT = UnfortunatelyYes endif ifneq (,$(findstring MINGW,$(uname_S))) + pathsep = ; NO_PREAD = YesPlease NO_OPENSSL = YesPlease NO_CURL = YesPlease @@ -1270,7 +1272,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl sed -e '1{' \ -e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \ -e ' h' \ - -e ' s=.*=use lib (split(/:/, $$ENV{GITPERLLIB} || "@@INSTLIBDIR@@"));=' \ + -e ' s=.*=use lib (split(/$(pathsep)/, $$ENV{GITPERLLIB} || "@@INSTLIBDIR@@"));=' \ -e ' H' \ -e ' x' \ -e '}' \ From 27e3219f1a78d2d7035565aa7ace882dbc2baa97 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Sat, 23 May 2009 10:04:49 +0200 Subject: [PATCH 649/654] MinGW: use POSIX signature of waitpid() Git's source code expects waitpid() to return a signed int status. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Steffen Prohaska <prohaska@zib.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- compat/mingw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index 762eb143a7..b1156b865e 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -109,7 +109,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, unsigned *status, unsigned options) +static inline int waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); From 0dbbbc1e26c9979e34031c09c641893123d18450 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Sat, 23 May 2009 10:04:50 +0200 Subject: [PATCH 650/654] MinGW: Add a simple getpass() We need getpass() to activate curl on MinGW. Although the default Makefile currently has 'NO_CURL = YesPlease', msysgit releases do provide curl support, so getpass() is used. [spr: - edited commit message. - squashed commit that provides getpass() declaration.] Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Steffen Prohaska <prohaska@zib.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- compat/mingw.c | 15 +++++++++++++++ compat/mingw.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index b723c4dfd6..e190fddf41 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1156,3 +1156,18 @@ int link(const char *oldpath, const char *newpath) } return 0; } + +char *getpass(const char *prompt) +{ + struct strbuf buf = STRBUF_INIT; + + fputs(prompt, stderr); + for (;;) { + char c = _getch(); + if (c == '\r' || c == '\n') + break; + strbuf_addch(&buf, c); + } + fputs("\n", stderr); + return strbuf_detach(&buf, NULL); +} diff --git a/compat/mingw.h b/compat/mingw.h index b1156b865e..4c50f5b1bc 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -38,6 +38,8 @@ struct passwd { char *pw_dir; }; +extern char *getpass(const char *prompt); + struct pollfd { int fd; /* file descriptor */ short events; /* requested events */ From b74d779bd90477f6514d0a9be4a75b4c40ed946c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin <johannes.schindelin@gmx.de> Date: Sat, 23 May 2009 10:04:51 +0200 Subject: [PATCH 651/654] MinGW: Fix compiler warning in merge-recursive GCC 4.4.0 on Windows does not like the format %zu. It is quite unlikely, though, that we need more merge bases than a %d can display, so replace the %zu by a %d. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Steffen Prohaska <prohaska@zib.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin-merge-recursive.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c index 703045bfc8..d26a96e486 100644 --- a/builtin-merge-recursive.c +++ b/builtin-merge-recursive.c @@ -45,8 +45,9 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix) bases[bases_count++] = sha; } else - warning("Cannot handle more than %zu bases. " - "Ignoring %s.", ARRAY_SIZE(bases)-1, argv[i]); + warning("Cannot handle more than %d bases. " + "Ignoring %s.", + (int)ARRAY_SIZE(bases)-1, argv[i]); } if (argc - i != 3) /* "--" "<head>" "<remote>" */ die("Not handling anything other than two heads merge."); From 5ffd3113d4109ae5d3595425af3ff4a781617631 Mon Sep 17 00:00:00 2001 From: Jim Meyering <jim@meyering.net> Date: Sat, 23 May 2009 14:26:44 +0200 Subject: [PATCH 652/654] post-receive-email: hooks.showrev: show how to include both web link and patch Add a comment showing how to include a web link (i.e. gitweb/cgit) and a patch in the email that is sent for each pushed commit. The quoting was tricky enough that it's worth documenting. To add two blank lines (i.e. put \n\n in the printf), you would need to say \\\\n\\\\n, and in the end, the pair of "echo" statements seemed better. This is used in glibc.git repository: http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=summary push-triggered messages have been sent to this list since May 21: http://sourceware.org/ml/glibc-cvs/2009-q2/ Signed-off-by: Junio C Hamano <gitster@pobox.com> --- contrib/hooks/post-receive-email | 4 ++++ 1 file changed, 4 insertions(+) mode change 100644 => 100755 contrib/hooks/post-receive-email diff --git a/contrib/hooks/post-receive-email b/contrib/hooks/post-receive-email old mode 100644 new mode 100755 index 60cbab65d3..2a66063e44 --- a/contrib/hooks/post-receive-email +++ b/contrib/hooks/post-receive-email @@ -44,6 +44,10 @@ # --pretty %s", displaying the commit id, author, date and log # message. To list full patches separated by a blank line, you # could set this to "git show -C %s; echo". +# To list a gitweb/cgit URL *and* a full patch for each change set, use this: +# "t=%s; printf 'http://.../?id=%%s' \$t; echo;echo; git show -C \$t; echo" +# Be careful if "..." contains things that will be expanded by shell "eval" +# or printf. # # Notes # ----- From 7a7eb5173d4e16f0323b2c4078e88fc0a40c38b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= <pclouds@gmail.com> Date: Sun, 24 May 2009 01:31:02 +1000 Subject: [PATCH 653/654] t/t3400-rebase.sh: add more tests to help migrating git-rebase.sh to C MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These new tests make sure I don't miss any check being performed before rebase is proceeded (which is well tested by other tests) Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- t/t3400-rebase.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index 6e391a3702..7f62bfb9dd 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -41,9 +41,40 @@ test_expect_success \ git tag topic ' +test_expect_success 'rebase on dirty worktree' ' + echo dirty >> A && + test_must_fail git rebase master' + +test_expect_success 'rebase on dirty cache' ' + git add A && + test_must_fail git rebase master' + test_expect_success 'rebase against master' ' + git reset --hard HEAD && git rebase master' +test_expect_success 'rebase against master twice' ' + git rebase master 2>err && + grep "Current branch my-topic-branch is up to date" err +' + +test_expect_success 'rebase against master twice with --force' ' + git rebase --force-rebase master >out && + grep "Current branch my-topic-branch is up to date, rebase forced" out +' + +test_expect_success 'rebase against master twice from another branch' ' + git checkout my-topic-branch^ && + git rebase master my-topic-branch 2>err && + grep "Current branch my-topic-branch is up to date" err +' + +test_expect_success 'rebase fast-forward to master' ' + git checkout my-topic-branch^ && + git rebase my-topic-branch 2>err && + grep "Fast-forwarded HEAD to my-topic-branch" err +' + test_expect_success \ 'the rebase operation should not have destroyed author information' \ '! (git log | grep "Author:" | grep "<>")' From 6589ebf107214a9e6db31764e847301f1adebc81 Mon Sep 17 00:00:00 2001 From: Alex Riesen <raa.lkml@gmail.com> Date: Sun, 24 May 2009 15:16:49 +0200 Subject: [PATCH 654/654] http-push.c::remove_locks(): fix use after free MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Noticed and reported by Serhat Şevki Dinçer. Signed-off-by: Alex Riesen <raa.lkml@gmail.com> Acked-by: Clemens Buchacher <drizzd@aon.at> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- http-push.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/http-push.c b/http-push.c index 6805288857..0696da0fec 100644 --- a/http-push.c +++ b/http-push.c @@ -1356,8 +1356,9 @@ static void remove_locks(void) fprintf(stderr, "Removing remote locks...\n"); while (lock) { + struct remote_lock *next = lock->next; unlock_remote(lock); - lock = lock->next; + lock = next; } }