From: Junio C Hamano Date: Thu, 28 Sep 2017 05:47:56 +0000 (+0900) Subject: Merge branch 'rs/resolve-ref-optional-result' X-Git-Tag: v2.15.0-rc0~41 X-Git-Url: https://www.git.lorimer.id.au/gitweb.git/diff_plain/73ecdc606eedbfd98ec66d50d44b3374425fd13b?hp=744c040b19412fa5075810eb1aced105fad96726 Merge branch 'rs/resolve-ref-optional-result' Code clean-up. * rs/resolve-ref-optional-result: refs: pass NULL to resolve_ref_unsafe() if hash is not needed refs: pass NULL to refs_resolve_ref_unsafe() if hash is not needed refs: make sha1 output parameter of refs_resolve_ref_unsafe() optional --- diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..3ede2628d2 --- /dev/null +++ b/.clang-format @@ -0,0 +1,165 @@ +# Defaults + +# Use tabs whenever we need to fill whitespace that spans at least from one tab +# stop to the next one. +UseTab: Always +TabWidth: 8 +IndentWidth: 8 +ContinuationIndentWidth: 8 +ColumnLimit: 80 + +# C Language specifics +Language: Cpp + +# Align parameters on the open bracket +# someLongFunction(argument1, +# argument2); +AlignAfterOpenBracket: Align + +# Don't align consecutive assignments +# int aaaa = 12; +# int b = 14; +AlignConsecutiveAssignments: false + +# Don't align consecutive declarations +# int aaaa = 12; +# double b = 3.14; +AlignConsecutiveDeclarations: false + +# Align escaped newlines as far left as possible +# #define A \ +# int aaaa; \ +# int b; \ +# int cccccccc; +AlignEscapedNewlines: Left + +# Align operands of binary and ternary expressions +# int aaa = bbbbbbbbbbb + +# cccccc; +AlignOperands: true + +# Don't align trailing comments +# int a; // Comment a +# int b = 2; // Comment b +AlignTrailingComments: false + +# By default don't allow putting parameters onto the next line +# myFunction(foo, bar, baz); +AllowAllParametersOfDeclarationOnNextLine: false + +# Don't allow short braced statements to be on a single line +# if (a) not if (a) return; +# return; +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false + +# By default don't add a line break after the return type of top-level functions +# int foo(); +AlwaysBreakAfterReturnType: None + +# Pack as many parameters or arguments onto the same line as possible +# int myFunction(int aaaaaaaaaaaa, int bbbbbbbb, +# int cccc); +BinPackArguments: true +BinPackParameters: true + +# Attach braces to surrounding context except break before braces on function +# definitions. +# void foo() +# { +# if (true) { +# } else { +# } +# }; +BreakBeforeBraces: Linux + +# Break after operators +# int valuve = aaaaaaaaaaaaa + +# bbbbbb - +# ccccccccccc; +BreakBeforeBinaryOperators: None +BreakBeforeTernaryOperators: false + +# Don't break string literals +BreakStringLiterals: false + +# Use the same indentation level as for the switch statement. +# Switch statement body is always indented one level more than case labels. +IndentCaseLabels: false + +# Don't indent a function definition or declaration if it is wrapped after the +# type +IndentWrappedFunctionNames: false + +# Align pointer to the right +# int *a; +PointerAlignment: Right + +# Don't insert a space after a cast +# x = (int32)y; not x = (int32) y; +SpaceAfterCStyleCast: false + +# Insert spaces before and after assignment operators +# int a = 5; not int a=5; +# a += 42; a+=42; +SpaceBeforeAssignmentOperators: true + +# Put a space before opening parentheses only after control statement keywords. +# void f() { +# if (true) { +# f(); +# } +# } +SpaceBeforeParens: ControlStatements + +# Don't insert spaces inside empty '()' +SpaceInEmptyParentheses: false + +# The number of spaces before trailing line comments (// - comments). +# This does not affect trailing block comments (/* - comments). +SpacesBeforeTrailingComments: 1 + +# Don't insert spaces in casts +# x = (int32) y; not x = ( int32 ) y; +SpacesInCStyleCastParentheses: false + +# Don't insert spaces inside container literals +# var arr = [1, 2, 3]; not var arr = [ 1, 2, 3 ]; +SpacesInContainerLiterals: false + +# Don't insert spaces after '(' or before ')' +# f(arg); not f( arg ); +SpacesInParentheses: false + +# Don't insert spaces after '[' or before ']' +# int a[5]; not int a[ 5 ]; +SpacesInSquareBrackets: false + +# Insert a space after '{' and before '}' in struct initializers +Cpp11BracedListStyle: false + +# A list of macros that should be interpreted as foreach loops instead of as +# function calls. +ForEachMacros: ['for_each_string_list_item'] + +# The maximum number of consecutive empty lines to keep. +MaxEmptyLinesToKeep: 1 + +# No empty line at the start of a block. +KeepEmptyLinesAtTheStartOfBlocks: false + +# Penalties +# This decides what order things should be done if a line is too long +PenaltyBreakAssignment: 100 +PenaltyBreakBeforeFirstCallParameter: 100 +PenaltyBreakComment: 100 +PenaltyBreakFirstLessLess: 0 +PenaltyBreakString: 100 +PenaltyExcessCharacter: 5 +PenaltyReturnTypeOnItsOwnLine: 0 + +# Don't sort #include's +SortIncludes: false 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/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 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 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 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 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 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.15.0.txt b/Documentation/RelNotes/2.15.0.txt index 9b5c417b0e..290cad5287 100644 --- a/Documentation/RelNotes/2.15.0.txt +++ b/Documentation/RelNotes/2.15.0.txt @@ -80,6 +80,10 @@ UI, Workflows & Features * The codepath to call external process filter for smudge/clean operation learned to show the progress meter. + * "git rev-parse" learned "--is-shallow-repository", that is to be + used in a way similar to existing "--is-bare-repository" and + friends. + Performance, Internal Implementation, Development Support etc. @@ -167,6 +171,24 @@ Performance, Internal Implementation, Development Support etc. * Many leaks of strbuf have been fixed. + * "git imap-send" has our own implementation of the protocol and also + can use more recent libCurl with the imap protocol support. Update + the latter so that it can use the credential subsystem, and then + make it the default option to use, so that we can eventually + deprecate and remove the former. + + * "make style" runs git-clang-format to help developers by pointing + out coding style issues. + + * A test to demonstrate "git mv" failing to adjust nested submodules + has been added. + (merge c514167df2 hv/mv-nested-submodules-test later to maint). + + * On Cygwin, "ulimit -s" does not report failure but it does not work + at all, which causes an unexpected success of some tests that + expect failures under a limited stack situation. This has been + fixed. + Also contains various documentation updates and code clean-ups. @@ -296,6 +318,47 @@ Fixes since v2.14 to match the behaviour of the former. (merge c818e74332 rk/commit-tree-make-F-verbatim later to maint). + * Many codepaths did not diagnose write failures correctly when disks + go full, due to their misuse of write_in_full() helper function, + which have been corrected. + (merge f48ecd38cb jk/write-in-full-fix later to maint). + + * "git help co" now says "co is aliased to ...", not "git co is". + (merge b3a8076e0d ks/help-alias-label later to maint). + + * "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. + (merge 4318094047 rs/archive-excluded-directory later to maint). + + * API error-proofing which happens to also squelch warnings from GCC. + (merge c788c54cde tg/refs-allowed-flags later to maint). + + * The explanation of the cut-line in the commit log editor has been + slightly tweaked. + (merge 8c4b1a3593 ks/commit-do-not-touch-cut-line later to maint). + + * "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. + (merge afe2fab72c aw/gc-lockfile-fscanf-fix later to maint). + + * The scripts to drive TravisCI has been reorganized and then an + optimization to avoid spending cycles on a branch whose tip is + tagged has been implemented. + (merge 8376eb4a8f ls/travis-scriptify later to maint). + + * The test linter has been taught that we do not like "echo -e". + (merge 1a6d46895d tb/test-lint-echo-e later to maint). + + * Code cmp.std.c nitpick. + (merge ac7da78ede mh/for-each-string-list-item-empty-fix later to maint). + + * A regression fix for 2.11 that made the code to read the list of + alternate object stores overrun the end of the string. + (merge f0f7bebef7 jk/info-alternates-fix later to maint). + * Other minor doc, test and build updates and code cleanups. (merge f094b89a4d ma/parse-maybe-bool later to maint). (merge 39b00fa4d4 jk/drop-sha1-entry-pos later to maint). @@ -309,3 +372,7 @@ Fixes since v2.14 (merge 276d0e35c0 ma/split-symref-update-fix later to maint). (merge 3bc4b8f7c7 bb/doc-eol-dirty later to maint). (merge c1bb33c99c jk/system-path-cleanup later to maint). + (merge ab46e6fc72 cc/subprocess-handshake-missing-capabilities later to maint). + (merge f7a32dd97f kd/doc-for-each-ref later to maint). + (merge be94568bc7 ez/doc-duplicated-words-fix later to maint). + (merge 01e4be6c3d ks/test-readme-phrasofix later to maint). 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..bd268a8fcc 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -38,7 +38,7 @@ $ git checkout -b --track / ------------ + You could omit , 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. diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt index 9e5169aa64..bebdcdec5a 100644 --- a/Documentation/git-filter-branch.txt +++ b/Documentation/git-filter-branch.txt @@ -14,7 +14,7 @@ SYNOPSIS [--commit-filter ] [--tag-name-filter ] [--subdirectory-filter ] [--prune-empty] [--original ] [-d ] [-f | --force] - [--] [...] + [--state-branch ] [--] [...] DESCRIPTION ----------- @@ -198,6 +198,12 @@ to other tags will be rewritten to point to the underlying commit. directory or when there are already refs starting with 'refs/original/', unless forced. +--state-branch :: + This option will cause the mapping from old to new objects to + be loaded from named branch upon startup and saved as a new + commit to that branch upon exit, enabling incremental of large + trees. If '' does not exist it will be created. + ...:: Arguments for 'git rev-list'. All positive refs included by these options are rewritten. You may also specify options diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index bb370c9c7b..66b4e0a405 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=] [--shell|--perl|--python|--tcl] [(--sort=)...] [--format=] [...] - [--points-at ] [(--merged | --no-merged) []] - [--contains []] [--no-contains []] + [--points-at=] + (--merged[=] | --no-merged[=]) + [--contains[=]] [--no-contains[=]] DESCRIPTION ----------- @@ -25,19 +26,25 @@ host language allowing their direct evaluation in that language. OPTIONS ------- -:: +...:: + 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=:: By default the command shows all refs that match ``. This option makes it stop after showing that many refs. -:: +--sort=:: 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= option multiple times, in which case the last key becomes the primary key. -:: +--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,12 +57,6 @@ OPTIONS `xx`; for example `%00` interpolates to `\0` (NUL), `%09` to `\t` (TAB) and `%0a` to `\n` (LF). -...:: - 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. - --shell:: --perl:: --python:: @@ -65,24 +66,24 @@ OPTIONS the specified host language. This is meant to produce a scriptlet that can directly be `eval`ed. ---points-at :: +--points-at=:: Only list refs which points at the given object. ---merged []:: +--merged[=]:: Only list refs whose tips are reachable from the specified commit (HEAD if not specified), incompatible with `--no-merged`. ---no-merged []:: +--no-merged[=]:: Only list refs whose tips are not reachable from the specified commit (HEAD if not specified), incompatible with `--merged`. ---contains []:: +--contains[=]:: Only list refs which contain the specified commit (HEAD if not specified). ---no-contains []:: +--no-contains[=]:: Only list refs which don't contain the specified commit (HEAD if not specified). 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-rev-parse.txt b/Documentation/git-rev-parse.txt index b1293f24bb..0917b8207b 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -235,6 +235,9 @@ print a message to stderr and exit with nonzero status. --is-bare-repository:: When the repository is bare print "true", otherwise "false". +--is-shallow-repository:: + When the repository is shallow print "true", otherwise "false". + --resolve-git-dir :: Check if is a valid repository or a gitfile that points at a valid repository, and print the location of the 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-update-index.txt b/Documentation/git-update-index.txt index e19eba62cd..75c7dd9dea 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/Makefile b/Makefile index ed5960e6b3..ed4ca438bd 100644 --- a/Makefile +++ b/Makefile @@ -2457,6 +2457,10 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE .PHONY: sparse $(SP_OBJ) sparse: $(SP_OBJ) +.PHONY: style +style: + git clang-format --style file --diff --extensions c,h + check: common-cmds.h @if sparse; \ then \ diff --git a/apply.c b/apply.c index 71cbbd141c..c022af53a2 100644 --- a/apply.c +++ b/apply.c @@ -2920,6 +2920,7 @@ static int apply_one_fragment(struct apply_state *state, if (plen && (ws_rule & WS_BLANK_AT_EOF) && ws_blank_line(patch + 1, plen, ws_rule)) is_blank_context = 1; + /* fallthrough */ case '-': memcpy(old, patch + 1, plen); add_line_info(&preimage, old, plen, @@ -2927,7 +2928,7 @@ static int apply_one_fragment(struct apply_state *state, old += plen; if (first == '-') break; - /* Fall-through for ' ' */ + /* fallthrough */ case '+': /* --no-add does not add new lines */ if (first == '+' && state->no_add) diff --git a/archive.c b/archive.c index 1ab8d3a1d7..1e41f4bbeb 100644 --- a/archive.c +++ b/archive.c @@ -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; diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 4ccbfaac31..f5fa4fd75a 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -97,7 +97,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: must be " "", obj_name); @@ -107,12 +107,13 @@ 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: must be ", obj_name); if (textconv_object(path, obj_context.mode, &oid, 1, &buf, &size)) break; + /* else fallthrough */ case 'p': type = sha1_object_info(oid.hash, NULL); diff --git a/builtin/checkout.c b/builtin/checkout.c index 5c202b7af5..d091f06274 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -436,6 +436,7 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o, * update paths in the work tree, and we cannot revert * them. */ + /* fallthrough */ case 0: return 0; default: diff --git a/builtin/describe.c b/builtin/describe.c index e77163e909..3dc1836480 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -158,18 +158,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/gc.c b/builtin/gc.c index c22787ac72..3c5eae0edf 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -258,7 +258,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/get-tar-commit-id.c b/builtin/get-tar-commit-id.c index e21c5416cd..6d9a79f9b3 100644 --- a/builtin/get-tar-commit-id.c +++ b/builtin/get-tar-commit-id.c @@ -33,8 +33,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix) if (!skip_prefix(content, "52 comment=", &comment)) return 1; - n = write_in_full(1, comment, 41); - if (n < 41) + if (write_in_full(1, comment, 41) < 0) die_errno("git get-tar-commit-id: write error"); return 0; diff --git a/builtin/help.c b/builtin/help.c index b3f60a8f30..d3c8fc4082 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -441,7 +441,7 @@ static const char *check_git_cmd(const char* cmd) alias = alias_lookup(cmd); if (alias) { - printf_ln(_("`git %s' is aliased to `%s'"), cmd, alias); + printf_ln(_("'%s' is aliased to '%s'"), cmd, alias); free(alias); exit(0); } diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index a57b4f058d..f721137eaf 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -1012,7 +1012,7 @@ static int want_object_in_pack(const unsigned char *sha1, return want; } - for (entry = packed_git_mru->head; entry; entry = entry->next) { + for (entry = packed_git_mru.head; entry; entry = entry->next) { struct packed_git *p = entry->item; off_t offset; @@ -1030,7 +1030,7 @@ static int want_object_in_pack(const unsigned char *sha1, } want = want_found_object(exclude, p); if (!exclude && want > 0) - mru_mark(packed_git_mru, entry); + mru_mark(&packed_git_mru, entry); if (want != -1) return want; } diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 65d89078ab..29a0f3b75f 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -743,7 +743,7 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed, size_t n; if (feed(feed_state, &buf, &n)) break; - if (write_in_full(proc.in, buf, n) != n) + if (write_in_full(proc.in, buf, n) < 0) break; } close(proc.in); diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c index bfb21ba7d2..6a9127a33c 100644 --- a/builtin/remote-ext.c +++ b/builtin/remote-ext.c @@ -57,7 +57,7 @@ static char *strip_escapes(const char *str, const char *service, special = str[rpos]; if (rpos == 1) break; - /* Fall-through to error. */ + /* fallthrough */ default: die("Bad remote-ext placeholder '%%%c'.", str[rpos]); diff --git a/builtin/rerere.c b/builtin/rerere.c index ffb66e2907..0bc40298c2 100644 --- a/builtin/rerere.c +++ b/builtin/rerere.c @@ -18,7 +18,7 @@ static int outf(void *dummy, mmbuffer_t *ptr, int nbuf) { int i; for (i = 0; i < nbuf; i++) - if (write_in_full(1, ptr[i].ptr, ptr[i].size) != ptr[i].size) + if (write_in_full(1, ptr[i].ptr, ptr[i].size) < 0) return -1; return 0; } diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 9f24004c0a..b9c13d3d9d 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -868,6 +868,11 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) : "false"); continue; } + if (!strcmp(arg, "--is-shallow-repository")) { + printf("%s\n", is_repository_shallow() ? "true" + : "false"); + continue; + } if (!strcmp(arg, "--shared-index-path")) { if (read_cache() < 0) die(_("Could not read the index")); diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index ea49710893..06ed02f994 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -1187,6 +1187,7 @@ static int push_check(int argc, const char **argv, const char *prefix) break; die("HEAD does not match the named branch in the superproject"); } + /* fallthrough */ default: die("src refspec '%s' must name a ref", rs->src); diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c index 281ca1db6c..32e0155577 100644 --- a/builtin/unpack-file.c +++ b/builtin/unpack-file.c @@ -15,7 +15,7 @@ static char *create_temp_file(struct object_id *oid) xsnprintf(path, sizeof(path), ".merge_file_XXXXXX"); fd = xmkstemp(path); - if (write_in_full(fd, buf, size) != size) + if (write_in_full(fd, buf, size) < 0) die_errno("unable to write temp-file"); close(fd); return path; diff --git a/cache.h b/cache.h index a916bc79e3..49b083ee0a 100644 --- a/cache.h +++ b/cache.h @@ -4,6 +4,7 @@ #include "git-compat-util.h" #include "strbuf.h" #include "hashmap.h" +#include "mru.h" #include "advice.h" #include "gettext.h" #include "convert.h" @@ -1589,8 +1590,7 @@ extern struct packed_git { * A most-recently-used ordered version of the packed_git list, which can * be iterated instead of packed_git (and marked via mru_mark). */ -struct mru; -extern struct mru *packed_git_mru; +extern struct mru packed_git_mru; struct pack_entry { off_t offset; 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 diff --git a/config.c b/config.c index cd5a69e630..7ab37bacae 100644 --- a/config.c +++ b/config.c @@ -2292,10 +2292,11 @@ static int write_error(const char *filename) return 4; } -static int store_write_section(int fd, const char *key) +static ssize_t write_section(int fd, const char *key) { const char *dot; - int i, success; + int i; + ssize_t ret; struct strbuf sb = STRBUF_INIT; dot = memchr(key, '.', store.baselen); @@ -2311,15 +2312,16 @@ static int store_write_section(int fd, const char *key) strbuf_addf(&sb, "[%.*s]\n", store.baselen, key); } - success = write_in_full(fd, sb.buf, sb.len) == sb.len; + ret = write_in_full(fd, sb.buf, sb.len); strbuf_release(&sb); - return success; + return ret; } -static int store_write_pair(int fd, const char *key, const char *value) +static ssize_t write_pair(int fd, const char *key, const char *value) { - int i, success; + int i; + ssize_t ret; int length = strlen(key + store.baselen + 1); const char *quote = ""; struct strbuf sb = STRBUF_INIT; @@ -2353,16 +2355,17 @@ static int store_write_pair(int fd, const char *key, const char *value) case '"': case '\\': strbuf_addch(&sb, '\\'); + /* fallthrough */ default: strbuf_addch(&sb, value[i]); break; } strbuf_addf(&sb, "%s\n", quote); - success = write_in_full(fd, sb.buf, sb.len) == sb.len; + ret = write_in_full(fd, sb.buf, sb.len); strbuf_release(&sb); - return success; + return ret; } static ssize_t find_beginning_of_line(const char *contents, size_t size, @@ -2491,8 +2494,8 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, } store.key = (char *)key; - if (!store_write_section(fd, key) || - !store_write_pair(fd, key, value)) + if (write_section(fd, key) < 0 || + write_pair(fd, key, value) < 0) goto write_err_out; } else { struct stat st; @@ -2602,11 +2605,10 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, /* write the first part of the config */ if (copy_end > copy_begin) { if (write_in_full(fd, contents + copy_begin, - copy_end - copy_begin) < - copy_end - copy_begin) + copy_end - copy_begin) < 0) goto write_err_out; if (new_line && - write_str_in_full(fd, "\n") != 1) + write_str_in_full(fd, "\n") < 0) goto write_err_out; } copy_begin = store.offset[i]; @@ -2615,18 +2617,17 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, /* write the pair (value == NULL means unset) */ if (value != NULL) { if (store.state == START) { - if (!store_write_section(fd, key)) + if (write_section(fd, key) < 0) goto write_err_out; } - if (!store_write_pair(fd, key, value)) + if (write_pair(fd, key, value) < 0) goto write_err_out; } /* write the rest of the config */ if (copy_begin < contents_sz) if (write_in_full(fd, contents + copy_begin, - contents_sz - copy_begin) < - contents_sz - copy_begin) + contents_sz - copy_begin) < 0) goto write_err_out; munmap(contents, contents_sz); @@ -2803,7 +2804,7 @@ int git_config_rename_section_in_file(const char *config_filename, continue; } store.baselen = strlen(new_name); - if (!store_write_section(out_fd, new_name)) { + if (write_section(out_fd, new_name) < 0) { ret = write_error(get_lock_file_path(lock)); goto out; } @@ -2829,7 +2830,7 @@ int git_config_rename_section_in_file(const char *config_filename, if (remove) continue; length = strlen(output); - if (write_in_full(out_fd, output, length) != length) { + if (write_in_full(out_fd, output, length) < 0) { ret = write_error(get_lock_file_path(lock)); goto out; } diff --git a/convert.c b/convert.c index a09935cb81..20d7ab67bd 100644 --- a/convert.c +++ b/convert.c @@ -1545,8 +1545,9 @@ static int ident_filter_fn(struct stream_filter *filter, switch (ident->state) { default: strbuf_add(&ident->left, head, ident->state); + /* fallthrough */ case IDENT_SKIPPING: - /* fallthru */ + /* fallthrough */ case IDENT_DRAINING: ident_drain(ident, &output, osize_p); } diff --git a/diff.c b/diff.c index ea7e5978bc..3c6a3e0faa 100644 --- a/diff.c +++ b/diff.c @@ -3738,7 +3738,7 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp, blob = buf.buf; size = buf.len; } - if (write_in_full(temp->tempfile->fd, blob, size) != size || + if (write_in_full(temp->tempfile->fd, blob, size) < 0 || close_tempfile_gently(temp->tempfile)) die_errno("unable to write temp-file"); temp->name = get_tempfile_path(temp->tempfile); diff --git a/entry.c b/entry.c index cb291aa88b..1c7e3c11d5 100644 --- a/entry.c +++ b/entry.c @@ -257,7 +257,8 @@ static int write_entry(struct cache_entry *ce, char *new; struct strbuf buf = STRBUF_INIT; unsigned long size; - size_t wrote, newsize = 0; + ssize_t wrote; + size_t newsize = 0; struct stat st; const struct submodule *sub; @@ -332,7 +333,7 @@ static int write_entry(struct cache_entry *ce, fstat_done = fstat_output(fd, state, &st); close(fd); free(new); - if (wrote != size) + if (wrote < 0) return error("unable to write file %s", path); break; case S_IFGITLINK: diff --git a/fast-import.c b/fast-import.c index 49516d60e6..35bf671f12 100644 --- a/fast-import.c +++ b/fast-import.c @@ -2952,7 +2952,7 @@ static void parse_reset_branch(const char *arg) static void cat_blob_write(const char *buf, unsigned long size) { - if (write_in_full(cat_blob_fd, buf, size) != size) + if (write_in_full(cat_blob_fd, buf, size) < 0) die_errno("Write to frontend failed"); } diff --git a/fsck.c b/fsck.c index 2d2d2e9432..2ad00fc4d0 100644 --- a/fsck.c +++ b/fsck.c @@ -588,6 +588,7 @@ static int fsck_tree(struct tree *item, struct fsck_options *options) case S_IFREG | 0664: if (!options->strict) break; + /* fallthrough */ default: has_bad_modes = 1; } 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-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-filter-branch.sh b/git-filter-branch.sh index 3a74602ef3..3365a3b866 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -86,7 +86,7 @@ USAGE="[--setup ] [--env-filter ] [--parent-filter ] [--msg-filter ] [--commit-filter ] [--tag-name-filter ] [--subdirectory-filter ] [--original ] - [-d ] [-f | --force] + [-d ] [-f | --force] [--state-branch ] [--] [...]" OPTIONS_SPEC= @@ -106,6 +106,7 @@ filter_msg=cat filter_commit= filter_tag_name= filter_subdir= +state_branch= orig_namespace=refs/original/ force= prune_empty= @@ -181,6 +182,9 @@ do --original) orig_namespace=$(expr "$OPTARG/" : '\(.*[^/]\)/*$')/ ;; + --state-branch) + state_branch="$OPTARG" + ;; *) usage ;; @@ -219,6 +223,13 @@ trap 'cd "$orig_dir"; rm -rf "$tempdir"' 0 ORIG_GIT_DIR="$GIT_DIR" ORIG_GIT_WORK_TREE="$GIT_WORK_TREE" ORIG_GIT_INDEX_FILE="$GIT_INDEX_FILE" +ORIG_GIT_AUTHOR_NAME="$GIT_AUTHOR_NAME" +ORIG_GIT_AUTHOR_EMAIL="$GIT_AUTHOR_EMAIL" +ORIG_GIT_AUTHOR_DATE="$GIT_AUTHOR_DATE" +ORIG_GIT_COMMITTER_NAME="$GIT_COMMITTER_NAME" +ORIG_GIT_COMMITTER_EMAIL="$GIT_COMMITTER_EMAIL" +ORIG_GIT_COMMITTER_DATE="$GIT_COMMITTER_DATE" + GIT_WORK_TREE=. export GIT_DIR GIT_WORK_TREE @@ -252,6 +263,26 @@ export GIT_INDEX_FILE # map old->new commit ids for rewriting parents mkdir ../map || die "Could not create map/ directory" +if test -n "$state_branch" +then + state_commit=$(git rev-parse --no-flags --revs-only "$state_branch") + if test -n "$state_commit" + then + echo "Populating map from $state_branch ($state_commit)" 1>&2 + perl -e'open(MAP, "-|", "git show $ARGV[0]:filter.map") or die; + while () { + m/(.*):(.*)/ or die; + open F, ">../map/$1" or die; + print F "$2" or die; + close(F) or die; + } + close(MAP) or die;' "$state_commit" \ + || die "Unable to load state from $state_branch:filter.map" + else + echo "Branch $state_branch does not exist. Will create" 1>&2 + fi +fi + # we need "--" only if there are no path arguments in $@ nonrevs=$(git rev-parse --no-revs "$@") || exit if test -z "$nonrevs" @@ -530,7 +561,7 @@ if [ "$filter_tag_name" ]; then }' \ -e '/^-----BEGIN PGP SIGNATURE-----/q' \ -e 'p' ) | - git mktag) || + git hash-object -t tag -w --stdin) || die "Could not create new tag object for $ref" if git cat-file tag "$ref" | \ sane_grep '^-----BEGIN PGP SIGNATURE-----' >/dev/null 2>&1 @@ -544,12 +575,9 @@ if [ "$filter_tag_name" ]; then done fi -cd "$orig_dir" -rm -rf "$tempdir" - -trap - 0 - unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE +unset GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE +unset GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL GIT_COMMITTER_DATE test -z "$ORIG_GIT_DIR" || { GIT_DIR="$ORIG_GIT_DIR" && export GIT_DIR } @@ -561,6 +589,58 @@ test -z "$ORIG_GIT_INDEX_FILE" || { GIT_INDEX_FILE="$ORIG_GIT_INDEX_FILE" && export GIT_INDEX_FILE } +test -z "$ORIG_GIT_AUTHOR_NAME" || { + GIT_AUTHOR_NAME="$ORIG_GIT_AUTHOR_NAME" && + export GIT_AUTHOR_NAME +} +test -z "$ORIG_GIT_AUTHOR_EMAIL" || { + GIT_AUTHOR_EMAIL="$ORIG_GIT_AUTHOR_EMAIL" && + export GIT_AUTHOR_EMAIL +} +test -z "$ORIG_GIT_AUTHOR_DATE" || { + GIT_AUTHOR_DATE="$ORIG_GIT_AUTHOR_DATE" && + export GIT_AUTHOR_DATE +} +test -z "$ORIG_GIT_COMMITTER_NAME" || { + GIT_COMMITTER_NAME="$ORIG_GIT_COMMITTER_NAME" && + export GIT_COMMITTER_NAME +} +test -z "$ORIG_GIT_COMMITTER_EMAIL" || { + GIT_COMMITTER_EMAIL="$ORIG_GIT_COMMITTER_EMAIL" && + export GIT_COMMITTER_EMAIL +} +test -z "$ORIG_GIT_COMMITTER_DATE" || { + GIT_COMMITTER_DATE="$ORIG_GIT_COMMITTER_DATE" && + export GIT_COMMITTER_DATE +} + +if test -n "$state_branch" +then + echo "Saving rewrite state to $state_branch" 1>&2 + state_blob=$( + perl -e'opendir D, "../map" or die; + open H, "|-", "git hash-object -w --stdin" or die; + foreach (sort readdir(D)) { + next if m/^\.\.?$/; + open F, "<../map/$_" or die; + chomp($f = ); + print H "$_:$f\n" or die; + } + close(H) or die;' || die "Unable to save state") + state_tree=$(/bin/echo -e "100644 blob $state_blob\tfilter.map" | git mktree) + if test -n "$state_commit" + then + state_commit=$(/bin/echo "Sync" | git commit-tree "$state_tree" -p "$state_commit") + else + state_commit=$(/bin/echo "Sync" | git commit-tree "$state_tree" ) + fi + git update-ref "$state_branch" "$state_commit" +fi + +cd "$orig_dir" +rm -rf "$tempdir" + +trap - 0 if [ "$(is_bare_repository)" = false ]; then git read-tree -u -m HEAD || exit diff --git a/http-backend.c b/http-backend.c index b8ce960a35..f3dc218b2a 100644 --- a/http-backend.c +++ b/http-backend.c @@ -358,7 +358,7 @@ static void inflate_request(const char *prog_name, int out, int buffer_input) die("zlib error inflating request, result %d", ret); n = stream.total_out - cnt; - if (write_in_full(out, out_buf, n) != n) + if (write_in_full(out, out_buf, n) < 0) die("%s aborted reading request", prog_name); cnt += n; @@ -379,7 +379,7 @@ static void copy_request(const char *prog_name, int out) ssize_t n = read_request(0, &buf); if (n < 0) die_errno("error reading request body"); - if (write_in_full(out, buf, n) != n) + if (write_in_full(out, buf, n) < 0) die("%s aborted reading request", prog_name); close(out); free(buf); diff --git a/http-push.c b/http-push.c index e4c9b065ce..d860c477c6 100644 --- a/http-push.c +++ b/http-push.c @@ -1523,6 +1523,7 @@ static int remote_exists(const char *path) break; case HTTP_ERROR: error("unable to access '%s': %s", url, curl_errorstr); + /* fallthrough */ default: ret = -1; } diff --git a/http.c b/http.c index 9e40a465fd..713525f38e 100644 --- a/http.c +++ b/http.c @@ -638,9 +638,7 @@ static int curl_trace(CURL *handle, curl_infotype type, char *data, size_t size, switch (type) { case CURLINFO_TEXT: trace_printf_key(&trace_curl, "== Info: %s", data); - default: /* we ignore unknown types by default */ - return 0; - + break; case CURLINFO_HEADER_OUT: text = "=> Send header"; curl_dump_header(text, (unsigned char *)data, size, DO_FILTER); @@ -665,6 +663,9 @@ static int curl_trace(CURL *handle, curl_infotype type, char *data, size_t size, text = "<= Recv SSL data"; curl_dump_data(text, (unsigned char *)data, size); break; + + default: /* we ignore unknown types by default */ + return 0; } return 0; } diff --git a/imap-send.c b/imap-send.c index b2d0b849bb..8c785f3ca2 100644 --- a/imap-send.c +++ b/imap-send.c @@ -35,11 +35,11 @@ typedef void *SSL; #include "http.h" #endif -#if defined(USE_CURL_FOR_IMAP_SEND) && defined(NO_OPENSSL) -/* only available option */ +#if defined(USE_CURL_FOR_IMAP_SEND) +/* Always default to curl if it's available. */ #define USE_CURL_DEFAULT 1 #else -/* strictly opt in */ +/* We don't have curl, so continue to use the historical implementation */ #define USE_CURL_DEFAULT 0 #endif @@ -926,6 +926,25 @@ static int auth_cram_md5(struct imap_store *ctx, struct imap_cmd *cmd, const cha return 0; } +static void server_fill_credential(struct imap_server_conf *srvc, struct credential *cred) +{ + if (srvc->user && srvc->pass) + return; + + cred->protocol = xstrdup(srvc->use_ssl ? "imaps" : "imap"); + cred->host = xstrdup(srvc->host); + + cred->username = xstrdup_or_null(srvc->user); + cred->password = xstrdup_or_null(srvc->pass); + + credential_fill(cred); + + if (!srvc->user) + srvc->user = xstrdup(cred->username); + if (!srvc->pass) + srvc->pass = xstrdup(cred->password); +} + static struct imap_store *imap_open_store(struct imap_server_conf *srvc, char *folder) { struct credential cred = CREDENTIAL_INIT; @@ -1078,20 +1097,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, char *f } #endif imap_info("Logging in...\n"); - if (!srvc->user || !srvc->pass) { - cred.protocol = xstrdup(srvc->use_ssl ? "imaps" : "imap"); - cred.host = xstrdup(srvc->host); - - cred.username = xstrdup_or_null(srvc->user); - cred.password = xstrdup_or_null(srvc->pass); - - credential_fill(&cred); - - if (!srvc->user) - srvc->user = xstrdup(cred.username); - if (!srvc->pass) - srvc->pass = xstrdup(cred.password); - } + server_fill_credential(srvc, &cred); if (srvc->auth_method) { struct imap_cmd_cb cb; @@ -1392,7 +1398,7 @@ static int append_msgs_to_imap(struct imap_server_conf *server, } #ifdef USE_CURL_FOR_IMAP_SEND -static CURL *setup_curl(struct imap_server_conf *srvc) +static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred) { CURL *curl; struct strbuf path = STRBUF_INIT; @@ -1405,6 +1411,7 @@ static CURL *setup_curl(struct imap_server_conf *srvc) if (!curl) die("curl_easy_init failed"); + server_fill_credential(&server, cred); curl_easy_setopt(curl, CURLOPT_USERNAME, server.user); curl_easy_setopt(curl, CURLOPT_PASSWORD, server.pass); @@ -1454,8 +1461,9 @@ static int curl_append_msgs_to_imap(struct imap_server_conf *server, struct buffer msgbuf = { STRBUF_INIT, 0 }; CURL *curl; CURLcode res = CURLE_OK; + struct credential cred = CREDENTIAL_INIT; - curl = setup_curl(server); + curl = setup_curl(server, &cred); curl_easy_setopt(curl, CURLOPT_READDATA, &msgbuf); fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : ""); @@ -1490,7 +1498,20 @@ static int curl_append_msgs_to_imap(struct imap_server_conf *server, curl_easy_cleanup(curl); curl_global_cleanup(); - return 0; + if (cred.username) { + if (res == CURLE_OK) + credential_approve(&cred); +#if LIBCURL_VERSION_NUM >= 0x070d01 + else if (res == CURLE_LOGIN_DENIED) +#else + else +#endif + credential_reject(&cred); + } + + credential_clear(&cred); + + return res != CURLE_OK; } #endif diff --git a/ll-merge.c b/ll-merge.c index 9fb855a900..a6ad2ec12d 100644 --- a/ll-merge.c +++ b/ll-merge.c @@ -154,7 +154,7 @@ static void create_temp(mmfile_t *src, char *path, size_t len) xsnprintf(path, len, ".merge_file_XXXXXX"); fd = xmkstemp(path); - if (write_in_full(fd, src->ptr, src->size) != src->size) + if (write_in_full(fd, src->ptr, src->size) < 0) die_errno("unable to write temp-file"); close(fd); } diff --git a/mailinfo.c b/mailinfo.c index f2387a3267..a89db22ab0 100644 --- a/mailinfo.c +++ b/mailinfo.c @@ -367,11 +367,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; @@ -822,6 +827,7 @@ static void handle_filter(struct mailinfo *mi, struct strbuf *line) if (!handle_commit_msg(mi, line)) break; mi->filter_stage++; + /* fallthrough */ case 1: handle_patch(mi, line); break; diff --git a/notes-merge.c b/notes-merge.c index b04d2f2131..597d43f65c 100644 --- a/notes-merge.c +++ b/notes-merge.c @@ -302,7 +302,7 @@ static void write_buf_to_worktree(const struct object_id *obj, fd = xopen(path, O_WRONLY | O_EXCL | O_CREAT, 0666); while (size > 0) { - long ret = write_in_full(fd, buf, size); + ssize_t ret = write_in_full(fd, buf, size); if (ret < 0) { /* Ignore epipe */ if (errno == EPIPE) diff --git a/packfile.c b/packfile.c index f86fa051c9..f69a5c8d60 100644 --- a/packfile.c +++ b/packfile.c @@ -40,9 +40,7 @@ static unsigned int pack_max_fds; static size_t peak_pack_mapped; static size_t pack_mapped; struct packed_git *packed_git; - -static struct mru packed_git_mru_storage; -struct mru *packed_git_mru = &packed_git_mru_storage; +struct mru packed_git_mru; #define SZ_FMT PRIuMAX static inline uintmax_t sz_fmt(size_t s) { return s; } @@ -861,9 +859,9 @@ static void prepare_packed_git_mru(void) { struct packed_git *p; - mru_clear(packed_git_mru); + mru_clear(&packed_git_mru); for (p = packed_git; p; p = p->next) - mru_append(packed_git_mru, p); + mru_append(&packed_git_mru, p); } static int prepare_packed_git_run_once = 0; @@ -1832,9 +1830,9 @@ int find_pack_entry(const unsigned char *sha1, struct pack_entry *e) if (!packed_git) return 0; - for (p = packed_git_mru->head; p; p = p->next) { + for (p = packed_git_mru.head; p; p = p->next) { if (fill_pack_entry(sha1, e, p->item)) { - mru_mark(packed_git_mru, p); + mru_mark(&packed_git_mru, p); return 1; } } diff --git a/pathspec.c b/pathspec.c index e2a23ebc96..cdefdc7cc0 100644 --- a/pathspec.c +++ b/pathspec.c @@ -526,10 +526,6 @@ static void NORETURN unsupported_magic(const char *pattern, pattern, sb.buf); } -/* - * Given command line arguments and a prefix, convert the input to - * pathspec. die() if any magic in magic_mask is used. - */ void parse_pathspec(struct pathspec *pathspec, unsigned magic_mask, unsigned flags, const char *prefix, const char **argv) diff --git a/pathspec.h b/pathspec.h index 60e6500401..6420d1080a 100644 --- a/pathspec.h +++ b/pathspec.h @@ -70,6 +70,13 @@ struct pathspec { */ #define PATHSPEC_LITERAL_PATH (1<<6) +/* + * Given command line arguments and a prefix, convert the input to + * pathspec. die() if any magic in magic_mask is used. + * + * Any arguments used are copied. It is safe for the caller to modify + * or free 'prefix' and 'args' after calling this function. + */ extern void parse_pathspec(struct pathspec *pathspec, unsigned magic_mask, unsigned flags, diff --git a/pkt-line.c b/pkt-line.c index f364944b93..647bbd3bce 100644 --- a/pkt-line.c +++ b/pkt-line.c @@ -94,9 +94,9 @@ void packet_flush(int fd) int packet_flush_gently(int fd) { packet_trace("0000", 4, 1); - if (write_in_full(fd, "0000", 4) == 4) - return 0; - return error("flush packet write failed"); + if (write_in_full(fd, "0000", 4) < 0) + return error("flush packet write failed"); + return 0; } void packet_buf_flush(struct strbuf *buf) @@ -137,19 +137,18 @@ static int packet_write_fmt_1(int fd, int gently, const char *fmt, va_list args) { static struct strbuf buf = STRBUF_INIT; - ssize_t count; strbuf_reset(&buf); format_packet(&buf, fmt, args); - count = write_in_full(fd, buf.buf, buf.len); - if (count == buf.len) - return 0; - - if (!gently) { - check_pipe(errno); - die_errno("packet write with format failed"); + if (write_in_full(fd, buf.buf, buf.len) < 0) { + if (!gently) { + check_pipe(errno); + die_errno("packet write with format failed"); + } + return error("packet write with format failed"); } - return error("packet write with format failed"); + + return 0; } void packet_write_fmt(int fd, const char *fmt, ...) @@ -184,9 +183,9 @@ static int packet_write_gently(const int fd_out, const char *buf, size_t size) packet_size = size + 4; set_packet_header(packet_write_buffer, packet_size); memcpy(packet_write_buffer + 4, buf, size); - if (write_in_full(fd_out, packet_write_buffer, packet_size) == packet_size) - return 0; - return error("packet write failed"); + if (write_in_full(fd_out, packet_write_buffer, packet_size) < 0) + return error("packet write failed"); + return 0; } void packet_buf_write(struct strbuf *buf, const char *fmt, ...) diff --git a/quote.c b/quote.c index 53b98a5b84..de2922ddd6 100644 --- a/quote.c +++ b/quote.c @@ -431,6 +431,7 @@ void tcl_quote_buf(struct strbuf *sb, const char *src) case '{': case '}': case '$': case '\\': case '"': strbuf_addch(sb, '\\'); + /* fallthrough */ default: strbuf_addch(sb, c); break; diff --git a/read-cache.c b/read-cache.c index b211c57af6..65f4fe8375 100644 --- a/read-cache.c +++ b/read-cache.c @@ -220,6 +220,7 @@ static int ce_modified_check_fs(const struct cache_entry *ce, struct stat *st) case S_IFDIR: if (S_ISGITLINK(ce->ce_mode)) return ce_compare_gitlink(ce) ? DATA_CHANGED : 0; + /* else fallthrough */ default: return TYPE_CHANGED; } @@ -1922,7 +1923,7 @@ static int ce_write_flush(git_SHA_CTX *context, int fd) unsigned int buffered = write_buffer_len; if (buffered) { git_SHA1_Update(context, write_buffer, buffered); - if (write_in_full(fd, write_buffer, buffered) != buffered) + if (write_in_full(fd, write_buffer, buffered) < 0) return -1; write_buffer_len = 0; } @@ -1971,7 +1972,7 @@ static int ce_flush(git_SHA_CTX *context, int fd, unsigned char *sha1) /* Flush first if not enough space for SHA1 signature */ if (left + 20 > WRITE_BUFFER_SIZE) { - if (write_in_full(fd, write_buffer, left) != left) + if (write_in_full(fd, write_buffer, left) < 0) return -1; left = 0; } @@ -1980,7 +1981,7 @@ static int ce_flush(git_SHA_CTX *context, int fd, unsigned char *sha1) git_SHA1_Final(write_buffer + left, context); hashcpy(sha1, write_buffer + left); left += 20; - return (write_in_full(fd, write_buffer, left) != left) ? -1 : 0; + return (write_in_full(fd, write_buffer, left) < 0) ? -1 : 0; } static void ce_smudge_racily_clean_entry(struct cache_entry *ce) @@ -2103,7 +2104,9 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce, if (!result) result = ce_write(c, fd, to_remove_vi, prefix_size); if (!result) - result = ce_write(c, fd, ce->name + common, ce_namelen(ce) - common + 1); + result = ce_write(c, fd, ce->name + common, ce_namelen(ce) - common); + if (!result) + result = ce_write(c, fd, padding, 1); strbuf_splice(previous_name, common, to_remove, ce->name + common, ce_namelen(ce) - common); diff --git a/refs.c b/refs.c index 97e33fdc7b..6042645c40 100644 --- a/refs.c +++ b/refs.c @@ -607,7 +607,7 @@ static int write_pseudoref(const char *pseudoref, const unsigned char *sha1, } } - if (write_in_full(fd, buf.buf, buf.len) != buf.len) { + if (write_in_full(fd, buf.buf, buf.len) < 0) { strbuf_addf(err, "could not write to '%s'", filename); rollback_lock_file(&lock); goto done; @@ -937,6 +937,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, @@ -1355,7 +1357,7 @@ int for_each_replace_ref(each_ref_fn fn, void *cb_data) return do_for_each_ref(get_main_ref_store(), git_replace_ref_base, fn, strlen(git_replace_ref_base), - 0, cb_data); + DO_FOR_EACH_INCLUDE_BROKEN, cb_data); } int for_each_namespaced_ref(each_ref_fn fn, void *cb_data) diff --git a/refs.h b/refs.h index 996d4ea54d..e1c5803f9a 100644 --- a/refs.h +++ b/refs.h @@ -345,6 +345,14 @@ int refs_pack_refs(struct ref_store *refs, unsigned int flags); #define REF_NODEREF 0x01 #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. */ diff --git a/refs/files-backend.c b/refs/files-backend.c index a3134d23ab..fec77744b4 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -1549,7 +1549,7 @@ static int log_ref_write_fd(int fd, const struct object_id *old_oid, written = len <= maxlen ? write_in_full(fd, logrec, len) : -1; free(logrec); - if (written != len) + if (written < 0) return -1; return 0; @@ -1628,8 +1628,8 @@ static int write_ref_to_lockfile(struct ref_lock *lock, return -1; } fd = get_lock_file_fd(&lock->lk); - if (write_in_full(fd, oid_to_hex(oid), GIT_SHA1_HEXSZ) != GIT_SHA1_HEXSZ || - write_in_full(fd, &term, 1) != 1 || + if (write_in_full(fd, oid_to_hex(oid), GIT_SHA1_HEXSZ) < 0 || + write_in_full(fd, &term, 1) < 0 || close_ref_gently(lock) < 0) { strbuf_addf(err, "couldn't write '%s'", get_lock_file_path(&lock->lk)); @@ -3005,8 +3005,8 @@ static int files_reflog_expire(struct ref_store *ref_store, rollback_lock_file(&reflog_lock); } else if (update && (write_in_full(get_lock_file_fd(&lock->lk), - oid_to_hex(&cb.last_kept_oid), GIT_SHA1_HEXSZ) != GIT_SHA1_HEXSZ || - write_str_in_full(get_lock_file_fd(&lock->lk), "\n") != 1 || + oid_to_hex(&cb.last_kept_oid), GIT_SHA1_HEXSZ) < 0 || + write_str_in_full(get_lock_file_fd(&lock->lk), "\n") < 1 || close_ref_gently(lock) < 0)) { status |= error("couldn't write %s", get_lock_file_path(&lock->lk)); diff --git a/rerere.c b/rerere.c index d77235645e..1ce440f4bb 100644 --- a/rerere.c +++ b/rerere.c @@ -258,7 +258,7 @@ static int write_rr(struct string_list *rr, int out_fd) rerere_id_hex(id), rr->items[i].string, 0); - if (write_in_full(out_fd, buf.buf, buf.len) != buf.len) + if (write_in_full(out_fd, buf.buf, buf.len) < 0) die("unable to write rerere record"); strbuf_release(&buf); diff --git a/revision.c b/revision.c index 9582a727ca..613168d397 100644 --- a/revision.c +++ b/revision.c @@ -21,6 +21,7 @@ #include "bisect.h" #include "packfile.h" #include "worktree.h" +#include "argv-array.h" volatile show_early_output_fn_t show_early_output; @@ -1672,31 +1673,15 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi return 0; } -struct cmdline_pathspec { - int alloc; - int nr; - const char **path; -}; - -static void append_prune_data(struct cmdline_pathspec *prune, const char **av) -{ - while (*av) { - ALLOC_GROW(prune->path, prune->nr + 1, prune->alloc); - prune->path[prune->nr++] = *(av++); - } -} - static void read_pathspec_from_stdin(struct rev_info *revs, struct strbuf *sb, - struct cmdline_pathspec *prune) + struct argv_array *prune) { - while (strbuf_getline(sb, stdin) != EOF) { - ALLOC_GROW(prune->path, prune->nr + 1, prune->alloc); - prune->path[prune->nr++] = xstrdup(sb->buf); - } + while (strbuf_getline(sb, stdin) != EOF) + argv_array_push(prune, sb->buf); } static void read_revisions_from_stdin(struct rev_info *revs, - struct cmdline_pathspec *prune) + struct argv_array *prune) { struct strbuf sb; int seen_dashdash = 0; @@ -2285,10 +2270,9 @@ static void NORETURN diagnose_missing_default(const char *def) int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *opt) { int i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0, revarg_opt; - struct cmdline_pathspec prune_data; + struct argv_array prune_data = ARGV_ARRAY_INIT; const char *submodule = NULL; - memset(&prune_data, 0, sizeof(prune_data)); if (opt) submodule = opt->submodule; @@ -2304,7 +2288,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s argv[i] = NULL; argc = i; if (argv[i + 1]) - append_prune_data(&prune_data, argv + i + 1); + argv_array_pushv(&prune_data, argv + i + 1); seen_dashdash = 1; break; } @@ -2365,14 +2349,14 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s for (j = i; j < argc; j++) verify_filename(revs->prefix, argv[j], j == i); - append_prune_data(&prune_data, argv + i); + argv_array_pushv(&prune_data, argv + i); break; } else got_rev_arg = 1; } - if (prune_data.nr) { + if (prune_data.argc) { /* * If we need to introduce the magic "a lone ':' means no * pathspec whatsoever", here is the place to do so. @@ -2387,11 +2371,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s * call init_pathspec() to set revs->prune_data here. * } */ - ALLOC_GROW(prune_data.path, prune_data.nr + 1, prune_data.alloc); - prune_data.path[prune_data.nr++] = NULL; parse_pathspec(&revs->prune_data, 0, 0, - revs->prefix, prune_data.path); + revs->prefix, prune_data.argv); } + argv_array_clear(&prune_data); if (revs->def == NULL) revs->def = opt ? opt->def : NULL; diff --git a/send-pack.c b/send-pack.c index b865f662e4..a8cc6b266e 100644 --- a/send-pack.c +++ b/send-pack.c @@ -497,7 +497,7 @@ int send_pack(struct send_pack_args *args, strbuf_release(&cap_buf); return atomic_push_failure(args, remote_refs, ref); } - /* Fallthrough for non atomic case. */ + /* else fallthrough */ default: continue; } diff --git a/sha1_file.c b/sha1_file.c index b4a67bb838..5a2014811f 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -398,7 +398,7 @@ static const char *parse_alt_odb_entry(const char *string, return end; } -static void link_alt_odb_entries(const char *alt, int len, int sep, +static void link_alt_odb_entries(const char *alt, int sep, const char *relative_base, int depth) { struct strbuf objdirbuf = STRBUF_INIT; @@ -427,28 +427,19 @@ static void link_alt_odb_entries(const char *alt, int len, int sep, static void read_info_alternates(const char * relative_base, int depth) { - char *map; - size_t mapsz; - struct stat st; char *path; - int fd; + struct strbuf buf = STRBUF_INIT; path = xstrfmt("%s/info/alternates", relative_base); - fd = git_open(path); - free(path); - if (fd < 0) - return; - if (fstat(fd, &st) || (st.st_size == 0)) { - close(fd); + if (strbuf_read_file(&buf, path, 1024) < 0) { + warn_on_fopen_errors(path); + free(path); return; } - mapsz = xsize_t(st.st_size); - map = xmmap(NULL, mapsz, PROT_READ, MAP_PRIVATE, fd, 0); - close(fd); - - link_alt_odb_entries(map, mapsz, '\n', relative_base, depth); - munmap(map, mapsz); + link_alt_odb_entries(buf.buf, '\n', relative_base, depth); + strbuf_release(&buf); + free(path); } struct alternate_object_database *alloc_alt_odb(const char *dir) @@ -503,7 +494,7 @@ void add_to_alternates_file(const char *reference) if (commit_lock_file(lock)) die_errno("unable to move new alternates file into place"); if (alt_odb_tail) - link_alt_odb_entries(reference, strlen(reference), '\n', NULL, 0); + link_alt_odb_entries(reference, '\n', NULL, 0); } free(alts); } @@ -516,7 +507,7 @@ void add_to_alternates_memory(const char *reference) */ prepare_alt_odb(); - link_alt_odb_entries(reference, strlen(reference), '\n', NULL, 0); + link_alt_odb_entries(reference, '\n', NULL, 0); } /* @@ -619,7 +610,7 @@ void prepare_alt_odb(void) if (!alt) alt = ""; alt_odb_tail = &alt_odb_list; - link_alt_odb_entries(alt, strlen(alt), PATH_SEP, NULL, 0); + link_alt_odb_entries(alt, PATH_SEP, NULL, 0); read_info_alternates(get_object_directory(), 0); } @@ -1850,7 +1841,7 @@ int index_path(struct object_id *oid, const char *path, struct stat *st, unsigne int read_pack_header(int fd, struct pack_header *header) { - if (read_in_full(fd, header, sizeof(*header)) < sizeof(*header)) + if (read_in_full(fd, header, sizeof(*header)) != sizeof(*header)) /* "eof before pack header was fully read" */ return PH_ERROR_EOF; diff --git a/shallow.c b/shallow.c index 1cc1c76415..eabb65d3a7 100644 --- a/shallow.c +++ b/shallow.c @@ -294,7 +294,7 @@ const char *setup_temporary_shallow(const struct oid_array *extra) if (write_shallow_commits(&sb, 0, extra)) { temp = xmks_tempfile(git_path("shallow_XXXXXX")); - if (write_in_full(temp->fd, sb.buf, sb.len) != sb.len || + if (write_in_full(temp->fd, sb.buf, sb.len) < 0 || close_tempfile_gently(temp) < 0) die_errno("failed to write to %s", get_tempfile_path(temp)); @@ -319,7 +319,7 @@ void setup_alternate_shallow(struct lock_file *shallow_lock, LOCK_DIE_ON_ERROR); check_shallow_file_for_update(); if (write_shallow_commits(&sb, 0, extra)) { - if (write_in_full(fd, sb.buf, sb.len) != sb.len) + if (write_in_full(fd, sb.buf, sb.len) < 0) die_errno("failed to write to %s", get_lock_file_path(shallow_lock)); *alternate_shallow_file = get_lock_file_path(shallow_lock); @@ -366,7 +366,7 @@ void prune_shallow(int show_only) LOCK_DIE_ON_ERROR); check_shallow_file_for_update(); if (write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY)) { - if (write_in_full(fd, sb.buf, sb.len) != sb.len) + if (write_in_full(fd, sb.buf, sb.len) < 0) die_errno("failed to write to %s", get_lock_file_path(&shallow_lock)); commit_lock_file(&shallow_lock); diff --git a/shell.c b/shell.c index fe2d314593..234b2d4f16 100644 --- a/shell.c +++ b/shell.c @@ -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 }, }; diff --git a/streaming.c b/streaming.c index 6f1c60f12b..5892b50bd8 100644 --- a/streaming.c +++ b/streaming.c @@ -540,7 +540,7 @@ int stream_blob_to_fd(int fd, const struct object_id *oid, struct stream_filter kept = 0; wrote = write_in_full(fd, buf, readlen); - if (wrote != readlen) + if (wrote < 0) goto close_and_exit; } if (kept && (lseek(fd, kept - 1, SEEK_CUR) == (off_t) -1 || 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 6ccfaaba99..6dde5062be 100644 --- a/sub-process.c +++ b/sub-process.c @@ -184,8 +184,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.c b/submodule.c index 075c55f3ca..b12600fc79 100644 --- a/submodule.c +++ b/submodule.c @@ -774,19 +774,36 @@ static int append_oid_to_argv(const struct object_id *oid, void *data) return 0; } +struct has_commit_data { + int result; + const char *path; +}; + static int check_has_commit(const struct object_id *oid, void *data) { - int *has_commit = data; + struct has_commit_data *cb = data; - if (!lookup_commit_reference(oid)) - *has_commit = 0; + enum object_type type = sha1_object_info(oid->hash, NULL); - return 0; + switch (type) { + case OBJ_COMMIT: + return 0; + case OBJ_BAD: + /* + * Object is missing or invalid. If invalid, an error message + * has already been printed. + */ + cb->result = 0; + return 0; + default: + die(_("submodule entry '%s' (%s) is a %s, not a commit"), + cb->path, oid_to_hex(oid), typename(type)); + } } static int submodule_has_commits(const char *path, struct oid_array *commits) { - int has_commit = 1; + struct has_commit_data has_commit = { 1, path }; /* * Perform a cheap, but incorrect check for the existence of 'commits'. @@ -802,7 +819,7 @@ static int submodule_has_commits(const char *path, struct oid_array *commits) oid_array_for_each_unique(commits, check_has_commit, &has_commit); - if (has_commit) { + if (has_commit.result) { /* * Even if the submodule is checked out and the commit is * present, make sure it exists in the submodule's object store @@ -821,12 +838,12 @@ static int submodule_has_commits(const char *path, struct oid_array *commits) cp.dir = path; if (capture_command(&cp, &out, GIT_MAX_HEXSZ + 1) || out.len) - has_commit = 0; + has_commit.result = 0; strbuf_release(&out); } - return has_commit; + return has_commit.result; } static int submodule_needs_pushing(const char *path, struct oid_array *commits) diff --git a/submodule.h b/submodule.h index 6b52133c88..f0da0277a4 100644 --- a/submodule.h +++ b/submodule.h @@ -120,7 +120,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); diff --git a/t/README b/t/README index 2f95860369..4b079e4494 100644 --- a/t/README +++ b/t/README @@ -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/.gitignore b/t/helper/.gitignore index 721650256e..7c9d28a834 100644 --- a/t/helper/.gitignore +++ b/t/helper/.gitignore @@ -35,3 +35,4 @@ /test-svn-fe /test-urlmatch-normalization /test-wildmatch +/test-write-cache diff --git a/t/helper/test-delta.c b/t/helper/test-delta.c index 59937dc1be..591730adc4 100644 --- a/t/helper/test-delta.c +++ b/t/helper/test-delta.c @@ -69,7 +69,7 @@ int cmd_main(int argc, const char **argv) } fd = open (argv[4], O_WRONLY|O_CREAT|O_TRUNC, 0666); - if (fd < 0 || write_in_full(fd, out_buf, out_size) != out_size) { + if (fd < 0 || write_in_full(fd, out_buf, out_size) < 0) { perror(argv[4]); return 1; } diff --git a/t/helper/test-line-buffer.c b/t/helper/test-line-buffer.c index 81575fe2ab..078dd7e29d 100644 --- a/t/helper/test-line-buffer.c +++ b/t/helper/test-line-buffer.c @@ -17,27 +17,17 @@ static uint32_t strtouint32(const char *s) static void handle_command(const char *command, const char *arg, struct line_buffer *buf) { - switch (*command) { - case 'b': - if (starts_with(command, "binary ")) { - struct strbuf sb = STRBUF_INIT; - strbuf_addch(&sb, '>'); - buffer_read_binary(buf, &sb, strtouint32(arg)); - fwrite(sb.buf, 1, sb.len, stdout); - strbuf_release(&sb); - return; - } - case 'c': - if (starts_with(command, "copy ")) { - buffer_copy_bytes(buf, strtouint32(arg)); - return; - } - case 's': - if (starts_with(command, "skip ")) { - buffer_skip_bytes(buf, strtouint32(arg)); - return; - } - default: + if (starts_with(command, "binary ")) { + struct strbuf sb = STRBUF_INIT; + strbuf_addch(&sb, '>'); + buffer_read_binary(buf, &sb, strtouint32(arg)); + fwrite(sb.buf, 1, sb.len, stdout); + strbuf_release(&sb); + } else if (starts_with(command, "copy ")) { + buffer_copy_bytes(buf, strtouint32(arg)); + } else if (starts_with(command, "skip ")) { + buffer_skip_bytes(buf, strtouint32(arg)); + } else { die("unrecognized command: %s", command); } } diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index dc98b4bc6d..664a3a4e4e 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -1253,7 +1253,10 @@ run_with_limited_open_files () { (ulimit -n 32 && "$@") } -test_lazy_prereq ULIMIT_FILE_DESCRIPTORS 'run_with_limited_open_files true' +test_lazy_prereq ULIMIT_FILE_DESCRIPTORS ' + test_have_prereq !MINGW,!CYGWIN && + run_with_limited_open_files true +' test_expect_success ULIMIT_FILE_DESCRIPTORS 'large transaction creating branches does not burst open file limit' ' ( diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh index 03d3c7f6d6..5c715fe2cf 100755 --- a/t/t1500-rev-parse.sh +++ b/t/t1500-rev-parse.sh @@ -116,6 +116,21 @@ test_expect_success 'git-path inside sub-dir' ' test_cmp expect actual ' +test_expect_success 'rev-parse --is-shallow-repository in shallow repo' ' + test_commit test_commit && + echo true >expect && + git clone --depth 1 --no-local . shallow && + test_when_finished "rm -rf shallow" && + git -C shallow rev-parse --is-shallow-repository >actual && + test_cmp expect actual +' + +test_expect_success 'rev-parse --is-shallow-repository in non-shallow repo' ' + echo false >expect && + git rev-parse --is-shallow-repository >actual && + test_cmp expect actual +' + test_expect_success 'showing the superproject correctly' ' git rev-parse --show-superproject-working-tree >out && test_must_be_empty out && 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/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh index 0f84a53146..39cb2c1c34 100755 --- a/t/t5531-deep-submodule-push.sh +++ b/t/t5531-deep-submodule-push.sh @@ -298,6 +298,16 @@ test_expect_success 'push succeeds if submodule commit disabling recursion from ) ' +test_expect_success 'submodule entry pointing at a tag is error' ' + git -C work/gar/bage tag -a test1 -m "tag" && + tag=$(git -C work/gar/bage rev-parse test1^{tag}) && + git -C work update-index --cacheinfo 160000 "$tag" gar/bage && + git -C work commit -m "bad commit" && + test_when_finished "git -C work reset --hard HEAD^" && + test_must_fail git -C work push --recurse-submodules=on-demand ../pub.git master 2>err && + test_i18ngrep "is a tag, not a commit" err +' + test_expect_success 'push fails if recurse submodules option passed as yes' ' ( cd work/gar/bage && diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh index aa74eb8f0d..70d92d24cb 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) && @@ -198,6 +202,31 @@ test_expect_success 'name-rev with exact tags' ' test_cmp expect actual ' +test_expect_success 'name-rev --all' ' + >expect.unsorted && + for rev in $(git rev-list --all) + do + git name-rev $rev >>expect.unsorted + done && + sort expect && + git name-rev --all >actual.unsorted && + sort actual && + test_cmp expect actual +' + +test_expect_success 'name-rev --stdin' ' + >expect.unsorted && + for rev in $(git rev-list --all) + do + name=$(git name-rev --name-only $rev) && + echo "$rev ($name)" >>expect.unsorted + done && + sort expect && + git rev-list --all | git name-rev --stdin >actual.unsorted && + sort actual && + test_cmp expect actual +' + test_expect_success 'describe --contains with the exact tags' ' echo "A^0" >expect && tag_object=$(git rev-parse refs/tags/A) && @@ -250,7 +279,38 @@ test_expect_success 'describe chokes on severely broken submodules' ' ' test_expect_success 'describe ignoring a borken submodule' ' git describe --broken >out && + test_when_finished "mv .git/modules/sub_moved .git/modules/sub1" && grep broken out ' +test_expect_failure ULIMIT_STACK_SIZE 'name-rev works in a deep repo' ' + i=1 && + while test $i -lt 8000 + do + echo "commit refs/heads/master +committer A U Thor $((1000000000 + $i * 100)) +0200 +data <expect && + git name-rev HEAD~4000 >actual && + test_cmp expect actual && + run_with_limited_stack git name-rev HEAD~4000 >actual && + test_cmp expect actual +' + +test_expect_success ULIMIT_STACK_SIZE 'describe works in a deep repo' ' + git tag -f far-far-away HEAD~7999 && + echo "far-far-away" >expect && + git describe --tags --abbrev=0 HEAD~4000 >actual && + test_cmp expect actual && + run_with_limited_stack git describe --tags --abbrev=0 HEAD~4000 >actual && + test_cmp expect actual +' + test_done diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index e365d1ff77..cbc5fb37fe 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -491,4 +491,29 @@ test_expect_success 'moving a submodule in nested directories' ' test_cmp actual expect ' +test_expect_failure 'moving nested submodules' ' + git commit -am "cleanup commit" && + mkdir sub_nested_nested && + (cd sub_nested_nested && + touch nested_level2 && + git init && + git add . && + git commit -m "nested level 2" + ) && + mkdir sub_nested && + (cd sub_nested && + touch nested_level1 && + git init && + git add . && + git commit -m "nested level 1" + git submodule add ../sub_nested_nested && + git commit -m "add nested level 2" + ) && + git submodule add ./sub_nested nested_move && + git commit -m "add nested_move" && + git submodule update --init --recursive && + git mv nested_move sub_nested_moved && + git status +' + test_done diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index dbcd6f623c..b545c33f83 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -1863,13 +1863,6 @@ test_expect_success 'version sort with very long prerelease suffix' ' git tag -l --sort=version:refname ' -run_with_limited_stack () { - (ulimit -s 128 && "$@") -} - -test_lazy_prereq ULIMIT_STACK_SIZE 'run_with_limited_stack true' - -# we require ulimit, this excludes Windows test_expect_success ULIMIT_STACK_SIZE '--contains and --no-contains work in a deep repo' ' >expect && i=1 && 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= 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/t9010-svn-fe.sh b/t/t9010-svn-fe.sh index 6dafe7e99a..8eaaca6f99 100755 --- a/t/t9010-svn-fe.sh +++ b/t/t9010-svn-fe.sh @@ -4,12 +4,13 @@ test_description='check svn dumpfile importer' . ./test-lib.sh +if test_have_prereq !PIPE +then + skip_all="svn dumpfile importer testing requires the PIPE prerequisite" + test_done +fi + reinit_git () { - if ! test_declared_prereq PIPE - then - echo >&4 "reinit_git: need to declare PIPE prerequisite" - return 127 - fi rm -fr .git && rm -f stream backflow && git init && @@ -54,19 +55,19 @@ text_no_props () { >empty -test_expect_success PIPE 'empty dump' ' +test_expect_success 'empty dump' ' reinit_git && echo "SVN-fs-dump-format-version: 2" >input && try_dump input ' -test_expect_success PIPE 'v4 dumps not supported' ' +test_expect_success 'v4 dumps not supported' ' reinit_git && echo "SVN-fs-dump-format-version: 4" >v4.dump && try_dump v4.dump must_fail ' -test_expect_failure PIPE 'empty revision' ' +test_expect_failure 'empty revision' ' reinit_git && printf "rev : %s\n" "" "" >expect && cat >emptyrev.dump <<-\EOF && @@ -86,7 +87,7 @@ test_expect_failure PIPE 'empty revision' ' test_cmp expect actual ' -test_expect_success PIPE 'empty properties' ' +test_expect_success 'empty properties' ' reinit_git && printf "rev : %s\n" "" "" >expect && cat >emptyprop.dump <<-\EOF && @@ -109,7 +110,7 @@ test_expect_success PIPE 'empty properties' ' test_cmp expect actual ' -test_expect_success PIPE 'author name and commit message' ' +test_expect_success 'author name and commit message' ' reinit_git && echo "" >expect.author && cat >message <<-\EOF && @@ -143,7 +144,7 @@ test_expect_success PIPE 'author name and commit message' ' test_cmp expect.author actual.author ' -test_expect_success PIPE 'unsupported properties are ignored' ' +test_expect_success 'unsupported properties are ignored' ' reinit_git && echo author >expect && cat >extraprop.dump <<-\EOF && @@ -168,7 +169,7 @@ test_expect_success PIPE 'unsupported properties are ignored' ' test_cmp expect actual ' -test_expect_failure PIPE 'timestamp and empty file' ' +test_expect_failure 'timestamp and empty file' ' echo author@example.com >expect.author && echo 1999-01-01 >expect.date && echo file >expect.files && @@ -210,7 +211,7 @@ test_expect_failure PIPE 'timestamp and empty file' ' test_cmp empty file ' -test_expect_success PIPE 'directory with files' ' +test_expect_success 'directory with files' ' reinit_git && printf "%s\n" directory/file1 directory/file2 >expect.files && echo hi >hi && @@ -263,7 +264,7 @@ test_expect_success PIPE 'directory with files' ' test_cmp hi directory/file2 ' -test_expect_success PIPE 'branch name with backslash' ' +test_expect_success 'branch name with backslash' ' reinit_git && sort <<-\EOF >expect.branch-files && trunk/file1 @@ -362,7 +363,7 @@ test_expect_success PIPE 'branch name with backslash' ' test_cmp expect.branch-files actual.branch-files ' -test_expect_success PIPE 'node without action' ' +test_expect_success 'node without action' ' reinit_git && cat >inaction.dump <<-\EOF && SVN-fs-dump-format-version: 3 @@ -383,7 +384,7 @@ test_expect_success PIPE 'node without action' ' try_dump inaction.dump must_fail ' -test_expect_success PIPE 'action: add node without text' ' +test_expect_success 'action: add node without text' ' reinit_git && cat >textless.dump <<-\EOF && SVN-fs-dump-format-version: 3 @@ -405,7 +406,7 @@ test_expect_success PIPE 'action: add node without text' ' try_dump textless.dump must_fail ' -test_expect_failure PIPE 'change file mode but keep old content' ' +test_expect_failure 'change file mode but keep old content' ' reinit_git && cat >expect <<-\EOF && OBJID @@ -481,7 +482,7 @@ test_expect_failure PIPE 'change file mode but keep old content' ' test_cmp hello actual.target ' -test_expect_success PIPE 'NUL in property value' ' +test_expect_success 'NUL in property value' ' reinit_git && echo "commit message" >expect.message && { @@ -507,7 +508,7 @@ test_expect_success PIPE 'NUL in property value' ' test_cmp expect.message actual.message ' -test_expect_success PIPE 'NUL in log message, file content, and property name' ' +test_expect_success 'NUL in log message, file content, and property name' ' # Caveat: svnadmin 1.6.16 (r1073529) truncates at \0 in the # svn:specialQnotreally example. reinit_git && @@ -587,7 +588,7 @@ test_expect_success PIPE 'NUL in log message, file content, and property name' ' test_cmp expect.hello2 actual.hello2 ' -test_expect_success PIPE 'change file mode and reiterate content' ' +test_expect_success 'change file mode and reiterate content' ' reinit_git && cat >expect <<-\EOF && OBJID @@ -667,7 +668,7 @@ test_expect_success PIPE 'change file mode and reiterate content' ' test_cmp hello actual.target ' -test_expect_success PIPE 'deltas supported' ' +test_expect_success 'deltas supported' ' reinit_git && { # (old) h + (inline) ello + (old) \n @@ -731,7 +732,7 @@ test_expect_success PIPE 'deltas supported' ' try_dump delta.dump ' -test_expect_success PIPE 'property deltas supported' ' +test_expect_success 'property deltas supported' ' reinit_git && cat >expect <<-\EOF && OBJID @@ -796,7 +797,7 @@ test_expect_success PIPE 'property deltas supported' ' test_cmp expect actual ' -test_expect_success PIPE 'properties on /' ' +test_expect_success 'properties on /' ' reinit_git && cat <<-\EOF >expect && OBJID @@ -850,7 +851,7 @@ test_expect_success PIPE 'properties on /' ' test_cmp expect actual ' -test_expect_success PIPE 'deltas for typechange' ' +test_expect_success 'deltas for typechange' ' reinit_git && cat >expect <<-\EOF && OBJID @@ -935,7 +936,7 @@ test_expect_success PIPE 'deltas for typechange' ' test_cmp expect actual ' -test_expect_success PIPE 'deltas need not consume the whole preimage' ' +test_expect_success 'deltas need not consume the whole preimage' ' reinit_git && cat >expect <<-\EOF && OBJID @@ -1040,7 +1041,7 @@ test_expect_success PIPE 'deltas need not consume the whole preimage' ' test_cmp expect.3 actual.3 ' -test_expect_success PIPE 'no hang for delta trying to read past end of preimage' ' +test_expect_success 'no hang for delta trying to read past end of preimage' ' reinit_git && { # COPY 1 @@ -1087,7 +1088,7 @@ test_expect_success 'set up svn repo' ' fi ' -test_expect_success SVNREPO,PIPE 't9135/svn.dump' ' +test_expect_success SVNREPO 't9135/svn.dump' ' mkdir -p simple-git && ( cd simple-git && 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 a738540ef2..9b61f16f7a 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1067,14 +1067,8 @@ test_i18ngrep () { test_lazy_prereq PIPE ' # test whether the filesystem supports FIFOs - case $(uname -s) in - CYGWIN*|MINGW*) - false - ;; - *) - rm -f testfifo && mkfifo testfifo - ;; - esac + test_have_prereq !MINGW,!CYGWIN && + rm -f testfifo && mkfifo testfifo ' test_lazy_prereq SYMLINKS ' @@ -1170,7 +1164,19 @@ run_with_limited_cmdline () { (ulimit -s 128 && "$@") } -test_lazy_prereq CMDLINE_LIMIT 'run_with_limited_cmdline true' +test_lazy_prereq CMDLINE_LIMIT ' + test_have_prereq !MINGW,!CYGWIN && + run_with_limited_cmdline true +' + +run_with_limited_stack () { + (ulimit -s 128 && "$@") +} + +test_lazy_prereq ULIMIT_STACK_SIZE ' + test_have_prereq !MINGW,!CYGWIN && + run_with_limited_stack true +' build_option () { git version --build-options | diff --git a/transport-helper.c b/transport-helper.c index 42b960ff86..c948d5215c 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -44,8 +44,7 @@ static void sendline(struct helper_data *helper, struct strbuf *buffer) { if (debug) fprintf(stderr, "Debug: Remote helper: -> %s", buffer->buf); - if (write_in_full(helper->helper->in, buffer->buf, buffer->len) - != buffer->len) + if (write_in_full(helper->helper->in, buffer->buf, buffer->len) < 0) die_errno("Full write to remote helper failed"); } @@ -74,7 +73,7 @@ static void write_constant(int fd, const char *str) { if (debug) fprintf(stderr, "Debug: Remote helper: -> %s", str); - if (write_in_full(fd, str, strlen(str)) != strlen(str)) + if (write_in_full(fd, str, strlen(str)) < 0) die_errno("Full write to remote helper failed"); } diff --git a/userdiff.c b/userdiff.c index 6321103ce2..dbfb4e13cd 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/wrapper.c b/wrapper.c index 36630e5d18..61aba0b5c1 100644 --- a/wrapper.c +++ b/wrapper.c @@ -652,7 +652,7 @@ int xsnprintf(char *dst, size_t max, const char *fmt, ...) void write_file_buf(const char *path, const char *buf, size_t len) { int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC, 0666); - if (write_in_full(fd, buf, len) != len) + if (write_in_full(fd, buf, len) < 0) die_errno(_("could not write to %s"), path); if (close(fd)) die_errno(_("could not close %s"), path); diff --git a/wt-status.c b/wt-status.c index ac972acbab..6f730ee8f2 100644 --- a/wt-status.c +++ b/wt-status.c @@ -934,7 +934,7 @@ size_t wt_status_locate_end(const char *s, size_t len) void wt_status_add_cut_line(FILE *fp) { - const char *explanation = _("Do not touch the line above.\nEverything below will be removed."); + const char *explanation = _("Do not modify or remove the line above.\nEverything below it will be ignored."); struct strbuf buf = STRBUF_INIT; fprintf(fp, "%c %s", comment_line_char, cut_line);