diff options
126 files changed, 1100 insertions, 674 deletions
@@ -194,6 +194,7 @@ Philippe Bruhat <book@cpan.org> Ralf Thielow <ralf.thielow@gmail.com> <ralf.thielow@googlemail.com> Ramsay Jones <ramsay@ramsayjones.plus.com> <ramsay@ramsay1.demon.co.uk> René Scharfe <l.s.r@web.de> <rene.scharfe@lsrfire.ath.cx> +René Scharfe <l.s.r@web.de> Rene Scharfe Richard Hansen <rhansen@rhansen.org> <hansenr@google.com> Richard Hansen <rhansen@rhansen.org> <rhansen@bbn.com> Robert Fitzsimons <robfitz@273k.net> diff --git a/.travis.yml b/.travis.yml index 278943d14a..fead995edd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,23 +61,8 @@ matrix: services: - docker before_install: - - docker pull daald/ubuntu32:xenial before_script: - script: - - > - docker run - --interactive - --env DEVELOPER - --env DEFAULT_TEST_TARGET - --env GIT_PROVE_OPTS - --env GIT_TEST_OPTS - --env GIT_TEST_CLONE_2GB - --volume "${PWD}:/usr/src/git" - daald/ubuntu32:xenial - /usr/src/git/ci/run-linux32-build.sh $(id -u $USER) - # Use the following command to debug the docker build locally: - # $ docker run -itv "${PWD}:/usr/src/git" --entrypoint /bin/bash daald/ubuntu32:xenial - # root@container:/# /usr/src/git/ci/run-linux32-build.sh + script: ci/run-linux32-docker.sh - env: Static Analysis os: linux compiler: @@ -86,9 +71,8 @@ matrix: packages: - coccinelle before_install: - script: - # "before_script" that builds Git is inherited from base job - - make coccicheck + # "before_script" that builds Git is inherited from base job + script: ci/run-static-analysis.sh after_failure: - env: Documentation os: linux @@ -99,70 +83,14 @@ matrix: - asciidoc - xmlto before_install: - before_script: gem install asciidoctor + before_script: script: ci/test-documentation.sh after_failure: -before_install: - - > - case "${TRAVIS_OS_NAME:-linux}" in - linux) - export GIT_TEST_HTTPD=YesPlease - - mkdir --parents custom/p4 - pushd custom/p4 - wget --quiet http://filehost.perforce.com/perforce/r$LINUX_P4_VERSION/bin.linux26x86_64/p4d - wget --quiet http://filehost.perforce.com/perforce/r$LINUX_P4_VERSION/bin.linux26x86_64/p4 - chmod u+x p4d - chmod u+x p4 - export PATH="$(pwd):$PATH" - popd - mkdir --parents custom/git-lfs - pushd custom/git-lfs - wget --quiet https://github.com/github/git-lfs/releases/download/v$LINUX_GIT_LFS_VERSION/git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz - tar --extract --gunzip --file "git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz" - cp git-lfs-$LINUX_GIT_LFS_VERSION/git-lfs . - export PATH="$(pwd):$PATH" - popd - ;; - osx) - brew update --quiet - # Uncomment this if you want to run perf tests: - # brew install gnu-time - brew install git-lfs gettext - brew link --force gettext - brew install caskroom/cask/perforce - ;; - esac; - echo "$(tput setaf 6)Perforce Server Version$(tput sgr0)"; - p4d -V | grep Rev.; - echo "$(tput setaf 6)Perforce Client Version$(tput sgr0)"; - p4 -V | grep Rev.; - echo "$(tput setaf 6)Git-LFS Version$(tput sgr0)"; - git-lfs version; - -before_script: make --jobs=2 - -script: - - > - mkdir -p $HOME/travis-cache; - ln -s $HOME/travis-cache/.prove t/.prove; - make --quiet test; - -after_failure: - - > - : '<-- Click here to see detailed test output! '; - for TEST_EXIT in t/test-results/*.exit; - do - if [ "$(cat "$TEST_EXIT")" != "0" ]; - then - TEST_OUT="${TEST_EXIT%exit}out"; - echo "------------------------------------------------------------------------"; - echo "$(tput setaf 1)${TEST_OUT}...$(tput sgr0)"; - echo "------------------------------------------------------------------------"; - cat "${TEST_OUT}"; - fi; - done; +before_install: ci/install-dependencies.sh +before_script: ci/run-build.sh +script: ci/run-tests.sh +after_failure: ci/print-test-failures.sh notifications: email: false diff --git a/.tsan-suppressions b/.tsan-suppressions new file mode 100644 index 0000000000..8c85014a0a --- /dev/null +++ b/.tsan-suppressions @@ -0,0 +1,10 @@ +# Suppressions for ThreadSanitizer (tsan). +# +# This file is used by setting the environment variable TSAN_OPTIONS to, e.g., +# "suppressions=$(pwd)/.tsan-suppressions". Observe that relative paths such as +# ".tsan-suppressions" might not work. + +# A static variable is written to racily, but we always write the same value, so +# in practice it (hopefully!) doesn't matter. +race:^want_color$ +race:^transfer_debug$ diff --git a/Documentation/RelNotes/2.10.5.txt b/Documentation/RelNotes/2.10.5.txt new file mode 100644 index 0000000000..a498fd6fdc --- /dev/null +++ b/Documentation/RelNotes/2.10.5.txt @@ -0,0 +1,17 @@ +Git v2.10.5 Release Notes +========================= + +Fixes since v2.10.4 +------------------- + + * "git cvsserver" no longer is invoked by "git daemon" by default, + as it is old and largely unmaintained. + + * Various Perl scripts did not use safe_pipe_capture() instead of + backticks, leaving them susceptible to end-user input. They have + been corrected. + +Credits go to joernchen <joernchen@phenoelit.de> for finding the +unsafe constructs in "git cvsserver", and to Jeff King at GitHub for +finding and fixing instances of the same issue in other scripts. + diff --git a/Documentation/RelNotes/2.11.4.txt b/Documentation/RelNotes/2.11.4.txt new file mode 100644 index 0000000000..ad4da8eb09 --- /dev/null +++ b/Documentation/RelNotes/2.11.4.txt @@ -0,0 +1,17 @@ +Git v2.11.4 Release Notes +========================= + +Fixes since v2.11.3 +------------------- + + * "git cvsserver" no longer is invoked by "git daemon" by default, + as it is old and largely unmaintained. + + * Various Perl scripts did not use safe_pipe_capture() instead of + backticks, leaving them susceptible to end-user input. They have + been corrected. + +Credits go to joernchen <joernchen@phenoelit.de> for finding the +unsafe constructs in "git cvsserver", and to Jeff King at GitHub for +finding and fixing instances of the same issue in other scripts. + diff --git a/Documentation/RelNotes/2.12.5.txt b/Documentation/RelNotes/2.12.5.txt new file mode 100644 index 0000000000..8fa73cfce7 --- /dev/null +++ b/Documentation/RelNotes/2.12.5.txt @@ -0,0 +1,17 @@ +Git v2.12.5 Release Notes +========================= + +Fixes since v2.12.4 +------------------- + + * "git cvsserver" no longer is invoked by "git daemon" by default, + as it is old and largely unmaintained. + + * Various Perl scripts did not use safe_pipe_capture() instead of + backticks, leaving them susceptible to end-user input. They have + been corrected. + +Credits go to joernchen <joernchen@phenoelit.de> for finding the +unsafe constructs in "git cvsserver", and to Jeff King at GitHub for +finding and fixing instances of the same issue in other scripts. + diff --git a/Documentation/RelNotes/2.13.6.txt b/Documentation/RelNotes/2.13.6.txt new file mode 100644 index 0000000000..afcae9c808 --- /dev/null +++ b/Documentation/RelNotes/2.13.6.txt @@ -0,0 +1,17 @@ +Git v2.13.6 Release Notes +========================= + +Fixes since v2.13.5 +------------------- + + * "git cvsserver" no longer is invoked by "git daemon" by default, + as it is old and largely unmaintained. + + * Various Perl scripts did not use safe_pipe_capture() instead of + backticks, leaving them susceptible to end-user input. They have + been corrected. + +Credits go to joernchen <joernchen@phenoelit.de> for finding the +unsafe constructs in "git cvsserver", and to Jeff King at GitHub for +finding and fixing instances of the same issue in other scripts. + diff --git a/Documentation/RelNotes/2.14.2.txt b/Documentation/RelNotes/2.14.2.txt index bcfe78f59d..bec9186ade 100644 --- a/Documentation/RelNotes/2.14.2.txt +++ b/Documentation/RelNotes/2.14.2.txt @@ -91,4 +91,15 @@ Fixes since v2.14.1 * "git archive" did not work well with pathspecs and the export-ignore attribute. + * "git cvsserver" no longer is invoked by "git daemon" by default, + as it is old and largely unmaintained. + + * Various Perl scripts did not use safe_pipe_capture() instead of + backticks, leaving them susceptible to end-user input. They have + been corrected. + Also contains various documentation updates and code clean-ups. + +Credits go to joernchen <joernchen@phenoelit.de> for finding the +unsafe constructs in "git cvsserver", and to Jeff King at GitHub for +finding and fixing instances of the same issue in other scripts. diff --git a/Documentation/RelNotes/2.14.3.txt b/Documentation/RelNotes/2.14.3.txt new file mode 100644 index 0000000000..61f569aa9a --- /dev/null +++ b/Documentation/RelNotes/2.14.3.txt @@ -0,0 +1,75 @@ +Git v2.14.3 Release Notes +========================= + +Fixes since v2.14.2 +------------------- + + * A helper function to read a single whole line into strbuf + mistakenly triggered OOM error at EOF under certain conditions, + which has been fixed. + + * In addition to "cc: <a@dd.re.ss> # cruft", "cc: a@dd.re.ss # cruft" + was taught to "git send-email" as a valid way to tell it that it + needs to also send a carbon copy to <a@dd.re.ss> in the trailer + section. + + * Fix regression to "gitk --bisect" by a recent update. + + * Unlike "git commit-tree < file", "git commit-tree -F file" did not + pass the contents of the file verbatim and instead completed an + incomplete line at the end, if exists. The latter has been updated + to match the behaviour of the former. + + * "git archive", especially when used with pathspec, stored an empty + directory in its output, even though Git itself never does so. + This has been fixed. + + * API error-proofing which happens to also squelch warnings from GCC. + + * "git gc" tries to avoid running two instances at the same time by + reading and writing pid/host from and to a lock file; it used to + use an incorrect fscanf() format when reading, which has been + corrected. + + * The test linter has been taught that we do not like "echo -e". + + * Code cmp.std.c nitpick. + + * "git describe --match" learned to take multiple patterns in v2.13 + series, but the feature ignored the patterns after the first one + and did not work at all. This has been fixed. + + * "git cat-file --textconv" started segfaulting recently, which + has been corrected. + + * The built-in pattern to detect the "function header" for HTML did + not match <H1>..<H6> elements without any attributes, which has + been fixed. + + * "git mailinfo" was loose in decoding quoted printable and produced + garbage when the two letters after the equal sign are not + hexadecimal. This has been fixed. + + * The documentation for '-X<option>' for merges was misleadingly + written to suggest that "-s theirs" exists, which is not the case. + + * Spell the name of our system as "Git" in the output from + request-pull script. + + * Fixes for a handful memory access issues identified by valgrind. + + * Backports a moral equivalent of 2015 fix to the poll emulation from + the upstream gnulib to fix occasional breakages on HPE NonStop. + + * In the "--format=..." option of the "git for-each-ref" command (and + its friends, i.e. the listing mode of "git branch/tag"), "%(atom:)" + (e.g. "%(refname:)", "%(body:)" used to error out. Instead, treat + them as if the colon and an empty string that follows it were not + there. + + * Users with "color.ui = always" in their configuration were broken + by a recent change that made plumbing commands to pay attention to + them as the patch created internally by "git add -p" were colored + (heh) and made unusable. This has been fixed. + +Also contains various documentation updates and code clean-ups. diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt index f4169fb1ec..b700beaff5 100644 --- a/Documentation/git-add.txt +++ b/Documentation/git-add.txt @@ -61,6 +61,9 @@ OPTIONS the working tree. Note that older versions of Git used to ignore removed files; use `--no-all` option if you want to add modified or new files but ignore removed ones. ++ +For more details about the <pathspec> syntax, see the 'pathspec' entry +in linkgit:gitglossary[7]. -n:: --dry-run:: diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index d0b3358771..7463dc44a7 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -92,10 +92,10 @@ OPTIONS all changes made to the branch ref, enabling use of date based sha1 expressions such as "<branchname>@\{yesterday}". Note that in non-bare repositories, reflogs are usually - enabled by default by the `core.logallrefupdates` config option. + enabled by default by the `core.logAllRefUpdates` config option. The negated form `--no-create-reflog` only overrides an earlier `--create-reflog`, but currently does not negate the setting of - `core.logallrefupdates`. + `core.logAllRefUpdates`. -f:: --force:: diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt index 204541c690..fb09cd69d6 100644 --- a/Documentation/git-cat-file.txt +++ b/Documentation/git-cat-file.txt @@ -192,7 +192,7 @@ newline. The available atoms are: The 40-hex object name of the object. `objecttype`:: - The type of of the object (the same as `cat-file -t` reports). + The type of the object (the same as `cat-file -t` reports). `objectsize`:: The size, in bytes, of the object (the same as `cat-file -s` diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index d6399c0af8..e108b0f74b 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -13,7 +13,8 @@ SYNOPSIS 'git checkout' [-q] [-f] [-m] [--detach] <commit> 'git checkout' [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>] 'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>... -'git checkout' [-p|--patch] [<tree-ish>] [--] [<paths>...] +'git checkout' [<tree-ish>] [--] <pathspec>... +'git checkout' (-p|--patch) [<tree-ish>] [--] [<paths>...] DESCRIPTION ----------- @@ -38,7 +39,7 @@ $ git checkout -b <branch> --track <remote>/<branch> ------------ + You could omit <branch>, in which case the command degenerates to -"check out the current branch", which is a glorified no-op with a +"check out the current branch", which is a glorified no-op with rather expensive side-effects to show only the tracking information, if exists, for the current branch. @@ -78,20 +79,13 @@ be used to detach HEAD at the tip of the branch (`git checkout + Omitting <branch> detaches HEAD at the tip of the current branch. -'git checkout' [-p|--patch] [<tree-ish>] [--] <pathspec>...:: +'git checkout' [<tree-ish>] [--] <pathspec>...:: - When <paths> or `--patch` are given, 'git checkout' 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` 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. -+ -'git checkout' with <paths> or `--patch` is used to restore modified or -deleted paths to their original contents from the index or replace paths -with the contents from a named <tree-ish> (most often a commit-ish). + Overwrite paths in the working tree by replacing with the + contents in the index or in the <tree-ish> (most often a + commit). When a <tree-ish> is given, the paths that + match the <pathspec> are updated both in the index and in + the working tree. + The index may contain unmerged entries because of a previous failed merge. By default, if you try to check out such an entry from the index, the @@ -101,6 +95,14 @@ specific side of the merge can be checked out of the index by using `--ours` or `--theirs`. With `-m`, changes made to the working tree file can be discarded to re-create the original conflicted merge result. +'git checkout' (-p|--patch) [<tree-ish>] [--] [<pathspec>...]:: + This is similar to the "check out paths to the working tree + from either the index or from a tree-ish" mode described + above, but lets you use the interactive interface to show + the "diff" output and choose which hunks to use in the + result. See below for the description of `--patch` option. + + OPTIONS ------- -q:: diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index bb370c9c7b..cbd0a6212a 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -10,8 +10,9 @@ SYNOPSIS [verse] 'git for-each-ref' [--count=<count>] [--shell|--perl|--python|--tcl] [(--sort=<key>)...] [--format=<format>] [<pattern>...] - [--points-at <object>] [(--merged | --no-merged) [<object>]] - [--contains [<object>]] [--no-contains [<object>]] + [--points-at=<object>] + (--merged[=<object>] | --no-merged[=<object>]) + [--contains[=<object>]] [--no-contains[=<object>]] DESCRIPTION ----------- @@ -25,19 +26,25 @@ host language allowing their direct evaluation in that language. OPTIONS ------- -<count>:: +<pattern>...:: + If one or more patterns are given, only refs are shown that + match against at least one pattern, either using fnmatch(3) or + literally, in the latter case matching completely or from the + beginning up to a slash. + +--count=<count>:: By default the command shows all refs that match `<pattern>`. This option makes it stop after showing that many refs. -<key>:: +--sort=<key>:: A field name to sort on. Prefix `-` to sort in descending order of the value. When unspecified, `refname` is used. You may use the --sort=<key> option multiple times, in which case the last key becomes the primary key. -<format>:: +--format=<format>:: A string that interpolates `%(fieldname)` from a ref being shown and the object it points at. If `fieldname` is prefixed with an asterisk (`*`) and the ref points @@ -50,11 +57,10 @@ OPTIONS `xx`; for example `%00` interpolates to `\0` (NUL), `%09` to `\t` (TAB) and `%0a` to `\n` (LF). -<pattern>...:: - If one or more patterns are given, only refs are shown that - match against at least one pattern, either using fnmatch(3) or - literally, in the latter case matching completely or from the - beginning up to a slash. +--color[=<when>]: + Respect any colors specified in the `--format` option. The + `<when>` field must be one of `always`, `never`, or `auto` (if + `<when>` is absent, behave as if `always` was given). --shell:: --perl:: @@ -65,24 +71,24 @@ OPTIONS the specified host language. This is meant to produce a scriptlet that can directly be `eval`ed. ---points-at <object>:: +--points-at=<object>:: Only list refs which points at the given object. ---merged [<object>]:: +--merged[=<object>]:: Only list refs whose tips are reachable from the specified commit (HEAD if not specified), incompatible with `--no-merged`. ---no-merged [<object>]:: +--no-merged[=<object>]:: Only list refs whose tips are not reachable from the specified commit (HEAD if not specified), incompatible with `--merged`. ---contains [<object>]:: +--contains[=<object>]:: Only list refs which contain the specified commit (HEAD if not specified). ---no-contains [<object>]:: +--no-contains[=<object>]:: Only list refs which don't contain the specified commit (HEAD if not specified). diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 5033483db4..5edb1da46f 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -296,6 +296,9 @@ providing this option will cause it to die. <pathspec>...:: If given, limit the search to paths matching at least one pattern. Both leading paths match and glob(7) patterns are supported. ++ +For more details about the <pathspec> syntax, see the 'pathspec' entry +in linkgit:gitglossary[7]. Examples -------- @@ -312,6 +315,9 @@ Examples Looks for a line that has `NODE` or `Unexpected` in files that have lines that match both. +`git grep solution -- :^Documentation`:: + Looks for `solution`, excluding files in `Documentation`. + GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt index be7db3048d..43677297f3 100644 --- a/Documentation/git-notes.txt +++ b/Documentation/git-notes.txt @@ -171,7 +171,7 @@ OPTIONS object that does not have notes attached to it. --stdin:: - Also read the object names to remove notes from from the standard + Also read the object names to remove notes from the standard input (there is no reason you cannot combine this with object names from the command line). diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt index 02576d8c0a..72bd809fb8 100644 --- a/Documentation/git-read-tree.txt +++ b/Documentation/git-read-tree.txt @@ -179,6 +179,7 @@ Here are the "carry forward" rules, where "I" denotes the index, "clean" means that index and work tree coincide, and "exists"/"nothing" refer to the presence of a path in the specified commit: +.... I H M Result ------------------------------------------------------- 0 nothing nothing nothing (does not happen) @@ -217,6 +218,7 @@ refer to the presence of a path in the specified commit: 19 no no yes exists exists keep index 20 yes yes no exists exists use M 21 no yes no exists exists fail +.... In all "keep index" cases, the index entry stays as in the original index file. If the entry is not up to date, diff --git a/Documentation/git-shell.txt b/Documentation/git-shell.txt index 2e30a3e42d..54cf2560be 100644 --- a/Documentation/git-shell.txt +++ b/Documentation/git-shell.txt @@ -79,6 +79,22 @@ EOF $ chmod +x $HOME/git-shell-commands/no-interactive-login ---------------- +To enable git-cvsserver access (which should generally have the +`no-interactive-login` example above as a prerequisite, as creating +the git-shell-commands directory allows interactive logins): + +---------------- +$ cat >$HOME/git-shell-commands/cvs <<\EOF +if ! test $# = 1 && test "$1" = "server" +then + echo >&2 "git-cvsserver only handles \"server\"" + exit 1 +fi +exec git cvsserver server +EOF +$ chmod +x $HOME/git-shell-commands/cvs +---------------- + SEE ALSO -------- ssh(1), diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index d47f198f15..9f3a78a36c 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -111,6 +111,8 @@ configuration variable documented in linkgit:git-config[1]. without options are equivalent to 'always' and 'never' respectively. +<pathspec>...:: + See the 'pathspec' entry in linkgit:gitglossary[7]. OUTPUT ------ diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 543fb425ee..956fc019f9 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -115,6 +115,11 @@ options for details. variable if it exists, or lexicographic order otherwise. See linkgit:git-config[1]. +--color[=<when>]: + Respect any colors specified in the `--format` option. The + `<when>` field must be one of `always`, `never`, or `auto` (if + `<when>` is absent, behave as if `always` was given). + -i:: --ignore-case:: Sorting and filtering tags are case insensitive. @@ -174,7 +179,7 @@ This option is only applicable when listing tags without annotation lines. `core.logAllRefUpdates` in linkgit:git-config[1]. The negated form `--no-create-reflog` only overrides an earlier `--create-reflog`, but currently does not negate the setting of - `core.logallrefupdates`. + `core.logAllRefUpdates`. <tagname>:: The name of the tag to create, delete, or describe. diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt index 1579abf3c3..a14e6aebd9 100644 --- a/Documentation/git-update-index.txt +++ b/Documentation/git-update-index.txt @@ -153,7 +153,7 @@ you will need to handle the situation manually. + Version 4 performs a simple pathname compression that reduces index size by 30%-50% on large repositories, which results in faster load -time. Version 4 is relatively young (first released in in 1.8.0 in +time. Version 4 is relatively young (first released in 1.8.0 in October 2012). Other Git implementations such as JGit and libgit2 may not support it yet. diff --git a/Documentation/git.txt b/Documentation/git.txt index 6e3a6767e5..98b9b46b9e 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -75,7 +75,7 @@ example the following invocations are equivalent: Note that omitting the `=` in `git -c foo.bar ...` is allowed and sets `foo.bar` to the boolean true value (just like `[foo]bar` would in a config file). Including the equals but with an empty value (like `git -c -foo.bar= ...`) sets `foo.bar` to the empty string which ` git config +foo.bar= ...`) sets `foo.bar` to the empty string which `git config --bool` will convert to `false`. --exec-path[=<path>]:: diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index c4f2be2542..4c68bc19d5 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -151,7 +151,10 @@ unspecified. This attribute sets a specific line-ending style to be used in the working directory. It enables end-of-line conversion without any -content checks, effectively setting the `text` attribute. +content checks, effectively setting the `text` attribute. Note that +setting this attribute on paths which are in the index with CRLF line +endings may make the paths to be considered dirty. Adding the path to +the index again will normalize the line endings in the index. Set to string value "crlf":: diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt index b71b943b12..6b8888d123 100644 --- a/Documentation/glossary-content.txt +++ b/Documentation/glossary-content.txt @@ -407,7 +407,7 @@ these forms: exclude;; After a path matches any non-exclude pathspec, it will be run - through all exclude pathspec (magic signature: `!` or its + through all exclude pathspecs (magic signature: `!` or its synonym `^`). If it matches, the path is ignored. When there is no non-exclude pathspec, the exclusion is applied to the result set as if invoked without any pathspec. diff --git a/Documentation/merge-strategies.txt b/Documentation/merge-strategies.txt index 2eb92b9327..a09d597463 100644 --- a/Documentation/merge-strategies.txt +++ b/Documentation/merge-strategies.txt @@ -39,7 +39,8 @@ even look at what the other tree contains at all. It discards everything the other tree did, declaring 'our' history contains all that happened in it. theirs;; - This is the opposite of 'ours'. + This is the opposite of 'ours'; note that, unlike 'ours', there is + no 'theirs' merge stragegy to confuse this merge option with. patience;; With this option, 'merge-recursive' spends a little extra time @@ -1 +1 @@ -Documentation/RelNotes/2.14.2.txt
\ No newline at end of file +Documentation/RelNotes/2.14.3.txt
\ No newline at end of file @@ -121,11 +121,6 @@ static int check_attr_export_subst(const struct attr_check *check) return check && ATTR_TRUE(check->items[1].value); } -static int should_queue_directories(const struct archiver_args *args) -{ - return args->pathspec.has_wildcard; -} - static int write_archive_entry(const unsigned char *sha1, const char *base, int baselen, const char *filename, unsigned mode, int stage, void *context) @@ -147,7 +142,7 @@ static int write_archive_entry(const unsigned char *sha1, const char *base, strbuf_addch(&path, '/'); path_without_prefix = path.buf + args->baselen; - if (!S_ISDIR(mode) || !should_queue_directories(args)) { + if (!S_ISDIR(mode)) { const struct attr_check *check; check = get_archive_attrs(path_without_prefix); if (check_attr_export_ignore(check)) @@ -169,14 +164,6 @@ static int write_archive_entry(const unsigned char *sha1, const char *base, return write_entry(args, sha1, path.buf, path.len, mode); } -static int write_archive_entry_buf(const unsigned char *sha1, struct strbuf *base, - const char *filename, unsigned mode, int stage, - void *context) -{ - return write_archive_entry(sha1, base->buf, base->len, - filename, mode, stage, context); -} - static void queue_directory(const unsigned char *sha1, struct strbuf *base, const char *filename, unsigned mode, int stage, struct archiver_context *c) @@ -290,9 +277,7 @@ int write_archive_entries(struct archiver_args *args, } err = read_tree_recursive(args->tree, "", 0, 0, &args->pathspec, - should_queue_directories(args) ? - queue_or_write_archive_entry : - write_archive_entry_buf, + queue_or_write_archive_entry, &context); if (err == READ_TREE_RECURSIVE) err = 0; @@ -357,8 +357,9 @@ int replace_each_worktree_head_symref(const char *oldref, const char *newref, if (worktrees[i]->is_detached) continue; - if (worktrees[i]->head_ref && - strcmp(oldref, worktrees[i]->head_ref)) + if (!worktrees[i]->head_ref) + continue; + if (strcmp(oldref, worktrees[i]->head_ref)) continue; refs = get_worktree_ref_store(worktrees[i]); diff --git a/builtin/branch.c b/builtin/branch.c index 16d391b407..8f779b02b5 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -92,7 +92,7 @@ static int git_branch_config(const char *var, const char *value, void *cb) return config_error_nonbool(var); return color_parse(value, branch_colors[slot]); } - return git_default_config(var, value, cb); + return git_color_default_config(var, value, cb); } static const char *branch_get_color(enum color_branch ix) @@ -216,7 +216,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, if (!head_rev) die(_("Couldn't look up commit object for HEAD")); } - for (i = 0; i < argc; i++, strbuf_release(&bname)) { + for (i = 0; i < argc; i++, strbuf_reset(&bname)) { char *target = NULL; int flags = 0; @@ -281,8 +281,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, } free(name); + strbuf_release(&bname); - return(ret); + return ret; } static int calc_maxwidth(struct ref_array *refs, int remote_bonus) diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 96b786e489..188ddc3e50 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -96,7 +96,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, return !has_object_file(&oid); case 'w': - if (!path[0]) + if (!path) die("git cat-file --filters %s: <object> must be " "<sha1:path>", obj_name); @@ -106,7 +106,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, break; case 'c': - if (!path[0]) + if (!path) die("git cat-file --textconv %s: <object> must be <sha1:path>", obj_name); diff --git a/builtin/clean.c b/builtin/clean.c index c1bafda5b6..057fc97fe4 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -125,7 +125,8 @@ static int git_clean_config(const char *var, const char *value, void *cb) return 0; } - return git_default_config(var, value, cb); + /* inspect the color.ui config variable and others */ + return git_color_default_config(var, value, cb); } static const char *clean_get_color(enum color_clean ix) diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c index a4a923d7c0..c1de41c67f 100644 --- a/builtin/commit-tree.c +++ b/builtin/commit-tree.c @@ -102,7 +102,6 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) if (fd && close(fd)) die_errno("git commit-tree: failed to close '%s'", argv[i]); - strbuf_complete_line(&buffer); continue; } diff --git a/builtin/describe.c b/builtin/describe.c index 89ea1cdd60..94ff2fba0b 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -155,18 +155,21 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi * pattern. */ if (patterns.nr) { + int found = 0; struct string_list_item *item; if (!is_tag) return 0; for_each_string_list_item(item, &patterns) { - if (!wildmatch(item->string, path + 10, 0)) + if (!wildmatch(item->string, path + 10, 0)) { + found = 1; break; + } + } - /* If we get here, no pattern matched. */ + if (!found) return 0; - } } /* Is it annotated? */ diff --git a/builtin/fast-export.c b/builtin/fast-export.c index d412c0a8f3..da42ee5e60 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -344,6 +344,7 @@ static void show_filemodify(struct diff_queue_struct *q, struct diff_options *options, void *data) { int i; + struct string_list *changed = data; /* * Handle files below a directory first, in case they are all deleted @@ -359,20 +360,31 @@ static void show_filemodify(struct diff_queue_struct *q, case DIFF_STATUS_DELETED: printf("D "); print_path(spec->path); + string_list_insert(changed, spec->path); putchar('\n'); break; case DIFF_STATUS_COPIED: case DIFF_STATUS_RENAMED: - printf("%c ", q->queue[i]->status); - print_path(ospec->path); - putchar(' '); - print_path(spec->path); - putchar('\n'); - - if (!oidcmp(&ospec->oid, &spec->oid) && - ospec->mode == spec->mode) - break; + /* + * If a change in the file corresponding to ospec->path + * has been observed, we cannot trust its contents + * because the diff is calculated based on the prior + * contents, not the current contents. So, declare a + * copy or rename only if there was no change observed. + */ + if (!string_list_has_string(changed, ospec->path)) { + printf("%c ", q->queue[i]->status); + print_path(ospec->path); + putchar(' '); + print_path(spec->path); + string_list_insert(changed, spec->path); + putchar('\n'); + + if (!oidcmp(&ospec->oid, &spec->oid) && + ospec->mode == spec->mode) + break; + } /* fallthrough */ case DIFF_STATUS_TYPE_CHANGED: @@ -393,6 +405,7 @@ static void show_filemodify(struct diff_queue_struct *q, get_object_mark(object)); } print_path(spec->path); + string_list_insert(changed, spec->path); putchar('\n'); break; @@ -528,7 +541,8 @@ static void anonymize_ident_line(const char **beg, const char **end) *end = out->buf + out->len; } -static void handle_commit(struct commit *commit, struct rev_info *rev) +static void handle_commit(struct commit *commit, struct rev_info *rev, + struct string_list *paths_of_changed_objects) { int saved_output_format = rev->diffopt.output_format; const char *commit_buffer; @@ -615,6 +629,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev) if (full_tree) printf("deleteall\n"); log_tree_diff_flush(rev); + string_list_clear(paths_of_changed_objects, 0); rev->diffopt.output_format = saved_output_format; printf("\n"); @@ -630,14 +645,15 @@ static void *anonymize_tag(const void *old, size_t *len) return strbuf_detach(&out, len); } -static void handle_tail(struct object_array *commits, struct rev_info *revs) +static void handle_tail(struct object_array *commits, struct rev_info *revs, + struct string_list *paths_of_changed_objects) { struct commit *commit; while (commits->nr) { commit = (struct commit *)commits->objects[commits->nr - 1].item; if (has_unshown_parent(commit)) return; - handle_commit(commit, revs); + handle_commit(commit, revs, paths_of_changed_objects); commits->nr--; } } @@ -977,6 +993,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) char *export_filename = NULL, *import_filename = NULL; uint32_t lastimportid; struct string_list refspecs_list = STRING_LIST_INIT_NODUP; + struct string_list paths_of_changed_objects = STRING_LIST_INIT_DUP; struct option options[] = { OPT_INTEGER(0, "progress", &progress, N_("show progress after <n> objects")), @@ -1049,14 +1066,15 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) if (prepare_revision_walk(&revs)) die("revision walk setup failed"); revs.diffopt.format_callback = show_filemodify; + revs.diffopt.format_callback_data = &paths_of_changed_objects; DIFF_OPT_SET(&revs.diffopt, RECURSIVE); while ((commit = get_revision(&revs))) { if (has_unshown_parent(commit)) { add_object_array(&commit->object, NULL, &commits); } else { - handle_commit(commit, &revs); - handle_tail(&commits, &revs); + handle_commit(commit, &revs, &paths_of_changed_objects); + handle_tail(&commits, &revs, &paths_of_changed_objects); } } diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 5d7c921a77..e931be9ce4 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -36,6 +36,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix) OPT_GROUP(""), OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")), OPT_STRING( 0 , "format", &format.format, N_("format"), N_("format to use for the output")), + OPT__COLOR(&format.use_color, N_("respect format colors")), OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"), N_("field name to sort on"), &parse_opt_ref_sorting), OPT_CALLBACK(0, "points-at", &filter.points_at, diff --git a/builtin/gc.c b/builtin/gc.c index e6b84475ae..53c19be8b2 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -257,7 +257,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid) int should_exit; if (!scan_fmt) - scan_fmt = xstrfmt("%s %%%dc", "%"SCNuMAX, HOST_NAME_MAX); + scan_fmt = xstrfmt("%s %%%ds", "%"SCNuMAX, HOST_NAME_MAX); fp = fopen(pidfile_path, "r"); memset(locking_host, 0, sizeof(locking_host)); should_exit = diff --git a/builtin/grep.c b/builtin/grep.c index 42ff87065a..7e79eb1a75 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -284,7 +284,7 @@ static int wait_all(void) static int grep_cmd_config(const char *var, const char *value, void *cb) { int st = grep_config(var, value, cb); - if (git_default_config(var, value, cb) < 0) + if (git_color_default_config(var, value, cb) < 0) st = -1; if (!strcmp(var, "grep.threads")) { diff --git a/builtin/name-rev.c b/builtin/name-rev.c index c41ea7c2a6..598da6c8bc 100644 --- a/builtin/name-rev.c +++ b/builtin/name-rev.c @@ -253,7 +253,7 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo struct commit *commit = (struct commit *)o; int from_tag = starts_with(path, "refs/tags/"); - if (taggerdate == ULONG_MAX) + if (taggerdate == TIME_MAX) taggerdate = ((struct commit *)o)->date; path = name_ref_abbrev(path, can_abbreviate_output); name_rev(commit, xstrdup(path), taggerdate, 0, 0, diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index c753e9237a..3af63ad54c 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -2170,7 +2170,10 @@ static void *threaded_find_deltas(void *arg) { struct thread_params *me = arg; + progress_lock(); while (me->remaining) { + progress_unlock(); + find_deltas(me->list, &me->remaining, me->window, me->depth, me->processed); @@ -2192,7 +2195,10 @@ static void *threaded_find_deltas(void *arg) pthread_cond_wait(&me->cond, &me->mutex); me->data_ready = 0; pthread_mutex_unlock(&me->mutex); + + progress_lock(); } + progress_unlock(); /* leave ->working 1 so that this doesn't get more work assigned */ return NULL; } @@ -2556,8 +2562,8 @@ struct in_pack_object { }; struct in_pack { - int alloc; - int nr; + unsigned int alloc; + unsigned int nr; struct in_pack_object *array; }; diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index c78b7b33d6..7f965fe74e 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -757,8 +757,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) continue; } if (!strcmp(arg, "--bisect")) { - for_each_ref_in("refs/bisect/bad", show_reference, NULL); - for_each_ref_in("refs/bisect/good", anti_reference, NULL); + for_each_fullref_in("refs/bisect/bad", show_reference, NULL, 0); + for_each_fullref_in("refs/bisect/good", anti_reference, NULL, 0); continue; } if (opt_with_value(arg, "--branches", &arg)) { diff --git a/builtin/show-branch.c b/builtin/show-branch.c index 28f245c8cc..7073a3eb97 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -554,7 +554,7 @@ static int git_show_branch_config(const char *var, const char *value, void *cb) return 0; } - return git_default_config(var, value, cb); + return git_color_default_config(var, value, cb); } static int omit_in_dense(struct commit *commit, struct commit **rev, int n) diff --git a/builtin/tag.c b/builtin/tag.c index 7a70d5a9bb..00382a56f5 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -158,7 +158,7 @@ static int git_tag_config(const char *var, const char *value, void *cb) if (starts_with(var, "column.")) return git_column_config(var, value, "tag", &colopts); - return git_default_config(var, value, cb); + return git_color_default_config(var, value, cb); } static void write_tag_body(int fd, const struct object_id *oid) @@ -411,6 +411,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) }, OPT_STRING( 0 , "format", &format.format, N_("format"), N_("format to use for the output")), + OPT__COLOR(&format.use_color, N_("respect format colors")), OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")), OPT_END() }; @@ -1264,8 +1264,8 @@ static inline unsigned int hexval(unsigned char c) */ static inline int hex2chr(const char *s) { - int val = hexval(s[0]); - return (val < 0) ? val : (val << 4) | hexval(s[1]); + unsigned int val = hexval(s[0]); + return (val & ~0xf) ? val : (val << 4) | hexval(s[1]); } /* Convert to/from hex/sha1 representation */ diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh new file mode 100755 index 0000000000..a29246af35 --- /dev/null +++ b/ci/install-dependencies.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# +# Install dependencies required to build and test Git on Linux and macOS +# + +. ${0%/*}/lib-travisci.sh + +P4WHENCE=http://filehost.perforce.com/perforce/r$LINUX_P4_VERSION +LFSWHENCE=https://github.com/github/git-lfs/releases/download/v$LINUX_GIT_LFS_VERSION + +case "${TRAVIS_OS_NAME:-linux}" in +linux) + export GIT_TEST_HTTPD=YesPlease + + mkdir --parents custom/p4 + pushd custom/p4 + wget --quiet "$P4WHENCE/bin.linux26x86_64/p4d" + wget --quiet "$P4WHENCE/bin.linux26x86_64/p4" + chmod u+x p4d + chmod u+x p4 + export PATH="$(pwd):$PATH" + popd + mkdir --parents custom/git-lfs + pushd custom/git-lfs + wget --quiet "$LFSWHENCE/git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz" + tar --extract --gunzip --file "git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz" + cp git-lfs-$LINUX_GIT_LFS_VERSION/git-lfs . + export PATH="$(pwd):$PATH" + popd + ;; +osx) + brew update --quiet + # Uncomment this if you want to run perf tests: + # brew install gnu-time + brew install git-lfs gettext + brew link --force gettext + brew install caskroom/cask/perforce + ;; +esac + +echo "$(tput setaf 6)Perforce Server Version$(tput sgr0)" +p4d -V | grep Rev. +echo "$(tput setaf 6)Perforce Client Version$(tput sgr0)" +p4 -V | grep Rev. +echo "$(tput setaf 6)Git-LFS Version$(tput sgr0)" +git-lfs version diff --git a/ci/lib-travisci.sh b/ci/lib-travisci.sh new file mode 100755 index 0000000000..b3ed0a0dda --- /dev/null +++ b/ci/lib-travisci.sh @@ -0,0 +1,28 @@ +# Library of functions shared by all CI scripts + +skip_branch_tip_with_tag () { + # Sometimes, a branch is pushed at the same time the tag that points + # at the same commit as the tip of the branch is pushed, and building + # both at the same time is a waste. + # + # Travis gives a tagname e.g. v2.14.0 in $TRAVIS_BRANCH when + # the build is triggered by a push to a tag. Let's see if + # $TRAVIS_BRANCH is exactly at a tag, and if so, if it is + # different from $TRAVIS_BRANCH. That way, we can tell if + # we are building the tip of a branch that is tagged and + # we can skip the build because we won't be skipping a build + # of a tag. + + if TAG=$(git describe --exact-match "$TRAVIS_BRANCH" 2>/dev/null) && + test "$TAG" != "$TRAVIS_BRANCH" + then + echo "Tip of $TRAVIS_BRANCH is exactly at $TAG" + exit 0 + fi +} + +# Set 'exit on error' for all CI scripts to let the caller know that +# something went wrong +set -e + +skip_branch_tip_with_tag diff --git a/ci/print-test-failures.sh b/ci/print-test-failures.sh new file mode 100755 index 0000000000..8c8973cbf3 --- /dev/null +++ b/ci/print-test-failures.sh @@ -0,0 +1,18 @@ +#!/bin/sh +# +# Print output of failing tests +# + +. ${0%/*}/lib-travisci.sh + +for TEST_EXIT in t/test-results/*.exit +do + if [ "$(cat "$TEST_EXIT")" != "0" ] + then + TEST_OUT="${TEST_EXIT%exit}out" + echo "------------------------------------------------------------------------" + echo "$(tput setaf 1)${TEST_OUT}...$(tput sgr0)" + echo "------------------------------------------------------------------------" + cat "${TEST_OUT}" + fi +done diff --git a/ci/run-build.sh b/ci/run-build.sh new file mode 100755 index 0000000000..4f940d1032 --- /dev/null +++ b/ci/run-build.sh @@ -0,0 +1,8 @@ +#!/bin/sh +# +# Build Git +# + +. ${0%/*}/lib-travisci.sh + +make --jobs=2 diff --git a/ci/run-linux32-docker.sh b/ci/run-linux32-docker.sh new file mode 100755 index 0000000000..0edf63acfa --- /dev/null +++ b/ci/run-linux32-docker.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# +# Download and run Docker image to build and test 32-bit Git +# + +. ${0%/*}/lib-travisci.sh + +docker pull daald/ubuntu32:xenial + +# Use the following command to debug the docker build locally: +# $ docker run -itv "${PWD}:/usr/src/git" --entrypoint /bin/bash daald/ubuntu32:xenial +# root@container:/# /usr/src/git/ci/run-linux32-build.sh + +docker run \ + --interactive \ + --env DEVELOPER \ + --env DEFAULT_TEST_TARGET \ + --env GIT_PROVE_OPTS \ + --env GIT_TEST_OPTS \ + --env GIT_TEST_CLONE_2GB \ + --volume "${PWD}:/usr/src/git" \ + daald/ubuntu32:xenial \ + /usr/src/git/ci/run-linux32-build.sh $(id -u $USER) diff --git a/ci/run-static-analysis.sh b/ci/run-static-analysis.sh new file mode 100755 index 0000000000..68dd0f080e --- /dev/null +++ b/ci/run-static-analysis.sh @@ -0,0 +1,8 @@ +#!/bin/sh +# +# Perform various static code analysis checks +# + +. ${0%/*}/lib-travisci.sh + +make coccicheck diff --git a/ci/run-tests.sh b/ci/run-tests.sh new file mode 100755 index 0000000000..f0c743de94 --- /dev/null +++ b/ci/run-tests.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# +# Test Git +# + +. ${0%/*}/lib-travisci.sh + +mkdir -p $HOME/travis-cache +ln -s $HOME/travis-cache/.prove t/.prove +make --quiet test diff --git a/ci/run-windows-build.sh b/ci/run-windows-build.sh index 2d98f6b2f9..8757b3a97c 100755 --- a/ci/run-windows-build.sh +++ b/ci/run-windows-build.sh @@ -6,6 +6,8 @@ # supported) and a commit hash. # +. ${0%/*}/lib-travisci.sh + test $# -ne 2 && echo "Unexpected number of parameters" && exit 1 test -z "$GFW_CI_TOKEN" && echo "GFW_CI_TOKEN not defined" && exit diff --git a/ci/test-documentation.sh b/ci/test-documentation.sh index 6214e6acb4..7a0a848e83 100755 --- a/ci/test-documentation.sh +++ b/ci/test-documentation.sh @@ -3,7 +3,9 @@ # Perform sanity checks on documentation and build it. # -set -e +. ${0%/*}/lib-travisci.sh + +gem install asciidoctor make check-builtins make check-docs @@ -338,6 +338,13 @@ static int check_auto_color(void) int want_color(int var) { + /* + * NEEDSWORK: This function is sometimes used from multiple threads, and + * we end up using want_auto racily. That "should not matter" since + * we always write the same value, but it's still wrong. This function + * is listed in .tsan-suppressions for the time being. + */ + static int want_auto = -1; if (var < 0) @@ -361,6 +368,14 @@ int git_color_config(const char *var, const char *value, void *cb) return 0; } +int git_color_default_config(const char *var, const char *value, void *cb) +{ + if (git_color_config(var, value, cb) < 0) + return -1; + + return git_default_config(var, value, cb); +} + void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb) { if (*color) diff --git a/commit-slab.h b/commit-slab.h index 333d81e370..dcaab8ca04 100644 --- a/commit-slab.h +++ b/commit-slab.h @@ -78,7 +78,7 @@ static MAYBE_UNUSED void init_ ##slabname(struct slabname *s) \ \ static MAYBE_UNUSED void clear_ ##slabname(struct slabname *s) \ { \ - int i; \ + unsigned int i; \ for (i = 0; i < s->slab_count; i++) \ free(s->slab[i]); \ s->slab_count = 0; \ @@ -89,13 +89,13 @@ static MAYBE_UNUSED elemtype *slabname## _at_peek(struct slabname *s, \ const struct commit *c, \ int add_if_missing) \ { \ - int nth_slab, nth_slot; \ + unsigned int nth_slab, nth_slot; \ \ nth_slab = c->index / s->slab_size; \ nth_slot = c->index % s->slab_size; \ \ if (s->slab_count <= nth_slab) { \ - int i; \ + unsigned int i; \ if (!add_if_missing) \ return NULL; \ REALLOC_ARRAY(s->slab, nth_slab + 1); \ diff --git a/compat/poll/poll.c b/compat/poll/poll.c index b10adc780f..ae03b74a6f 100644 --- a/compat/poll/poll.c +++ b/compat/poll/poll.c @@ -438,6 +438,10 @@ poll (struct pollfd *pfd, nfds_t nfd, int timeout) pfd[i].revents = happened; rc++; } + else + { + pfd[i].revents = 0; + } } return rc; @@ -16,7 +16,6 @@ #include "string-list.h" #include "utf8.h" #include "dir.h" -#include "color.h" struct config_source { struct config_source *prev; @@ -1351,9 +1350,6 @@ int git_default_config(const char *var, const char *value, void *dummy) if (starts_with(var, "advice.")) return git_default_advice_config(var, value); - if (git_color_config(var, value, dummy) < 0) - return -1; - if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) { pager_use_color = git_config_bool(var,value); return 0; @@ -2159,7 +2155,7 @@ static struct { size_t *offset; unsigned int offset_alloc; enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state; - int seen; + unsigned int seen; } store; static int matches(const char *key, const char *value) @@ -2406,7 +2402,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, { int fd = -1, in_fd = -1; int ret; - struct lock_file *lock = NULL; + static struct lock_file lock; char *filename_buf = NULL; char *contents = NULL; size_t contents_sz; @@ -2425,8 +2421,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, * The lock serves a purpose in addition to locking: the new * contents of .git/config will be written into it. */ - lock = xcalloc(1, sizeof(struct lock_file)); - fd = hold_lock_file_for_update(lock, config_filename, 0); + fd = hold_lock_file_for_update(&lock, config_filename, 0); if (fd < 0) { error_errno("could not lock config file %s", config_filename); free(store.key); @@ -2539,8 +2534,8 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, close(in_fd); in_fd = -1; - if (chmod(get_lock_file_path(lock), st.st_mode & 07777) < 0) { - error_errno("chmod on %s failed", get_lock_file_path(lock)); + if (chmod(get_lock_file_path(&lock), st.st_mode & 07777) < 0) { + error_errno("chmod on %s failed", get_lock_file_path(&lock)); ret = CONFIG_NO_WRITE; goto out_free; } @@ -2593,28 +2588,19 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, contents = NULL; } - if (commit_lock_file(lock) < 0) { + if (commit_lock_file(&lock) < 0) { error_errno("could not write config file %s", config_filename); ret = CONFIG_NO_WRITE; - lock = NULL; goto out_free; } - /* - * lock is committed, so don't try to roll it back below. - * NOTE: Since lockfile.c keeps a linked list of all created - * lock_file structures, it isn't safe to free(lock). It's - * better to just leave it hanging around. - */ - lock = NULL; ret = 0; /* Invalidate the config cache */ git_config_clear(); out_free: - if (lock) - rollback_lock_file(lock); + rollback_lock_file(&lock); free(filename_buf); if (contents) munmap(contents, contents_sz); @@ -2623,7 +2609,7 @@ out_free: return ret; write_err_out: - ret = write_error(get_lock_file_path(lock)); + ret = write_error(get_lock_file_path(&lock)); goto out_free; } diff --git a/contrib/coccinelle/array.cocci b/contrib/coccinelle/array.cocci index c61d1ca8dc..01586821dc 100644 --- a/contrib/coccinelle/array.cocci +++ b/contrib/coccinelle/array.cocci @@ -4,7 +4,7 @@ T *dst; T *src; expression n; @@ -- memcpy(dst, src, n * sizeof(*dst)); +- memcpy(dst, src, (n) * sizeof(*dst)); + COPY_ARRAY(dst, src, n); @@ @@ -13,7 +13,7 @@ T *dst; T *src; expression n; @@ -- memcpy(dst, src, n * sizeof(*src)); +- memcpy(dst, src, (n) * sizeof(*src)); + COPY_ARRAY(dst, src, n); @@ @@ -22,7 +22,7 @@ T *dst; T *src; expression n; @@ -- memcpy(dst, src, n * sizeof(T)); +- memcpy(dst, src, (n) * sizeof(T)); + COPY_ARRAY(dst, src, n); @@ @@ -47,7 +47,7 @@ type T; T *ptr; expression n; @@ -- ptr = xmalloc(n * sizeof(*ptr)); +- ptr = xmalloc((n) * sizeof(*ptr)); + ALLOC_ARRAY(ptr, n); @@ @@ -55,5 +55,5 @@ type T; T *ptr; expression n; @@ -- ptr = xmalloc(n * sizeof(T)); +- ptr = xmalloc((n) * sizeof(T)); + ALLOC_ARRAY(ptr, n); diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index d934417475..0e16f017a4 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1385,7 +1385,7 @@ _git_describe () __gitcomp " --all --tags --contains --abbrev= --candidates= --exact-match --debug --long --match --always --first-parent - --exclude + --exclude --dirty --broken " return esac diff --git a/contrib/diff-highlight/Makefile b/contrib/diff-highlight/Makefile index fbf5c58249..f2be7cc924 100644 --- a/contrib/diff-highlight/Makefile +++ b/contrib/diff-highlight/Makefile @@ -17,4 +17,7 @@ shebang.perl: FORCE test: all $(MAKE) -C t +clean: + $(RM) diff-highlight + .PHONY: FORCE @@ -1041,7 +1041,6 @@ static void convert_attrs(struct conv_attrs *ca, const char *path) ca->crlf_action = git_path_check_crlf(ccheck + 4); if (ca->crlf_action == CRLF_UNDEFINED) ca->crlf_action = git_path_check_crlf(ccheck + 0); - ca->attr_action = ca->crlf_action; ca->ident = git_path_check_ident(ccheck + 1); ca->drv = git_path_check_convert(ccheck + 2); if (ca->crlf_action != CRLF_BINARY) { @@ -1055,12 +1054,14 @@ static void convert_attrs(struct conv_attrs *ca, const char *path) else if (eol_attr == EOL_CRLF) ca->crlf_action = CRLF_TEXT_CRLF; } - ca->attr_action = ca->crlf_action; } else { ca->drv = NULL; ca->crlf_action = CRLF_UNDEFINED; ca->ident = 0; } + + /* Save attr and make a decision for action */ + ca->attr_action = ca->crlf_action; if (ca->crlf_action == CRLF_TEXT) ca->crlf_action = text_eol_is_crlf() ? CRLF_TEXT_CRLF : CRLF_TEXT_INPUT; if (ca->crlf_action == CRLF_UNDEFINED && auto_crlf == AUTO_CRLF_FALSE) @@ -299,6 +299,9 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) return 0; } + if (git_color_config(var, value, cb) < 0) + return -1; + return git_diff_basic_config(var, value, cb); } @@ -825,7 +828,7 @@ static void emit_rewrite_diff(const char *name_a, struct diff_words_buffer { mmfile_t text; - long alloc; + unsigned long alloc; struct diff_words_orig { const char *begin, *end; } *orig; diff --git a/exec_cmd.c b/exec_cmd.c index fb94aeba9c..ce192a2d64 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -5,21 +5,14 @@ #define MAX_ARGS 32 static const char *argv_exec_path; + +#ifdef RUNTIME_PREFIX static const char *argv0_path; -char *system_path(const char *path) +static const char *system_prefix(void) { -#ifdef RUNTIME_PREFIX static const char *prefix; -#else - static const char *prefix = PREFIX; -#endif - struct strbuf d = STRBUF_INIT; - - if (is_absolute_path(path)) - return xstrdup(path); -#ifdef RUNTIME_PREFIX assert(argv0_path); assert(is_absolute_path(argv0_path)); @@ -32,10 +25,7 @@ char *system_path(const char *path) "but prefix computation failed. " "Using static fallback '%s'.\n", prefix); } -#endif - - strbuf_addf(&d, "%s/%s", prefix, path); - return strbuf_detach(&d, NULL); + return prefix; } void git_extract_argv0_path(const char *argv0) @@ -51,6 +41,30 @@ void git_extract_argv0_path(const char *argv0) argv0_path = xstrndup(argv0, slash - argv0); } +#else + +static const char *system_prefix(void) +{ + return PREFIX; +} + +void git_extract_argv0_path(const char *argv0) +{ +} + +#endif /* RUNTIME_PREFIX */ + +char *system_path(const char *path) +{ + struct strbuf d = STRBUF_INIT; + + if (is_absolute_path(path)) + return xstrdup(path); + + strbuf_addf(&d, "%s/%s", system_prefix(), path); + return strbuf_detach(&d, NULL); +} + void git_set_argv_exec_path(const char *exec_path) { argv_exec_path = exec_path; diff --git a/fast-import.c b/fast-import.c index 395524039b..32ac5323f6 100644 --- a/fast-import.c +++ b/fast-import.c @@ -3188,10 +3188,10 @@ static void checkpoint(void) checkpoint_requested = 0; if (object_count) { cycle_packfile(); - dump_branches(); - dump_tags(); - dump_marks(); } + dump_branches(); + dump_tags(); + dump_marks(); } static void parse_checkpoint(void) @@ -358,15 +358,15 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op continue; if (S_ISDIR(entry.mode)) { - obj = &lookup_tree(entry.oid)->object; - if (name) + obj = (struct object *)lookup_tree(entry.oid); + if (name && obj) put_object_name(options, obj, "%s%s/", name, entry.path); result = options->walk(obj, OBJ_TREE, data, options); } else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) { - obj = &lookup_blob(entry.oid)->object; - if (name) + obj = (struct object *)lookup_blob(entry.oid); + if (name && obj) put_object_name(options, obj, "%s%s", name, entry.path); result = options->walk(obj, OBJ_BLOB, data, options); diff --git a/git-archimport.perl b/git-archimport.perl index 9cb123a07d..b7c173c345 100755 --- a/git-archimport.perl +++ b/git-archimport.perl @@ -983,7 +983,7 @@ sub find_parents { # check that we actually know about the branch next unless -e "$git_dir/refs/heads/$branch"; - my $mergebase = `git-merge-base $branch $ps->{branch}`; + my $mergebase = safe_pipe_capture(qw(git-merge-base), $branch, $ps->{branch}); if ($?) { # Don't die here, Arch supports one-way cherry-picking # between branches with no common base (or any relationship @@ -1074,7 +1074,7 @@ sub find_parents { sub git_rev_parse { my $name = shift; - my $val = `git-rev-parse $name`; + my $val = safe_pipe_capture(qw(git-rev-parse), $name); die "Error: git-rev-parse $name" if $?; chomp $val; return $val; diff --git a/git-compat-util.h b/git-compat-util.h index 7d2c0ca759..bf4869dcef 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -900,9 +900,11 @@ static inline char *xstrdup_or_null(const char *str) static inline size_t xsize_t(off_t len) { - if (len > (size_t) len) + size_t size = (size_t) len; + + if (len != (off_t) size) die("Cannot handle files this big"); - return (size_t)len; + return size; } __attribute__((format (printf, 3, 4))) diff --git a/git-cvsimport.perl b/git-cvsimport.perl index 1e4e65a45d..36929921ea 100755 --- a/git-cvsimport.perl +++ b/git-cvsimport.perl @@ -642,6 +642,7 @@ sub is_sha1 { sub get_headref ($) { my $name = shift; + $name =~ s/'/'\\''/; my $r = `git rev-parse --verify '$name' 2>/dev/null`; return undef unless $? == 0; chomp $r; diff --git a/git-cvsserver.perl b/git-cvsserver.perl index d50c85ed7b..ae1044273d 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -356,7 +356,7 @@ sub req_Root return 0; } - my @gitvars = `git config -l`; + my @gitvars = safe_pipe_capture(qw(git config -l)); if ($?) { print "E problems executing git-config on the server -- this is not a git repository or the PATH is not set correctly.\n"; print "E \n"; @@ -841,7 +841,7 @@ sub req_Modified # Save the file data in $state $state->{entries}{$state->{directory}.$data}{modified_filename} = $filename; $state->{entries}{$state->{directory}.$data}{modified_mode} = $mode; - $state->{entries}{$state->{directory}.$data}{modified_hash} = `git hash-object $filename`; + $state->{entries}{$state->{directory}.$data}{modified_hash} = safe_pipe_capture('git','hash-object',$filename); $state->{entries}{$state->{directory}.$data}{modified_hash} =~ s/\s.*$//s; #$log->debug("req_Modified : file=$data mode=$mode size=$size"); @@ -943,7 +943,7 @@ sub req_co # Provide list of modules, if -c was used. if (exists $state->{opt}{c}) { - my $showref = `git show-ref --heads`; + my $showref = safe_pipe_capture(qw(git show-ref --heads)); for my $line (split '\n', $showref) { if ( $line =~ m% refs/heads/(.*)$% ) { print "M $1\t$1\n"; @@ -1181,7 +1181,7 @@ sub req_update # projects (heads in this case) to checkout. # if ($state->{module} eq '') { - my $showref = `git show-ref --heads`; + my $showref = safe_pipe_capture(qw(git show-ref --heads)); print "E cvs update: Updating .\n"; for my $line (split '\n', $showref) { if ( $line =~ m% refs/heads/(.*)$% ) { @@ -1463,7 +1463,7 @@ sub req_update # transmit file, format is single integer on a line by itself (file # size) followed by the file contents # TODO : we should copy files in blocks - my $data = `cat $mergedFile`; + my $data = safe_pipe_capture('cat', $mergedFile); $log->debug("File size : " . length($data)); print length($data) . "\n"; print $data; @@ -1579,7 +1579,7 @@ sub req_ci $branchRef = "refs/heads/$stickyInfo->{tag}"; } - $parenthash = `git show-ref -s $branchRef`; + $parenthash = safe_pipe_capture('git', 'show-ref', '-s', $branchRef); chomp $parenthash; if ($parenthash !~ /^[0-9a-f]{40}$/) { @@ -1687,7 +1687,7 @@ sub req_ci return; } - my $treehash = `git write-tree`; + my $treehash = safe_pipe_capture(qw(git write-tree)); chomp $treehash; $log->debug("Treehash : $treehash, Parenthash : $parenthash"); @@ -1704,7 +1704,7 @@ sub req_ci } close $msg_fh; - my $commithash = `git commit-tree $treehash -p $parenthash < $msg_filename`; + my $commithash = safe_pipe_capture('git', 'commit-tree', $treehash, '-p', $parenthash, '-F', $msg_filename); chomp($commithash); $log->info("Commit hash : $commithash"); @@ -2854,12 +2854,12 @@ sub transmitfile die "Need filehash" unless ( defined ( $filehash ) and $filehash =~ /^[a-zA-Z0-9]{40}$/ ); - my $type = `git cat-file -t $filehash`; + my $type = safe_pipe_capture('git', 'cat-file', '-t', $filehash); chomp $type; die ( "Invalid type '$type' (expected 'blob')" ) unless ( defined ( $type ) and $type eq "blob" ); - my $size = `git cat-file -s $filehash`; + my $size = safe_pipe_capture('git', 'cat-file', '-s', $filehash); chomp $size; $log->debug("transmitfile($filehash) size=$size, type=$type"); @@ -3040,7 +3040,7 @@ sub ensureWorkTree chdir $work->{emptyDir} or die "Unable to chdir to $work->{emptyDir}\n"; - my $ver = `git show-ref -s refs/heads/$state->{module}`; + my $ver = safe_pipe_capture('git', 'show-ref', '-s', "refs/heads/$state->{module}"); chomp $ver; if ($ver !~ /^[0-9a-f]{40}$/) { @@ -3287,7 +3287,7 @@ sub open_blob_or_die die "Need filehash\n"; } - my $type = `git cat-file -t $name`; + my $type = safe_pipe_capture('git', 'cat-file', '-t', $name); chomp $type; unless ( defined ( $type ) and $type eq "blob" ) @@ -3296,7 +3296,7 @@ sub open_blob_or_die die ( "Invalid type '$type' (expected 'blob')" ) } - my $size = `git cat-file -s $name`; + my $size = safe_pipe_capture('git', 'cat-file', '-s', $name); chomp $size; $log->debug("open_blob_or_die($name) size=$size, type=$type"); @@ -3406,6 +3406,22 @@ sub refHashEqual return $out; } +# an alternative to `command` that allows input to be passed as an array +# to work around shell problems with weird characters in arguments + +sub safe_pipe_capture { + + my @output; + + if (my $pid = open my $child, '-|') { + @output = (<$child>); + close $child or die join(' ',@_).": $! $?"; + } else { + exec(@_) or die "$! $?"; # exec() can fail the executable can't be found + } + return wantarray ? @output : join('',@output); +} + package GITCVS::log; @@ -3797,10 +3813,10 @@ sub update # first lets get the commit list $ENV{GIT_DIR} = $self->{git_path}; - my $commitsha1 = `git rev-parse $self->{module}`; + my $commitsha1 = ::safe_pipe_capture('git', 'rev-parse', $self->{module}); chomp $commitsha1; - my $commitinfo = `git cat-file commit $self->{module} 2>&1`; + my $commitinfo = ::safe_pipe_capture('git', 'cat-file', 'commit', $self->{module}); unless ( $commitinfo =~ /tree\s+[a-zA-Z0-9]{40}/ ) { die("Invalid module '$self->{module}'"); @@ -3882,7 +3898,7 @@ sub update # several candidate merge bases. let's assume # that the first one is the best one. my $base = eval { - safe_pipe_capture('git', 'merge-base', + ::safe_pipe_capture('git', 'merge-base', $lastpicked, $parent); }; # The two branches may not be related at all, @@ -4749,7 +4765,7 @@ sub getMetaFromCommithash return $retVal; } - my($fileHash)=safe_pipe_capture("git","rev-parse","$revCommit:$filename"); + my($fileHash) = ::safe_pipe_capture("git","rev-parse","$revCommit:$filename"); chomp $fileHash; if(!($fileHash=~/^[0-9a-f]{40}$/)) { @@ -4844,8 +4860,8 @@ sub lookupCommitRef return $commitHash; } - $commitHash=safe_pipe_capture("git","rev-parse","--verify","--quiet", - $self->unescapeRefName($ref)); + $commitHash = ::safe_pipe_capture("git","rev-parse","--verify","--quiet", + $self->unescapeRefName($ref)); $commitHash=~s/\s*$//; if(!($commitHash=~/^[0-9a-f]{40}$/)) { @@ -4854,7 +4870,7 @@ sub lookupCommitRef if( defined($commitHash) ) { - my $type=safe_pipe_capture("git","cat-file","-t",$commitHash); + my $type = ::safe_pipe_capture("git","cat-file","-t",$commitHash); if( ! ($type=~/^commit\s*$/ ) ) { $commitHash=undef; @@ -4907,7 +4923,7 @@ sub commitmessage return $message; } - my @lines = safe_pipe_capture("git", "cat-file", "commit", $commithash); + my @lines = ::safe_pipe_capture("git", "cat-file", "commit", $commithash); shift @lines while ( $lines[0] =~ /\S/ ); $message = join("",@lines); $message .= " " if ( $message =~ /\n$/ ); @@ -5056,25 +5072,6 @@ sub in_array return $retval; } -=head2 safe_pipe_capture - -an alternative to `command` that allows input to be passed as an array -to work around shell problems with weird characters in arguments - -=cut -sub safe_pipe_capture { - - my @output; - - if (my $pid = open my $child, '-|') { - @output = (<$child>); - close $child or die join(' ',@_).": $! $?"; - } else { - exec(@_) or die "$! $?"; # exec() can fail the executable can't be found - } - return wantarray ? @output : join('',@output); -} - =head2 mangle_dirname create a string from a directory name that is suitable to use as diff --git a/git-request-pull.sh b/git-request-pull.sh index eebd33276d..13c172bd94 100755 --- a/git-request-pull.sh +++ b/git-request-pull.sh @@ -128,7 +128,7 @@ git show -s --format='The following changes since commit %H: %s (%ci) -are available in the git repository at: +are available in the Git repository at: ' $merge_base && echo " $url $pretty_remote" && git show -s --format=' diff --git a/git-send-email.perl b/git-send-email.perl index fa6526986e..2208dcc213 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -155,7 +155,6 @@ sub format_2822_time { } my $have_email_valid = eval { require Email::Valid; 1 }; -my $have_mail_address = eval { require Mail::Address; 1 }; my $smtp; my $auth; my $num_sent = 0; @@ -490,11 +489,7 @@ my ($repoauthor, $repocommitter); ($repocommitter) = Git::ident_person(@repo, 'committer'); sub parse_address_line { - if ($have_mail_address) { - return map { $_->format } Mail::Address->parse($_[0]); - } else { - return Git::parse_mailboxes($_[0]); - } + return Git::parse_mailboxes($_[0]); } sub split_addrs { @@ -1089,6 +1084,26 @@ sub sanitize_address { } +sub strip_garbage_one_address { + my ($addr) = @_; + chomp $addr; + if ($addr =~ /^(("[^"]*"|[^"<]*)? *<[^>]*>).*/) { + # "Foo Bar" <foobar@example.com> [possibly garbage here] + # Foo Bar <foobar@example.com> [possibly garbage here] + return $1; + } + if ($addr =~ /^(<[^>]*>).*/) { + # <foo@example.com> [possibly garbage here] + # if garbage contains other addresses, they are ignored. + return $1; + } + if ($addr =~ /^([^"#,\s]*)/) { + # address without quoting: remove anything after the address + return $1; + } + return $addr; +} + sub sanitize_address_list { return (map { sanitize_address($_) } @_); } @@ -1590,10 +1605,12 @@ foreach my $t (@files) { # Now parse the message body while(<$fh>) { $message .= $_; - if (/^(Signed-off-by|Cc): ([^>]*>?)/i) { + if (/^(Signed-off-by|Cc): (.*)/i) { chomp; my ($what, $c) = ($1, $2); - chomp $c; + # strip garbage for the address we'll use: + $c = strip_garbage_one_address($c); + # sanitize a bit more to decide whether to suppress the address: my $sc = sanitize_address($c); if ($sc eq $sender) { next if ($suppress_cc{'self'}); diff --git a/http-push.c b/http-push.c index c91f40a610..df969609be 100644 --- a/http-push.c +++ b/http-push.c @@ -1017,7 +1017,7 @@ static int get_oid_hex_from_objpath(const char *path, struct object_id *oid) memcpy(hex, path, 2); path += 2; path++; /* skip '/' */ - memcpy(hex, path, GIT_SHA1_HEXSZ - 2); + memcpy(hex + 2, path, GIT_SHA1_HEXSZ - 2); return get_oid_hex(hex, oid); } diff --git a/line-log.c b/line-log.c index ab0709f9ae..545ad0f28b 100644 --- a/line-log.c +++ b/line-log.c @@ -90,7 +90,7 @@ static int range_cmp(const void *_r, const void *_s) */ static void range_set_check_invariants(struct range_set *rs) { - int i; + unsigned int i; if (!rs) return; @@ -110,8 +110,8 @@ static void range_set_check_invariants(struct range_set *rs) */ void sort_and_merge_range_set(struct range_set *rs) { - int i; - int o = 0; /* output cursor */ + unsigned int i; + unsigned int o = 0; /* output cursor */ QSORT(rs->ranges, rs->nr, range_cmp); @@ -144,7 +144,7 @@ void sort_and_merge_range_set(struct range_set *rs) static void range_set_union(struct range_set *out, struct range_set *a, struct range_set *b) { - int i = 0, j = 0; + unsigned int i = 0, j = 0; struct range *ra = a->ranges; struct range *rb = b->ranges; /* cannot make an alias of out->ranges: it may change during grow */ @@ -186,7 +186,7 @@ static void range_set_union(struct range_set *out, static void range_set_difference(struct range_set *out, struct range_set *a, struct range_set *b) { - int i, j = 0; + unsigned int i, j = 0; for (i = 0; i < a->nr; i++) { long start = a->ranges[i].start; long end = a->ranges[i].end; @@ -397,7 +397,7 @@ static void diff_ranges_filter_touched(struct diff_ranges *out, struct diff_ranges *diff, struct range_set *rs) { - int i, j = 0; + unsigned int i, j = 0; assert(out->target.nr == 0); @@ -426,7 +426,7 @@ static void range_set_shift_diff(struct range_set *out, struct range_set *rs, struct diff_ranges *diff) { - int i, j = 0; + unsigned int i, j = 0; long offset = 0; struct range *src = rs->ranges; struct range *target = diff->target.ranges; @@ -873,7 +873,7 @@ static char *output_prefix(struct diff_options *opt) static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *range) { - int i, j = 0; + unsigned int i, j = 0; long p_lines, t_lines; unsigned long *p_ends = NULL, *t_ends = NULL; struct diff_filepair *pair = range->pair; @@ -906,7 +906,7 @@ static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *rang long t_start = range->ranges.ranges[i].start; long t_end = range->ranges.ranges[i].end; long t_cur = t_start; - int j_last; + unsigned int j_last; while (j < diff->target.nr && diff->target.ranges[j].end < t_start) j++; diff --git a/line-log.h b/line-log.h index 7a5c24e2df..e2a5ee7c6d 100644 --- a/line-log.h +++ b/line-log.h @@ -14,7 +14,7 @@ struct range { /* A set of ranges. The ranges must always be disjoint and sorted. */ struct range_set { - int alloc, nr; + unsigned int alloc, nr; struct range *ranges; }; diff --git a/mailinfo.c b/mailinfo.c index bd574cb752..70187e3eb3 100644 --- a/mailinfo.c +++ b/mailinfo.c @@ -368,11 +368,16 @@ static struct strbuf *decode_q_segment(const struct strbuf *q_seg, int rfc2047) while ((c = *in++) != 0) { if (c == '=') { - int d = *in++; + int ch, d = *in; if (d == '\n' || !d) break; /* drop trailing newline */ - strbuf_addch(out, (hexval(d) << 4) | hexval(*in++)); - continue; + ch = hex2chr(in); + if (ch >= 0) { + strbuf_addch(out, ch); + in += 2; + continue; + } + /* garbage -- fall through */ } if (rfc2047 && c == '_') /* rfc2047 4.2 (2) */ c = 0x20; @@ -33,11 +33,10 @@ static struct strbuf *get_pathname(void) return sb; } -static char *cleanup_path(char *path) +static const char *cleanup_path(const char *path) { /* Clean it up */ - if (!memcmp(path, "./", 2)) { - path += 2; + if (skip_prefix(path, "./", &path)) { while (*path == '/') path++; } @@ -46,7 +45,7 @@ static char *cleanup_path(char *path) static void strbuf_cleanup_path(struct strbuf *sb) { - char *path = cleanup_path(sb->buf); + const char *path = cleanup_path(sb->buf); if (path > sb->buf) strbuf_remove(sb, 0, path - sb->buf); } @@ -63,7 +62,7 @@ char *mksnpath(char *buf, size_t n, const char *fmt, ...) strlcpy(buf, bad_path, n); return buf; } - return cleanup_path(buf); + return (char *)cleanup_path(buf); } static int dir_prefix(const char *buf, const char *dir) @@ -636,8 +635,9 @@ void strbuf_git_common_path(struct strbuf *sb, int validate_headref(const char *path) { struct stat st; - char *buf, buffer[256]; - unsigned char sha1[20]; + char buffer[256]; + const char *refname; + struct object_id oid; int fd; ssize_t len; @@ -661,24 +661,24 @@ int validate_headref(const char *path) len = read_in_full(fd, buffer, sizeof(buffer)-1); close(fd); + if (len < 0) + return -1; + buffer[len] = '\0'; + /* * Is it a symbolic ref? */ - if (len < 4) - return -1; - if (!memcmp("ref:", buffer, 4)) { - buf = buffer + 4; - len -= 4; - while (len && isspace(*buf)) - buf++, len--; - if (len >= 5 && !memcmp("refs/", buf, 5)) + if (skip_prefix(buffer, "ref:", &refname)) { + while (isspace(*refname)) + refname++; + if (starts_with(refname, "refs/")) return 0; } /* * Is this a detached HEAD? */ - if (!get_sha1_hex(buffer, sha1)) + if (!get_oid_hex(buffer, &oid)) return 0; return -1; diff --git a/pkt-line.c b/pkt-line.c index 4823d3bb9d..647bbd3bce 100644 --- a/pkt-line.c +++ b/pkt-line.c @@ -136,8 +136,9 @@ static void format_packet(struct strbuf *out, const char *fmt, va_list args) static int packet_write_fmt_1(int fd, int gently, const char *fmt, va_list args) { - struct strbuf buf = STRBUF_INIT; + static struct strbuf buf = STRBUF_INIT; + strbuf_reset(&buf); format_packet(&buf, fmt, args); if (write_in_full(fd, buf.buf, buf.len) < 0) { if (!gently) { diff --git a/ref-filter.c b/ref-filter.c index bc591f4f3d..f3e53d4448 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -415,8 +415,16 @@ static int parse_ref_filter_atom(const struct ref_format *format, REALLOC_ARRAY(used_atom, used_atom_cnt); used_atom[at].name = xmemdupz(atom, ep - atom); used_atom[at].type = valid_atom[i].cmp_type; - if (arg) + if (arg) { arg = used_atom[at].name + (arg - atom) + 1; + if (!*arg) { + /* + * Treat empty sub-arguments list as NULL (i.e., + * "%(atom:)" is equivalent to "%(atom)"). + */ + arg = NULL; + } + } memset(&used_atom[at].u, 0, sizeof(used_atom[at].u)); if (valid_atom[i].parser) valid_atom[i].parser(format, &used_atom[at], arg); @@ -921,6 +921,8 @@ int ref_transaction_update(struct ref_transaction *transaction, return -1; } + flags &= REF_TRANSACTION_UPDATE_ALLOWED_FLAGS; + flags |= (new_sha1 ? REF_HAVE_NEW : 0) | (old_sha1 ? REF_HAVE_OLD : 0); ref_transaction_add_update(transaction, refname, flags, @@ -355,6 +355,14 @@ int refs_pack_refs(struct ref_store *refs, unsigned int flags); #define REF_FORCE_CREATE_REFLOG 0x40 /* + * Flags that can be passed in to ref_transaction_update + */ +#define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \ + REF_ISPRUNING | \ + REF_FORCE_CREATE_REFLOG | \ + REF_NODEREF + +/* * Setup reflog before using. Fill in err and return -1 on failure. */ int refs_create_reflog(struct ref_store *refs, const char *refname, diff --git a/revision.c b/revision.c index f032ab2e5c..7da0907c85 100644 --- a/revision.c +++ b/revision.c @@ -1103,7 +1103,7 @@ static void add_rev_cmdline(struct rev_info *revs, unsigned flags) { struct rev_cmdline_info *info = &revs->cmdline; - int nr = info->nr; + unsigned int nr = info->nr; ALLOC_GROW(info->rev, nr + 1, info->alloc); info->rev[nr].item = item; diff --git a/run-command.c b/run-command.c index b5e6eb37c0..014b2165b5 100644 --- a/run-command.c +++ b/run-command.c @@ -452,7 +452,7 @@ static char **prep_childenv(const char *const *deltaenv) } /* Create an array of 'char *' to be used as the childenv */ - childenv = xmalloc((env.nr + 1) * sizeof(char *)); + ALLOC_ARRAY(childenv, env.nr + 1); for (i = 0; i < env.nr; i++) childenv[i] = env.items[i].util; childenv[env.nr] = NULL; diff --git a/sha1-lookup.c b/sha1-lookup.c index 5f069214d9..2552b7902c 100644 --- a/sha1-lookup.c +++ b/sha1-lookup.c @@ -99,219 +99,3 @@ int sha1_pos(const unsigned char *sha1, void *table, size_t nr, } while (lo < hi); return -lo-1; } - -/* - * Conventional binary search loop looks like this: - * - * unsigned lo, hi; - * do { - * unsigned 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 as 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 set it to hi, - * and repeat the search. - * - * - if it is strictly lower than the target, we update lo to - * one slot after it, because we allow lo to be at the target. - * - * If the loop exits, there is no matching entry. - * - * 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. - * - * Now, we can take advantage of the fact that SHA-1 is a good hash - * function, and as long as there are enough entries in the table, we - * can expect uniform distribution. An entry that begins with for - * example "deadbeef..." is much likely to appear much later than in - * the midway of the table. It can reasonably be expected to be near - * 87% (222/256) from the top of the table. - * - * However, we do not want to pick "mi" too precisely. If the entry at - * the 87% in the above example turns out to be higher than the target - * we are looking for, we would end up narrowing the search space down - * only by 13%, instead of 50% we would get if we did a simple binary - * search. So we would want to hedge our bets by being less aggressive. - * - * The table at "table" holds at least "nr" entries of "elem_size" - * bytes each. Each entry has the SHA-1 key at "key_offset". The - * table is sorted by the SHA-1 key of the entries. The caller wants - * to find the entry with "key", and knows that the entry at "lo" is - * not higher than the entry it is looking for, and that the entry at - * "hi" is higher than the entry it is looking for. - */ -int sha1_entry_pos(const void *table, - size_t elem_size, - size_t key_offset, - unsigned lo, unsigned hi, unsigned nr, - const unsigned char *key) -{ - const unsigned char *base = table; - const unsigned char *hi_key, *lo_key; - unsigned ofs_0; - static int debug_lookup = -1; - - if (debug_lookup < 0) - debug_lookup = !!getenv("GIT_DEBUG_LOOKUP"); - - if (!nr || lo >= hi) - return -1; - - if (nr == hi) - hi_key = NULL; - else - hi_key = base + elem_size * hi + key_offset; - lo_key = base + elem_size * lo + key_offset; - - ofs_0 = 0; - do { - int cmp; - unsigned ofs, mi, range; - unsigned lov, hiv, kyv; - const unsigned char *mi_key; - - range = hi - lo; - if (hi_key) { - for (ofs = ofs_0; ofs < 20; ofs++) - if (lo_key[ofs] != hi_key[ofs]) - break; - ofs_0 = ofs; - /* - * byte 0 thru (ofs-1) are the same between - * lo and hi; ofs is the first byte that is - * different. - * - * If ofs==20, then no bytes are different, - * meaning we have entries with duplicate - * keys. We know that we are in a solid run - * of this entry (because the entries are - * sorted, and our lo and hi are the same, - * there can be nothing but this single key - * in between). So we can stop the search. - * Either one of these entries is it (and - * we do not care which), or we do not have - * it. - * - * Furthermore, we know that one of our - * endpoints must be the edge of the run of - * duplicates. For example, given this - * sequence: - * - * idx 0 1 2 3 4 5 - * key A C C C C D - * - * If we are searching for "B", we might - * hit the duplicate run at lo=1, hi=3 - * (e.g., by first mi=3, then mi=0). But we - * can never have lo > 1, because B < C. - * That is, if our key is less than the - * run, we know that "lo" is the edge, but - * we can say nothing of "hi". Similarly, - * if our key is greater than the run, we - * know that "hi" is the edge, but we can - * say nothing of "lo". - * - * Therefore if we do not find it, we also - * know where it would go if it did exist: - * just on the far side of the edge that we - * know about. - */ - if (ofs == 20) { - mi = lo; - mi_key = base + elem_size * mi + key_offset; - cmp = memcmp(mi_key, key, 20); - if (!cmp) - return mi; - if (cmp < 0) - return -1 - hi; - else - return -1 - lo; - } - - hiv = hi_key[ofs_0]; - if (ofs_0 < 19) - hiv = (hiv << 8) | hi_key[ofs_0+1]; - } else { - hiv = 256; - if (ofs_0 < 19) - hiv <<= 8; - } - lov = lo_key[ofs_0]; - kyv = key[ofs_0]; - if (ofs_0 < 19) { - lov = (lov << 8) | lo_key[ofs_0+1]; - kyv = (kyv << 8) | key[ofs_0+1]; - } - assert(lov < hiv); - - if (kyv < lov) - return -1 - lo; - if (hiv < kyv) - return -1 - hi; - - /* - * Even if we know the target is much closer to 'hi' - * than 'lo', if we pick too precisely and overshoot - * (e.g. when we know 'mi' is closer to 'hi' than to - * 'lo', pick 'mi' that is higher than the target), we - * end up narrowing the search space by a smaller - * amount (i.e. the distance between 'mi' and 'hi') - * than what we would have (i.e. about half of 'lo' - * and 'hi'). Hedge our bets to pick 'mi' less - * aggressively, i.e. make 'mi' a bit closer to the - * middle than we would otherwise pick. - */ - kyv = (kyv * 6 + lov + hiv) / 8; - if (lov < hiv - 1) { - if (kyv == lov) - kyv++; - else if (kyv == hiv) - kyv--; - } - mi = (range - 1) * (kyv - lov) / (hiv - lov) + lo; - - if (debug_lookup) { - printf("lo %u hi %u rg %u mi %u ", lo, hi, range, mi); - printf("ofs %u lov %x, hiv %x, kyv %x\n", - ofs_0, lov, hiv, kyv); - } - if (!(lo <= mi && mi < hi)) - die("assertion failure lo %u mi %u hi %u %s", - lo, mi, hi, sha1_to_hex(key)); - - mi_key = base + elem_size * mi + key_offset; - cmp = memcmp(mi_key + ofs_0, key + ofs_0, 20 - ofs_0); - if (!cmp) - return mi; - if (cmp > 0) { - hi = mi; - hi_key = mi_key; - } else { - lo = mi + 1; - lo_key = mi_key + elem_size; - } - } while (lo < hi); - return -lo-1; -} diff --git a/sha1-lookup.h b/sha1-lookup.h index 20af285681..cf5314f402 100644 --- a/sha1-lookup.h +++ b/sha1-lookup.h @@ -7,10 +7,4 @@ 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, - unsigned lo, unsigned hi, unsigned nr, - const unsigned char *key); #endif diff --git a/sha1_file.c b/sha1_file.c index 20a9d39c00..4d0e0c554d 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -2761,7 +2761,6 @@ off_t find_pack_entry_one(const unsigned char *sha1, const uint32_t *level1_ofs = p->index_data; const unsigned char *index = p->index_data; unsigned hi, lo, stride; - static int use_lookup = -1; static int debug_lookup = -1; if (debug_lookup < 0) @@ -2791,16 +2790,6 @@ off_t find_pack_entry_one(const unsigned char *sha1, printf("%02x%02x%02x... lo %u hi %u nr %"PRIu32"\n", sha1[0], sha1[1], sha1[2], lo, hi, p->num_objects); - if (use_lookup < 0) - use_lookup = !!getenv("GIT_USE_LOOKUP"); - if (use_lookup) { - int pos = sha1_entry_pos(index, stride, 0, - lo, hi, p->num_objects, sha1); - if (pos < 0) - return 0; - return nth_packed_object_offset(p, pos); - } - while (lo < hi) { unsigned mi = (lo + hi) / 2; int cmp = hashcmp(index + mi * stride, sha1); @@ -2963,10 +2952,14 @@ static int sha1_loose_object_info(const unsigned char *sha1, } else if ((status = parse_sha1_header_extended(hdr, oi, flags)) < 0) status = error("unable to parse %s header", sha1_to_hex(sha1)); - if (status >= 0 && oi->contentp) + if (status >= 0 && oi->contentp) { *oi->contentp = unpack_sha1_rest(&stream, hdr, *oi->sizep, sha1); - else + if (!*oi->contentp) { + git_inflate_end(&stream); + status = -1; + } + } else git_inflate_end(&stream); munmap(map, mapsize); @@ -25,19 +25,6 @@ static int do_generic_cmd(const char *me, char *arg) return execv_git_cmd(my_argv); } -static int do_cvs_cmd(const char *me, char *arg) -{ - const char *cvsserver_argv[3] = { - "cvsserver", "server", NULL - }; - - if (!arg || strcmp(arg, "server")) - die("git-cvsserver only handles server: %s", arg); - - setup_path(); - return execv_git_cmd(cvsserver_argv); -} - static int is_valid_cmd_name(const char *cmd) { /* Test command contains no . or / characters */ @@ -134,7 +121,6 @@ static struct commands { { "git-receive-pack", do_generic_cmd }, { "git-upload-pack", do_generic_cmd }, { "git-upload-archive", do_generic_cmd }, - { "cvs", do_cvs_cmd }, { NULL }, }; @@ -476,6 +476,7 @@ int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term) /* Translate slopbuf to NULL, as we cannot call realloc on it */ if (!sb->alloc) sb->buf = NULL; + errno = 0; r = getdelim(&sb->buf, &sb->alloc, term, fp); if (r > 0) { @@ -82,8 +82,12 @@ extern char strbuf_slopbuf[]; extern void strbuf_init(struct strbuf *, size_t); /** - * Release a string buffer and the memory it used. You should not use the - * string buffer after using this function, unless you initialize it again. + * Release a string buffer and the memory it used. After this call, the + * strbuf points to an empty string that does not need to be free()ed, as + * if it had been set to `STRBUF_INIT` and never modified. + * + * To clear a strbuf in preparation for further use without the overhead + * of free()ing and malloc()ing again, use strbuf_reset() instead. */ extern void strbuf_release(struct strbuf *); @@ -91,6 +95,9 @@ extern void strbuf_release(struct strbuf *); * Detach the string from the strbuf and returns it; you now own the * storage the string occupies and it is your responsibility from then on * to release it with `free(3)` when you are done with it. + * + * The strbuf that previously held the string is reset to `STRBUF_INIT` so + * it can be reused after calling this function. */ extern char *strbuf_detach(struct strbuf *, size_t *); @@ -147,7 +154,10 @@ static inline void strbuf_setlen(struct strbuf *sb, size_t len) if (len > (sb->alloc ? sb->alloc - 1 : 0)) die("BUG: strbuf_setlen() beyond buffer"); sb->len = len; - sb->buf[len] = '\0'; + if (sb->buf != strbuf_slopbuf) + sb->buf[len] = '\0'; + else + assert(!strbuf_slopbuf[0]); } /** diff --git a/string-list.h b/string-list.h index 29bfb7ae45..79ae567cbc 100644 --- a/string-list.h +++ b/string-list.h @@ -32,8 +32,10 @@ void string_list_clear_func(struct string_list *list, string_list_clear_func_t c typedef int (*string_list_each_func_t)(struct string_list_item *, void *); int for_each_string_list(struct string_list *list, string_list_each_func_t, void *cb_data); -#define for_each_string_list_item(item,list) \ - for (item = (list)->items; item < (list)->items + (list)->nr; ++item) +#define for_each_string_list_item(item,list) \ + for (item = (list)->items; \ + item && item < (list)->items + (list)->nr; \ + ++item) /* * Apply want to each item in list, retaining only the ones for which diff --git a/sub-process.c b/sub-process.c index fcc4832c14..80571567f2 100644 --- a/sub-process.c +++ b/sub-process.c @@ -74,13 +74,12 @@ int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, co { int err; struct child_process *process; - const char *argv[] = { cmd, NULL }; entry->cmd = cmd; process = &entry->process; child_process_init(process); - process->argv = argv; + argv_array_push(&process->args, cmd); process->use_shell = 1; process->in = -1; process->out = -1; @@ -181,8 +180,8 @@ static int handshake_capabilities(struct child_process *process, if (supported_capabilities) *supported_capabilities |= capabilities[i].flag; } else { - warning("subprocess '%s' requested unsupported capability '%s'", - process->argv[0], p); + die("subprocess '%s' requested unsupported capability '%s'", + process->argv[0], p); } } diff --git a/submodule.h b/submodule.h index e85b144863..3c239d1ecf 100644 --- a/submodule.h +++ b/submodule.h @@ -129,7 +129,7 @@ extern int submodule_move_head(const char *path, /* * Prepare the "env_array" parameter of a "struct child_process" for executing - * a submodule by clearing any repo-specific envirionment variables, but + * a submodule by clearing any repo-specific environment variables, but * retaining any config in the environment. */ extern void prepare_submodule_repo_env(struct argv_array *out); @@ -265,12 +265,12 @@ or: $ sh ./t9200-git-cvsexport-commit.sh --run='-3 21' -As noted above, the test set is built going though items left to -right, so this: +As noted above, the test set is built by going through the items +from left to right, so this: $ sh ./t9200-git-cvsexport-commit.sh --run='1-4 !3' -will run tests 1, 2, and 4. Items that comes later have higher +will run tests 1, 2, and 4. Items that come later have higher precedence. It means that this: $ sh ./t9200-git-cvsexport-commit.sh --run='!3 1-4' diff --git a/t/check-non-portable-shell.pl b/t/check-non-portable-shell.pl index b170cbc045..03dc9d2852 100755 --- a/t/check-non-portable-shell.pl +++ b/t/check-non-portable-shell.pl @@ -17,7 +17,7 @@ sub err { while (<>) { chomp; /\bsed\s+-i/ and err 'sed -i is not portable'; - /\becho\s+-n/ and err 'echo -n is not portable (please use printf)'; + /\becho\s+-[neE]/ and err 'echo with option is not portable (please use printf)'; /^\s*declare\s+/ and err 'arrays/declare not portable'; /^\s*[^#]\s*which\s/ and err 'which is not portable (please use type)'; /\btest\s+[^=]*==/ and err '"test a == b" is not portable (please use =)'; diff --git a/t/helper/test-string-list.c b/t/helper/test-string-list.c index c502fa16d3..829ec3d7d2 100644 --- a/t/helper/test-string-list.c +++ b/t/helper/test-string-list.c @@ -108,7 +108,7 @@ int cmd_main(int argc, const char **argv) * Split by newline, but don't create a string_list item * for the empty string after the last separator. */ - if (sb.buf[sb.len - 1] == '\n') + if (sb.len && sb.buf[sb.len - 1] == '\n') strbuf_setlen(&sb, sb.len - 1); string_list_split_in_place(&list, sb.buf, '\n', -1); diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index 4087150db1..cb4b66e29d 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -222,6 +222,28 @@ test_expect_success 'unparseable tree object' ' test_i18ngrep ! "fatal: empty filename in tree entry" out ' +hex2oct() { + perl -ne 'printf "\\%03o", hex for /../g' +} + +test_expect_success 'tree entry with type mismatch' ' + test_when_finished "remove_object \$blob" && + test_when_finished "remove_object \$tree" && + test_when_finished "remove_object \$commit" && + test_when_finished "git update-ref -d refs/heads/type_mismatch" && + blob=$(echo blob | git hash-object -w --stdin) && + blob_bin=$(echo $blob | hex2oct) && + tree=$( + printf "40000 dir\0${blob_bin}100644 file\0${blob_bin}" | + git hash-object -t tree --stdin -w --literally + ) && + commit=$(git commit-tree $tree) && + git update-ref refs/heads/type_mismatch $commit && + test_must_fail git fsck >out 2>&1 && + test_i18ngrep "is a blob, not a tree" out && + test_i18ngrep ! "dangling blob" out +' + test_expect_success 'tag pointing to nonexistent' ' cat >invalid-tag <<-\EOF && object ffffffffffffffffffffffffffffffffffffffff diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 9d707d2a40..5fc2fb425b 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -162,6 +162,19 @@ test_expect_success 'git branch -M baz bam should add entries to .git/logs/HEAD' grep "^0\{40\}.*$msg$" .git/logs/HEAD ' +test_expect_success 'git branch -M should leave orphaned HEAD alone' ' + git init orphan && + ( + cd orphan && + test_commit initial && + git checkout --orphan lonely && + grep lonely .git/HEAD && + test_path_is_missing .git/refs/head/lonely && + git branch -M master mistress && + grep lonely .git/HEAD + ) +' + test_expect_success 'resulting reflog can be shown by log -g' ' oid=$(git rev-parse HEAD) && cat >expect <<-EOF && diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh index d2aec0f38b..ee6787614c 100755 --- a/t/t3203-branch-output.sh +++ b/t/t3203-branch-output.sh @@ -253,13 +253,7 @@ test_expect_success '%(color) omitted without tty' ' ' test_expect_success TTY '%(color) present with tty' ' - test_terminal env TERM=vt100 git branch $color_args >actual.raw && - test_decode_color <actual.raw >actual && - test_cmp expect.color actual -' - -test_expect_success 'color.branch=always overrides auto-color' ' - git -c color.branch=always branch $color_args >actual.raw && + test_terminal git branch $color_args >actual.raw && test_decode_color <actual.raw >actual && test_cmp expect.color actual ' diff --git a/t/t3205-branch-color.sh b/t/t3205-branch-color.sh index 9343550f50..4f1e16bb44 100755 --- a/t/t3205-branch-color.sh +++ b/t/t3205-branch-color.sh @@ -12,7 +12,6 @@ test_expect_success 'set up some sample branches' ' # choose non-default colors to make sure config # is taking effect test_expect_success 'set up some color config' ' - git config color.branch always && git config color.branch.local blue && git config color.branch.remote yellow && git config color.branch.current cyan @@ -24,7 +23,7 @@ test_expect_success 'regular output shows colors' ' <BLUE>other<RESET> <YELLOW>remotes/origin/master<RESET> EOF - git branch -a >actual.raw && + git branch --color -a >actual.raw && test_decode_color <actual.raw >actual && test_cmp expect actual ' @@ -36,7 +35,7 @@ test_expect_success 'verbose output shows colors' ' <BLUE>other <RESET> $oid foo <YELLOW>remotes/origin/master<RESET> $oid foo EOF - git branch -v -a >actual.raw && + git branch --color -v -a >actual.raw && test_decode_color <actual.raw >actual && test_cmp expect actual ' diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index 2f3e7cea64..a49c12c79b 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -2,6 +2,7 @@ test_description='add -i basic tests' . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-terminal.sh if ! test_have_prereq PERL then @@ -380,14 +381,11 @@ test_expect_success 'patch mode ignores unmerged entries' ' test_cmp expected diff ' -test_expect_success 'diffs can be colorized' ' +test_expect_success TTY 'diffs can be colorized' ' git reset --hard && - # force color even though the test script has no terminal - test_config color.ui always && - echo content >test && - printf y | git add -p >output 2>&1 && + printf y | test_terminal git add -p >output 2>&1 && # We do not want to depend on the exact coloring scheme # git uses for diffs, so just check that we saw some kind of color. @@ -485,4 +483,14 @@ test_expect_success 'hunk-editing handles custom comment char' ' git diff --exit-code ' +test_expect_success 'add -p works even with color.ui=always' ' + git reset --hard && + echo change >>file && + test_config color.ui always && + echo y | git add -p && + echo file >expect && + git diff --cached --name-only >actual && + test_cmp expect actual +' + test_done diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index 289806d0c7..94597ff284 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -821,7 +821,7 @@ test_expect_success 'diff that introduces a line with only tabs' ' echo "test" >x && git commit -m "initial" x && echo "{NTN}" | tr "NT" "\n\t" >>x && - git -c color.diff=always diff | test_decode_color >current && + git diff --color | test_decode_color >current && cat >expected <<-\EOF && <BOLD>diff --git a/x b/x<RESET> @@ -851,7 +851,7 @@ test_expect_success 'diff that introduces and removes ws breakages' ' echo "2. and a new line " } >x && - git -c color.diff=always diff | + git diff --color | test_decode_color >current && cat >expected <<-\EOF && @@ -923,15 +923,15 @@ test_expect_success 'ws-error-highlight test setup' ' test_expect_success 'test --ws-error-highlight option' ' - git -c color.diff=always diff --ws-error-highlight=default,old | + git diff --color --ws-error-highlight=default,old | test_decode_color >current && test_cmp expect.default-old current && - git -c color.diff=always diff --ws-error-highlight=all | + git diff --color --ws-error-highlight=all | test_decode_color >current && test_cmp expect.all current && - git -c color.diff=always diff --ws-error-highlight=none | + git diff --color --ws-error-highlight=none | test_decode_color >current && test_cmp expect.none current @@ -939,15 +939,15 @@ test_expect_success 'test --ws-error-highlight option' ' test_expect_success 'test diff.wsErrorHighlight config' ' - git -c color.diff=always -c diff.wsErrorHighlight=default,old diff | + git -c diff.wsErrorHighlight=default,old diff --color | test_decode_color >current && test_cmp expect.default-old current && - git -c color.diff=always -c diff.wsErrorHighlight=all diff | + git -c diff.wsErrorHighlight=all diff --color | test_decode_color >current && test_cmp expect.all current && - git -c color.diff=always -c diff.wsErrorHighlight=none diff | + git -c diff.wsErrorHighlight=none diff --color | test_decode_color >current && test_cmp expect.none current @@ -955,18 +955,18 @@ test_expect_success 'test diff.wsErrorHighlight config' ' test_expect_success 'option overrides diff.wsErrorHighlight' ' - git -c color.diff=always -c diff.wsErrorHighlight=none \ - diff --ws-error-highlight=default,old | + git -c diff.wsErrorHighlight=none \ + diff --color --ws-error-highlight=default,old | test_decode_color >current && test_cmp expect.default-old current && - git -c color.diff=always -c diff.wsErrorHighlight=default \ - diff --ws-error-highlight=all | + git -c diff.wsErrorHighlight=default \ + diff --color --ws-error-highlight=all | test_decode_color >current && test_cmp expect.all current && - git -c color.diff=always -c diff.wsErrorHighlight=all \ - diff --ws-error-highlight=none | + git -c diff.wsErrorHighlight=all \ + diff --color --ws-error-highlight=none | test_decode_color >current && test_cmp expect.none current diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 36d120c969..8f155da7a5 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -750,7 +750,7 @@ test_expect_success 'log.decorate config parsing' ' ' test_expect_success TTY 'log output on a TTY' ' - git log --oneline --decorate >expect.short && + git log --color --oneline --decorate >expect.short && test_terminal git log --oneline >actual && test_cmp expect.short actual diff --git a/t/t5001-archive-attr.sh b/t/t5001-archive-attr.sh index 897f6f06d5..e9aa97117a 100755 --- a/t/t5001-archive-attr.sh +++ b/t/t5001-archive-attr.sh @@ -73,7 +73,7 @@ test_expect_missing archive-pathspec/ignored-by-tree test_expect_missing archive-pathspec/ignored-by-tree.d test_expect_missing archive-pathspec/ignored-by-tree.d/file test_expect_exists archive-pathspec/ignored-by-worktree -test_expect_missing archive-pathspec/excluded-by-pathspec.d failure +test_expect_missing archive-pathspec/excluded-by-pathspec.d test_expect_missing archive-pathspec/excluded-by-pathspec.d/file test_expect_success 'git archive with wildcard pathspec' ' diff --git a/t/t5002-archive-attr-pattern.sh b/t/t5002-archive-attr-pattern.sh index 6667d159ab..bda6d7d7e9 100755 --- a/t/t5002-archive-attr-pattern.sh +++ b/t/t5002-archive-attr-pattern.sh @@ -76,7 +76,7 @@ test_expect_missing archive/deep/and/slashless/ && test_expect_missing archive/deep/and/slashless/foo && test_expect_missing archive/deep/with/wildcard/ && test_expect_missing archive/deep/with/wildcard/foo && -test_expect_exists archive/one-level-lower/ +test_expect_missing archive/one-level-lower/ test_expect_missing archive/one-level-lower/two-levels-lower/ignored-only-if-dir/ test_expect_missing archive/one-level-lower/two-levels-lower/ignored-ony-if-dir/ignored-by-ignored-dir diff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh index f6207f42b5..ced44355ca 100755 --- a/t/t5004-archive-corner-cases.sh +++ b/t/t5004-archive-corner-cases.sh @@ -108,14 +108,14 @@ test_expect_success 'archive empty subtree with no pathspec' ' git archive --format=tar $root_tree >subtree-all.tar && make_dir extract && "$TAR" xf subtree-all.tar -C extract && - check_dir extract sub + check_dir extract ' test_expect_success 'archive empty subtree by direct pathspec' ' git archive --format=tar $root_tree -- sub >subtree-path.tar && make_dir extract && "$TAR" xf subtree-path.tar -C extract && - check_dir extract sub + check_dir extract ' ZIPINFO=zipinfo diff --git a/t/t5150-request-pull.sh b/t/t5150-request-pull.sh index 82c33b88e7..08c210f035 100755 --- a/t/t5150-request-pull.sh +++ b/t/t5150-request-pull.sh @@ -68,7 +68,7 @@ test_expect_success 'setup: two scripts for reading pull requests' ' cat <<-\EOT >read-request.sed && #!/bin/sed -nf # Note that a request could ask for "tag $tagname" - / in the git repository at:$/!d + / in the Git repository at:$/!d n /^$/ n s/ tag \([^ ]*\)$/ tag--\1/ @@ -192,7 +192,7 @@ test_expect_success 'pull request format' ' SUBJECT (DATE) - are available in the git repository at: + are available in the Git repository at: URL BRANCH diff --git a/t/t5308-pack-detect-duplicates.sh b/t/t5308-pack-detect-duplicates.sh index 9c5a8766ab..156ae9e9d3 100755 --- a/t/t5308-pack-detect-duplicates.sh +++ b/t/t5308-pack-detect-duplicates.sh @@ -56,20 +56,11 @@ test_expect_success 'create batch-check test vectors' ' EOF ' -test_expect_success 'lookup in duplicated pack (binary search)' ' +test_expect_success 'lookup in duplicated pack' ' git cat-file --batch-check <input >actual && test_cmp expect actual ' -test_expect_success 'lookup in duplicated pack (GIT_USE_LOOKUP)' ' - ( - GIT_USE_LOOKUP=1 && - export GIT_USE_LOOKUP && - git cat-file --batch-check <input >actual - ) && - test_cmp expect actual -' - test_expect_success 'index-pack can reject packs with duplicates' ' clear_packs && create_pack dups.pack 2 && diff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh index 534903bbd2..a661408038 100755 --- a/t/t6002-rev-list-bisect.sh +++ b/t/t6002-rev-list-bisect.sh @@ -236,17 +236,31 @@ test_sequence "--bisect" # # -test_expect_success '--bisect can default to good/bad refs' ' +test_expect_success 'set up fake --bisect refs' ' git update-ref refs/bisect/bad c3 && good=$(git rev-parse b1) && git update-ref refs/bisect/good-$good $good && good=$(git rev-parse c1) && - git update-ref refs/bisect/good-$good $good && + git update-ref refs/bisect/good-$good $good +' +test_expect_success 'rev-list --bisect can default to good/bad refs' ' # the only thing between c3 and c1 is c2 git rev-parse c2 >expect && git rev-list --bisect >actual && test_cmp expect actual ' +test_expect_success 'rev-parse --bisect can default to good/bad refs' ' + git rev-parse c3 ^b1 ^c1 >expect && + git rev-parse --bisect >actual && + + # output order depends on the refnames, which in turn depends on + # the exact sha1s. We just want to make sure we have the same set + # of lines in any order. + sort <expect >expect.sorted && + sort <actual >actual.sorted && + test_cmp expect.sorted actual.sorted +' + test_done diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh index b326d550f3..98be78b4a2 100755 --- a/t/t6006-rev-list-format.sh +++ b/t/t6006-rev-list-format.sh @@ -229,8 +229,7 @@ do ' test_expect_success TTY "$desc respects --color=auto (stdout is tty)" ' - test_terminal env TERM=vt100 \ - git log --format=$color -1 --color=auto >actual && + test_terminal git log --format=$color -1 --color=auto >actual && has_color actual ' diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh index aa74eb8f0d..25110ea55d 100755 --- a/t/t6120-describe.sh +++ b/t/t6120-describe.sh @@ -182,10 +182,14 @@ check_describe "test2-lightweight-*" --tags --match="test2-*" check_describe "test2-lightweight-*" --long --tags --match="test2-*" HEAD^ -check_describe "test1-lightweight-*" --long --tags --match="test1-*" --match="test2-*" HEAD^ +check_describe "test2-lightweight-*" --long --tags --match="test1-*" --match="test2-*" HEAD^ check_describe "test2-lightweight-*" --long --tags --match="test1-*" --no-match --match="test2-*" HEAD^ +check_describe "test1-lightweight-*" --long --tags --match="test1-*" --match="test3-*" HEAD + +check_describe "test1-lightweight-*" --long --tags --match="test3-*" --match="test1-*" HEAD + test_expect_success 'name-rev with exact tags' ' echo A >expect && tag_object=$(git rev-parse refs/tags/A) && diff --git a/t/t6132-pathspec-exclude.sh b/t/t6132-pathspec-exclude.sh index 9dd5cde5fc..eb829fce97 100755 --- a/t/t6132-pathspec-exclude.sh +++ b/t/t6132-pathspec-exclude.sh @@ -25,7 +25,7 @@ EOF test_cmp expect actual ' -test_expect_success 'exclude only no longer errors out' ' +test_expect_success 'exclude only pathspec uses default implicit pathspec' ' git log --oneline --format=%s -- . ":(exclude)sub" >expect && git log --oneline --format=%s -- ":(exclude)sub" >actual && test_cmp expect actual @@ -183,4 +183,15 @@ EOF test_cmp expect actual ' +test_expect_success 'multiple exclusions' ' + git ls-files -- ":^*/file2" ":^sub2" >actual && + cat <<-\EOF >expect && + file + sub/file + sub/sub/file + sub/sub/sub/file + EOF + test_cmp expect actual +' + test_done diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index 2274a4b733..d0ad902911 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -51,6 +51,7 @@ test_atom() { } test_atom head refname refs/heads/master +test_atom head refname: refs/heads/master test_atom head refname:short master test_atom head refname:lstrip=1 heads/master test_atom head refname:lstrip=2 master @@ -425,8 +426,7 @@ test_expect_success 'set up color tests' ' ' test_expect_success TTY '%(color) shows color with a tty' ' - test_terminal env TERM=vt100 \ - git for-each-ref --format="$color_format" >actual.raw && + test_terminal git for-each-ref --format="$color_format" >actual.raw && test_decode_color <actual.raw >actual && test_cmp expected.color actual ' @@ -436,12 +436,17 @@ test_expect_success '%(color) does not show color without tty' ' test_cmp expected.bare actual ' -test_expect_success 'color.ui=always can override tty check' ' - git -c color.ui=always for-each-ref --format="$color_format" >actual.raw && +test_expect_success '--color can override tty check' ' + git for-each-ref --color --format="$color_format" >actual.raw && test_decode_color <actual.raw >actual && test_cmp expected.color actual ' +test_expect_success 'color.ui=always does not override tty check' ' + git -c color.ui=always for-each-ref --format="$color_format" >actual && + test_cmp expected.bare actual +' + cat >expected <<\EOF heads/master tags/master diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index dbcd6f623c..62aa322846 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -1914,7 +1914,13 @@ test_expect_success '%(color) omitted without tty' ' ' test_expect_success TTY '%(color) present with tty' ' - test_terminal env TERM=vt100 git tag $color_args >actual.raw && + test_terminal git tag $color_args >actual.raw && + test_decode_color <actual.raw >actual && + test_cmp expect.color actual +' + +test_expect_success '--color overrides auto-color' ' + git tag --color $color_args >actual.raw && test_decode_color <actual.raw >actual && test_cmp expect.color actual ' diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh index 9128ec5acd..f0f1abd1c2 100755 --- a/t/t7006-pager.sh +++ b/t/t7006-pager.sh @@ -239,7 +239,7 @@ test_expect_success 'no color when stdout is a regular file' ' test_expect_success TTY 'color when writing to a pager' ' rm -f paginated.out && test_config color.ui auto && - test_terminal env TERM=vt100 git log && + test_terminal git log && colorful paginated.out ' @@ -247,7 +247,7 @@ test_expect_success TTY 'colors are suppressed by color.pager' ' rm -f paginated.out && test_config color.ui auto && test_config color.pager false && - test_terminal env TERM=vt100 git log && + test_terminal git log && ! colorful paginated.out ' @@ -266,7 +266,7 @@ test_expect_success 'color when writing to a file intended for a pager' ' test_expect_success TTY 'colors are sent to pager for external commands' ' test_config alias.externallog "!git log" && test_config color.ui auto && - test_terminal env TERM=vt100 git -p externallog && + test_terminal git -p externallog && colorful paginated.out ' diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh index 725687d5d5..d33a3cb331 100755 --- a/t/t7502-commit.sh +++ b/t/t7502-commit.sh @@ -171,9 +171,9 @@ test_expect_success 'verbose' ' test_expect_success 'verbose respects diff config' ' - test_config color.diff always && + test_config diff.noprefix true && git status -v >actual && - grep "\[1mdiff --git" actual + grep "diff --git negative negative" actual ' mesg_with_comment_and_newlines=' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 43d19a9b22..a3d760e63a 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -6,6 +6,7 @@ test_description='git status' . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-terminal.sh test_expect_success 'status -h in broken repository' ' git config --global advice.statusuoption false && @@ -667,7 +668,7 @@ test_expect_success 'setup unique colors' ' ' -test_expect_success 'status with color.ui' ' +test_expect_success TTY 'status with color.ui' ' cat >expect <<\EOF && On branch <GREEN>master<RESET> Your branch and '\''upstream'\'' have diverged, @@ -694,14 +695,14 @@ Untracked files: <BLUE>untracked<RESET> EOF - test_config color.ui always && - git status | test_decode_color >output && + test_config color.ui auto && + test_terminal git status | test_decode_color >output && test_i18ncmp expect output ' -test_expect_success 'status with color.status' ' - test_config color.status always && - git status | test_decode_color >output && +test_expect_success TTY 'status with color.status' ' + test_config color.status auto && + test_terminal git status | test_decode_color >output && test_i18ncmp expect output ' @@ -714,19 +715,19 @@ cat >expect <<\EOF <BLUE>??<RESET> untracked EOF -test_expect_success 'status -s with color.ui' ' +test_expect_success TTY 'status -s with color.ui' ' - git config color.ui always && - git status -s | test_decode_color >output && + git config color.ui auto && + test_terminal git status -s | test_decode_color >output && test_cmp expect output ' -test_expect_success 'status -s with color.status' ' +test_expect_success TTY 'status -s with color.status' ' git config --unset color.ui && - git config color.status always && - git status -s | test_decode_color >output && + git config color.status auto && + test_terminal git status -s | test_decode_color >output && test_cmp expect output ' @@ -741,9 +742,9 @@ cat >expect <<\EOF <BLUE>??<RESET> untracked EOF -test_expect_success 'status -s -b with color.status' ' +test_expect_success TTY 'status -s -b with color.status' ' - git status -s -b | test_decode_color >output && + test_terminal git status -s -b | test_decode_color >output && test_i18ncmp expect output ' @@ -757,20 +758,20 @@ A dir2/added ?? untracked EOF -test_expect_success 'status --porcelain ignores color.ui' ' +test_expect_success TTY 'status --porcelain ignores color.ui' ' git config --unset color.status && - git config color.ui always && - git status --porcelain | test_decode_color >output && + git config color.ui auto && + test_terminal git status --porcelain | test_decode_color >output && test_cmp expect output ' -test_expect_success 'status --porcelain ignores color.status' ' +test_expect_success TTY 'status --porcelain ignores color.status' ' git config --unset color.ui && - git config color.status always && - git status --porcelain | test_decode_color >output && + git config color.status auto && + test_terminal git status --porcelain | test_decode_color >output && test_cmp expect output ' diff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh index d8242e467e..0f86c19174 100755 --- a/t/t8010-cat-file-filters.sh +++ b/t/t8010-cat-file-filters.sh @@ -51,6 +51,11 @@ test_expect_success '--path=<path> complains without --textconv/--filters' ' grep "path.*needs.*filters" err ' +test_expect_success '--textconv/--filters complain without path' ' + test_must_fail git cat-file --textconv HEAD && + test_must_fail git cat-file --filters HEAD +' + test_expect_success 'cat-file --textconv --batch works' ' sha1=$(git rev-parse -q --verify HEAD:world.txt) && test_config diff.txt.textconv "tr A-Za-z N-ZA-Mn-za-m <" && diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index d1e4e8ad19..f30980895c 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -148,6 +148,8 @@ cat >expected-cc <<\EOF !two@example.com! !three@example.com! !four@example.com! +!five@example.com! +!six@example.com! EOF " @@ -161,6 +163,8 @@ test_expect_success $PREREQ 'cc trailer with various syntax' ' Cc: <two@example.com> # trailing comments are ignored Cc: <three@example.com>, <not.four@example.com> one address per line Cc: "Some # Body" <four@example.com> [ <also.a.comment> ] + Cc: five@example.com # not.six@example.com + Cc: six@example.com, not.seven@example.com EOF clean_fake_sendmail && git send-email -1 --to=recipient@example.com \ diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 67b8c50a5a..d47560b634 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -3120,4 +3120,146 @@ test_expect_success 'U: validate root delete result' ' compare_diff_raw expect actual ' +### +### series V (checkpoint) +### + +# The commands in input_file should not produce any output on the file +# descriptor set with --cat-blob-fd (or stdout if unspecified). +# +# To make sure you're observing the side effects of checkpoint *before* +# fast-import terminates (and thus writes out its state), check that the +# fast-import process is still running using background_import_still_running +# *after* evaluating the test conditions. +background_import_then_checkpoint () { + options=$1 + input_file=$2 + + mkfifo V.input + exec 8<>V.input + rm V.input + + mkfifo V.output + exec 9<>V.output + rm V.output + + git fast-import $options <&8 >&9 & + echo $! >V.pid + # We don't mind if fast-import has already died by the time the test + # ends. + test_when_finished "exec 8>&-; exec 9>&-; kill $(cat V.pid) || true" + + # Start in the background to ensure we adhere strictly to (blocking) + # pipes writing sequence. We want to assume that the write below could + # block, e.g. if fast-import blocks writing its own output to &9 + # because there is no reader on &9 yet. + ( + cat "$input_file" + echo "checkpoint" + echo "progress checkpoint" + ) >&8 & + + error=1 ;# assume the worst + while read output <&9 + do + if test "$output" = "progress checkpoint" + then + error=0 + break + fi + # otherwise ignore cruft + echo >&2 "cruft: $output" + done + + if test $error -eq 1 + then + false + fi +} + +background_import_still_running () { + if ! kill -0 "$(cat V.pid)" + then + echo >&2 "background fast-import terminated too early" + false + fi +} + +test_expect_success PIPE 'V: checkpoint helper does not get stuck with extra output' ' + cat >input <<-INPUT_END && + progress foo + progress bar + + INPUT_END + + background_import_then_checkpoint "" input && + background_import_still_running +' + +test_expect_success PIPE 'V: checkpoint updates refs after reset' ' + cat >input <<-\INPUT_END && + reset refs/heads/V + from refs/heads/U + + INPUT_END + + background_import_then_checkpoint "" input && + test "$(git rev-parse --verify V)" = "$(git rev-parse --verify U)" && + background_import_still_running +' + +test_expect_success PIPE 'V: checkpoint updates refs and marks after commit' ' + cat >input <<-INPUT_END && + commit refs/heads/V + mark :1 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data 0 + from refs/heads/U + + INPUT_END + + background_import_then_checkpoint "--export-marks=marks.actual" input && + + echo ":1 $(git rev-parse --verify V)" >marks.expected && + + test "$(git rev-parse --verify V^)" = "$(git rev-parse --verify U)" && + test_cmp marks.expected marks.actual && + background_import_still_running +' + +# Re-create the exact same commit, but on a different branch: no new object is +# created in the database, but the refs and marks still need to be updated. +test_expect_success PIPE 'V: checkpoint updates refs and marks after commit (no new objects)' ' + cat >input <<-INPUT_END && + commit refs/heads/V2 + mark :2 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data 0 + from refs/heads/U + + INPUT_END + + background_import_then_checkpoint "--export-marks=marks.actual" input && + + echo ":2 $(git rev-parse --verify V2)" >marks.expected && + + test "$(git rev-parse --verify V2)" = "$(git rev-parse --verify V)" && + test_cmp marks.expected marks.actual && + background_import_still_running +' + +test_expect_success PIPE 'V: checkpoint updates tags after tag' ' + cat >input <<-INPUT_END && + tag Vtag + from refs/heads/V + tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data 0 + + INPUT_END + + background_import_then_checkpoint "" input && + git show-ref -d Vtag && + background_import_still_running +' + test_done diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh index 8dcb05c4a5..866ddf6058 100755 --- a/t/t9350-fast-export.sh +++ b/t/t9350-fast-export.sh @@ -234,7 +234,7 @@ test_expect_success 'fast-export -C -C | fast-import' ' mkdir new && git --git-dir=new/.git init && git fast-export -C -C --signed-tags=strip --all > output && - grep "^C file6 file7\$" output && + grep "^C file2 file4\$" output && cat output | (cd new && git fast-import && @@ -522,4 +522,22 @@ test_expect_success 'delete refspec' ' test_cmp expected actual ' +test_expect_success 'when using -C, do not declare copy when source of copy is also modified' ' + test_create_repo src && + echo a_line >src/file.txt && + git -C src add file.txt && + git -C src commit -m 1st_commit && + + cp src/file.txt src/file2.txt && + echo another_line >>src/file.txt && + git -C src add file.txt file2.txt && + git -C src commit -m 2nd_commit && + + test_create_repo dst && + git -C src fast-export --all -C | git -C dst fast-import && + git -C src show >expected && + git -C dst show >actual && + test_cmp expected actual +' + test_done diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index 432c61d246..c30660d606 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -588,4 +588,52 @@ test_expect_success 'cvs annotate' ' test_cmp ../expect ../actual ' +#------------ +# running via git-shell +#------------ + +cd "$WORKDIR" + +test_expect_success 'create remote-cvs helper' ' + write_script remote-cvs <<-\EOF + exec git shell -c "cvs server" + EOF +' + +test_expect_success 'cvs server does not run with vanilla git-shell' ' + ( + cd cvswork && + CVS_SERVER=$WORKDIR/remote-cvs && + export CVS_SERVER && + test_must_fail cvs log merge + ) +' + +test_expect_success 'configure git shell to run cvs server' ' + mkdir "$HOME"/git-shell-commands && + + write_script "$HOME"/git-shell-commands/cvs <<-\EOF && + if ! test $# = 1 && test "$1" = "server" + then + echo >&2 "git-cvsserver only handles \"server\"" + exit 1 + fi + exec git cvsserver server + EOF + + # Should not be used, but part of the recommended setup + write_script "$HOME"/git-shell-commands/no-interactive-login <<-\EOF + echo Interactive login forbidden + EOF +' + +test_expect_success 'cvs server can run with recommended config' ' + ( + cd cvswork && + CVS_SERVER=$WORKDIR/remote-cvs && + export CVS_SERVER && + cvs log merge + ) +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 51f52dcd4e..5fbd8d4a90 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -99,7 +99,6 @@ unset VISUAL EMAIL LANGUAGE COLUMNS $("$PERL_PATH" -e ' my $ok = join("|", qw( TRACE DEBUG - USE_LOOKUP TEST .*_TEST PROVE diff --git a/t/test-terminal.perl b/t/test-terminal.perl index 96b6a03e1c..46bf618479 100755 --- a/t/test-terminal.perl +++ b/t/test-terminal.perl @@ -80,6 +80,7 @@ sub copy_stdio { if ($#ARGV < 1) { die "usage: test-terminal program args"; } +$ENV{TERM} = 'vt100'; my $master_in = new IO::Pty; my $master_out = new IO::Pty; my $master_err = new IO::Pty; @@ -142,13 +142,13 @@ int parse_tag_buffer(struct tag *item, const void *data, unsigned long size) bufptr = nl + 1; if (!strcmp(type, blob_type)) { - item->tagged = &lookup_blob(&oid)->object; + item->tagged = (struct object *)lookup_blob(&oid); } else if (!strcmp(type, tree_type)) { - item->tagged = &lookup_tree(&oid)->object; + item->tagged = (struct object *)lookup_tree(&oid); } else if (!strcmp(type, commit_type)) { - item->tagged = &lookup_commit(&oid)->object; + item->tagged = (struct object *)lookup_commit(&oid); } else if (!strcmp(type, tag_type)) { - item->tagged = &lookup_tag(&oid)->object; + item->tagged = (struct object *)lookup_tag(&oid); } else { error("Unknown type %s", type); item->tagged = NULL; diff --git a/transport-helper.c b/transport-helper.c index 2128a32f1c..a72ed18efb 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -1116,6 +1116,13 @@ int transport_helper_init(struct transport *transport, const char *name) __attribute__((format (printf, 1, 2))) static void transfer_debug(const char *fmt, ...) { + /* + * NEEDSWORK: This function is sometimes used from multiple threads, and + * we end up using debug_enabled racily. That "should not matter" since + * we always write the same value, but it's still wrong. This function + * is listed in .tsan-suppressions for the time being. + */ + va_list args; char msgbuf[PBUFFERSIZE]; static int debug_enabled = -1; diff --git a/tree-walk.c b/tree-walk.c index 6a42e402b0..d459feda23 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -581,12 +581,11 @@ enum follow_symlinks_result get_tree_entry_follow_symlinks(unsigned char *tree_s int retval = MISSING_OBJECT; struct dir_state *parents = NULL; size_t parents_alloc = 0; - ssize_t parents_nr = 0; + size_t i, parents_nr = 0; unsigned char current_tree_sha1[20]; struct strbuf namebuf = STRBUF_INIT; struct tree_desc t; int follows_remaining = GET_TREE_ENTRY_FOLLOW_SYMLINKS_MAX_LINKS; - int i; init_tree_desc(&t, NULL, 0UL); strbuf_addstr(&namebuf, name); diff --git a/userdiff.c b/userdiff.c index 2c1502f719..d314667220 100644 --- a/userdiff.c +++ b/userdiff.c @@ -38,7 +38,7 @@ IPATTERN("fortran", "|//|\\*\\*|::|[/<>=]="), IPATTERN("fountain", "^((\\.[^.]|(int|ext|est|int\\.?/ext|i/e)[. ]).*)$", "[^ \t-]+"), -PATTERNS("html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$", +PATTERNS("html", "^[ \t]*(<[Hh][1-6]([ \t].*)?>.*)$", "[^<>= \t]+"), PATTERNS("java", "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n" diff --git a/worktree.c b/worktree.c index e28ffbeb09..c0c5a2b373 100644 --- a/worktree.c +++ b/worktree.c @@ -30,7 +30,7 @@ static void add_head_info(struct worktree *wt) target = refs_resolve_ref_unsafe(get_worktree_ref_store(wt), "HEAD", - RESOLVE_REF_READING, + 0, wt->head_sha1, &flags); if (!target) return; |