From: Junio C Hamano Date: Fri, 19 Sep 2014 18:38:37 +0000 (-0700) Subject: Merge branch 'tb/crlf-tests' X-Git-Tag: v2.2.0-rc0~109 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/70f003e1070f16594529d9fb0cc6c670c1e415e2?hp=5f4e02e5173c64b5b760f35283c4b0094bb85881 Merge branch 'tb/crlf-tests' * tb/crlf-tests: MinGW: update tests to handle a native eol of crlf Makefile: propagate NATIVE_CRLF to C t0027: Tests for core.eol=native, eol=lf, eol=crlf --- diff --git a/.gitignore b/.gitignore index 42294e59a1..5bfb234591 100644 --- a/.gitignore +++ b/.gitignore @@ -165,6 +165,7 @@ /git-upload-archive /git-upload-pack /git-var +/git-verify-commit /git-verify-pack /git-verify-tag /git-web--browse @@ -177,9 +178,11 @@ /gitweb/static/gitweb.min.* /test-chmtime /test-ctype +/test-config /test-date /test-delta /test-dump-cache-tree +/test-dump-split-index /test-scrap-cache-tree /test-genrandom /test-hashmap diff --git a/.mailmap b/.mailmap index 11057cbcdf..8aefb5a452 100644 --- a/.mailmap +++ b/.mailmap @@ -85,6 +85,7 @@ Jeff King Jeff Muizelaar Jens Axboe Jens Axboe +Jens Lindström Jens Lindstrom Jim Meyering Joachim Berdal Haga Johannes Schindelin @@ -113,6 +114,7 @@ Karsten Blees Karsten Blees Kay Sievers Kay Sievers +Kazuki Saitoh kazuki saitoh Keith Cascio Kent Engstrom Kevin Leung @@ -202,6 +204,7 @@ Seth Falcon Shawn O. Pearce Simon Hausmann Simon Hausmann +Stefan Beller Stefan Naewe Stefan Naewe Stefan Sperling @@ -229,6 +232,7 @@ Tommi Virtanen Tommy Thorn Tony Luck Tor Arne Vestbø +Trần Ngọc Quân Tran Ngoc Quan Trent Piepho Trent Piepho Uwe Kleine-König diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines index 4d90c77c7b..894546dd75 100644 --- a/Documentation/CodingGuidelines +++ b/Documentation/CodingGuidelines @@ -404,6 +404,15 @@ For Python scripts: documentation for version 2.6 does not mention this prefix, it has been supported since version 2.6.0. +Error Messages + + - Do not end error messages with a full stop. + + - Do not capitalize ("unable to open %s", not "Unable to open %s") + + - Say what the error is first ("cannot open %s", not "%s: cannot open") + + Writing Documentation: Most (if not all) of the documentation pages are written in the diff --git a/Documentation/RelNotes/2.0.2.txt b/Documentation/RelNotes/2.0.2.txt new file mode 100644 index 0000000000..8e8321b2ef --- /dev/null +++ b/Documentation/RelNotes/2.0.2.txt @@ -0,0 +1,32 @@ +Git v2.0.2 Release Notes +======================== + + * Documentation for "git submodule sync" forgot to say that the subcommand + can take the "--recursive" option. + + * Mishandling of patterns in .gitignore that has trailing SPs quoted + with backslashes (e.g. ones that end with "\ ") have been + corrected. + + * Recent updates to "git repack" started to duplicate objects that + are in packfiles marked with .keep flag into the new packfile by + mistake. + + * "git clone -b brefs/tags/bar" would have mistakenly thought we were + following a single tag, even though it was a name of the branch, + because it incorrectly used strstr(). + + * "%G" (nothing after G) is an invalid pretty format specifier, but + the parser did not notice it as garbage. + + * Code to avoid adding the same alternate object store twice was + subtly broken for a long time, but nobody seems to have noticed. + + * A handful of code paths had to read the commit object more than + once when showing header fields that are usually not parsed. The + internal data structure to keep track of the contents of the commit + object has been updated to reduce the need for this double-reading, + and to allow the caller find the length of the object. + + * During "git rebase --merge", a conflicted patch could not be + skipped with "--skip" if the next one also conflicted. diff --git a/Documentation/RelNotes/2.0.3.txt b/Documentation/RelNotes/2.0.3.txt new file mode 100644 index 0000000000..4047b46bbe --- /dev/null +++ b/Documentation/RelNotes/2.0.3.txt @@ -0,0 +1,17 @@ +Git v2.0.3 Release Notes +======================== + + * An ancient rewrite passed a wrong pointer to a curl library + function in a rarely used code path. + + * "filter-branch" left an empty single-parent commit that results when + all parents of a merge commit gets mapped to the same commit, even + under "--prune-empty". + + * "log --show-signature" incorrectly decided the color to paint a + mergetag that was and was not correctly validated. + + * "log --show-signature" did not pay attention to "--graph" option. + +Also a lot of fixes to the tests and some updates to the docs are +included. diff --git a/Documentation/RelNotes/2.0.4.txt b/Documentation/RelNotes/2.0.4.txt new file mode 100644 index 0000000000..7e340921a2 --- /dev/null +++ b/Documentation/RelNotes/2.0.4.txt @@ -0,0 +1,5 @@ +Git v2.0.4 Release Notes +======================== + + * An earlier update to v2.0.2 broken output from "git diff-tree", + which is fixed in this release. diff --git a/Documentation/RelNotes/2.1.0.txt b/Documentation/RelNotes/2.1.0.txt index 828a439dc1..ae4753728e 100644 --- a/Documentation/RelNotes/2.1.0.txt +++ b/Documentation/RelNotes/2.1.0.txt @@ -12,7 +12,7 @@ Backward compatibility notes $ git config core.pager "less -S" to restore the traditional behaviour. It is expected that people - find output from the most subcommands easier to read with the new + find output from most subcommands easier to read with the new default, except for "blame" which tends to produce really long lines. To override the new default only for "git blame", you can do this: @@ -31,7 +31,7 @@ UI, Workflows & Features default value "FRSX" when we spawn "less" as the pager. "S" (chop long lines instead of wrapping) has been removed from this default set of options, because it is more or less a personal taste thing, - as opposed to others that have good justifications (i.e. "R" is + as opposed to the others that have good justifications (i.e. "R" is very much justified because many kinds of output we produce are colored and "FX" is justified because output we produce is often shorter than a page). @@ -39,41 +39,47 @@ UI, Workflows & Features * The logic and data used to compute the display width needed for UTF-8 strings have been updated to match Unicode 7.0 better. - * HTTP-based transports learned to propagate the error messages from - the webserver better to the client coming over the HTTP transport. + * HTTP-based transports learned to better propagate the error messages from + the webserver to the client coming over the HTTP transport. * The completion script for bash (in contrib/) has been updated to - handle aliases that define complex sequence of commands better. + better handle aliases that define a complex sequence of commands. - * The "core.preloadindex" configuration variable is by default - enabled, allowing modern platforms to take advantage of the - multiple cores they have. + * The "core.preloadindex" configuration variable is enabled by default, + allowing modern platforms to take advantage of their + multiple cores. - * "git commit --date=" option learned to read from more + * "git clone" applies the "if cloning from a local disk, physically + copy the repository using hardlinks, unless otherwise told not to with + --no-local" optimization when the url.*.insteadOf mechanism rewrites a + remote-repository "git clone $URL" into a + clone from a local disk. + + * "git commit --date=" option learned more timestamp formats, including "--date=now". * The `core.commentChar` configuration variable is used to specify a - custom comment character other than the default "#" to be used in - the commit log editor. This can be set to `auto` to attempt to - choose a different character that does not conflict with what - already starts a line in the message being edited for cases like + custom comment character (other than the default "#") for + the commit message editor. This can be set to `auto` to attempt to + choose a different character that does not conflict with any that + already starts a line in the message being edited, for cases like "git commit --amend". - * "git format-patch" learned --signature-file= to take the mail - signature from. + * "git format-patch" learned --signature-file= to add the contents + of a file as a signature to the mail message it produces. - * "git grep" learned grep.fullname configuration variable to force - "--full-name" to be default. This may cause regressions on - scripted users that do not expect this new behaviour. + * "git grep" learned the grep.fullname configuration variable to force + "--full-name" to be the default. This may cause regressions for + scripted users who do not expect this new behaviour. * "git imap-send" learned to ask the credential helper for auth material. - * "git log" and friends now understand the value "auto" set to the + * "git log" and friends now understand the value "auto" for the "log.decorate" configuration variable to enable the "--decorate" option automatically when the output is sent to tty. - * "git merge" without argument, even when there is an upstream + * "git merge" without an argument, even when there is an upstream defined for the current branch, refused to run until merge.defaultToUpstream is set to true. Flip the default of that configuration variable to true. @@ -81,19 +87,21 @@ UI, Workflows & Features * "git mergetool" learned to drive the vimdiff3 backend. * mergetool.prompt used to default to 'true', always asking "do you - really want to run the tool on this path?". Among the two - purposes this prompt serves, ignore the use case to confirm that - the user wants to view particular path with the named tool, and - redefine the meaning of the prompt only to confirm the choice of - the tool made by the autodetection (for those who configured the - tool explicitly, the prompt shown for the latter purpose is - simply annoying). - - Strictly speaking, this is a backward incompatible change and the + really want to run the tool on this path?". The default has been + changed to 'false'. However, the prompt will still appear if + mergetool used its autodetection system to guess which tool to use. + Users who explicitly specify or configure a tool will no longer see + the prompt by default. + + Strictly speaking, this is a backward incompatible change and users need to explicitly set the variable to 'true' if they want - to resurrect the now-ignored use case. + to be prompted to confirm running the tool on each path. + + * "git replace" learned the "--edit" subcommand to create a + replacement by editing an existing object. - * "git replace" learned the "--edit" subcommand. + * "git replace" learned a "--graft" option to rewrite the parents of a + commit. * "git send-email" learned "--to-cover" and "--cc-cover" options, to tell it to copy To: and Cc: headers found in the first input file @@ -106,11 +114,35 @@ UI, Workflows & Features * "git tag" when editing the tag message shows the name of the tag being edited as a comment in the editor. + * "git tag" learned to pay attention to "tag.sort" configuration, to + be used as the default sort order when no --sort= option + is given. + + * A new "git verify-commit" command, to check GPG signatures in signed + commits, in a way similar to "git verify-tag" is used to check + signed tags, was added. + Performance, Internal Implementation, etc. * Build procedure for 'subtree' (in contrib/) has been cleaned up. + * Support for the profile-feedback build, which has + bit-rotted for quite a while, has been updated. + + * An experimental format to use two files (the base file and + incremental changes relative to it) to represent the index has been + introduced; this may reduce I/O cost of rewriting a large index + when only small part of the working tree changes. + + * Effort to shrink the size of patches Windows folks maintain on top + by upstreaming them continues. More tests that are not applicable + to the Windows environment are identified and either skipped or + made more portable. + + * Eradication of "test $condition -a $condition" from our scripts + continues. + * The `core.deltabasecachelimit` used to default to 16 MiB , but this proved to be too small, and has been bumped to 96 MiB. @@ -118,13 +150,16 @@ Performance, Internal Implementation, etc. structure that is used to keep track of the work to be done. * "git diff" that compares 3-or-more trees (e.g. parents and the - result of a merge) have been optimized. + result of a merge) has been optimized. * The API to update/delete references are being converted to handle updates to multiple references in a transactional way. As an example, "update-ref --stdin [-z]" has been updated to use this API. + * skip_prefix() and strip_suffix() API functions are used a lot more + widely throughout the codebase now. + * Parts of the test scripts can be skipped by using a range notation, e.g. "sh t1234-test.sh --run='1-4 6 8-'" to omit test piece 5 and 7 and run everything else. @@ -151,8 +186,8 @@ notes for details). to a tty. (merge 38de156 mn/sideband-no-ansi later to maint). - * Mishandling of patterns in .gitignore that has trailing SPs quoted - with backslashes (e.g. ones that end with "\ ") have been + * Mishandling of patterns in .gitignore that have trailing SPs quoted + with backslashes (e.g. ones that end with "\ ") has been corrected. (merge 97c1364be6b pb/trim-trailing-spaces later to maint). @@ -166,6 +201,11 @@ notes for details). be checked out currently. (merge e3fa568 jc/revision-dash-count-parsing later to maint). + * Code to avoid adding the same alternate object store twice was + subtly broken for a long time, but nobody seems to have noticed. + (merge 80b4785 rs/fix-alt-odb-path-comparison later to maint). + (merge 539e750 ek/alt-odb-entry-fix later to maint). + * The "%<(10,trunc)%s" pretty format specifier in the log family of commands is used to truncate the string to a given length (e.g. 10 in the example) with padding to column-align the output, but did @@ -173,7 +213,18 @@ notes for details). columns are different. (merge 7d50987 as/pretty-truncate later to maint). - * The "mailmap.file" configuration option did not support the tilde + * "%G" (nothing after G) is an invalid pretty format specifier, but + the parser did not notice it as garbage. + (merge 958b2eb jk/pretty-G-format-fixes later to maint). + + * A handful of code paths had to read the commit object more than + once when showing header fields that are usually not parsed. The + internal data structure to keep track of the contents of the commit + object has been updated to reduce the need for this double-reading, + and to allow the caller find the length of the object. + (merge 218aa3a jk/commit-buffer-length later to maint). + + * The "mailmap.file" configuration option did not support tilde expansion (i.e. ~user/path and ~/path). (merge 9352fd5 ow/config-mailmap-pathname later to maint). @@ -182,13 +233,23 @@ notes for details). couple of options unique to "git merge". (merge 8fee872 jk/complete-merge-pull later to maint). + * The unix-domain socket used by the sample credential cache daemon + tried to unlink an existing stale one at a wrong path, if the path + to the socket was given as an overlong path that does not fit in + the sun_path member of the sockaddr_un structure. + (merge 2869b3e rs/fix-unlink-unix-socket later to maint). + + * An ancient rewrite passed a wrong pointer to a curl library + function in a rarely used code path. + (merge 479eaa8 ah/fix-http-push later to maint). + * "--ignore-space-change" option of "git apply" ignored the spaces - at the beginning of line too aggressively, which is inconsistent - with the option of the same name "diff" and "git diff" have. + at the beginning of lines too aggressively, which is inconsistent + with the option of the same name that "diff" and "git diff" have. (merge 14d3bb4 jc/apply-ignore-whitespace later to maint). - * "git blame" miscounted number of columns needed to show localized - timestamps, resulting in jaggy left-side-edge of the source code + * "git blame" miscounted the number of columns needed to show localized + timestamps, resulting in a jaggy left-side-edge for the source code lines in its output. (merge dd75553 jx/blame-align-relative-time later to maint). @@ -197,15 +258,25 @@ notes for details). line endings. (merge 4d4813a bc/blame-crlf-test later to maint). - * "git commit --allow-empty-messag -C $commit" did not work when the + * "git clone -b brefs/tags/bar" would have mistakenly thought we were + following a single tag, even though it was a name of the branch, + because it incorrectly used strstr(). + (merge 60a5f5f jc/fix-clone-single-starting-at-a-tag later to maint). + + * "git commit --allow-empty-message -C $commit" did not work when the commit did not have any log message. (merge 076cbd6 jk/commit-C-pick-empty later to maint). * "git diff --find-copies-harder" sometimes pretended as if the mode - bits have changed for paths that are marked with assume-unchanged + bits have changed for paths that are marked with the assume-unchanged bit. (merge 5304810 jk/diff-files-assume-unchanged later to maint). + * "filter-branch" left an empty single-parent commit that results when + all parents of a merge commit get mapped to the same commit, even + under "--prune-empty". + (merge 79bc4ef cb/filter-branch-prune-empty-degenerate-merges later to maint). + * "git format-patch" did not enforce the rule that the "--follow" option from the log/diff family of commands must be used with exactly one pathspec. @@ -231,7 +302,14 @@ notes for details). distinguish missing objects from type errors. (merge 77583e7 jk/index-pack-report-missing later to maint). - * "git mailinfo" used to read beyond the end of header string while + * "log --show-signature" incorrectly decided the color to paint a + mergetag that was and was not correctly validated. + (merge 42c55ce mg/fix-log-mergetag-color later to maint). + + * "log --show-signature" did not pay attention to the "--graph" option. + (merge cf3983d zk/log-graph-showsig later to maint). + + * "git mailinfo" used to read beyond the ends of header strings while parsing an incoming e-mail message to extract the patch. (merge b1a013d rs/mailinfo-header-cmp later to maint). @@ -240,13 +318,18 @@ notes for details). except for case differences. (merge baa37bf dt/merge-recursive-case-insensitive later to maint). + * Merging changes into a file that ends in an incomplete line made the + last line into a complete one, even when the other branch did not + change anything around the end of file. + (merge ba31180 mk/merge-incomplete-files later to maint). + * "git pack-objects" unnecessarily copied the previous contents when extending the hashtable, even though it will populate the table from scratch anyway. (merge fb79947 rs/pack-objects-no-unnecessary-realloc later to maint). * Recent updates to "git repack" started to duplicate objects that - are in packfiles marked with .keep flag into the new packfile by + are in packfiles marked with the .keep flag into the new packfile by mistake. (merge d078d85 jk/repack-pack-keep-objects later to maint). @@ -270,6 +353,13 @@ notes for details). emptying the insn sheet. (merge ddb5432 rr/rebase-autostash-fix later to maint). + * "git rebase --fork-point" did not filter out patch-identical + commits correctly. + + * During "git rebase --merge", a conflicted patch could not be + skipped with "--skip" if the next one also conflicted. + (merge 95104c7 bc/fix-rebase-merge-skip later to maint). + * "git show -s" (i.e. show log message only) used to incorrectly emit an extra blank line after a merge commit. (merge ad2f725 mk/show-s-no-extra-blank-line-for-merges later to maint). @@ -277,14 +367,14 @@ notes for details). * "git status", even though it is a read-only operation, tries to update the index with refreshed lstat(2) info to optimize future accesses to the working tree opportunistically, but this could - race with a "read-write" operation that modify the index while it + race with a "read-write" operation that modifies the index while it is running. Detect such a race and avoid overwriting the index. (merge 426ddee ym/fix-opportunistic-index-update-race later to maint). * "git status" (and "git commit") behaved as if changes in a modified submodule are not there if submodule.*.ignore configuration is set, which was misleading. The configuration is only to unclutter diff - output during the course of development, and should not to hide + output during the course of development, and not to hide changes in the "status" output to cause the users forget to commit them. (merge c215d3d jl/status-added-submodule-is-never-ignored later to maint). diff --git a/Documentation/RelNotes/2.2.0.txt b/Documentation/RelNotes/2.2.0.txt new file mode 100644 index 0000000000..22b73618fc --- /dev/null +++ b/Documentation/RelNotes/2.2.0.txt @@ -0,0 +1,132 @@ +Git v2.2 Release Notes +====================== + +Updates since v2.1 +------------------ + +Ports + + * Building on older MacOS X systems automatically sets + the necessary NO_APPLE_COMMON_CRYPTO build-time option. + + +UI, Workflows & Features + + * "git config --edit --global" starts from a skeletal per-user + configuration file contents, instead of a total blank, when the + user does not already have any. This immediately reduces the + need for a later "Have you forgotten setting core.user?" and we + can add more to the template as we gain more experience. + + * "git stash list -p" used to be almost always a no-op because each + stash entry is represented as a merge commit. It learned to show + the difference between the base commit version and the working tree + version, which is in line with what "git show" gives. + +Performance, Internal Implementation, etc. + + * The API to manipulate the "refs" is currently undergoing a revamp + to make it more transactional, with the eventual goal to allow + all-or-none atomic updates and migrating the storage to something + other than the traditional filesystem based one (e.g. databases). + + * We no longer attempt to keep track of individual dependencies to + the header files in the build procedure, relying on automated + dependency generation support from modern compilers. + + * In tests, we have been using NOT_{MINGW,CYGWIN} test prerequisites + long before negated prerequisites e.g. !MINGW were invented. + The former has been converted to the latter to avoid confusion. + + * Looking up remotes configuration in a repository with very many + remotes defined has been optimized. + + * There are cases where you lock and open to write a file, close it + to show the updated contents to external processes, and then have + to update the file again while still holding the lock, but the + lockfile API lacked support for such an access pattern. + + * The API to allocate the structure to keep track of commit + decoration has been updated to make it less cumbersome to use. + + * An in-core caching layer to let us avoid reading the same + configuration files number of times has been added. A few commands + have been converted to use this subsystem. + + * Various code paths have been cleaned up and simplified by using + "strbuf", "starts_with()", and "skip_prefix()" APIs more. + + * A few codepaths that died when large blobs that would not fit in + core are involved in their operation have been taught to punt + instead, by e.g. marking too large a blob as not to be diffed. + + * A few more code paths in "commit" and "checkout" have been taught + to repopulate the cache-tree in the index, to help speed up later + "write-tree" (used in "commit") and "diff-index --cached" (used in + "status"). + + +Also contains various documentation updates and code clean-ups. + + +Fixes since v2.1 +---------------- + +Unless otherwise noted, all the fixes since v2.1 in the maintenance +track are contained in this release (see the maintenance releases' +notes for details). + + * "git log --pretty/format=" with an empty format string did not + mean the more obvious "No output whatsoever" but "Use default + format", which was counterintuitive. + (merge b9c7d6e jk/pretty-empty-format later to maint). + + * Implementations of "tar" that do not understand an extended pax + header would extract the contents of it in a regular file; make + sure the permission bits of this file follows the same tar.umask + configuration setting. + + * "git -c section.var command" and "git -c section.var= command" + should pass the configuration differently (the former should be a + boolean true, the latter should be an empty string). + (merge a789ca7 jk/command-line-config-empty-string later to maint). + + * Applying a patch not generated by Git in a subdirectory used to + check the whitespace breakage using the attributes for incorrect + paths. Also whitespace checks were performed even for paths + excluded via "git apply --exclude=" mechanism. + (merge 477a08a jc/apply-ws-prefix later to maint). + + * "git bundle create" with date-range specification were meant to + exclude tags outside the range, but it didn't. + (merge 2c8544a lf/bundle-exclusion later to maint). + + * "git add x" where x that used to be a directory has become a + symbolic link to a directory misbehaved. + (merge ccad42d rs/refresh-beyond-symlink later to maint). + + * The prompt script checked $GIT_DIR/ref/stash file to see if there + is a stash, which was a no-no. + (merge 0fa7f01 jk/prompt-stash-could-be-packed later to maint). + + * Pack-protocol documentation had a minor typo. + (merge 5d146f7 sp/pack-protocol-doc-on-shallow later to maint). + + * "git checkout -m" did not switch to another branch while carrying + the local changes forward when a path was deleted from the index. + (merge 6a143aa jn/unpack-trees-checkout-m-carry-deletion later to maint). + + * With sufficiently long refnames, "git fast-import" could have + overflown an on-stack buffer. + (merge c252785 jk/fast-import-fixes later to maint). + + * After "pack-refs --prune" packed refs at the top-level, it failed + to prune them. + (merge afd11d3 jk/prune-top-level-refs-after-packing later to maint). + + * Progress output from "git gc --auto" was visible in "git fetch -q". + (merge 6fceed3 nd/fetch-pass-quiet-to-gc-child-process later to maint). + + * We used to pass -1000 to poll(2), expecting it to also mean "no + timeout", which should be spelled as -1. + (merge 6c71f8b et/spell-poll-infinite-with-minus-one-only later to maint). diff --git a/Documentation/config.txt b/Documentation/config.txt index 1d718bdb96..3b5b24aeb7 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -499,7 +499,8 @@ core.bigFileThreshold:: Files larger than this size are stored deflated, without attempting delta compression. Storing large files without delta compression avoids excessive memory usage, at the - slight expense of increased disk usage. + slight expense of increased disk usage. Additionally files + larger than this size are always treated as binary. + Default is 512 MiB on all platforms. This should be reasonable for most projects as source code and other text files can still @@ -2354,6 +2355,11 @@ submodule..ignore:: "--ignore-submodules" option. The 'git submodule' commands are not affected by this setting. +tag.sort:: + This variable controls the sort ordering of tags when displayed by + linkgit:git-tag[1]. Without the "--sort=" option provided, the + value of this variable will be used as the default. + tar.umask:: This variable can be used to restrict the permission bits of tar archive entries. The default is 0002, which turns off the diff --git a/Documentation/git-fast-export.txt b/Documentation/git-fast-export.txt index 221506b04b..dbe9a46833 100644 --- a/Documentation/git-fast-export.txt +++ b/Documentation/git-fast-export.txt @@ -105,6 +105,11 @@ marks the same across runs. in the commit (as opposed to just listing the files which are different from the commit's first parent). +--anonymize:: + Anonymize the contents of the repository while still retaining + the shape of the history and stored tree. See the section on + `ANONYMIZING` below. + --refspec:: Apply the specified refspec to each ref exported. Multiple of them can be specified. @@ -141,6 +146,62 @@ referenced by that revision range contains the string 'refs/heads/master'. +ANONYMIZING +----------- + +If the `--anonymize` option is given, git will attempt to remove all +identifying information from the repository while still retaining enough +of the original tree and history patterns to reproduce some bugs. The +goal is that a git bug which is found on a private repository will +persist in the anonymized repository, and the latter can be shared with +git developers to help solve the bug. + +With this option, git will replace all refnames, paths, blob contents, +commit and tag messages, names, and email addresses in the output with +anonymized data. Two instances of the same string will be replaced +equivalently (e.g., two commits with the same author will have the same +anonymized author in the output, but bear no resemblance to the original +author string). The relationship between commits, branches, and tags is +retained, as well as the commit timestamps (but the commit messages and +refnames bear no resemblance to the originals). The relative makeup of +the tree is retained (e.g., if you have a root tree with 10 files and 3 +trees, so will the output), but their names and the contents of the +files will be replaced. + +If you think you have found a git bug, you can start by exporting an +anonymized stream of the whole repository: + +--------------------------------------------------- +$ git fast-export --anonymize --all >anon-stream +--------------------------------------------------- + +Then confirm that the bug persists in a repository created from that +stream (many bugs will not, as they really do depend on the exact +repository contents): + +--------------------------------------------------- +$ git init anon-repo +$ cd anon-repo +$ git fast-import <../anon-stream +$ ... test your bug ... +--------------------------------------------------- + +If the anonymized repository shows the bug, it may be worth sharing +`anon-stream` along with a regular bug report. Note that the anonymized +stream compresses very well, so gzipping it is encouraged. If you want +to examine the stream to see that it does not contain any private data, +you can peruse it directly before sending. You may also want to try: + +--------------------------------------------------- +$ perl -pe 's/\d+/X/g' :: -Instead of initializing the repository where it is supposed to be, -place a filesytem-agnostic Git symbolic link there, pointing to the -specified path, and initialize a Git repository at the path. The -result is Git repository can be separated from working tree. If this -is reinitialization, the repository will be moved to the specified -path. +Instead of initializing the repository as a directory to either `$GIT_DIR` or +`./.git/`, create a text file there containing the path to the actual +repository. This file acts as filesystem-agnostic Git symbolic link to the +repository. ++ +If this is reinitialization, the repository will be moved to the specified path. --shared[=(false|true|umask|group|all|world|everybody|0xxx)]:: @@ -72,60 +72,65 @@ repository. When specified, the config variable "core.sharedRepository" is set so that files and directories under `$GIT_DIR` are created with the requested permissions. When not specified, Git will use permissions reported by umask(2). - ++ The option can have the following values, defaulting to 'group' if no value is given: ++ +-- +'umask' (or 'false'):: - - 'umask' (or 'false'): Use permissions reported by umask(2). The default, - when `--shared` is not specified. +Use permissions reported by umask(2). The default, when `--shared` is not +specified. - - 'group' (or 'true'): Make the repository group-writable, (and g+sx, since - the git group may be not the primary group of all users). - This is used to loosen the permissions of an otherwise safe umask(2) value. - Note that the umask still applies to the other permission bits (e.g. if - umask is '0022', using 'group' will not remove read privileges from other - (non-group) users). See '0xxx' for how to exactly specify the repository - permissions. +'group' (or 'true'):: - - 'all' (or 'world' or 'everybody'): Same as 'group', but make the repository - readable by all users. +Make the repository group-writable, (and g+sx, since the git group may be not +the primary group of all users). This is used to loosen the permissions of an +otherwise safe umask(2) value. Note that the umask still applies to the other +permission bits (e.g. if umask is '0022', using 'group' will not remove read +privileges from other (non-group) users). See '0xxx' for how to exactly specify +the repository permissions. - - '0xxx': '0xxx' is an octal number and each file will have mode '0xxx'. - '0xxx' will override users' umask(2) value (and not only loosen permissions - as 'group' and 'all' does). '0640' will create a repository which is - group-readable, but not group-writable or accessible to others. '0660' will - create a repo that is readable and writable to the current user and group, - but inaccessible to others. +'all' (or 'world' or 'everybody'):: -By default, the configuration flag receive.denyNonFastForwards is enabled +Same as 'group', but make the repository readable by all users. + +'0xxx':: + +'0xxx' is an octal number and each file will have mode '0xxx'. '0xxx' will +override users' umask(2) value (and not only loosen permissions as 'group' and +'all' does). '0640' will create a repository which is group-readable, but not +group-writable or accessible to others. '0660' will create a repo that is +readable and writable to the current user and group, but inaccessible to others. +-- + +By default, the configuration flag `receive.denyNonFastForwards` is enabled in shared repositories, so that you cannot force a non fast-forwarding push into it. -If you name a (possibly non-existent) directory at the end of the command -line, the command is run inside the directory (possibly after creating it). +If you provide a 'directory', the command is run inside it. If this directory +does not exist, it will be created. -- - TEMPLATE DIRECTORY ------------------ The template directory contains files and directories that will be copied to the `$GIT_DIR` after it is created. -The template directory used will (in order): +The template directory will be one of the following (in order): - - The argument given with the `--template` option. + - the argument given with the `--template` option; - - The contents of the `$GIT_TEMPLATE_DIR` environment variable. + - the contents of the `$GIT_TEMPLATE_DIR` environment variable; - - The `init.templatedir` configuration variable. + - the `init.templatedir` configuration variable; or - - The default template directory: `/usr/share/git-core/templates`. + - the default template directory: `/usr/share/git-core/templates`. -The default template directory includes some directory structure, some -suggested "exclude patterns", and copies of sample "hook" files. -The suggested patterns and hook files are all modifiable and extensible. +The default template directory includes some directory structure, suggested +"exclude patterns" (see linkgit:gitignore[5]), and sample hook files (see linkgit:githooks[5]). EXAMPLES -------- @@ -136,10 +141,12 @@ Start a new Git repository for an existing code base:: $ cd /path/to/my/codebase $ git init <1> $ git add . <2> +$ git commit <3> ---------------- + -<1> prepare /path/to/my/codebase/.git directory -<2> add all existing file to the index +<1> Create a /path/to/my/codebase/.git directory. +<2> Add all existing files to the index. +<3> Record the pristine state as the first commit in the history. GIT --- diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index 21cd455508..c0d7403b9a 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -33,7 +33,7 @@ When the command line does not specify what to push with `...` arguments or `--all`, `--mirror`, `--tags` options, the command finds the default `` by consulting `remote.*.push` configuration, and if it is not found, honors `push.default` configuration to decide -what to push (See gitlink:git-config[1] for the meaning of `push.default`). +what to push (See linkgit:git-config[1] for the meaning of `push.default`). OPTIONS[[OPTIONS]] diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 2a93c645bd..f14100a160 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -316,11 +316,8 @@ which makes little sense. -f:: --force-rebase:: - Force the rebase even if the current branch is a descendant - of the commit you are rebasing onto. Normally non-interactive rebase will - exit with the message "Current branch is up to date" in such a - situation. - Incompatible with the --interactive option. + Force a rebase even if the current branch is up-to-date and + the command without `--force` would return without doing anything. + You may find this (or --no-ff with an interactive rebase) helpful after reverting a topic branch merge, as this option recreates the topic branch with diff --git a/Documentation/git-replace.txt b/Documentation/git-replace.txt index 61461b9f33..8fff598fd6 100644 --- a/Documentation/git-replace.txt +++ b/Documentation/git-replace.txt @@ -10,6 +10,7 @@ SYNOPSIS [verse] 'git replace' [-f] 'git replace' [-f] --edit +'git replace' [-f] --graft [...] 'git replace' -d ... 'git replace' [--format=] [-l []] @@ -73,6 +74,23 @@ OPTIONS newly created object. See linkgit:git-var[1] for details about how the editor will be chosen. +--raw:: + When editing, provide the raw object contents rather than + pretty-printed ones. Currently this only affects trees, which + will be shown in their binary form. This is harder to work with, + but can help when repairing a tree that is so corrupted it + cannot be pretty-printed. Note that you may need to configure + your editor to cleanly read and write binary data. + +--graft [...]:: + Create a graft commit. A new commit is created with the same + content as except that its parents will be + [...] instead of 's parents. A replacement ref + is then created to replace with the newly created + commit. See contrib/convert-grafts-to-replace-refs.sh for an + example script based on this option that can convert grafts to + replace refs. + -l :: --list :: List replace refs for objects that match the given pattern (or diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index 7a1585def0..fd7f8b5bc1 100644 --- a/Documentation/git-rev-list.txt +++ b/Documentation/git-rev-list.txt @@ -45,7 +45,7 @@ SYNOPSIS [ \--regexp-ignore-case | -i ] [ \--extended-regexp | -E ] [ \--fixed-strings | -F ] - [ \--date=(local|relative|default|iso|rfc|short) ] + [ \--date=(local|relative|default|iso|iso-strict|rfc|short) ] [ [\--objects | \--objects-edge] [ \--unpacked ] ] [ \--pretty | \--header ] [ \--bisect ] diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index 987395d22a..0b84769bd9 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -102,7 +102,7 @@ eval "set -- $(git rev-parse --sq --prefix "$prefix" "$@")" + If you want to make sure that the output actually names an object in your object database and/or can be used as a specific type of object -you require, you can add "^{type}" peeling operator to the parameter. +you require, you can add "\^{type}" peeling operator to the parameter. For example, `git rev-parse "$VAR^{commit}"` will make sure `$VAR` names an existing object that is a commit-ish (i.e. a commit, or an annotated tag that points at a commit). To make sure that `$VAR` @@ -245,6 +245,10 @@ print a message to stderr and exit with nonzero status. --show-toplevel:: Show the absolute path of the top-level directory. +--shared-index-path:: + Show the path to the shared index file in split index mode, or + empty if not in split-index mode. + Other Options ~~~~~~~~~~~~~ diff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt index dc3a568baa..2a0de42a75 100644 --- a/Documentation/git-send-pack.txt +++ b/Documentation/git-send-pack.txt @@ -35,6 +35,16 @@ OPTIONS Instead of explicitly specifying which refs to update, update all heads that locally exist. +--stdin:: + Take the list of refs from stdin, one per line. If there + are refs specified on the command line in addition to this + option, then the refs from stdin are processed after those + on the command line. ++ +If '--stateless-rpc' is specified together with this option then +the list of refs must be in packet format (pkt-line). Each ref must +be in a separate packet, and the list must end with a flush packet. + --dry-run:: Do everything except actually send the updates. @@ -77,7 +87,8 @@ this flag. Without '--all' and without any '', the heads that exist both on the local side and on the remote side are updated. -When one or more '' are specified explicitly, it can be either a +When one or more '' are specified explicitly (whether on the +command line or via `--stdin`), it can be either a single pattern, or a pair of such pattern separated by a colon ":" (this means that a ref name cannot have a colon in it). A single pattern '' is just a shorthand for ':'. diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index 44c970ce18..ef8ef1c545 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -386,11 +386,13 @@ Any other arguments are passed directly to 'git log' tree-ish to specify which branch should be searched). When given a tree-ish, returns the corresponding SVN revision number. + +-B;; --before;; Don't require an exact match if given an SVN revision, instead find the commit corresponding to the state of the SVN repository (on the current branch) at the specified revision. + +-A;; --after;; Don't require an exact match if given an SVN revision; if there is not an exact match return the closest match searching forward in the @@ -608,21 +610,6 @@ config key: svn.authorsfile Make 'git svn' less verbose. Specify a second time to make it even less verbose. ---repack[=]:: ---repack-flags=:: - These should help keep disk usage sane for large fetches with - many revisions. -+ ---repack takes an optional argument for the number of revisions -to fetch before repacking. This defaults to repacking every -1000 commits fetched if no argument is specified. -+ ---repack-flags are passed directly to 'git repack'. -+ -[verse] -config key: svn.repack -config key: svn.repackflags - -m:: --merge:: -s:: diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index b424a1bc48..320908369f 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -99,7 +99,9 @@ OPTIONS Sort in a specific order. Supported type is "refname" (lexicographic order), "version:refname" or "v:refname" (tag names are treated as versions). Prepend "-" to reverse sort - order. + order. When this option is not given, the sort order defaults to the + value configured for the 'tag.sort' variable if it exists, or + lexicographic order otherwise. See linkgit:git-config[1]. --column[=]:: --no-column:: @@ -317,6 +319,7 @@ include::date-formats.txt[] SEE ALSO -------- linkgit:git-check-ref-format[1]. +linkgit:git-config[1]. GIT --- diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt index d6de4a008c..dfc09d93d8 100644 --- a/Documentation/git-update-index.txt +++ b/Documentation/git-update-index.txt @@ -161,6 +161,17 @@ may not support it yet. Only meaningful with `--stdin` or `--index-info`; paths are separated with NUL character instead of LF. +--split-index:: +--no-split-index:: + Enable or disable split index mode. If enabled, the index is + split into two files, $GIT_DIR/index and $GIT_DIR/sharedindex.. + Changes are accumulated in $GIT_DIR/index while the shared + index file contains all index entries stays unchanged. If + split-index mode is already enabled and `--split-index` is + given again, all changes in $GIT_DIR/index are pushed back to + the shared index file. This mode is designed for very large + indexes that take a signficant amount of time to read or write. + \--:: Do not interpret any more arguments as options. diff --git a/Documentation/git-verify-commit.txt b/Documentation/git-verify-commit.txt new file mode 100644 index 0000000000..9413e2802a --- /dev/null +++ b/Documentation/git-verify-commit.txt @@ -0,0 +1,28 @@ +git-verify-commit(1) +==================== + +NAME +---- +git-verify-commit - Check the GPG signature of commits + +SYNOPSIS +-------- +[verse] +'git verify-commit' ... + +DESCRIPTION +----------- +Validates the gpg signature created by 'git commit -S'. + +OPTIONS +------- +-v:: +--verbose:: + Print the contents of the commit object before validating it. + +...:: + SHA-1 identifiers of Git commit objects. + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Documentation/git.txt b/Documentation/git.txt index 7924209671..26de4dd548 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,17 @@ unreleased) version of Git, that is available from the 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v2.0.1/git.html[documentation for release 2.0.1] +* link:v2.1.0/git.html[documentation for release 2.1] * release notes for + link:RelNotes/2.1.0.txt[2.1]. + +* link:v2.0.4/git.html[documentation for release 2.0.4] + +* release notes for + link:RelNotes/2.0.4.txt[2.0.4], + link:RelNotes/2.0.3.txt[2.0.3], + link:RelNotes/2.0.2.txt[2.0.2], link:RelNotes/2.0.1.txt[2.0.1], link:RelNotes/2.0.0.txt[2.0.0]. @@ -444,6 +452,11 @@ example the following invocations are equivalent: given will override values from configuration files. The is expected in the same format as listed by 'git config' (subkeys separated by dots). ++ +Note that omitting the `=` in `git -c foo.bar ...` is allowed and sets +`foo.bar` to the boolean true value (just like `[foo]bar` would in a +config file). Including the equals but with an empty value (like `git -c +foo.bar= ...`) sets `foo.bar` to the empty string. --exec-path[=]:: Path to wherever your core Git programs are installed. @@ -905,31 +918,54 @@ for further details. based on whether stdout appears to be redirected to a file or not. 'GIT_TRACE':: - If this variable is set to "1", "2" or "true" (comparison - is case insensitive), Git will print `trace:` messages on - stderr telling about alias expansion, built-in command - execution and external command execution. - If this variable is set to an integer value greater than 1 - and lower than 10 (strictly) then Git will interpret this - value as an open file descriptor and will try to write the - trace messages into this file descriptor. - Alternatively, if this variable is set to an absolute path - (starting with a '/' character), Git will interpret this - as a file path and will try to write the trace messages - into it. + Enables general trace messages, e.g. alias expansion, built-in + command execution and external command execution. ++ +If this variable is set to "1", "2" or "true" (comparison +is case insensitive), trace messages will be printed to +stderr. ++ +If the variable is set to an integer value greater than 2 +and lower than 10 (strictly) then Git will interpret this +value as an open file descriptor and will try to write the +trace messages into this file descriptor. ++ +Alternatively, if the variable is set to an absolute path +(starting with a '/' character), Git will interpret this +as a file path and will try to write the trace messages +into it. ++ +Unsetting the variable, or setting it to empty, "0" or +"false" (case insensitive) disables trace messages. 'GIT_TRACE_PACK_ACCESS':: - If this variable is set to a path, a file will be created at - the given path logging all accesses to any packs. For each + Enables trace messages for all accesses to any packs. For each access, the pack file name and an offset in the pack is recorded. This may be helpful for troubleshooting some pack-related performance problems. + See 'GIT_TRACE' for available trace output options. 'GIT_TRACE_PACKET':: - If this variable is set, it shows a trace of all packets - coming in or out of a given program. This can help with - debugging object negotiation or other protocol issues. Tracing - is turned off at a packet starting with "PACK". + Enables trace messages for all packets coming in or out of a + given program. This can help with debugging object negotiation + or other protocol issues. Tracing is turned off at a packet + starting with "PACK". + See 'GIT_TRACE' for available trace output options. + +'GIT_TRACE_PERFORMANCE':: + Enables performance related trace messages, e.g. total execution + time of each Git command. + See 'GIT_TRACE' for available trace output options. + +'GIT_TRACE_SETUP':: + Enables trace messages printing the .git, working tree and current + working directory after Git has completed its setup phase. + See 'GIT_TRACE' for available trace output options. + +'GIT_TRACE_SHALLOW':: + Enables trace messages that can help debugging fetching / + cloning of shallow repositories. + See 'GIT_TRACE' for available trace output options. GIT_LITERAL_PATHSPECS:: Setting this variable to `1` will cause Git to treat all @@ -1043,7 +1079,7 @@ Authors ------- Git was started by Linus Torvalds, and is currently maintained by Junio C Hamano. Numerous contributions have come from the Git mailing list -. http://www.ohloh.net/p/git/contributors/summary +. http://www.openhub.net/p/git/contributors/summary gives you a more complete list of contributors. If you have a clone of git.git itself, the diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 643c1ba929..9b45bda748 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -440,8 +440,8 @@ Unspecified:: A path to which the `diff` attribute is unspecified first gets its contents inspected, and if it looks like - text, it is treated as text. Otherwise it would - generate `Binary files differ`. + text and is smaller than core.bigFileThreshold, it is treated + as text. Otherwise it would generate `Binary files differ`. String:: diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt index 17d2ea6c1e..79653f3134 100644 --- a/Documentation/gitrepository-layout.txt +++ b/Documentation/gitrepository-layout.txt @@ -155,6 +155,10 @@ index:: The current index file for the repository. It is usually not found in a bare repository. +sharedindex.:: + The shared index part, to be referenced by $GIT_DIR/index and + other temporary index files. Only valid in split index mode. + info:: Additional information about the repository is recorded in this directory. diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt index 85d63532a3..6c30723740 100644 --- a/Documentation/pretty-formats.txt +++ b/Documentation/pretty-formats.txt @@ -115,18 +115,20 @@ The placeholders are: - '%aD': author date, RFC2822 style - '%ar': author date, relative - '%at': author date, UNIX timestamp -- '%ai': author date, ISO 8601 format +- '%ai': author date, ISO 8601-like format +- '%aI': author date, strict ISO 8601 format - '%cn': committer name - '%cN': committer name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1]) - '%ce': committer email - '%cE': committer email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1]) -- '%cd': committer date +- '%cd': committer date (format respects --date= option) - '%cD': committer date, RFC2822 style - '%cr': committer date, relative - '%ct': committer date, UNIX timestamp -- '%ci': committer date, ISO 8601 format +- '%ci': committer date, ISO 8601-like format +- '%cI': committer date, strict ISO 8601 format - '%d': ref names, like the --decorate option of linkgit:git-log[1] - '%e': encoding - '%s': subject diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index deb8cca917..5d311b8d46 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -677,7 +677,7 @@ include::pretty-options.txt[] --relative-date:: Synonym for `--date=relative`. ---date=(relative|local|default|iso|rfc|short|raw):: +--date=(relative|local|default|iso|iso-strict|rfc|short|raw):: Only takes effect for dates shown in human-readable format, such as when using `--pretty`. `log.date` config variable sets a default value for the log command's `--date` option. @@ -687,7 +687,16 @@ e.g. ``2 hours ago''. + `--date=local` shows timestamps in user's local time zone. + -`--date=iso` (or `--date=iso8601`) shows timestamps in ISO 8601 format. +`--date=iso` (or `--date=iso8601`) shows timestamps in a ISO 8601-like format. +The differences to the strict ISO 8601 format are: + + - a space instead of the `T` date/time delimiter + - a space between time and time zone + - no colon between hours and minutes of the time zone + ++ +`--date=iso-strict` (or `--date=iso8601-strict`) shows timestamps in strict +ISO 8601 format. + `--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822 format, often found in email messages. diff --git a/Documentation/technical/api-config.txt b/Documentation/technical/api-config.txt index 230b3a0f60..0d8b99b368 100644 --- a/Documentation/technical/api-config.txt +++ b/Documentation/technical/api-config.txt @@ -77,6 +77,99 @@ To read a specific file in git-config format, use `git_config_from_file`. This takes the same callback and data parameters as `git_config`. +Querying For Specific Variables +------------------------------- + +For programs wanting to query for specific variables in a non-callback +manner, the config API provides two functions `git_config_get_value` +and `git_config_get_value_multi`. They both read values from an internal +cache generated previously from reading the config files. + +`int git_config_get_value(const char *key, const char **value)`:: + + Finds the highest-priority value for the configuration variable `key`, + stores the pointer to it in `value` and returns 0. When the + configuration variable `key` is not found, returns 1 without touching + `value`. The caller should not free or modify `value`, as it is owned + by the cache. + +`const struct string_list *git_config_get_value_multi(const char *key)`:: + + Finds and returns the value list, sorted in order of increasing priority + for the configuration variable `key`. When the configuration variable + `key` is not found, returns NULL. The caller should not free or modify + the returned pointer, as it is owned by the cache. + +`void git_config_clear(void)`:: + + Resets and invalidates the config cache. + +The config API also provides type specific API functions which do conversion +as well as retrieval for the queried variable, including: + +`int git_config_get_int(const char *key, int *dest)`:: + + Finds and parses the value to an integer for the configuration variable + `key`. Dies on error; otherwise, stores the value of the parsed integer in + `dest` and returns 0. When the configuration variable `key` is not found, + returns 1 without touching `dest`. + +`int git_config_get_ulong(const char *key, unsigned long *dest)`:: + + Similar to `git_config_get_int` but for unsigned longs. + +`int git_config_get_bool(const char *key, int *dest)`:: + + Finds and parses the value into a boolean value, for the configuration + variable `key` respecting keywords like "true" and "false". Integer + values are converted into true/false values (when they are non-zero or + zero, respectively). Other values cause a die(). If parsing is successful, + stores the value of the parsed result in `dest` and returns 0. When the + configuration variable `key` is not found, returns 1 without touching + `dest`. + +`int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)`:: + + Similar to `git_config_get_bool`, except that integers are copied as-is, + and `is_bool` flag is unset. + +`int git_config_get_maybe_bool(const char *key, int *dest)`:: + + Similar to `git_config_get_bool`, except that it returns -1 on error + rather than dying. + +`int git_config_get_string_const(const char *key, const char **dest)`:: + + Allocates and copies the retrieved string into the `dest` parameter for + the configuration variable `key`; if NULL string is given, prints an + error message and returns -1. When the configuration variable `key` is + not found, returns 1 without touching `dest`. + +`int git_config_get_string(const char *key, char **dest)`:: + + Similar to `git_config_get_string_const`, except that retrieved value + copied into the `dest` parameter is a mutable string. + +`int git_config_get_pathname(const char *key, const char **dest)`:: + + Similar to `git_config_get_string`, but expands `~` or `~user` into + the user's home directory when found at the beginning of the path. + +`git_die_config(const char *key, const char *err, ...)`:: + + First prints the error message specified by the caller in `err` and then + dies printing the line number and the file name of the highest priority + value for the configuration variable `key`. + +`void git_die_config_linenr(const char *key, const char *filename, int linenr)`:: + + Helper function which formats the die error message according to the + parameters entered. Used by `git_die_config()`. It can be used by callers + handling `git_config_get_value_multi()` to print the correct error message + for the desired value. + +See test-config.c for usage examples. + Value Parsing Helpers --------------------- @@ -134,7 +227,98 @@ int read_file_with_include(const char *file, config_fn_t fn, void *data) `git_config` respects includes automatically. The lower-level `git_config_from_file` does not. +Custom Configsets +----------------- + +A `config_set` can be used to construct an in-memory cache for +config-like files that the caller specifies (i.e., files like `.gitmodules`, +`~/.gitconfig` etc.). For example, + +--------------------------------------- +struct config_set gm_config; +git_configset_init(&gm_config); +int b; +/* we add config files to the config_set */ +git_configset_add_file(&gm_config, ".gitmodules"); +git_configset_add_file(&gm_config, ".gitmodules_alt"); + +if (!git_configset_get_bool(gm_config, "submodule.frotz.ignore", &b)) { + /* hack hack hack */ +} + +/* when we are done with the configset */ +git_configset_clear(&gm_config); +---------------------------------------- + +Configset API provides functions for the above mentioned work flow, including: + +`void git_configset_init(struct config_set *cs)`:: + + Initializes the config_set `cs`. + +`int git_configset_add_file(struct config_set *cs, const char *filename)`:: + + Parses the file and adds the variable-value pairs to the `config_set`, + dies if there is an error in parsing the file. Returns 0 on success, or + -1 if the file does not exist or is inaccessible. The user has to decide + if he wants to free the incomplete configset or continue using it when + the function returns -1. + +`int git_configset_get_value(struct config_set *cs, const char *key, const char **value)`:: + + Finds the highest-priority value for the configuration variable `key` + and config set `cs`, stores the pointer to it in `value` and returns 0. + When the configuration variable `key` is not found, returns 1 without + touching `value`. The caller should not free or modify `value`, as it + is owned by the cache. + +`const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key)`:: + + Finds and returns the value list, sorted in order of increasing priority + for the configuration variable `key` and config set `cs`. When the + configuration variable `key` is not found, returns NULL. The caller + should not free or modify the returned pointer, as it is owned by the cache. + +`void git_configset_clear(struct config_set *cs)`:: + + Clears `config_set` structure, removes all saved variable-value pairs. + +In addition to above functions, the `config_set` API provides type specific +functions in the vein of `git_config_get_int` and family but with an extra +parameter, pointer to struct `config_set`. +They all behave similarly to the `git_config_get*()` family described in +"Querying For Specific Variables" above. + Writing Config Files -------------------- -TODO +Git gives multiple entry points in the Config API to write config values to +files namely `git_config_set_in_file` and `git_config_set`, which write to +a specific config file or to `.git/config` respectively. They both take a +key/value pair as parameter. +In the end they both call `git_config_set_multivar_in_file` which takes four +parameters: + +- the name of the file, as a string, to which key/value pairs will be written. + +- the name of key, as a string. This is in canonical "flat" form: the section, + subsection, and variable segments will be separated by dots, and the section + and variable segments will be all lowercase. + E.g., `core.ignorecase`, `diff.SomeType.textconv`. + +- the value of the variable, as a string. If value is equal to NULL, it will + remove the matching key from the config file. + +- the value regex, as a string. It will disregard key/value pairs where value + does not match. + +- a multi_replace value, as an int. If value is equal to zero, nothing or only + one matching key/value is replaced, else all matching key/values (regardless + how many) are removed, before the new pair is written. + +It returns 0 on success. + +Also, there are functions `git_config_rename_section` and +`git_config_rename_section_in_file` with parameters `old_name` and `new_name` +for renaming or removing sections in the config files. If NULL is passed +through `new_name` parameter, the section will be removed from the config file. diff --git a/Documentation/technical/api-hashmap.txt b/Documentation/technical/api-hashmap.txt index b977ae8bbb..ad7a5bddd2 100644 --- a/Documentation/technical/api-hashmap.txt +++ b/Documentation/technical/api-hashmap.txt @@ -8,11 +8,19 @@ Data Structures `struct hashmap`:: - The hash table structure. + The hash table structure. Members can be used as follows, but should + not be modified directly: + -The `size` member keeps track of the total number of entries. The `cmpfn` -member is a function used to compare two entries for equality. The `table` and -`tablesize` members store the hash table and its size, respectively. +The `size` member keeps track of the total number of entries (0 means the +hashmap is empty). ++ +`tablesize` is the allocated size of the hash table. A non-0 value indicates +that the hashmap is initialized. It may also be useful for statistical purposes +(i.e. `size / tablesize` is the current load factor). ++ +`cmpfn` stores the comparison function specified in `hashmap_init()`. In +advanced scenarios, it may be useful to change this, e.g. to switch between +case-sensitive and case-insensitive lookup. `struct hashmap_entry`:: @@ -58,6 +66,15 @@ Functions + `strihash` and `memihash` are case insensitive versions. +`unsigned int sha1hash(const unsigned char *sha1)`:: + + Converts a cryptographic hash (e.g. SHA-1) into an int-sized hash code + for use in hash tables. Cryptographic hashes are supposed to have + uniform distribution, so in contrast to `memhash()`, this just copies + the first `sizeof(int)` bytes without shuffling any bits. Note that + the results will be different on big-endian and little-endian + platforms, so they should not be stored or transferred over the net. + `void hashmap_init(struct hashmap *map, hashmap_cmp_fn equals_function, size_t initial_size)`:: Initializes a hashmap structure. @@ -101,6 +118,20 @@ hashmap_entry) that has at least been initialized with the proper hash code If an entry with matching hash code is found, `key` and `keydata` are passed to `hashmap_cmp_fn` to decide whether the entry matches the key. +`void *hashmap_get_from_hash(const struct hashmap *map, unsigned int hash, const void *keydata)`:: + + Returns the hashmap entry for the specified hash code and key data, + or NULL if not found. ++ +`map` is the hashmap structure. ++ +`hash` is the hash code of the entry to look up. ++ +If an entry with matching hash code is found, `keydata` is passed to +`hashmap_cmp_fn` to decide whether the entry matches the key. The +`entry_or_key` parameter points to a bogus hashmap_entry structure that +should not be used in the comparison. + `void *hashmap_get_next(const struct hashmap *map, const void *entry)`:: Returns the next equal hashmap entry, or NULL if not found. This can be @@ -162,6 +193,21 @@ more entries. `hashmap_iter_first` is a combination of both (i.e. initializes the iterator and returns the first entry, if any). +`const char *strintern(const char *string)`:: +`const void *memintern(const void *data, size_t len)`:: + + Returns the unique, interned version of the specified string or data, + similar to the `String.intern` API in Java and .NET, respectively. + Interned strings remain valid for the entire lifetime of the process. ++ +Can be used as `[x]strdup()` or `xmemdupz` replacement, except that interned +strings / data must not be modified or freed. ++ +Interned strings are best used for short strings with high probability of +duplicates. ++ +Uses a hashmap to store the pool of interned strings. + Usage example ------------- diff --git a/Documentation/technical/api-run-command.txt b/Documentation/technical/api-run-command.txt index 69510ae57a..842b8389eb 100644 --- a/Documentation/technical/api-run-command.txt +++ b/Documentation/technical/api-run-command.txt @@ -13,6 +13,10 @@ produces in the caller in order to process it. Functions --------- +`child_process_init` + + Initialize a struct child_process variable. + `start_command`:: Start a sub-process. Takes a pointer to a `struct child_process` @@ -96,8 +100,8 @@ command to run in a sub-process. The caller: -1. allocates and clears (memset(&chld, 0, sizeof(chld));) a - struct child_process variable; +1. allocates and clears (using child_process_init() or + CHILD_PROCESS_INIT) a struct child_process variable; 2. initializes the members; 3. calls start_command(); 4. processes the data; diff --git a/Documentation/technical/api-strbuf.txt b/Documentation/technical/api-strbuf.txt index f9c06a7573..430302c2f4 100644 --- a/Documentation/technical/api-strbuf.txt +++ b/Documentation/technical/api-strbuf.txt @@ -307,6 +307,16 @@ same behaviour as well. use it unless you need the correct position in the file descriptor. +`strbuf_getcwd`:: + + Set the buffer to the path of the current working directory. + +`strbuf_add_absolute_path` + + Add a path to a buffer, converting a relative path to an + absolute one in the process. Symbolic links are not + resolved. + `stripspace`:: Strip whitespace from a buffer. The second parameter controls if diff --git a/Documentation/technical/api-string-list.txt b/Documentation/technical/api-string-list.txt index f1add51efe..d51a6579c8 100644 --- a/Documentation/technical/api-string-list.txt +++ b/Documentation/technical/api-string-list.txt @@ -68,6 +68,11 @@ Functions * General ones (works with sorted and unsorted lists as well) +`string_list_init`:: + + Initialize the members of the string_list, set `strdup_strings` + member according to the value of the second parameter. + `filter_string_list`:: Apply a function to each item in a list, retaining only the diff --git a/Documentation/technical/api-trace.txt b/Documentation/technical/api-trace.txt new file mode 100644 index 0000000000..097a651d96 --- /dev/null +++ b/Documentation/technical/api-trace.txt @@ -0,0 +1,97 @@ +trace API +========= + +The trace API can be used to print debug messages to stderr or a file. Trace +code is inactive unless explicitly enabled by setting `GIT_TRACE*` environment +variables. + +The trace implementation automatically adds `timestamp file:line ... \n` to +all trace messages. E.g.: + +------------ +23:59:59.123456 git.c:312 trace: built-in: git 'foo' +00:00:00.000001 builtin/foo.c:99 foo: some message +------------ + +Data Structures +--------------- + +`struct trace_key`:: + + Defines a trace key (or category). The default (for API functions that + don't take a key) is `GIT_TRACE`. ++ +E.g. to define a trace key controlled by environment variable `GIT_TRACE_FOO`: ++ +------------ +static struct trace_key trace_foo = TRACE_KEY_INIT(FOO); + +static void trace_print_foo(const char *message) +{ + trace_print_key(&trace_foo, message); +} +------------ ++ +Note: don't use `const` as the trace implementation stores internal state in +the `trace_key` structure. + +Functions +--------- + +`int trace_want(struct trace_key *key)`:: + + Checks whether the trace key is enabled. Used to prevent expensive + string formatting before calling one of the printing APIs. + +`void trace_disable(struct trace_key *key)`:: + + Disables tracing for the specified key, even if the environment + variable was set. + +`void trace_printf(const char *format, ...)`:: +`void trace_printf_key(struct trace_key *key, const char *format, ...)`:: + + Prints a formatted message, similar to printf. + +`void trace_argv_printf(const char **argv, const char *format, ...)``:: + + Prints a formatted message, followed by a quoted list of arguments. + +`void trace_strbuf(struct trace_key *key, const struct strbuf *data)`:: + + Prints the strbuf, without additional formatting (i.e. doesn't + choke on `%` or even `\0`). + +`uint64_t getnanotime(void)`:: + + Returns nanoseconds since the epoch (01/01/1970), typically used + for performance measurements. ++ +Currently there are high precision timer implementations for Linux (using +`clock_gettime(CLOCK_MONOTONIC)`) and Windows (`QueryPerformanceCounter`). +Other platforms use `gettimeofday` as time source. + +`void trace_performance(uint64_t nanos, const char *format, ...)`:: +`void trace_performance_since(uint64_t start, const char *format, ...)`:: + + Prints the elapsed time (in nanoseconds), or elapsed time since + `start`, followed by a formatted message. Enabled via environment + variable `GIT_TRACE_PERFORMANCE`. Used for manual profiling, e.g.: ++ +------------ +uint64_t start = getnanotime(); +/* code section to measure */ +trace_performance_since(start, "foobar"); +------------ ++ +------------ +uint64_t t = 0; +for (;;) { + /* ignore */ + t -= getnanotime(); + /* code section to measure */ + t += getnanotime(); + /* ignore */ +} +trace_performance(t, "frotz"); +------------ diff --git a/Documentation/technical/index-format.txt b/Documentation/technical/index-format.txt index f352a9b22e..fe6f31667d 100644 --- a/Documentation/technical/index-format.txt +++ b/Documentation/technical/index-format.txt @@ -129,6 +129,9 @@ Git index format (Version 4) In version 4, the padding after the pathname does not exist. + Interpretation of index entries in split index mode is completely + different. See below for details. + == Extensions === Cached tree @@ -198,3 +201,35 @@ Git index format - At most three 160-bit object names of the entry in stages from 1 to 3 (nothing is written for a missing stage). +=== Split index + + In split index mode, the majority of index entries could be stored + in a separate file. This extension records the changes to be made on + top of that to produce the final index. + + The signature for this extension is { 'l', 'i, 'n', 'k' }. + + The extension consists of: + + - 160-bit SHA-1 of the shared index file. The shared index file path + is $GIT_DIR/sharedindex.. If all 160 bits are zero, the + index does not require a shared index file. + + - An ewah-encoded delete bitmap, each bit represents an entry in the + shared index. If a bit is set, its corresponding entry in the + shared index will be removed from the final index. Note, because + a delete operation changes index entry positions, but we do need + original positions in replace phase, it's best to just mark + entries for removal, then do a mass deletion after replacement. + + - An ewah-encoded replace bitmap, each bit represents an entry in + the shared index. If a bit is set, its corresponding entry in the + shared index will be replaced with an entry in this index + file. All replaced entries are stored in sorted order in this + index. The first "1" bit in the replace bitmap corresponds to the + first index entry, the second "1" bit to the second entry and so + on. Replaced entries may have empty path names to save space. + + The remaining index entries after replaced ones will be added to the + final index. These added entries are also sorted by entry namme then + stage. diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt index 18dea8d15f..569c48a352 100644 --- a/Documentation/technical/pack-protocol.txt +++ b/Documentation/technical/pack-protocol.txt @@ -467,7 +467,7 @@ references. ---- update-request = *shallow command-list [pack-file] - shallow = PKT-LINE("shallow" SP obj-id) + shallow = PKT-LINE("shallow" SP obj-id LF) command-list = PKT-LINE(command NUL capability-list LF) *PKT-LINE(command LF) diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 40adbf7bf7..153d55d2b9 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.0.0.GIT +DEF_VER=v2.1.0.GIT LF=' ' diff --git a/INSTALL b/INSTALL index ba01e7421e..6ec7a24e1a 100644 --- a/INSTALL +++ b/INSTALL @@ -28,7 +28,7 @@ set up install paths (via config.mak.autogen), so you can write instead If you're willing to trade off (much) longer build time for a later faster git you can also do a profile feedback build with - $ make prefix=/usr PROFILE=BUILD all + $ make prefix=/usr profile # make prefix=/usr PROFILE=BUILD install This will run the complete test suite as training workload and then @@ -36,10 +36,20 @@ rebuild git with the generated profile feedback. This results in a git which is a few percent faster on CPU intensive workloads. This may be a good tradeoff for distribution packagers. +Alternatively you can run profile feedback only with the git benchmark +suite. This runs significantly faster than the full test suite, but +has less coverage: + + $ make prefix=/usr profile-fast + # make prefix=/usr PROFILE=BUILD install + Or if you just want to install a profile-optimized version of git into your home directory, you could run: - $ make PROFILE=BUILD install + $ make profile-install + +or + $ make profile-fast-install As a caveat: a profile-optimized build takes a *lot* longer since the git tree must be built twice, and in order for the profiling diff --git a/Makefile b/Makefile index 7d12e8edc2..d8284bd309 100644 --- a/Makefile +++ b/Makefile @@ -317,9 +317,6 @@ all:: # dependency rules. The default is "auto", which means to use computed header # dependencies if your compiler is detected to support it. # -# Define CHECK_HEADER_DEPENDENCIES to check for problems in the hard-coded -# dependency rules. -# # Define NATIVE_CRLF if your platform uses CRLF for line endings. # # Define XDL_FAST_HASH to use an alternative line-hashing method in @@ -340,6 +337,8 @@ all:: # # Define GMTIME_UNRELIABLE_ERRORS if your gmtime() function does not # return NULL when it receives a bogus time_t. +# +# Define HAVE_CLOCK_GETTIME if your platform has clock_gettime in librt. GIT-VERSION-FILE: FORCE @$(SHELL_PATH) ./GIT-VERSION-GEN @@ -430,7 +429,6 @@ XDIFF_OBJS = VCSSVN_OBJS = GENERATED_H = EXTRA_CPPFLAGS = -LIB_H = LIB_OBJS = PROGRAM_OBJS = PROGRAMS = @@ -549,9 +547,11 @@ PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS)) TEST_PROGRAMS_NEED_X += test-chmtime TEST_PROGRAMS_NEED_X += test-ctype +TEST_PROGRAMS_NEED_X += test-config TEST_PROGRAMS_NEED_X += test-date TEST_PROGRAMS_NEED_X += test-delta TEST_PROGRAMS_NEED_X += test-dump-cache-tree +TEST_PROGRAMS_NEED_X += test-dump-split-index TEST_PROGRAMS_NEED_X += test-genrandom TEST_PROGRAMS_NEED_X += test-hashmap TEST_PROGRAMS_NEED_X += test-index-version @@ -628,131 +628,11 @@ VCSSVN_LIB = vcs-svn/lib.a GENERATED_H += common-cmds.h -LIB_H += advice.h -LIB_H += archive.h -LIB_H += argv-array.h -LIB_H += attr.h -LIB_H += bisect.h -LIB_H += blob.h -LIB_H += branch.h -LIB_H += builtin.h -LIB_H += bulk-checkin.h -LIB_H += bundle.h -LIB_H += cache-tree.h -LIB_H += cache.h -LIB_H += color.h -LIB_H += column.h -LIB_H += commit.h -LIB_H += compat/bswap.h -LIB_H += compat/mingw.h -LIB_H += compat/obstack.h -LIB_H += compat/poll/poll.h -LIB_H += compat/precompose_utf8.h -LIB_H += compat/terminal.h -LIB_H += compat/win32/dirent.h -LIB_H += compat/win32/pthread.h -LIB_H += compat/win32/syslog.h -LIB_H += connected.h -LIB_H += convert.h -LIB_H += credential.h -LIB_H += csum-file.h -LIB_H += decorate.h -LIB_H += delta.h -LIB_H += diff.h -LIB_H += diffcore.h -LIB_H += dir.h -LIB_H += exec_cmd.h -LIB_H += ewah/ewok.h -LIB_H += ewah/ewok_rlw.h -LIB_H += fetch-pack.h -LIB_H += fmt-merge-msg.h -LIB_H += fsck.h -LIB_H += gettext.h -LIB_H += git-compat-util.h -LIB_H += gpg-interface.h -LIB_H += graph.h -LIB_H += grep.h -LIB_H += hashmap.h -LIB_H += help.h -LIB_H += http.h -LIB_H += kwset.h -LIB_H += levenshtein.h -LIB_H += line-log.h -LIB_H += line-range.h -LIB_H += list-objects.h -LIB_H += ll-merge.h -LIB_H += log-tree.h -LIB_H += mailmap.h -LIB_H += merge-blobs.h -LIB_H += merge-recursive.h -LIB_H += mergesort.h -LIB_H += notes-cache.h -LIB_H += notes-merge.h -LIB_H += notes-utils.h -LIB_H += notes.h -LIB_H += object.h -LIB_H += pack-objects.h -LIB_H += pack-revindex.h -LIB_H += pack.h -LIB_H += pack-bitmap.h -LIB_H += parse-options.h -LIB_H += patch-ids.h -LIB_H += pathspec.h -LIB_H += pkt-line.h -LIB_H += prio-queue.h -LIB_H += progress.h -LIB_H += prompt.h -LIB_H += quote.h -LIB_H += reachable.h -LIB_H += reflog-walk.h -LIB_H += refs.h -LIB_H += remote.h -LIB_H += rerere.h -LIB_H += resolve-undo.h -LIB_H += revision.h -LIB_H += run-command.h -LIB_H += send-pack.h -LIB_H += sequencer.h -LIB_H += sha1-array.h -LIB_H += sha1-lookup.h -LIB_H += shortlog.h -LIB_H += sideband.h -LIB_H += sigchain.h -LIB_H += strbuf.h -LIB_H += streaming.h -LIB_H += string-list.h -LIB_H += submodule.h -LIB_H += tag.h -LIB_H += tar.h -LIB_H += thread-utils.h -LIB_H += transport.h -LIB_H += tree-walk.h -LIB_H += tree.h -LIB_H += unpack-trees.h -LIB_H += unicode_width.h -LIB_H += url.h -LIB_H += urlmatch.h -LIB_H += userdiff.h -LIB_H += utf8.h -LIB_H += varint.h -LIB_H += vcs-svn/fast_export.h -LIB_H += vcs-svn/line_buffer.h -LIB_H += vcs-svn/repo_tree.h -LIB_H += vcs-svn/sliding_window.h -LIB_H += vcs-svn/svndiff.h -LIB_H += vcs-svn/svndump.h -LIB_H += walker.h -LIB_H += wildmatch.h -LIB_H += wt-status.h -LIB_H += xdiff-interface.h -LIB_H += xdiff/xdiff.h -LIB_H += xdiff/xdiffi.h -LIB_H += xdiff/xemit.h -LIB_H += xdiff/xinclude.h -LIB_H += xdiff/xmacros.h -LIB_H += xdiff/xprepare.h -LIB_H += xdiff/xtypes.h -LIB_H += xdiff/xutils.h +LIB_H = $(shell $(FIND) . \ + -name .git -prune -o \ + -name t -prune -o \ + -name Documentation -prune -o \ + -name '*.h' -print) LIB_OBJS += abspath.o LIB_OBJS += advice.o @@ -875,6 +755,7 @@ LIB_OBJS += sha1_name.o LIB_OBJS += shallow.o LIB_OBJS += sideband.o LIB_OBJS += sigchain.o +LIB_OBJS += split-index.o LIB_OBJS += strbuf.o LIB_OBJS += streaming.o LIB_OBJS += string-list.o @@ -999,6 +880,7 @@ BUILTIN_OBJS += builtin/update-ref.o BUILTIN_OBJS += builtin/update-server-info.o BUILTIN_OBJS += builtin/upload-archive.o BUILTIN_OBJS += builtin/var.o +BUILTIN_OBJS += builtin/verify-commit.o BUILTIN_OBJS += builtin/verify-pack.o BUILTIN_OBJS += builtin/verify-tag.o BUILTIN_OBJS += builtin/write-tree.o @@ -1020,11 +902,6 @@ sysconfdir = etc endif endif -ifdef CHECK_HEADER_DEPENDENCIES -COMPUTE_HEADER_DEPENDENCIES = no -USE_COMPUTED_HEADER_DEPENDENCIES = -endif - ifndef COMPUTE_HEADER_DEPENDENCIES COMPUTE_HEADER_DEPENDENCIES = auto endif @@ -1376,7 +1253,6 @@ ifdef NO_INET_PTON endif ifndef NO_UNIX_SOCKETS LIB_OBJS += unix-socket.o - LIB_H += unix-socket.h PROGRAM_OBJS += credential-cache.o PROGRAM_OBJS += credential-cache--daemon.o endif @@ -1400,12 +1276,10 @@ endif ifdef BLK_SHA1 SHA1_HEADER = "block-sha1/sha1.h" LIB_OBJS += block-sha1/sha1.o - LIB_H += block-sha1/sha1.h else ifdef PPC_SHA1 SHA1_HEADER = "ppc/sha1.h" LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o - LIB_H += ppc/sha1.h else ifdef APPLE_COMMON_CRYPTO COMPAT_CFLAGS += -DCOMMON_DIGEST_FOR_OPENSSL @@ -1500,6 +1374,11 @@ ifdef GMTIME_UNRELIABLE_ERRORS BASIC_CFLAGS += -DGMTIME_UNRELIABLE_ERRORS endif +ifdef HAVE_CLOCK_GETTIME + BASIC_CFLAGS += -DHAVE_CLOCK_GETTIME + EXTLIBS += -lrt +endif + ifeq ($(TCLTK_PATH),) NO_TCLTK = NoThanks endif @@ -1555,13 +1434,13 @@ endif PROFILE_DIR := $(CURDIR) ifeq ("$(PROFILE)","GEN") - CFLAGS += -fprofile-generate=$(PROFILE_DIR) -DNO_NORETURN=1 + BASIC_CFLAGS += -fprofile-generate=$(PROFILE_DIR) -DNO_NORETURN=1 EXTLIBS += -lgcov export CCACHE_DISABLE = t V = 1 else ifneq ("$(PROFILE)","") - CFLAGS += -fprofile-use=$(PROFILE_DIR) -fprofile-correction -DNO_NORETURN=1 + BASIC_CFLAGS += -fprofile-use=$(PROFILE_DIR) -fprofile-correction -DNO_NORETURN=1 export CCACHE_DISABLE = t V = 1 endif @@ -1646,12 +1525,24 @@ SHELL = $(SHELL_PATH) all:: shell_compatibility_test ifeq "$(PROFILE)" "BUILD" -ifeq ($(filter all,$(MAKECMDGOALS)),all) -all:: profile-clean +all:: profile +endif + +profile:: profile-clean $(MAKE) PROFILE=GEN all $(MAKE) PROFILE=GEN -j1 test -endif -endif + @if test -n "$$GIT_PERF_REPO" || test -d .git; then \ + $(MAKE) PROFILE=GEN -j1 perf; \ + else \ + echo "Skipping profile of perf tests..."; \ + fi + $(MAKE) PROFILE=USE all + +profile-fast: profile-clean + $(MAKE) PROFILE=GEN all + $(MAKE) PROFILE=GEN -j1 perf + $(MAKE) PROFILE=USE all + all:: $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS ifneq (,$X) @@ -1918,29 +1809,13 @@ $(dep_dirs): missing_dep_dirs := $(filter-out $(wildcard $(dep_dirs)),$(dep_dirs)) dep_file = $(dir $@).depend/$(notdir $@).d dep_args = -MF $(dep_file) -MQ $@ -MMD -MP -ifdef CHECK_HEADER_DEPENDENCIES -$(error cannot compute header dependencies outside a normal build. \ -Please unset CHECK_HEADER_DEPENDENCIES and try again) -endif endif ifneq ($(COMPUTE_HEADER_DEPENDENCIES),yes) -ifndef CHECK_HEADER_DEPENDENCIES dep_dirs = missing_dep_dirs = dep_args = endif -endif - -ifdef CHECK_HEADER_DEPENDENCIES -ifndef PRINT_HEADER_DEPENDENCIES -missing_deps = $(filter-out $(notdir $^), \ - $(notdir $(shell $(MAKE) -s $@ \ - CHECK_HEADER_DEPENDENCIES=YesPlease \ - USE_COMPUTED_HEADER_DEPENDENCIES=YesPlease \ - PRINT_HEADER_DEPENDENCIES=YesPlease))) -endif -endif ASM_SRC := $(wildcard $(OBJECTS:o=S)) ASM_OBJ := $(ASM_SRC:S=o) @@ -1948,45 +1823,10 @@ C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS)) .SUFFIXES: -ifdef PRINT_HEADER_DEPENDENCIES -$(C_OBJ): %.o: %.c FORCE - echo $^ -$(ASM_OBJ): %.o: %.S FORCE - echo $^ - -ifndef CHECK_HEADER_DEPENDENCIES -$(error cannot print header dependencies during a normal build. \ -Please set CHECK_HEADER_DEPENDENCIES and try again) -endif -endif - -ifndef PRINT_HEADER_DEPENDENCIES -ifdef CHECK_HEADER_DEPENDENCIES -$(C_OBJ): %.o: %.c $(dep_files) FORCE - @set -e; echo CHECK $@; \ - missing_deps="$(missing_deps)"; \ - if test "$$missing_deps"; \ - then \ - echo missing dependencies: $$missing_deps; \ - false; \ - fi -$(ASM_OBJ): %.o: %.S $(dep_files) FORCE - @set -e; echo CHECK $@; \ - missing_deps="$(missing_deps)"; \ - if test "$$missing_deps"; \ - then \ - echo missing dependencies: $$missing_deps; \ - false; \ - fi -endif -endif - -ifndef CHECK_HEADER_DEPENDENCIES $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< -endif %.s: %.c GIT-CFLAGS FORCE $(QUIET_CC)$(CC) -o $@ -S $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< @@ -2113,9 +1953,9 @@ XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \ XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell \ --keyword=gettextln --keyword=eval_gettextln XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl -LOCALIZED_C := $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H) -LOCALIZED_SH := $(SCRIPT_SH) -LOCALIZED_PERL := $(SCRIPT_PERL) +LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H) +LOCALIZED_SH = $(SCRIPT_SH) +LOCALIZED_PERL = $(SCRIPT_PERL) ifdef XGETTEXT_INCLUDE_TESTS LOCALIZED_C += t/t0200/test.c @@ -2123,7 +1963,7 @@ LOCALIZED_SH += t/t0200/test.sh LOCALIZED_PERL += t/t0200/test.perl endif -po/git.pot: $(LOCALIZED_C) +po/git.pot: $(GENERATED_H) FORCE $(QUIET_XGETTEXT)$(XGETTEXT) -o$@+ $(XGETTEXT_FLAGS_C) $(LOCALIZED_C) $(QUIET_XGETTEXT)$(XGETTEXT) -o$@+ --join-existing $(XGETTEXT_FLAGS_SH) \ $(LOCALIZED_SH) @@ -2338,6 +2178,12 @@ mergetools_instdir_SQ = $(subst ','\'',$(mergetools_instdir)) install_bindir_programs := $(patsubst %,%$X,$(BINDIR_PROGRAMS_NEED_X)) $(BINDIR_PROGRAMS_NO_X) +profile-install: profile + $(MAKE) install + +profile-fast-install: profile-fast + $(MAKE) install + install: all $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' diff --git a/RelNotes b/RelNotes index bf76091401..c473b35ad9 120000 --- a/RelNotes +++ b/RelNotes @@ -1 +1 @@ -Documentation/RelNotes/2.1.0.txt \ No newline at end of file +Documentation/RelNotes/2.2.0.txt \ No newline at end of file diff --git a/abspath.c b/abspath.c index ca33558a91..5edb4e7816 100644 --- a/abspath.c +++ b/abspath.c @@ -33,7 +33,7 @@ int is_directory(const char *path) */ static const char *real_path_internal(const char *path, int die_on_error) { - static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1]; + static struct strbuf sb = STRBUF_INIT; char *retval = NULL; /* @@ -41,16 +41,14 @@ static const char *real_path_internal(const char *path, int die_on_error) * here so that we can chdir() back to it at the end of the * function: */ - char cwd[1024] = ""; - - int buf_index = 1; + struct strbuf cwd = STRBUF_INIT; int depth = MAXDEPTH; char *last_elem = NULL; struct stat st; /* We've already done it */ - if (path == buf || path == next_buf) + if (path == sb.buf) return path; if (!*path) { @@ -60,41 +58,38 @@ static const char *real_path_internal(const char *path, int die_on_error) goto error_out; } - if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) { - if (die_on_error) - die("Too long path: %.*s", 60, path); - else - goto error_out; - } + strbuf_reset(&sb); + strbuf_addstr(&sb, path); while (depth--) { - if (!is_directory(buf)) { - char *last_slash = find_last_dir_sep(buf); + if (!is_directory(sb.buf)) { + char *last_slash = find_last_dir_sep(sb.buf); if (last_slash) { last_elem = xstrdup(last_slash + 1); - last_slash[1] = '\0'; + strbuf_setlen(&sb, last_slash - sb.buf + 1); } else { - last_elem = xstrdup(buf); - *buf = '\0'; + last_elem = xmemdupz(sb.buf, sb.len); + strbuf_reset(&sb); } } - if (*buf) { - if (!*cwd && !getcwd(cwd, sizeof(cwd))) { + if (sb.len) { + if (!cwd.len && strbuf_getcwd(&cwd)) { if (die_on_error) die_errno("Could not get current working directory"); else goto error_out; } - if (chdir(buf)) { + if (chdir(sb.buf)) { if (die_on_error) - die_errno("Could not switch to '%s'", buf); + die_errno("Could not switch to '%s'", + sb.buf); else goto error_out; } } - if (!getcwd(buf, PATH_MAX)) { + if (strbuf_getcwd(&sb)) { if (die_on_error) die_errno("Could not get current working directory"); else @@ -102,48 +97,35 @@ static const char *real_path_internal(const char *path, int die_on_error) } if (last_elem) { - size_t len = strlen(buf); - if (len + strlen(last_elem) + 2 > PATH_MAX) { - if (die_on_error) - die("Too long path name: '%s/%s'", - buf, last_elem); - else - goto error_out; - } - if (len && !is_dir_sep(buf[len - 1])) - buf[len++] = '/'; - strcpy(buf + len, last_elem); + if (sb.len && !is_dir_sep(sb.buf[sb.len - 1])) + strbuf_addch(&sb, '/'); + strbuf_addstr(&sb, last_elem); free(last_elem); last_elem = NULL; } - if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) { - ssize_t len = readlink(buf, next_buf, PATH_MAX); + if (!lstat(sb.buf, &st) && S_ISLNK(st.st_mode)) { + struct strbuf next_sb = STRBUF_INIT; + ssize_t len = strbuf_readlink(&next_sb, sb.buf, 0); if (len < 0) { if (die_on_error) - die_errno("Invalid symlink '%s'", buf); - else - goto error_out; - } - if (PATH_MAX <= len) { - if (die_on_error) - die("symbolic link too long: %s", buf); + die_errno("Invalid symlink '%s'", + sb.buf); else goto error_out; } - next_buf[len] = '\0'; - buf = next_buf; - buf_index = 1 - buf_index; - next_buf = bufs[buf_index]; + strbuf_swap(&sb, &next_sb); + strbuf_release(&next_sb); } else break; } - retval = buf; + retval = sb.buf; error_out: free(last_elem); - if (*cwd && chdir(cwd)) - die_errno("Could not change back to '%s'", cwd); + if (cwd.len && chdir(cwd.buf)) + die_errno("Could not change back to '%s'", cwd.buf); + strbuf_release(&cwd); return retval; } @@ -158,54 +140,16 @@ const char *real_path_if_valid(const char *path) return real_path_internal(path, 0); } -static const char *get_pwd_cwd(void) -{ - static char cwd[PATH_MAX + 1]; - char *pwd; - struct stat cwd_stat, pwd_stat; - if (getcwd(cwd, PATH_MAX) == NULL) - return NULL; - pwd = getenv("PWD"); - if (pwd && strcmp(pwd, cwd)) { - stat(cwd, &cwd_stat); - if ((cwd_stat.st_dev || cwd_stat.st_ino) && - !stat(pwd, &pwd_stat) && - pwd_stat.st_dev == cwd_stat.st_dev && - pwd_stat.st_ino == cwd_stat.st_ino) { - strlcpy(cwd, pwd, PATH_MAX); - } - } - return cwd; -} - /* * Use this to get an absolute path from a relative one. If you want * to resolve links, you should use real_path. - * - * If the path is already absolute, then return path. As the user is - * never meant to free the return value, we're safe. */ const char *absolute_path(const char *path) { - static char buf[PATH_MAX + 1]; - - if (!*path) { - die("The empty string is not a valid path"); - } else if (is_absolute_path(path)) { - if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) - die("Too long path: %.*s", 60, path); - } else { - size_t len; - const char *fmt; - const char *cwd = get_pwd_cwd(); - if (!cwd) - die_errno("Cannot determine the current working directory"); - len = strlen(cwd); - fmt = (len > 0 && is_dir_sep(cwd[len - 1])) ? "%s%s" : "%s/%s"; - if (snprintf(buf, PATH_MAX, fmt, cwd, path) >= PATH_MAX) - die("Too long path: %.*s", 60, path); - } - return buf; + static struct strbuf sb = STRBUF_INIT; + strbuf_reset(&sb); + strbuf_add_absolute_path(&sb, path); + return sb.buf; } /* diff --git a/advice.c b/advice.c index c50ebdf5fe..3b8bf3c6da 100644 --- a/advice.c +++ b/advice.c @@ -61,9 +61,12 @@ void advise(const char *advice, ...) int git_default_advice_config(const char *var, const char *value) { - const char *k = skip_prefix(var, "advice."); + const char *k; int i; + if (!skip_prefix(var, "advice.", &k)) + return 0; + for (i = 0; i < ARRAY_SIZE(advice_config); i++) { if (strcmp(k, advice_config[i].name)) continue; @@ -83,8 +86,7 @@ int error_resolve_conflict(const char *me) * other commands doing a merge do. */ advise(_("Fix them up in the work tree, and then use 'git add/rm '\n" - "as appropriate to mark resolution and make a commit, or use\n" - "'git commit -a'.")); + "as appropriate to mark resolution and make a commit.")); return -1; } diff --git a/alias.c b/alias.c index 5efc3d6986..6aa164a362 100644 --- a/alias.c +++ b/alias.c @@ -1,25 +1,13 @@ #include "cache.h" -static const char *alias_key; -static char *alias_val; - -static int alias_lookup_cb(const char *k, const char *v, void *cb) -{ - if (starts_with(k, "alias.") && !strcmp(k + 6, alias_key)) { - if (!v) - return config_error_nonbool(k); - alias_val = xstrdup(v); - return 0; - } - return 0; -} - char *alias_lookup(const char *alias) { - alias_key = alias; - alias_val = NULL; - git_config(alias_lookup_cb, NULL); - return alias_val; + char *v = NULL; + struct strbuf key = STRBUF_INIT; + strbuf_addf(&key, "alias.%s", alias); + git_config_get_string(key.buf, &v); + strbuf_release(&key); + return v; } #define SPLIT_CMDLINE_BAD_ENDING 1 diff --git a/alloc.c b/alloc.c index f3ee745695..12afadfacd 100644 --- a/alloc.c +++ b/alloc.c @@ -18,25 +18,6 @@ #define BLOCKING 1024 -#define DEFINE_ALLOCATOR(name, type) \ -static unsigned int name##_allocs; \ -void *alloc_##name##_node(void) \ -{ \ - static int nr; \ - static type *block; \ - void *ret; \ - \ - if (!nr) { \ - nr = BLOCKING; \ - block = xmalloc(BLOCKING * sizeof(type)); \ - } \ - nr--; \ - name##_allocs++; \ - ret = block++; \ - memset(ret, 0, sizeof(type)); \ - return ret; \ -} - union any_object { struct object object; struct blob blob; @@ -45,11 +26,75 @@ union any_object { struct tag tag; }; -DEFINE_ALLOCATOR(blob, struct blob) -DEFINE_ALLOCATOR(tree, struct tree) -DEFINE_ALLOCATOR(commit, struct commit) -DEFINE_ALLOCATOR(tag, struct tag) -DEFINE_ALLOCATOR(object, union any_object) +struct alloc_state { + int count; /* total number of nodes allocated */ + int nr; /* number of nodes left in current allocation */ + void *p; /* first free node in current allocation */ +}; + +static inline void *alloc_node(struct alloc_state *s, size_t node_size) +{ + void *ret; + + if (!s->nr) { + s->nr = BLOCKING; + s->p = xmalloc(BLOCKING * node_size); + } + s->nr--; + s->count++; + ret = s->p; + s->p = (char *)s->p + node_size; + memset(ret, 0, node_size); + return ret; +} + +static struct alloc_state blob_state; +void *alloc_blob_node(void) +{ + struct blob *b = alloc_node(&blob_state, sizeof(struct blob)); + b->object.type = OBJ_BLOB; + return b; +} + +static struct alloc_state tree_state; +void *alloc_tree_node(void) +{ + struct tree *t = alloc_node(&tree_state, sizeof(struct tree)); + t->object.type = OBJ_TREE; + return t; +} + +static struct alloc_state tag_state; +void *alloc_tag_node(void) +{ + struct tag *t = alloc_node(&tag_state, sizeof(struct tag)); + t->object.type = OBJ_TAG; + return t; +} + +static struct alloc_state object_state; +void *alloc_object_node(void) +{ + struct object *obj = alloc_node(&object_state, sizeof(union any_object)); + obj->type = OBJ_NONE; + return obj; +} + +static struct alloc_state commit_state; + +unsigned int alloc_commit_index(void) +{ + static unsigned int count; + return count++; +} + +void *alloc_commit_node(void) +{ + struct commit *c = alloc_node(&commit_state, sizeof(struct commit)); + c->object.type = OBJ_COMMIT; + c->index = alloc_commit_index(); + return c; +} static void report(const char *name, unsigned int count, size_t size) { @@ -57,13 +102,14 @@ static void report(const char *name, unsigned int count, size_t size) name, count, (uintmax_t) size); } -#define REPORT(name) \ - report(#name, name##_allocs, name##_allocs * sizeof(struct name) >> 10) +#define REPORT(name, type) \ + report(#name, name##_state.count, name##_state.count * sizeof(type) >> 10) void alloc_report(void) { - REPORT(blob); - REPORT(tree); - REPORT(commit); - REPORT(tag); + REPORT(blob, struct blob); + REPORT(tree, struct tree); + REPORT(commit, struct commit); + REPORT(tag, struct tag); + REPORT(object, union any_object); } diff --git a/archive-tar.c b/archive-tar.c index 719b6298e6..df2f4c8a64 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -192,7 +192,7 @@ static int write_extended_header(struct archiver_args *args, unsigned int mode; memset(&header, 0, sizeof(header)); *header.typeflag = TYPEFLAG_EXT_HEADER; - mode = 0100666; + mode = 0100666 & ~tar_umask; sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1)); prepare_header(args, &header, mode, size); write_blocked(&header, sizeof(header)); @@ -300,7 +300,7 @@ static int write_global_extended_header(struct archiver_args *args) strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40); memset(&header, 0, sizeof(header)); *header.typeflag = TYPEFLAG_GLOBAL_HEADER; - mode = 0100666; + mode = 0100666 & ~tar_umask; strcpy(header.name, "pax_global_header"); prepare_header(args, &header, mode, ext_header.len); write_blocked(&header, sizeof(header)); @@ -395,7 +395,7 @@ static int write_tar_filter_archive(const struct archiver *ar, struct archiver_args *args) { struct strbuf cmd = STRBUF_INIT; - struct child_process filter; + struct child_process filter = CHILD_PROCESS_INIT; const char *argv[2]; int r; @@ -406,7 +406,6 @@ static int write_tar_filter_archive(const struct archiver *ar, if (args->compression_level >= 0) strbuf_addf(&cmd, " -%d", args->compression_level); - memset(&filter, 0, sizeof(filter)); argv[0] = cmd.buf; argv[1] = NULL; filter.argv = argv; diff --git a/archive.c b/archive.c index 3fc0fb2928..952a659bcb 100644 --- a/archive.c +++ b/archive.c @@ -402,14 +402,6 @@ static int parse_archive_args(int argc, const char **argv, return argc; } -static int git_default_archive_config(const char *var, const char *value, - void *cb) -{ - if (!strcmp(var, "uploadarchive.allowunreachable")) - remote_allow_unreachable = git_config_bool(var, value); - return git_default_config(var, value, cb); -} - int write_archive(int argc, const char **argv, const char *prefix, int setup_prefix, const char *name_hint, int remote) { @@ -420,7 +412,9 @@ int write_archive(int argc, const char **argv, const char *prefix, if (setup_prefix && prefix == NULL) prefix = setup_git_directory_gently(&nongit); - git_config(git_default_archive_config, NULL); + git_config_get_bool("uploadarchive.allowunreachable", &remote_allow_unreachable); + git_config(git_default_config, NULL); + init_tar_archiver(); init_zip_archiver(); diff --git a/bisect.c b/bisect.c index d6e851d783..df09cbc8ca 100644 --- a/bisect.c +++ b/bisect.c @@ -215,11 +215,12 @@ static struct commit_list *best_bisection_sorted(struct commit_list *list, int n } qsort(array, cnt, sizeof(*array), compare_commit_dist); for (p = list, i = 0; i < cnt; i++) { - struct name_decoration *r = xmalloc(sizeof(*r) + 100); + char buf[100]; /* enough for dist=%d */ struct object *obj = &(array[i].commit->object); - sprintf(r->name, "dist=%d", array[i].distance); - r->next = add_decoration(&name_decoration, obj, r); + snprintf(buf, sizeof(buf), "dist=%d", array[i].distance); + add_name_decoration(DECORATION_NONE, buf, obj); + p->item = array[i].commit; p = p->next; } diff --git a/blob.c b/blob.c index ae320bd8fa..1fcb8e44b0 100644 --- a/blob.c +++ b/blob.c @@ -7,15 +7,8 @@ struct blob *lookup_blob(const unsigned char *sha1) { struct object *obj = lookup_object(sha1); if (!obj) - return create_object(sha1, OBJ_BLOB, alloc_blob_node()); - if (!obj->type) - obj->type = OBJ_BLOB; - if (obj->type != OBJ_BLOB) { - error("Object %s is a %s, not a blob", - sha1_to_hex(sha1), typename(obj->type)); - return NULL; - } - return (struct blob *) obj; + return create_object(sha1, alloc_blob_node()); + return object_as_type(obj, OBJ_BLOB, 0); } int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size) diff --git a/branch.c b/branch.c index 660097bc29..9a2228ebb4 100644 --- a/branch.c +++ b/branch.c @@ -50,11 +50,11 @@ static int should_setup_rebase(const char *origin) void install_branch_config(int flag, const char *local, const char *origin, const char *remote) { - const char *shortname = skip_prefix(remote, "refs/heads/"); + const char *shortname = NULL; struct strbuf key = STRBUF_INIT; int rebasing = should_setup_rebase(origin); - if (shortname + if (skip_prefix(remote, "refs/heads/", &shortname) && !strcmp(local, shortname) && !origin) { warning(_("Not setting branch %s as its own upstream."), @@ -140,33 +140,17 @@ static int setup_tracking(const char *new_ref, const char *orig_ref, return 0; } -struct branch_desc_cb { - const char *config_name; - const char *value; -}; - -static int read_branch_desc_cb(const char *var, const char *value, void *cb) -{ - struct branch_desc_cb *desc = cb; - if (strcmp(desc->config_name, var)) - return 0; - free((char *)desc->value); - return git_config_string(&desc->value, var, value); -} - int read_branch_desc(struct strbuf *buf, const char *branch_name) { - struct branch_desc_cb cb; + char *v = NULL; struct strbuf name = STRBUF_INIT; strbuf_addf(&name, "branch.%s.description", branch_name); - cb.config_name = name.buf; - cb.value = NULL; - if (git_config(read_branch_desc_cb, &cb) < 0) { + if (git_config_get_string(name.buf, &v)) { strbuf_release(&name); return -1; } - if (cb.value) - strbuf_addstr(buf, cb.value); + strbuf_addstr(buf, v); + free(v); strbuf_release(&name); return 0; } @@ -226,7 +210,6 @@ void create_branch(const char *head, int force, int reflog, int clobber_head, int quiet, enum branch_track track) { - struct ref_lock *lock = NULL; struct commit *commit; unsigned char sha1[20]; char *real_ref, msg[PATH_MAX + 20]; @@ -285,15 +268,6 @@ void create_branch(const char *head, die(_("Not a valid branch point: '%s'."), start_name); hashcpy(sha1, commit->object.sha1); - if (!dont_change_ref) { - lock = lock_any_ref_for_update(ref.buf, NULL, 0, NULL); - if (!lock) - die_errno(_("Failed to lock ref for update")); - } - - if (reflog) - log_all_ref_updates = 1; - if (forcing) snprintf(msg, sizeof msg, "branch: Reset to %s", start_name); @@ -301,13 +275,26 @@ void create_branch(const char *head, snprintf(msg, sizeof msg, "branch: Created from %s", start_name); + if (reflog) + log_all_ref_updates = 1; + + if (!dont_change_ref) { + struct ref_transaction *transaction; + struct strbuf err = STRBUF_INIT; + + transaction = ref_transaction_begin(&err); + if (!transaction || + ref_transaction_update(transaction, ref.buf, sha1, + null_sha1, 0, !forcing, &err) || + ref_transaction_commit(transaction, msg, &err)) + die("%s", err.buf); + ref_transaction_free(transaction); + strbuf_release(&err); + } + if (real_ref && track) setup_tracking(ref.buf + 11, real_ref, track, quiet); - if (!dont_change_ref) - if (write_ref_sha1(lock, sha1, msg) < 0) - die_errno(_("Failed to write ref")); - strbuf_release(&ref); free(real_ref); } diff --git a/builtin.h b/builtin.h index c47c110e0f..5d91f31ca2 100644 --- a/builtin.h +++ b/builtin.h @@ -128,6 +128,7 @@ extern int cmd_update_server_info(int argc, const char **argv, const char *prefi extern int cmd_upload_archive(int argc, const char **argv, const char *prefix); extern int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix); extern int cmd_var(int argc, const char **argv, const char *prefix); +extern int cmd_verify_commit(int argc, const char **argv, const char *prefix); extern int cmd_verify_tag(int argc, const char **argv, const char *prefix); extern int cmd_version(int argc, const char **argv, const char *prefix); extern int cmd_whatchanged(int argc, const char **argv, const char *prefix); diff --git a/builtin/add.c b/builtin/add.c index 459208a326..352b85e8db 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -180,7 +180,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) char *file = git_pathdup("ADD_EDIT.patch"); const char *apply_argv[] = { "apply", "--recount", "--cached", NULL, NULL }; - struct child_process child; + struct child_process child = CHILD_PROCESS_INIT; struct rev_info rev; int out; struct stat st; @@ -214,7 +214,6 @@ static int edit_patch(int argc, const char **argv, const char *prefix) if (!st.st_size) die(_("Empty patch. Aborted.")); - memset(&child, 0, sizeof(child)); child.git_cmd = 1; child.argv = apply_argv; if (run_command(&child)) @@ -299,7 +298,6 @@ static int add_files(struct dir_struct *dir, int flags) int cmd_add(int argc, const char **argv, const char *prefix) { int exit_status = 0; - int newfd; struct pathspec pathspec; struct dir_struct dir; int flags; @@ -345,7 +343,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) add_new_files = !take_worktree_changes && !refresh_only; require_pathspec = !take_worktree_changes; - newfd = hold_locked_index(&lock_file, 1); + hold_locked_index(&lock_file, 1); flags = ((verbose ? ADD_CACHE_VERBOSE : 0) | (show_only ? ADD_CACHE_PRETEND : 0) | @@ -443,8 +441,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) finish: if (active_cache_changed) { - if (write_cache(newfd, active_cache, active_nr) || - commit_locked_index(&lock_file)) + if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) die(_("Unable to write new index file")); } diff --git a/builtin/annotate.c b/builtin/annotate.c index fc43eed36b..da413ae0d1 100644 --- a/builtin/annotate.c +++ b/builtin/annotate.c @@ -5,20 +5,18 @@ */ #include "git-compat-util.h" #include "builtin.h" +#include "argv-array.h" int cmd_annotate(int argc, const char **argv, const char *prefix) { - const char **nargv; + struct argv_array args = ARGV_ARRAY_INIT; int i; - nargv = xmalloc(sizeof(char *) * (argc + 2)); - nargv[0] = "annotate"; - nargv[1] = "-c"; + argv_array_pushl(&args, "annotate", "-c", NULL); for (i = 1; i < argc; i++) { - nargv[i+1] = argv[i]; + argv_array_push(&args, argv[i]); } - nargv[argc + 1] = NULL; - return cmd_blame(argc + 1, nargv, prefix); + return cmd_blame(args.argc, args.argv, prefix); } diff --git a/builtin/apply.c b/builtin/apply.c index 9c5724eacc..f204cca5d2 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -1075,7 +1075,7 @@ static int gitdiff_index(const char *line, struct patch *patch) line = ptr + 2; ptr = strchr(line, ' '); - eol = strchr(line, '\n'); + eol = strchrnul(line, '\n'); if (!ptr || eol < ptr) ptr = eol; @@ -1281,9 +1281,7 @@ static int parse_git_header(const char *line, int len, unsigned int size, struct */ patch->def_name = git_header_name(line, len); if (patch->def_name && root) { - char *s = xmalloc(root_len + strlen(patch->def_name) + 1); - strcpy(s, root); - strcpy(s + root_len, patch->def_name); + char *s = xstrfmt("%s%s", root, patch->def_name); free(patch->def_name); patch->def_name = s; } @@ -1922,6 +1920,66 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch) return used; } +static void prefix_one(char **name) +{ + char *old_name = *name; + if (!old_name) + return; + *name = xstrdup(prefix_filename(prefix, prefix_length, *name)); + free(old_name); +} + +static void prefix_patch(struct patch *p) +{ + if (!prefix || p->is_toplevel_relative) + return; + prefix_one(&p->new_name); + prefix_one(&p->old_name); +} + +/* + * include/exclude + */ + +static struct string_list limit_by_name; +static int has_include; +static void add_name_limit(const char *name, int exclude) +{ + struct string_list_item *it; + + it = string_list_append(&limit_by_name, name); + it->util = exclude ? NULL : (void *) 1; +} + +static int use_patch(struct patch *p) +{ + const char *pathname = p->new_name ? p->new_name : p->old_name; + int i; + + /* Paths outside are not touched regardless of "--include" */ + if (0 < prefix_length) { + int pathlen = strlen(pathname); + if (pathlen <= prefix_length || + memcmp(prefix, pathname, prefix_length)) + return 0; + } + + /* See if it matches any of exclude/include rule */ + for (i = 0; i < limit_by_name.nr; i++) { + struct string_list_item *it = &limit_by_name.items[i]; + if (!wildmatch(it->string, pathname, 0, NULL)) + return (it->util != NULL); + } + + /* + * If we had any include, a path that does not match any rule is + * not used. Otherwise, we saw bunch of exclude rules (or none) + * and such a path is used. + */ + return !has_include; +} + + /* * Read the patch text in "buffer" that extends for "size" bytes; stop * reading after seeing a single patch (i.e. changes to a single file). @@ -1937,9 +1995,14 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch) if (offset < 0) return offset; - patch->ws_rule = whitespace_rule(patch->new_name - ? patch->new_name - : patch->old_name); + prefix_patch(patch); + + if (!use_patch(patch)) + patch->ws_rule = 0; + else + patch->ws_rule = whitespace_rule(patch->new_name + ? patch->new_name + : patch->old_name); patchsize = parse_single_patch(buffer + offset + hdrsize, size - offset - hdrsize, patch); @@ -2869,9 +2932,7 @@ static int apply_binary_fragment(struct image *img, struct patch *patch) case BINARY_LITERAL_DEFLATED: clear_image(img); img->len = fragment->size; - img->buf = xmalloc(img->len+1); - memcpy(img->buf, fragment->patch, img->len); - img->buf[img->len] = '\0'; + img->buf = xmemdupz(fragment->patch, img->len); return 0; } return -1; @@ -3086,13 +3147,15 @@ static void prepare_fn_table(struct patch *patch) } } -static int checkout_target(struct cache_entry *ce, struct stat *st) +static int checkout_target(struct index_state *istate, + struct cache_entry *ce, struct stat *st) { struct checkout costate; memset(&costate, 0, sizeof(costate)); costate.base_dir = ""; costate.refresh_cache = 1; + costate.istate = istate; if (checkout_entry(ce, &costate, NULL) || lstat(ce->name, st)) return error(_("cannot checkout %s"), ce->name); return 0; @@ -3259,7 +3322,7 @@ static int load_current(struct image *image, struct patch *patch) if (lstat(name, &st)) { if (errno != ENOENT) return error(_("%s: %s"), name, strerror(errno)); - if (checkout_target(ce, &st)) + if (checkout_target(&the_index, ce, &st)) return -1; } if (verify_index_match(ce, &st)) @@ -3413,7 +3476,7 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s } *ce = active_cache[pos]; if (stat_ret < 0) { - if (checkout_target(*ce, st)) + if (checkout_target(&the_index, *ce, st)) return -1; } if (!cached && verify_index_match(*ce, st)) @@ -3646,7 +3709,7 @@ static void build_fake_ancestor(struct patch *list, const char *filename) { struct patch *patch; struct index_state result = { NULL }; - int fd; + static struct lock_file lock; /* Once we start supporting the reverse patch, it may be * worth showing the new sha1 prefix, but until then... @@ -3684,8 +3747,8 @@ static void build_fake_ancestor(struct patch *list, const char *filename) die ("Could not add %s to temporary index", name); } - fd = open(filename, O_WRONLY | O_CREAT, 0666); - if (fd < 0 || write_index(&result, fd) || close(fd)) + hold_lock_file_for_update(&lock, filename, LOCK_DIE_ON_ERROR); + if (write_locked_index(&result, &lock, COMMIT_LOCK)) die ("Could not write temporary index to %s", filename); discard_index(&result); @@ -3847,9 +3910,10 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned ce->ce_flags = create_ce_flags(0); ce->ce_namelen = namelen; if (S_ISGITLINK(mode)) { - const char *s = buf; + const char *s; - if (get_sha1_hex(s + strlen("Subproject commit "), ce->sha1)) + if (!skip_prefix(buf, "Subproject commit ", &s) || + get_sha1_hex(s, ce->sha1)) die(_("corrupt patch for submodule %s"), path); } else { if (!cached) { @@ -4128,64 +4192,6 @@ static int write_out_results(struct patch *list) static struct lock_file lock_file; -static struct string_list limit_by_name; -static int has_include; -static void add_name_limit(const char *name, int exclude) -{ - struct string_list_item *it; - - it = string_list_append(&limit_by_name, name); - it->util = exclude ? NULL : (void *) 1; -} - -static int use_patch(struct patch *p) -{ - const char *pathname = p->new_name ? p->new_name : p->old_name; - int i; - - /* Paths outside are not touched regardless of "--include" */ - if (0 < prefix_length) { - int pathlen = strlen(pathname); - if (pathlen <= prefix_length || - memcmp(prefix, pathname, prefix_length)) - return 0; - } - - /* See if it matches any of exclude/include rule */ - for (i = 0; i < limit_by_name.nr; i++) { - struct string_list_item *it = &limit_by_name.items[i]; - if (!wildmatch(it->string, pathname, 0, NULL)) - return (it->util != NULL); - } - - /* - * If we had any include, a path that does not match any rule is - * not used. Otherwise, we saw bunch of exclude rules (or none) - * and such a path is used. - */ - return !has_include; -} - - -static void prefix_one(char **name) -{ - char *old_name = *name; - if (!old_name) - return; - *name = xstrdup(prefix_filename(prefix, prefix_length, *name)); - free(old_name); -} - -static void prefix_patches(struct patch *p) -{ - if (!prefix || p->is_toplevel_relative) - return; - for ( ; p; p = p->next) { - prefix_one(&p->new_name); - prefix_one(&p->old_name); - } -} - #define INACCURATE_EOF (1<<0) #define RECOUNT (1<<1) @@ -4211,8 +4217,6 @@ static int apply_patch(int fd, const char *filename, int options) break; if (apply_in_reverse) reverse_patches(patch); - if (prefix) - prefix_patches(patch); if (use_patch(patch)) { patch_stats(patch); *listp = patch; @@ -4270,13 +4274,11 @@ static int apply_patch(int fd, const char *filename, int options) return 0; } -static int git_apply_config(const char *var, const char *value, void *cb) +static void git_apply_config(void) { - if (!strcmp(var, "apply.whitespace")) - return git_config_string(&apply_default_whitespace, var, value); - else if (!strcmp(var, "apply.ignorewhitespace")) - return git_config_string(&apply_default_ignorewhitespace, var, value); - return git_default_config(var, value, cb); + git_config_get_string_const("apply.whitespace", &apply_default_whitespace); + git_config_get_string_const("apply.ignorewhitespace", &apply_default_ignorewhitespace); + git_config(git_default_config, NULL); } static int option_parse_exclude(const struct option *opt, @@ -4424,7 +4426,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix_) prefix = prefix_; prefix_length = prefix ? strlen(prefix) : 0; - git_config(git_apply_config, NULL); + git_apply_config(); if (apply_default_whitespace) parse_whitespace_option(apply_default_whitespace); if (apply_default_ignorewhitespace) @@ -4503,8 +4505,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix_) } if (update_index) { - if (write_cache(newfd, active_cache, active_nr) || - commit_locked_index(&lock_file)) + if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) die(_("Unable to write new index file")); } diff --git a/builtin/blame.c b/builtin/blame.c index 662e3fec44..3838be2b02 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -1371,11 +1371,8 @@ static struct commit_list *first_scapegoat(struct rev_info *revs, struct commit static int num_scapegoats(struct rev_info *revs, struct commit *commit) { - int cnt; struct commit_list *l = first_scapegoat(revs, commit); - for (cnt = 0; l; l = l->next) - cnt++; - return cnt; + return commit_list_count(l); } /* Distribute collected unsorted blames to the respected sorted lists @@ -1655,7 +1652,7 @@ static void get_commit_info(struct commit *commit, { int len; const char *subject, *encoding; - char *message; + const char *message; commit_info_init(ret); @@ -1666,7 +1663,7 @@ static void get_commit_info(struct commit *commit, &ret->author_time, &ret->author_tz); if (!detailed) { - logmsg_free(message, commit); + unuse_commit_buffer(commit, message); return; } @@ -1680,7 +1677,7 @@ static void get_commit_info(struct commit *commit, else strbuf_addf(&ret->summary, "(%s)", sha1_to_hex(commit->object.sha1)); - logmsg_free(message, commit); + unuse_commit_buffer(commit, message); } /* @@ -2251,6 +2248,18 @@ static void append_merge_parents(struct commit_list **tail) strbuf_release(&line); } +/* + * This isn't as simple as passing sb->buf and sb->len, because we + * want to transfer ownership of the buffer to the commit (so we + * must use detach). + */ +static void set_commit_buffer_from_strbuf(struct commit *c, struct strbuf *sb) +{ + size_t len; + void *buf = strbuf_detach(sb, &len); + set_commit_buffer(c, buf, len); +} + /* * Prepare a dummy commit that represents the work tree (or staged) item. * Note that annotating work tree item never works in the reverse. @@ -2272,10 +2281,9 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, struct strbuf msg = STRBUF_INIT; time(&now); - commit = xcalloc(1, sizeof(*commit)); + commit = alloc_commit_node(); commit->object.parsed = 1; commit->date = now; - commit->object.type = OBJ_COMMIT; parent_tail = &commit->parents; if (!resolve_ref_unsafe("HEAD", head_sha1, 1, NULL)) @@ -2299,7 +2307,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, ident, ident, path, (!contents_from ? path : (!strcmp(contents_from, "-") ? "standard input" : contents_from))); - commit->buffer = strbuf_detach(&msg, NULL); + set_commit_buffer_from_strbuf(commit, &msg); if (!contents_from || strcmp("-", contents_from)) { struct stat st; @@ -2377,7 +2385,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, * right now, but someday we might optimize diff-index --cached * with cache-tree information. */ - cache_tree_invalidate_path(active_cache_tree, path); + cache_tree_invalidate_path(&the_index, path); return commit; } @@ -2572,6 +2580,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix) case DATE_RFC2822: blame_date_width = sizeof("Thu, 19 Oct 2006 16:00:04 -0700"); break; + case DATE_ISO8601_STRICT: + blame_date_width = sizeof("2006-10-19T16:00:04-07:00"); + break; case DATE_ISO8601: blame_date_width = sizeof("2006-10-19 16:00:04 -0700"); break; @@ -2692,14 +2703,11 @@ int cmd_blame(int argc, const char **argv, const char *prefix) * uninteresting. */ if (prepare_revision_walk(&revs)) - die("revision walk setup failed"); + die(_("revision walk setup failed")); if (is_null_sha1(sb.final->object.sha1)) { - char *buf; o = sb.final->util; - buf = xmalloc(o->file.size + 1); - memcpy(buf, o->file.ptr, o->file.size + 1); - sb.final_buf = buf; + sb.final_buf = xmemdupz(o->file.ptr, o->file.size); sb.final_buf_size = o->file.size; } else { diff --git a/builtin/branch.c b/builtin/branch.c index 652b1d2d14..ced422b627 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -294,13 +294,13 @@ static char *resolve_symref(const char *src, const char *prefix) { unsigned char sha1[20]; int flag; - const char *dst, *cp; + const char *dst; dst = resolve_ref_unsafe(src, sha1, 0, &flag); if (!(dst && (flag & REF_ISSYMREF))) return NULL; - if (prefix && (cp = skip_prefix(dst, prefix))) - dst = cp; + if (prefix) + skip_prefix(dst, prefix, &dst); return xstrdup(dst); } @@ -653,7 +653,9 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru add_pending_object(&ref_list.revs, (struct object *) filter, ""); ref_list.revs.limited = 1; - prepare_revision_walk(&ref_list.revs); + + if (prepare_revision_walk(&ref_list.revs)) + die(_("revision walk setup failed")); if (verbose) ref_list.maxwidth = calc_maxwidth(&ref_list); } diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index 61e75eb60c..05edd9e1df 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -135,6 +135,7 @@ static int option_parse_u(const struct option *opt, int *newfd = opt->value; state.refresh_cache = 1; + state.istate = &the_index; if (*newfd < 0) *newfd = hold_locked_index(&lock_file, 1); return 0; @@ -279,8 +280,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) checkout_all(prefix, prefix_length); if (0 <= newfd && - (write_cache(newfd, active_cache, active_nr) || - commit_locked_index(&lock_file))) + write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) die("Unable to write new index file"); return 0; } diff --git a/builtin/checkout.c b/builtin/checkout.c index f1dc56e55f..8afdf2b5c4 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -225,7 +225,6 @@ static int checkout_paths(const struct checkout_opts *opts, int flag; struct commit *head; int errs = 0; - int newfd; struct lock_file *lock_file; if (opts->track != BRANCH_TRACK_UNSPECIFIED) @@ -256,7 +255,7 @@ static int checkout_paths(const struct checkout_opts *opts, lock_file = xcalloc(1, sizeof(struct lock_file)); - newfd = hold_locked_index(lock_file, 1); + hold_locked_index(lock_file, 1); if (read_cache_preload(&opts->pathspec) < 0) return error(_("corrupt index file")); @@ -337,6 +336,7 @@ static int checkout_paths(const struct checkout_opts *opts, memset(&state, 0, sizeof(state)); state.force = 1; state.refresh_cache = 1; + state.istate = &the_index; for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; if (ce->ce_flags & CE_MATCHED) { @@ -352,8 +352,7 @@ static int checkout_paths(const struct checkout_opts *opts, } } - if (write_cache(newfd, active_cache, active_nr) || - commit_locked_index(lock_file)) + if (write_locked_index(&the_index, lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); read_ref_full("HEAD", rev, 0, &flag); @@ -444,8 +443,8 @@ static int merge_working_tree(const struct checkout_opts *opts, { int ret; struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); - int newfd = hold_locked_index(lock_file, 1); + hold_locked_index(lock_file, 1); if (read_cache_preload(NULL) < 0) return error(_("corrupt index file")); @@ -553,8 +552,13 @@ static int merge_working_tree(const struct checkout_opts *opts, } } - if (write_cache(newfd, active_cache, active_nr) || - commit_locked_index(lock_file)) + if (!active_cache_tree) + active_cache_tree = cache_tree(); + + if (!cache_tree_fully_valid(active_cache_tree)) + cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR); + + if (write_locked_index(&the_index, lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); if (!opts->force && !opts->quiet) @@ -776,8 +780,8 @@ static int switch_branches(const struct checkout_opts *opts, if (!(flag & REF_ISSYMREF)) old.path = NULL; - if (old.path && starts_with(old.path, "refs/heads/")) - old.name = old.path + strlen("refs/heads/"); + if (old.path) + skip_prefix(old.path, "refs/heads/", &old.name); if (!new->name) { new->name = "HEAD"; diff --git a/builtin/clean.c b/builtin/clean.c index 9a9151575d..3beeea6ec0 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -48,7 +48,7 @@ enum color_clean { CLEAN_COLOR_PROMPT = 2, CLEAN_COLOR_HEADER = 3, CLEAN_COLOR_HELP = 4, - CLEAN_COLOR_ERROR = 5, + CLEAN_COLOR_ERROR = 5 }; #define MENU_OPTS_SINGLETON 01 @@ -67,7 +67,7 @@ struct menu_item { char hotkey; const char *title; int selected; - int (*fn)(); + int (*fn)(void); }; enum menu_stuff_type { @@ -621,8 +621,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff) nr += chosen[i]; } - result = xmalloc(sizeof(int) * (nr + 1)); - memset(result, 0, sizeof(int) * (nr + 1)); + result = xcalloc(nr + 1, sizeof(int)); for (i = 0; i < stuff->nr && j < nr; i++) { if (chosen[i]) result[j++] = i; diff --git a/builtin/clone.c b/builtin/clone.c index b12989d1ca..3927edfb6e 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -584,11 +584,11 @@ static void update_remote_refs(const struct ref *refs, static void update_head(const struct ref *our, const struct ref *remote, const char *msg) { - if (our && starts_with(our->name, "refs/heads/")) { + const char *head; + if (our && skip_prefix(our->name, "refs/heads/", &head)) { /* Local default branch link */ create_symref("HEAD", our->name, NULL); if (!option_bare) { - const char *head = skip_prefix(our->name, "refs/heads/"); update_ref(msg, "HEAD", our->old_sha1, NULL, 0, UPDATE_REFS_DIE_ON_ERR); install_branch_config(0, head, option_origin, our->name); @@ -617,7 +617,7 @@ static int checkout(void) struct unpack_trees_options opts; struct tree *tree; struct tree_desc t; - int err = 0, fd; + int err = 0; if (option_no_checkout) return 0; @@ -641,7 +641,7 @@ static int checkout(void) setup_work_tree(); lock_file = xcalloc(1, sizeof(struct lock_file)); - fd = hold_locked_index(lock_file, 1); + hold_locked_index(lock_file, 1); memset(&opts, 0, sizeof opts); opts.update = 1; @@ -657,8 +657,7 @@ static int checkout(void) if (unpack_trees(1, &t, &opts) < 0) die(_("unable to checkout working tree")); - if (write_cache(fd, active_cache, active_nr) || - commit_locked_index(lock_file)) + if (write_locked_index(&the_index, lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); err |= run_hook_le(NULL, "post-checkout", sha1_to_hex(null_sha1), @@ -686,9 +685,10 @@ static void write_config(struct string_list *config) } } -static void write_refspec_config(const char* src_ref_prefix, - const struct ref* our_head_points_at, - const struct ref* remote_head_points_at, struct strbuf* branch_top) +static void write_refspec_config(const char *src_ref_prefix, + const struct ref *our_head_points_at, + const struct ref *remote_head_points_at, + struct strbuf *branch_top) { struct strbuf key = STRBUF_INIT; struct strbuf value = STRBUF_INIT; @@ -696,16 +696,19 @@ static void write_refspec_config(const char* src_ref_prefix, if (option_mirror || !option_bare) { if (option_single_branch && !option_mirror) { if (option_branch) { - if (strstr(our_head_points_at->name, "refs/tags/")) + if (starts_with(our_head_points_at->name, "refs/tags/")) strbuf_addf(&value, "+%s:%s", our_head_points_at->name, our_head_points_at->name); else strbuf_addf(&value, "+%s:%s%s", our_head_points_at->name, branch_top->buf, option_branch); } else if (remote_head_points_at) { + const char *head = remote_head_points_at->name; + if (!skip_prefix(head, "refs/heads/", &head)) + die("BUG: remote HEAD points at non-head?"); + strbuf_addf(&value, "+%s:%s%s", remote_head_points_at->name, - branch_top->buf, - skip_prefix(remote_head_points_at->name, "refs/heads/")); + branch_top->buf, head); } /* * otherwise, the next "git fetch" will @@ -797,18 +800,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix) die(_("repository '%s' does not exist"), repo_name); else repo = repo_name; - is_local = option_local != 0 && path && !is_bundle; - if (is_local) { - if (option_depth) - warning(_("--depth is ignored in local clones; use file:// instead.")); - if (!access(mkpath("%s/shallow", path), F_OK)) { - if (option_local > 0) - warning(_("source repository is shallow, ignoring --local")); - is_local = 0; - } - } - if (option_local > 0 && !is_local) - warning(_("--local is ignored")); /* no need to be strict, transport_set_option() will validate it again */ if (option_depth && atoi(option_depth) < 1) @@ -901,6 +892,19 @@ int cmd_clone(int argc, const char **argv, const char *prefix) remote = remote_get(option_origin); transport = transport_get(remote, remote->url[0]); + path = get_repo_path(remote->url[0], &is_bundle); + is_local = option_local != 0 && path && !is_bundle; + if (is_local) { + if (option_depth) + warning(_("--depth is ignored in local clones; use file:// instead.")); + if (!access(mkpath("%s/shallow", path), F_OK)) { + if (option_local > 0) + warning(_("source repository is shallow, ignoring --local")); + is_local = 0; + } + } + if (option_local > 0 && !is_local) + warning(_("--local is ignored")); transport->cloning = 1; if (!transport->get_refs_list || (!is_local && !transport->fetch)) @@ -1001,5 +1005,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) strbuf_release(&key); strbuf_release(&value); junk_mode = JUNK_LEAVE_ALL; + + free(refspec); return err; } diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c index 987a4c3d73..8a66c74e0f 100644 --- a/builtin/commit-tree.c +++ b/builtin/commit-tree.c @@ -123,8 +123,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) die_errno("git commit-tree: failed to read"); } - if (commit_tree(&buffer, tree_sha1, parents, commit_sha1, - NULL, sign_commit)) { + if (commit_tree(buffer.buf, buffer.len, tree_sha1, parents, + commit_sha1, NULL, sign_commit)) { strbuf_release(&buffer); return 1; } diff --git a/builtin/commit.c b/builtin/commit.c index 5e2221c8e8..b0fe7847d3 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -42,7 +42,20 @@ static const char * const builtin_status_usage[] = { NULL }; -static const char implicit_ident_advice[] = +static const char implicit_ident_advice_noconfig[] = +N_("Your name and email address were configured automatically based\n" +"on your username and hostname. Please check that they are accurate.\n" +"You can suppress this message by setting them explicitly. Run the\n" +"following command and follow the instructions in your editor to edit\n" +"your configuration file:\n" +"\n" +" git config --global --edit\n" +"\n" +"After doing this, you may fix the identity used for this commit with:\n" +"\n" +" git commit --amend --reset-author\n"); + +static const char implicit_ident_advice_config[] = N_("Your name and email address were configured automatically based\n" "on your username and hostname. Please check that they are accurate.\n" "You can suppress this message by setting them explicitly:\n" @@ -305,7 +318,6 @@ static void refresh_cache_or_die(int refresh_flags) static char *prepare_index(int argc, const char **argv, const char *prefix, const struct commit *current_head, int is_status) { - int fd; struct string_list partial; struct pathspec pathspec; int refresh_flags = REFRESH_QUIET; @@ -321,12 +333,11 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, if (interactive) { char *old_index_env = NULL; - fd = hold_locked_index(&index_lock, 1); + hold_locked_index(&index_lock, 1); refresh_cache_or_die(refresh_flags); - if (write_cache(fd, active_cache, active_nr) || - close_lock_file(&index_lock)) + if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK)) die(_("unable to create temporary index")); old_index_env = getenv(INDEX_ENVIRONMENT); @@ -342,6 +353,13 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, discard_cache(); read_cache_from(index_lock.filename); + if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) { + if (reopen_lock_file(&index_lock) < 0) + die(_("unable to write index file")); + if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK)) + die(_("unable to update temporary index")); + } else + warning(_("Failed to update main cache tree")); commit_style = COMMIT_NORMAL; return index_lock.filename; @@ -360,12 +378,11 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, * (B) on failure, rollback the real index. */ if (all || (also && pathspec.nr)) { - fd = hold_locked_index(&index_lock, 1); + hold_locked_index(&index_lock, 1); add_files_to_cache(also ? prefix : NULL, &pathspec, 0); refresh_cache_or_die(refresh_flags); update_main_cache_tree(WRITE_TREE_SILENT); - if (write_cache(fd, active_cache, active_nr) || - close_lock_file(&index_lock)) + if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK)) die(_("unable to write new_index file")); commit_style = COMMIT_NORMAL; return index_lock.filename; @@ -381,12 +398,16 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, * We still need to refresh the index here. */ if (!only && !pathspec.nr) { - fd = hold_locked_index(&index_lock, 1); + hold_locked_index(&index_lock, 1); refresh_cache_or_die(refresh_flags); - if (active_cache_changed) { + if (active_cache_changed + || !cache_tree_fully_valid(active_cache_tree)) { update_main_cache_tree(WRITE_TREE_SILENT); - if (write_cache(fd, active_cache, active_nr) || - commit_locked_index(&index_lock)) + active_cache_changed = 1; + } + if (active_cache_changed) { + if (write_locked_index(&the_index, &index_lock, + COMMIT_LOCK)) die(_("unable to write new_index file")); } else { rollback_lock_file(&index_lock); @@ -423,8 +444,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, die(_("cannot do a partial commit during a cherry-pick.")); } - memset(&partial, 0, sizeof(partial)); - partial.strdup_strings = 1; + string_list_init(&partial, 1); if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, &pathspec)) exit(1); @@ -432,24 +452,23 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, if (read_cache() < 0) die(_("cannot read the index")); - fd = hold_locked_index(&index_lock, 1); + hold_locked_index(&index_lock, 1); add_remove_files(&partial); refresh_cache(REFRESH_QUIET); - if (write_cache(fd, active_cache, active_nr) || - close_lock_file(&index_lock)) + update_main_cache_tree(WRITE_TREE_SILENT); + if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK)) die(_("unable to write new_index file")); - fd = hold_lock_file_for_update(&false_lock, - git_path("next-index-%"PRIuMAX, - (uintmax_t) getpid()), - LOCK_DIE_ON_ERROR); + hold_lock_file_for_update(&false_lock, + git_path("next-index-%"PRIuMAX, + (uintmax_t) getpid()), + LOCK_DIE_ON_ERROR); create_base_index(current_head); add_remove_files(&partial); refresh_cache(REFRESH_QUIET); - if (write_cache(fd, active_cache, active_nr) || - close_lock_file(&false_lock)) + if (write_locked_index(&the_index, &false_lock, CLOSE_LOCK)) die(_("unable to write temporary index file")); discard_cache(); @@ -526,77 +545,80 @@ static int sane_ident_split(struct ident_split *person) return 1; } -static int parse_force_date(const char *in, char *out, int len) +static int parse_force_date(const char *in, struct strbuf *out) { - if (len < 1) - return -1; - *out++ = '@'; - len--; + strbuf_addch(out, '@'); - if (parse_date(in, out, len) < 0) { + if (parse_date(in, out) < 0) { int errors = 0; unsigned long t = approxidate_careful(in, &errors); if (errors) return -1; - snprintf(out, len, "%lu", t); + strbuf_addf(out, "%lu", t); } return 0; } +static void set_ident_var(char **buf, char *val) +{ + free(*buf); + *buf = val; +} + +static char *envdup(const char *var) +{ + const char *val = getenv(var); + return val ? xstrdup(val) : NULL; +} + static void determine_author_info(struct strbuf *author_ident) { char *name, *email, *date; struct ident_split author; - char date_buf[64]; - name = getenv("GIT_AUTHOR_NAME"); - email = getenv("GIT_AUTHOR_EMAIL"); - date = getenv("GIT_AUTHOR_DATE"); + name = envdup("GIT_AUTHOR_NAME"); + email = envdup("GIT_AUTHOR_EMAIL"); + date = envdup("GIT_AUTHOR_DATE"); if (author_message) { - const char *a, *lb, *rb, *eol; + struct ident_split ident; size_t len; + const char *a; - a = strstr(author_message_buffer, "\nauthor "); + a = find_commit_header(author_message_buffer, "author", &len); if (!a) - die(_("invalid commit: %s"), author_message); - - lb = strchrnul(a + strlen("\nauthor "), '<'); - rb = strchrnul(lb, '>'); - eol = strchrnul(rb, '\n'); - if (!*lb || !*rb || !*eol) - die(_("invalid commit: %s"), author_message); - - if (lb == a + strlen("\nauthor ")) - /* \nauthor */ - name = xcalloc(1, 1); - else - name = xmemdupz(a + strlen("\nauthor "), - (lb - strlen(" ") - - (a + strlen("\nauthor ")))); - email = xmemdupz(lb + strlen("<"), rb - (lb + strlen("<"))); - len = eol - (rb + strlen("> ")); - date = xmalloc(len + 2); - *date = '@'; - memcpy(date + 1, rb + strlen("> "), len); - date[len + 1] = '\0'; + die(_("commit '%s' lacks author header"), author_message); + if (split_ident_line(&ident, a, len) < 0) + die(_("commit '%s' has malformed author line"), author_message); + + set_ident_var(&name, xmemdupz(ident.name_begin, ident.name_end - ident.name_begin)); + set_ident_var(&email, xmemdupz(ident.mail_begin, ident.mail_end - ident.mail_begin)); + + if (ident.date_begin) { + struct strbuf date_buf = STRBUF_INIT; + strbuf_addch(&date_buf, '@'); + strbuf_add(&date_buf, ident.date_begin, ident.date_end - ident.date_begin); + strbuf_addch(&date_buf, ' '); + strbuf_add(&date_buf, ident.tz_begin, ident.tz_end - ident.tz_begin); + set_ident_var(&date, strbuf_detach(&date_buf, NULL)); + } } if (force_author) { - const char *lb = strstr(force_author, " <"); - const char *rb = strchr(force_author, '>'); + struct ident_split ident; - if (!lb || !rb) + if (split_ident_line(&ident, force_author, strlen(force_author)) < 0) die(_("malformed --author parameter")); - name = xstrndup(force_author, lb - force_author); - email = xstrndup(lb + 2, rb - (lb + 2)); + set_ident_var(&name, xmemdupz(ident.name_begin, ident.name_end - ident.name_begin)); + set_ident_var(&email, xmemdupz(ident.mail_begin, ident.mail_end - ident.mail_begin)); } if (force_date) { - if (parse_force_date(force_date, date_buf, sizeof(date_buf))) + struct strbuf date_buf = STRBUF_INIT; + if (parse_force_date(force_date, &date_buf)) die(_("invalid date format: %s"), force_date); - date = date_buf; + set_ident_var(&date, strbuf_detach(&date_buf, NULL)); } strbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT)); @@ -606,6 +628,10 @@ static void determine_author_info(struct strbuf *author_ident) export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0); export_one("GIT_AUTHOR_DATE", author.date_begin, author.tz_end, '@'); } + + free(name); + free(email); + free(date); } static void split_ident_or_die(struct ident_split *id, const struct strbuf *buf) @@ -707,7 +733,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, char *buffer; buffer = strstr(use_message_buffer, "\n\n"); if (buffer) - strbuf_add(&sb, buffer + 2, strlen(buffer + 2)); + strbuf_addstr(&sb, buffer + 2); hook_arg1 = "commit"; hook_arg2 = use_message; } else if (fixup_message) { @@ -1020,7 +1046,7 @@ static int message_is_empty(struct strbuf *sb) static int template_untouched(struct strbuf *sb) { struct strbuf tmpl = STRBUF_INIT; - char *start; + const char *start; if (cleanup_mode == CLEANUP_NONE && sb->len) return 0; @@ -1029,8 +1055,7 @@ static int template_untouched(struct strbuf *sb) return 0; stripspace(&tmpl, cleanup_mode == CLEANUP_ALL); - start = (char *)skip_prefix(sb->buf, tmpl.buf); - if (!start) + if (!skip_prefix(sb->buf, tmpl.buf, &start)) start = sb->buf; strbuf_release(&tmpl); return rest_is_empty(sb, start - sb->buf); @@ -1055,7 +1080,8 @@ static const char *find_author_by_nickname(const char *name) revs.mailmap = &mailmap; read_mailmap(revs.mailmap, NULL); - prepare_revision_walk(&revs); + if (prepare_revision_walk(&revs)) + die(_("revision walk setup failed")); commit = get_revision(&revs); if (commit) { struct pretty_print_context ctx = {0}; @@ -1409,6 +1435,24 @@ int cmd_status(int argc, const char **argv, const char *prefix) return 0; } +static const char *implicit_ident_advice(void) +{ + char *user_config = NULL; + char *xdg_config = NULL; + int config_exists; + + home_config_paths(&user_config, &xdg_config, "config"); + config_exists = file_exists(user_config) || file_exists(xdg_config); + free(user_config); + free(xdg_config); + + if (config_exists) + return _(implicit_ident_advice_config); + else + return _(implicit_ident_advice_noconfig); + +} + static void print_summary(const char *prefix, const unsigned char *sha1, int initial_commit) { @@ -1447,7 +1491,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1, strbuf_addbuf_percentquote(&format, &committer_ident); if (advice_implicit_identity) { strbuf_addch(&format, '\n'); - strbuf_addstr(&format, _(implicit_ident_advice)); + strbuf_addstr(&format, implicit_ident_advice()); } } strbuf_release(&author_ident); @@ -1515,7 +1559,7 @@ static int run_rewrite_hook(const unsigned char *oldsha1, { /* oldsha1 SP newsha1 LF NUL */ static char buf[2*40 + 3]; - struct child_process proc; + struct child_process proc = CHILD_PROCESS_INIT; const char *argv[3]; int code; size_t n; @@ -1527,7 +1571,6 @@ static int run_rewrite_hook(const unsigned char *oldsha1, argv[1] = "amend"; argv[2] = NULL; - memset(&proc, 0, sizeof(proc)); proc.argv = argv; proc.in = -1; proc.stdout_to_stderr = 1; @@ -1627,11 +1670,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix) const char *index_file, *reflog_msg; char *nl; unsigned char sha1[20]; - struct ref_lock *ref_lock; struct commit_list *parents = NULL, **pptr = &parents; struct stat statbuf; struct commit *current_head = NULL; struct commit_extra_header *extra = NULL; + struct ref_transaction *transaction; + struct strbuf err = STRBUF_INIT; if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(builtin_commit_usage, builtin_commit_options); @@ -1745,24 +1789,14 @@ int cmd_commit(int argc, const char **argv, const char *prefix) append_merge_tag_headers(parents, &tail); } - if (commit_tree_extended(&sb, active_cache_tree->sha1, parents, sha1, - author_ident.buf, sign_commit, extra)) { + if (commit_tree_extended(sb.buf, sb.len, active_cache_tree->sha1, + parents, sha1, author_ident.buf, sign_commit, extra)) { rollback_index_files(); die(_("failed to write commit object")); } strbuf_release(&author_ident); free_commit_extra_headers(extra); - ref_lock = lock_any_ref_for_update("HEAD", - !current_head - ? NULL - : current_head->object.sha1, - 0, NULL); - if (!ref_lock) { - rollback_index_files(); - die(_("cannot lock HEAD ref")); - } - nl = strchr(sb.buf, '\n'); if (nl) strbuf_setlen(&sb, nl + 1 - sb.buf); @@ -1771,10 +1805,17 @@ int cmd_commit(int argc, const char **argv, const char *prefix) strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg)); strbuf_insert(&sb, strlen(reflog_msg), ": ", 2); - if (write_ref_sha1(ref_lock, sha1, sb.buf) < 0) { + transaction = ref_transaction_begin(&err); + if (!transaction || + ref_transaction_update(transaction, "HEAD", sha1, + current_head + ? current_head->object.sha1 : NULL, + 0, !!current_head, &err) || + ref_transaction_commit(transaction, sb.buf, &err)) { rollback_index_files(); - die(_("cannot update HEAD ref")); + die("%s", err.buf); } + ref_transaction_free(transaction); unlink(git_path("CHERRY_PICK_HEAD")); unlink(git_path("REVERT_HEAD")); @@ -1785,7 +1826,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (commit_index_files()) die (_("Repository has been updated, but unable to write\n" - "new_index file. Check that disk is not full or quota is\n" + "new_index file. Check that disk is not full and quota is\n" "not exceeded, and then \"git reset HEAD\" to recover.")); rerere(0); @@ -1803,5 +1844,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (!quiet) print_summary(prefix, sha1, !current_head); + strbuf_release(&err); return 0; } diff --git a/builtin/config.c b/builtin/config.c index fcd8474701..aba71355f8 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -445,6 +445,20 @@ static int get_urlmatch(const char *var, const char *url) return 0; } +static char *default_user_config(void) +{ + struct strbuf buf = STRBUF_INIT; + strbuf_addf(&buf, + _("# This is Git's per-user configuration file.\n" + "[core]\n" + "# Please adapt and uncomment the following lines:\n" + "# user = %s\n" + "# email = %s\n"), + ident_default_name(), + ident_default_email()); + return strbuf_detach(&buf, NULL); +} + int cmd_config(int argc, const char **argv, const char *prefix) { int nongit = !startup_info->have_repository; @@ -551,6 +565,8 @@ int cmd_config(int argc, const char **argv, const char *prefix) } } else if (actions == ACTION_EDIT) { + const char *config_file = given_config_source.file ? + given_config_source.file : git_path("config"); check_argc(argc, 0, 0); if (!given_config_source.file && nongit) die("not in a git directory"); @@ -559,9 +575,18 @@ int cmd_config(int argc, const char **argv, const char *prefix) if (given_config_source.blob) die("editing blobs is not supported"); git_config(git_default_config, NULL); - launch_editor(given_config_source.file ? - given_config_source.file : git_path("config"), - NULL, NULL); + if (use_global_config) { + int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666); + if (fd) { + char *content = default_user_config(); + write_str_in_full(fd, content); + free(content); + close(fd); + } + else if (errno != EEXIST) + die_errno(_("cannot create configuration file %s"), config_file); + } + launch_editor(config_file, NULL, NULL); } else if (actions == ACTION_SET) { int ret; diff --git a/builtin/describe.c b/builtin/describe.c index 24d740c8b1..ee6a3b998f 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -56,18 +56,9 @@ static int commit_name_cmp(const struct commit_name *cn1, return hashcmp(cn1->peeled, peeled ? peeled : cn2->peeled); } -static inline unsigned int hash_sha1(const unsigned char *sha1) -{ - unsigned int hash; - memcpy(&hash, sha1, sizeof(hash)); - return hash; -} - static inline struct commit_name *find_commit_name(const unsigned char *peeled) { - struct commit_name key; - hashmap_entry_init(&key, hash_sha1(peeled)); - return hashmap_get(&names, &key, peeled); + return hashmap_get_from_hash(&names, sha1hash(peeled), peeled); } static int replace_name(struct commit_name *e, @@ -114,7 +105,7 @@ static void add_to_known_names(const char *path, if (!e) { e = xmalloc(sizeof(struct commit_name)); hashcpy(e->peeled, peeled); - hashmap_entry_init(e, hash_sha1(peeled)); + hashmap_entry_init(e, sha1hash(peeled)); hashmap_add(&names, e); e->path = NULL; } diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c index be6417d166..1c4ad6223e 100644 --- a/builtin/diff-tree.c +++ b/builtin/diff-tree.c @@ -22,14 +22,10 @@ static int stdin_diff_commit(struct commit *commit, char *line, int len) if (isspace(line[40]) && !get_sha1_hex(line+41, sha1)) { /* Graft the fake parents locally to the commit */ int pos = 41; - struct commit_list **pptr, *parents; + struct commit_list **pptr; /* Free the real parent list */ - for (parents = commit->parents; parents; ) { - struct commit_list *tmp = parents->next; - free(parents); - parents = tmp; - } + free_commit_list(commit->parents); commit->parents = NULL; pptr = &(commit->parents); while (line[pos] && !get_sha1_hex(line + pos, sha1)) { @@ -72,9 +68,7 @@ static int diff_tree_stdin(char *line) line[len-1] = 0; if (get_sha1_hex(line, sha1)) return -1; - obj = lookup_unknown_object(sha1); - if (!obj || !obj->parsed) - obj = parse_object(sha1); + obj = parse_object(sha1); if (!obj) return -1; if (obj->type == OBJ_COMMIT) diff --git a/builtin/fast-export.c b/builtin/fast-export.c index ef4481615f..b8182c241d 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -18,6 +18,7 @@ #include "parse-options.h" #include "quote.h" #include "remote.h" +#include "blob.h" static const char *fast_export_usage[] = { N_("git fast-export [rev-list-opts]"), @@ -34,6 +35,7 @@ static int full_tree; static struct string_list extra_refs = STRING_LIST_INIT_NODUP; static struct refspec *refspecs; static int refspecs_nr; +static int anonymize; static int parse_opt_signed_tag_mode(const struct option *opt, const char *arg, int unset) @@ -81,6 +83,76 @@ static int has_unshown_parent(struct commit *commit) return 0; } +struct anonymized_entry { + struct hashmap_entry hash; + const char *orig; + size_t orig_len; + const char *anon; + size_t anon_len; +}; + +static int anonymized_entry_cmp(const void *va, const void *vb, + const void *data) +{ + const struct anonymized_entry *a = va, *b = vb; + return a->orig_len != b->orig_len || + memcmp(a->orig, b->orig, a->orig_len); +} + +/* + * Basically keep a cache of X->Y so that we can repeatedly replace + * the same anonymized string with another. The actual generation + * is farmed out to the generate function. + */ +static const void *anonymize_mem(struct hashmap *map, + void *(*generate)(const void *, size_t *), + const void *orig, size_t *len) +{ + struct anonymized_entry key, *ret; + + if (!map->cmpfn) + hashmap_init(map, anonymized_entry_cmp, 0); + + hashmap_entry_init(&key, memhash(orig, *len)); + key.orig = orig; + key.orig_len = *len; + ret = hashmap_get(map, &key, NULL); + + if (!ret) { + ret = xmalloc(sizeof(*ret)); + hashmap_entry_init(&ret->hash, key.hash.hash); + ret->orig = xstrdup(orig); + ret->orig_len = *len; + ret->anon = generate(orig, len); + ret->anon_len = *len; + hashmap_put(map, ret); + } + + *len = ret->anon_len; + return ret->anon; +} + +/* + * We anonymize each component of a path individually, + * so that paths a/b and a/c will share a common root. + * The paths are cached via anonymize_mem so that repeated + * lookups for "a" will yield the same value. + */ +static void anonymize_path(struct strbuf *out, const char *path, + struct hashmap *map, + void *(*generate)(const void *, size_t *)) +{ + while (*path) { + const char *end_of_component = strchrnul(path, '/'); + size_t len = end_of_component - path; + const char *c = anonymize_mem(map, generate, path, &len); + strbuf_add(out, c, len); + path = end_of_component; + if (*path) + strbuf_addch(out, *path++); + } +} + /* Since intptr_t is C99, we do not use it here */ static inline uint32_t *mark_to_ptr(uint32_t mark) { @@ -119,6 +191,26 @@ static void show_progress(void) printf("progress %d objects\n", counter); } +/* + * Ideally we would want some transformation of the blob data here + * that is unreversible, but would still be the same size and have + * the same data relationship to other blobs (so that we get the same + * delta and packing behavior as the original). But the first and last + * requirements there are probably mutually exclusive, so let's take + * the easy way out for now, and just generate arbitrary content. + * + * There's no need to cache this result with anonymize_mem, since + * we already handle blob content caching with marks. + */ +static char *anonymize_blob(unsigned long *size) +{ + static int counter; + struct strbuf out = STRBUF_INIT; + strbuf_addf(&out, "anonymous blob %d", counter++); + *size = out.len; + return strbuf_detach(&out, NULL); +} + static void export_blob(const unsigned char *sha1) { unsigned long size; @@ -137,12 +229,19 @@ static void export_blob(const unsigned char *sha1) if (object && object->flags & SHOWN) return; - buf = read_sha1_file(sha1, &type, &size); - if (!buf) - die ("Could not read blob %s", sha1_to_hex(sha1)); - if (check_sha1_signature(sha1, buf, size, typename(type)) < 0) - die("sha1 mismatch in blob %s", sha1_to_hex(sha1)); - object = parse_object_buffer(sha1, type, size, buf, &eaten); + if (anonymize) { + buf = anonymize_blob(&size); + object = (struct object *)lookup_blob(sha1); + eaten = 0; + } else { + buf = read_sha1_file(sha1, &type, &size); + if (!buf) + die ("Could not read blob %s", sha1_to_hex(sha1)); + if (check_sha1_signature(sha1, buf, size, typename(type)) < 0) + die("sha1 mismatch in blob %s", sha1_to_hex(sha1)); + object = parse_object_buffer(sha1, type, size, buf, &eaten); + } + if (!object) die("Could not read blob %s", sha1_to_hex(sha1)); @@ -190,7 +289,7 @@ static int depth_first(const void *a_, const void *b_) return (a->status == 'R') - (b->status == 'R'); } -static void print_path(const char *path) +static void print_path_1(const char *path) { int need_quote = quote_c_style(path, NULL, NULL, 0); if (need_quote) @@ -201,6 +300,43 @@ static void print_path(const char *path) printf("%s", path); } +static void *anonymize_path_component(const void *path, size_t *len) +{ + static int counter; + struct strbuf out = STRBUF_INIT; + strbuf_addf(&out, "path%d", counter++); + return strbuf_detach(&out, len); +} + +static void print_path(const char *path) +{ + if (!anonymize) + print_path_1(path); + else { + static struct hashmap paths; + static struct strbuf anon = STRBUF_INIT; + + anonymize_path(&anon, path, &paths, anonymize_path_component); + print_path_1(anon.buf); + strbuf_reset(&anon); + } +} + +static void *generate_fake_sha1(const void *old, size_t *len) +{ + static uint32_t counter = 1; /* avoid null sha1 */ + unsigned char *out = xcalloc(20, 1); + put_be32(out + 16, counter++); + return out; +} + +static const unsigned char *anonymize_sha1(const unsigned char *sha1) +{ + static struct hashmap sha1s; + size_t len = 20; + return anonymize_mem(&sha1s, generate_fake_sha1, sha1, &len); +} + static void show_filemodify(struct diff_queue_struct *q, struct diff_options *options, void *data) { @@ -245,7 +381,9 @@ static void show_filemodify(struct diff_queue_struct *q, */ if (no_data || S_ISGITLINK(spec->mode)) printf("M %06o %s ", spec->mode, - sha1_to_hex(spec->sha1)); + sha1_to_hex(anonymize ? + anonymize_sha1(spec->sha1) : + spec->sha1)); else { struct object *object = lookup_object(spec->sha1); printf("M %06o :%d ", spec->mode, @@ -279,19 +417,130 @@ static const char *find_encoding(const char *begin, const char *end) return bol; } +static void *anonymize_ref_component(const void *old, size_t *len) +{ + static int counter; + struct strbuf out = STRBUF_INIT; + strbuf_addf(&out, "ref%d", counter++); + return strbuf_detach(&out, len); +} + +static const char *anonymize_refname(const char *refname) +{ + /* + * If any of these prefixes is found, we will leave it intact + * so that tags remain tags and so forth. + */ + static const char *prefixes[] = { + "refs/heads/", + "refs/tags/", + "refs/remotes/", + "refs/" + }; + static struct hashmap refs; + static struct strbuf anon = STRBUF_INIT; + int i; + + /* + * We also leave "master" as a special case, since it does not reveal + * anything interesting. + */ + if (!strcmp(refname, "refs/heads/master")) + return refname; + + strbuf_reset(&anon); + for (i = 0; i < ARRAY_SIZE(prefixes); i++) { + if (skip_prefix(refname, prefixes[i], &refname)) { + strbuf_addstr(&anon, prefixes[i]); + break; + } + } + + anonymize_path(&anon, refname, &refs, anonymize_ref_component); + return anon.buf; +} + +/* + * We do not even bother to cache commit messages, as they are unlikely + * to be repeated verbatim, and it is not that interesting when they are. + */ +static char *anonymize_commit_message(const char *old) +{ + static int counter; + return xstrfmt("subject %d\n\nbody\n", counter++); +} + +static struct hashmap idents; +static void *anonymize_ident(const void *old, size_t *len) +{ + static int counter; + struct strbuf out = STRBUF_INIT; + strbuf_addf(&out, "User %d ", counter, counter); + counter++; + return strbuf_detach(&out, len); +} + +/* + * Our strategy here is to anonymize the names and email addresses, + * but keep timestamps intact, as they influence things like traversal + * order (and by themselves should not be too revealing). + */ +static void anonymize_ident_line(const char **beg, const char **end) +{ + static struct strbuf buffers[] = { STRBUF_INIT, STRBUF_INIT }; + static unsigned which_buffer; + + struct strbuf *out; + struct ident_split split; + const char *end_of_header; + + out = &buffers[which_buffer++]; + which_buffer %= ARRAY_SIZE(buffers); + strbuf_reset(out); + + /* skip "committer", "author", "tagger", etc */ + end_of_header = strchr(*beg, ' '); + if (!end_of_header) + die("BUG: malformed line fed to anonymize_ident_line: %.*s", + (int)(*end - *beg), *beg); + end_of_header++; + strbuf_add(out, *beg, end_of_header - *beg); + + if (!split_ident_line(&split, end_of_header, *end - end_of_header) && + split.date_begin) { + const char *ident; + size_t len; + + len = split.mail_end - split.name_begin; + ident = anonymize_mem(&idents, anonymize_ident, + split.name_begin, &len); + strbuf_add(out, ident, len); + strbuf_addch(out, ' '); + strbuf_add(out, split.date_begin, split.tz_end - split.date_begin); + } else { + strbuf_addstr(out, "Malformed Ident 0 -0000"); + } + + *beg = out->buf; + *end = out->buf + out->len; +} + static void handle_commit(struct commit *commit, struct rev_info *rev) { int saved_output_format = rev->diffopt.output_format; + const char *commit_buffer; const char *author, *author_end, *committer, *committer_end; const char *encoding, *message; char *reencoded = NULL; struct commit_list *p; + const char *refname; int i; rev->diffopt.output_format = DIFF_FORMAT_CALLBACK; parse_commit_or_die(commit); - author = strstr(commit->buffer, "\nauthor "); + commit_buffer = get_commit_buffer(commit, NULL); + author = strstr(commit_buffer, "\nauthor "); if (!author) die ("Could not find author in commit %s", sha1_to_hex(commit->object.sha1)); @@ -324,13 +573,22 @@ static void handle_commit(struct commit *commit, struct rev_info *rev) if (!S_ISGITLINK(diff_queued_diff.queue[i]->two->mode)) export_blob(diff_queued_diff.queue[i]->two->sha1); + refname = commit->util; + if (anonymize) { + refname = anonymize_refname(refname); + anonymize_ident_line(&committer, &committer_end); + anonymize_ident_line(&author, &author_end); + } + mark_next_object(&commit->object); - if (!is_encoding_utf8(encoding)) + if (anonymize) + reencoded = anonymize_commit_message(message); + else if (!is_encoding_utf8(encoding)) reencoded = reencode_string(message, "UTF-8", encoding); if (!commit->parents) - printf("reset %s\n", (const char*)commit->util); + printf("reset %s\n", refname); printf("commit %s\nmark :%"PRIu32"\n%.*s\n%.*s\ndata %u\n%s", - (const char *)commit->util, last_idnum, + refname, last_idnum, (int)(author_end - author), author, (int)(committer_end - committer), committer, (unsigned)(reencoded @@ -338,6 +596,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev) ? strlen(message) : 0), reencoded ? reencoded : message ? message : ""); free(reencoded); + unuse_commit_buffer(commit, commit_buffer); for (i = 0, p = commit->parents; p; p = p->next) { int mark = get_object_mark(&p->item->object); @@ -360,6 +619,14 @@ static void handle_commit(struct commit *commit, struct rev_info *rev) show_progress(); } +static void *anonymize_tag(const void *old, size_t *len) +{ + static int counter; + struct strbuf out = STRBUF_INIT; + strbuf_addf(&out, "tag message %d", counter++); + return strbuf_detach(&out, len); +} + static void handle_tail(struct object_array *commits, struct rev_info *revs) { struct commit *commit; @@ -416,6 +683,17 @@ static void handle_tag(const char *name, struct tag *tag) } else { tagger++; tagger_end = strchrnul(tagger, '\n'); + if (anonymize) + anonymize_ident_line(&tagger, &tagger_end); + } + + if (anonymize) { + name = anonymize_refname(name); + if (message) { + static struct hashmap tags; + message = anonymize_mem(&tags, anonymize_tag, + message, &message_size); + } } /* handle signed tags */ @@ -581,6 +859,8 @@ static void handle_tags_and_duplicates(void) handle_tag(name, (struct tag *)object); break; case OBJ_COMMIT: + if (anonymize) + name = anonymize_refname(name); /* create refs pointing to already seen commits */ commit = (struct commit *)object; printf("reset %s\nfrom :%d\n\n", name, @@ -716,6 +996,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "no-data", &no_data, N_("Skip output of blob data")), OPT_STRING_LIST(0, "refspec", &refspecs_list, N_("refspec"), N_("Apply refspec to exported refs")), + OPT_BOOL(0, "anonymize", &anonymize, N_("anonymize output")), OPT_END() }; diff --git a/builtin/fetch.c b/builtin/fetch.c index dd46b61d9a..159fb7e916 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1082,16 +1082,11 @@ static int fetch_one(struct remote *remote, int argc, const char **argv) refs = xcalloc(argc + 1, sizeof(const char *)); for (i = 0; i < argc; i++) { if (!strcmp(argv[i], "tag")) { - char *ref; i++; if (i >= argc) die(_("You need to specify a tag name.")); - ref = xmalloc(strlen(argv[i]) * 2 + 22); - strcpy(ref, "refs/tags/"); - strcat(ref, argv[i]); - strcat(ref, ":refs/tags/"); - strcat(ref, argv[i]); - refs[j++] = ref; + refs[j++] = xstrfmt("refs/tags/%s:refs/tags/%s", + argv[i], argv[i]); } else refs[j++] = argv[i]; } @@ -1115,9 +1110,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) struct string_list list = STRING_LIST_INIT_NODUP; struct remote *remote; int result = 0; - static const char *argv_gc_auto[] = { - "gc", "--auto", NULL, - }; + struct argv_array argv_gc_auto = ARGV_ARRAY_INIT; packet_trace_identity("fetch"); @@ -1203,7 +1196,11 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) list.strdup_strings = 1; string_list_clear(&list, 0); - run_command_v_opt(argv_gc_auto, RUN_GIT_CMD); + argv_array_pushl(&argv_gc_auto, "gc", "--auto", NULL); + if (verbosity < 0) + argv_array_push(&argv_gc_auto, "--quiet"); + run_command_v_opt(argv_gc_auto.argv, RUN_GIT_CMD); + argv_array_clear(&argv_gc_auto); return result; } diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index 3906eda877..79df05ef52 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -100,7 +100,8 @@ static int handle_line(char *line, struct merge_parents *merge_parents) { int i, len = strlen(line); struct origin_data *origin_data; - char *src, *origin; + char *src; + const char *origin; struct src_data *src_data; struct string_list_item *item; int pulling_head = 0; @@ -164,8 +165,7 @@ static int handle_line(char *line, struct merge_parents *merge_parents) origin = line; string_list_append(&src_data->tag, origin + 4); src_data->head_status |= 2; - } else if (starts_with(line, "remote-tracking branch ")) { - origin = line + strlen("remote-tracking branch "); + } else if (skip_prefix(line, "remote-tracking branch ", &origin)) { string_list_append(&src_data->r_branch, origin); src_data->head_status |= 2; } else { @@ -178,11 +178,8 @@ static int handle_line(char *line, struct merge_parents *merge_parents) int len = strlen(origin); if (origin[0] == '\'' && origin[len - 1] == '\'') origin = xmemdupz(origin + 1, len - 2); - } else { - char *new_origin = xmalloc(strlen(origin) + strlen(src) + 5); - sprintf(new_origin, "%s of %s", origin, src); - origin = new_origin; - } + } else + origin = xstrfmt("%s of %s", origin, src); if (strcmp(".", src)) origin_data->is_local_branch = 0; string_list_append(&origins, origin)->util = origin_data; @@ -230,12 +227,14 @@ static void add_branch_desc(struct strbuf *out, const char *name) static void record_person(int which, struct string_list *people, struct commit *commit) { + const char *buffer; char *name_buf, *name, *name_end; struct string_list_item *elem; const char *field; field = (which == 'a') ? "\nauthor " : "\ncommitter "; - name = strstr(commit->buffer, field); + buffer = get_commit_buffer(commit, NULL); + name = strstr(buffer, field); if (!name) return; name += strlen(field); @@ -247,6 +246,7 @@ static void record_person(int which, struct string_list *people, if (name_end < name) return; name_buf = xmemdupz(name, name_end - name + 1); + unuse_commit_buffer(commit, buffer); elem = string_list_lookup(people, name_buf); if (!elem) { @@ -297,8 +297,8 @@ static void credit_people(struct strbuf *out, if (!them->nr || (them->nr == 1 && me && - (me = skip_prefix(me, them->items->string)) != NULL && - skip_prefix(me, " <"))) + skip_prefix(me, them->items->string, &me) && + starts_with(me, " <"))) return; strbuf_addf(out, "\n%c %s ", comment_line_char, label); add_people_count(out, them); diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 4135980f20..47bd624696 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -283,18 +283,6 @@ static void grab_tag_values(struct atom_value *val, int deref, struct object *ob } } -static int num_parents(struct commit *commit) -{ - struct commit_list *parents; - int i; - - for (i = 0, parents = commit->parents; - parents; - parents = parents->next) - i++; - return i; -} - /* See grab_values */ static void grab_commit_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz) { @@ -315,12 +303,12 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object } if (!strcmp(name, "numparent")) { char *s = xmalloc(40); - v->ul = num_parents(commit); + v->ul = commit_list_count(commit->parents); sprintf(s, "%lu", v->ul); v->s = s; } else if (!strcmp(name, "parent")) { - int num = num_parents(commit); + int num = commit_list_count(commit->parents); int i; struct commit_list *parents; char *s = xmalloc(41 * num + 1); diff --git a/builtin/fsck.c b/builtin/fsck.c index fc150c8821..d42a27da89 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -310,8 +310,7 @@ static int fsck_obj(struct object *obj) if (obj->type == OBJ_COMMIT) { struct commit *commit = (struct commit *) obj; - free(commit->buffer); - commit->buffer = NULL; + free_commit_buffer(commit); if (!commit->parents && show_root) printf("root %s\n", sha1_to_hex(commit->object.sha1)); @@ -482,11 +481,6 @@ static int fsck_handle_reflog(const char *logname, const unsigned char *sha1, in return 0; } -static int is_branch(const char *refname) -{ - return !strcmp(refname, "HEAD") || starts_with(refname, "refs/heads/"); -} - static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { struct object *obj; diff --git a/builtin/gc.c b/builtin/gc.c index 8d219d8c42..ced1456e1e 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -55,44 +55,33 @@ static void remove_pidfile_on_signal(int signo) raise(signo); } -static int gc_config(const char *var, const char *value, void *cb) +static void gc_config(void) { - if (!strcmp(var, "gc.packrefs")) { + const char *value; + + if (!git_config_get_value("gc.packrefs", &value)) { if (value && !strcmp(value, "notbare")) pack_refs = -1; else - pack_refs = git_config_bool(var, value); - return 0; - } - if (!strcmp(var, "gc.aggressivewindow")) { - aggressive_window = git_config_int(var, value); - return 0; - } - if (!strcmp(var, "gc.aggressivedepth")) { - aggressive_depth = git_config_int(var, value); - return 0; - } - if (!strcmp(var, "gc.auto")) { - gc_auto_threshold = git_config_int(var, value); - return 0; - } - if (!strcmp(var, "gc.autopacklimit")) { - gc_auto_pack_limit = git_config_int(var, value); - return 0; + pack_refs = git_config_bool("gc.packrefs", value); } - if (!strcmp(var, "gc.autodetach")) { - detach_auto = git_config_bool(var, value); - return 0; - } - if (!strcmp(var, "gc.pruneexpire")) { - if (value && strcmp(value, "now")) { + + git_config_get_int("gc.aggressivewindow", &aggressive_window); + git_config_get_int("gc.aggressivedepth", &aggressive_depth); + git_config_get_int("gc.auto", &gc_auto_threshold); + git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit); + git_config_get_bool("gc.autodetach", &detach_auto); + + if (!git_config_get_string_const("gc.pruneexpire", &prune_expire)) { + if (strcmp(prune_expire, "now")) { unsigned long now = approxidate("now"); - if (approxidate(value) >= now) - return error(_("Invalid %s: '%s'"), var, value); + if (approxidate(prune_expire) >= now) { + git_die_config("gc.pruneexpire", _("Invalid gc.pruneexpire: '%s'"), + prune_expire); + } } - return git_config_string(&prune_expire, var, value); } - return git_default_config(var, value, cb); + git_config(git_default_config, NULL); } static int too_many_loose_objects(void) @@ -301,7 +290,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix) argv_array_pushl(&prune, "prune", "--expire", NULL ); argv_array_pushl(&rerere, "rerere", "gc", NULL); - git_config(gc_config, NULL); + gc_config(); if (pack_refs < 0) pack_refs = !is_bare_repository(); diff --git a/builtin/help.c b/builtin/help.c index 1fdefeb686..8343b4027d 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -79,12 +79,11 @@ static const char *get_man_viewer_info(const char *name) static int check_emacsclient_version(void) { struct strbuf buffer = STRBUF_INIT; - struct child_process ec_process; + struct child_process ec_process = CHILD_PROCESS_INIT; const char *argv_ec[] = { "emacsclient", "--version", NULL }; int version; /* emacsclient prints its version number on stderr */ - memset(&ec_process, 0, sizeof(ec_process)); ec_process.argv = argv_ec; ec_process.err = -1; ec_process.stdout_to_stderr = 1; diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 18f57de58b..eebf1a8fc2 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -112,6 +112,10 @@ static pthread_mutex_t deepest_delta_mutex; #define deepest_delta_lock() lock_mutex(&deepest_delta_mutex) #define deepest_delta_unlock() unlock_mutex(&deepest_delta_mutex) +static pthread_mutex_t type_cas_mutex; +#define type_cas_lock() lock_mutex(&type_cas_mutex) +#define type_cas_unlock() unlock_mutex(&type_cas_mutex) + static pthread_key_t key; static inline void lock_mutex(pthread_mutex_t *mutex) @@ -135,6 +139,7 @@ static void init_thread(void) init_recursive_mutex(&read_mutex); pthread_mutex_init(&counter_mutex, NULL); pthread_mutex_init(&work_mutex, NULL); + pthread_mutex_init(&type_cas_mutex, NULL); if (show_stat) pthread_mutex_init(&deepest_delta_mutex, NULL); pthread_key_create(&key, NULL); @@ -157,6 +162,7 @@ static void cleanup_thread(void) pthread_mutex_destroy(&read_mutex); pthread_mutex_destroy(&counter_mutex); pthread_mutex_destroy(&work_mutex); + pthread_mutex_destroy(&type_cas_mutex); if (show_stat) pthread_mutex_destroy(&deepest_delta_mutex); for (i = 0; i < nr_threads; i++) @@ -362,8 +368,7 @@ static void set_thread_data(struct thread_local *data) static struct base_data *alloc_base_data(void) { - struct base_data *base = xmalloc(sizeof(struct base_data)); - memset(base, 0, sizeof(*base)); + struct base_data *base = xcalloc(1, sizeof(struct base_data)); base->ref_last = -1; base->ofs_last = -1; return base; @@ -786,7 +791,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, } if (obj->type == OBJ_COMMIT) { struct commit *commit = (struct commit *) obj; - commit->buffer = NULL; + if (detach_commit_buffer(commit, NULL) != data) + die("BUG: parse_object_buffer transmogrified our buffer"); } obj->flags |= FLAG_CHECKED; } @@ -862,7 +868,6 @@ static void resolve_delta(struct object_entry *delta_obj, { void *base_data, *delta_data; - delta_obj->real_type = base->obj->real_type; if (show_stat) { delta_obj->delta_depth = base->obj->delta_depth + 1; deepest_delta_lock(); @@ -888,6 +893,26 @@ static void resolve_delta(struct object_entry *delta_obj, counter_unlock(); } +/* + * Standard boolean compare-and-swap: atomically check whether "*type" is + * "want"; if so, swap in "set" and return true. Otherwise, leave it untouched + * and return false. + */ +static int compare_and_swap_type(enum object_type *type, + enum object_type want, + enum object_type set) +{ + enum object_type old; + + type_cas_lock(); + old = *type; + if (old == want) + *type = set; + type_cas_unlock(); + + return old == want; +} + static struct base_data *find_unresolved_deltas_1(struct base_data *base, struct base_data *prev_base) { @@ -915,7 +940,10 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base, struct object_entry *child = objects + deltas[base->ref_first].obj_no; struct base_data *result = alloc_base_data(); - assert(child->real_type == OBJ_REF_DELTA); + if (!compare_and_swap_type(&child->real_type, OBJ_REF_DELTA, + base->obj->real_type)) + die("BUG: child->real_type != OBJ_REF_DELTA"); + resolve_delta(child, base, result); if (base->ref_first == base->ref_last && base->ofs_last == -1) free_base_data(base); @@ -929,6 +957,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base, struct base_data *result = alloc_base_data(); assert(child->real_type == OBJ_OFS_DELTA); + child->real_type = base->obj->real_type; resolve_delta(child, base, result); if (base->ofs_first == base->ofs_last) free_base_data(base); @@ -1505,7 +1534,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) const char *curr_index; const char *index_name = NULL, *pack_name = NULL; const char *keep_name = NULL, *keep_msg = NULL; - char *index_name_buf = NULL, *keep_name_buf = NULL; + struct strbuf index_name_buf = STRBUF_INIT, + keep_name_buf = STRBUF_INIT; struct pack_idx_entry **idx_objects; struct pack_idx_option opts; unsigned char pack_sha1[20]; @@ -1602,24 +1632,22 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) if (fix_thin_pack && !from_stdin) die(_("--fix-thin cannot be used without --stdin")); if (!index_name && pack_name) { - int len = strlen(pack_name); - if (!has_extension(pack_name, ".pack")) + size_t len; + if (!strip_suffix(pack_name, ".pack", &len)) die(_("packfile name '%s' does not end with '.pack'"), pack_name); - index_name_buf = xmalloc(len); - memcpy(index_name_buf, pack_name, len - 5); - strcpy(index_name_buf + len - 5, ".idx"); - index_name = index_name_buf; + strbuf_add(&index_name_buf, pack_name, len); + strbuf_addstr(&index_name_buf, ".idx"); + index_name = index_name_buf.buf; } if (keep_msg && !keep_name && pack_name) { - int len = strlen(pack_name); - if (!has_extension(pack_name, ".pack")) + size_t len; + if (!strip_suffix(pack_name, ".pack", &len)) die(_("packfile name '%s' does not end with '.pack'"), pack_name); - keep_name_buf = xmalloc(len); - memcpy(keep_name_buf, pack_name, len - 5); - strcpy(keep_name_buf + len - 5, ".keep"); - keep_name = keep_name_buf; + strbuf_add(&keep_name_buf, pack_name, len); + strbuf_addstr(&keep_name_buf, ".idx"); + keep_name = keep_name_buf.buf; } if (verify) { if (!index_name) @@ -1667,8 +1695,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) else close(input_fd); free(objects); - free(index_name_buf); - free(keep_name_buf); + strbuf_release(&index_name_buf); + strbuf_release(&keep_name_buf); if (pack_name == NULL) free((void *) curr_pack); if (index_name == NULL) diff --git a/builtin/init-db.c b/builtin/init-db.c index 56f85e239a..587a5055ed 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -330,12 +330,12 @@ int set_git_dir_init(const char *git_dir, const char *real_git_dir, * moving the target repo later on in separate_git_dir() */ git_link = xstrdup(real_path(git_dir)); + set_git_dir(real_path(real_git_dir)); } else { - real_git_dir = real_path(git_dir); + set_git_dir(real_path(git_dir)); git_link = NULL; } - set_git_dir(real_path(real_git_dir)); return 0; } @@ -426,8 +426,9 @@ int init_db(const char *template_dir, unsigned int flags) static int guess_repository_type(const char *git_dir) { - char cwd[PATH_MAX]; const char *slash; + char *cwd; + int cwd_is_git_dir; /* * "GIT_DIR=. git init" is always bare. @@ -435,9 +436,10 @@ static int guess_repository_type(const char *git_dir) */ if (!strcmp(".", git_dir)) return 1; - if (!getcwd(cwd, sizeof(cwd))) - die_errno(_("cannot tell cwd")); - if (!strcmp(git_dir, cwd)) + cwd = xgetcwd(); + cwd_is_git_dir = !strcmp(git_dir, cwd); + free(cwd); + if (cwd_is_git_dir) return 1; /* * "GIT_DIR=.git or GIT_DIR=something/.git is usually not. @@ -535,10 +537,9 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) usage(init_db_usage[0]); } if (is_bare_repository_cfg == 1) { - static char git_dir[PATH_MAX+1]; - - setenv(GIT_DIR_ENVIRONMENT, - getcwd(git_dir, sizeof(git_dir)), argc > 0); + char *cwd = xgetcwd(); + setenv(GIT_DIR_ENVIRONMENT, cwd, argc > 0); + free(cwd); } if (init_shared_repository != -1) @@ -572,13 +573,10 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) git_work_tree_cfg = xstrdup(real_path(rel)); free(rel); } - if (!git_work_tree_cfg) { - git_work_tree_cfg = xcalloc(PATH_MAX, 1); - if (!getcwd(git_work_tree_cfg, PATH_MAX)) - die_errno (_("Cannot access current working directory")); - } + if (!git_work_tree_cfg) + git_work_tree_cfg = xgetcwd(); if (work_tree) - set_git_work_tree(real_path(work_tree)); + set_git_work_tree(work_tree); else set_git_work_tree(git_work_tree_cfg); if (access(get_git_work_tree(), X_OK)) @@ -587,7 +585,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) } else { if (work_tree) - set_git_work_tree(real_path(work_tree)); + set_git_work_tree(work_tree); } set_git_dir_init(git_dir, real_git_dir, 1); diff --git a/builtin/log.c b/builtin/log.c index a7ba211731..e4d812208d 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -347,8 +347,7 @@ static int cmd_log_walk(struct rev_info *rev) rev->max_count++; if (!rev->reflog_info) { /* we allow cycles in reflog ancestry */ - free(commit->buffer); - commit->buffer = NULL; + free_commit_buffer(commit); } free_commit_list(commit->parents); commit->parents = NULL; @@ -862,9 +861,10 @@ static void add_branch_description(struct strbuf *buf, const char *branch_name) read_branch_desc(&desc, branch_name); if (desc.len) { strbuf_addch(buf, '\n'); - strbuf_add(buf, desc.buf, desc.len); + strbuf_addbuf(buf, &desc); strbuf_addch(buf, '\n'); } + strbuf_release(&desc); } static char *find_branch_name(struct rev_info *rev) @@ -872,7 +872,7 @@ static char *find_branch_name(struct rev_info *rev) int i, positive = -1; unsigned char branch_sha1[20]; const unsigned char *tip_sha1; - const char *ref; + const char *ref, *v; char *full_ref, *branch = NULL; for (i = 0; i < rev->cmdline.nr; i++) { @@ -888,9 +888,9 @@ static char *find_branch_name(struct rev_info *rev) ref = rev->cmdline.rev[positive].name; tip_sha1 = rev->cmdline.rev[positive].item->sha1; if (dwim_ref(ref, strlen(ref), branch_sha1, &full_ref) && - starts_with(full_ref, "refs/heads/") && + skip_prefix(full_ref, "refs/heads/", &v) && !hashcmp(tip_sha1, branch_sha1)) - branch = xstrdup(full_ref + strlen("refs/heads/")); + branch = xstrdup(v); free(full_ref); return branch; } @@ -925,9 +925,12 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, log_write_email_headers(rev, head, &pp.subject, &pp.after_subject, &need_8bit_cte); - for (i = 0; !need_8bit_cte && i < nr; i++) - if (has_non_ascii(list[i]->buffer)) + for (i = 0; !need_8bit_cte && i < nr; i++) { + const char *buf = get_commit_buffer(list[i], NULL); + if (has_non_ascii(buf)) need_8bit_cte = 1; + unuse_commit_buffer(list[i], buf); + } if (!branch_name) branch_name = find_branch_name(rev); @@ -1394,10 +1397,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (check_head) { unsigned char sha1[20]; - const char *ref; + const char *ref, *v; ref = resolve_ref_unsafe("HEAD", sha1, 1, NULL); - if (ref && starts_with(ref, "refs/heads/")) - branch_name = xstrdup(ref + strlen("refs/heads/")); + if (ref && skip_prefix(ref, "refs/heads/", &v)) + branch_name = xstrdup(v); else branch_name = xstrdup(""); /* no branch */ } @@ -1528,8 +1531,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) reopen_stdout(rev.numbered_files ? NULL : commit, NULL, &rev, quiet)) die(_("Failed to create output files")); shown = log_tree_commit(&rev, commit); - free(commit->buffer); - commit->buffer = NULL; + free_commit_buffer(commit); /* We put one extra blank line between formatted * patches and this flag is used by log-tree code diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 47c38808a2..99cee20fb0 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -474,7 +474,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) OPT_BOOL('k', "killed", &show_killed, N_("show files on the filesystem that need to be removed")), OPT_BIT(0, "directory", &dir.flags, - N_("show 'other' directories' name only"), + N_("show 'other' directories' names only"), DIR_SHOW_OTHER_DIRECTORIES), OPT_NEGBIT(0, "empty-directory", &dir.flags, N_("don't show empty directories"), diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c index 06296d4bdf..763cda098c 100644 --- a/builtin/mailsplit.c +++ b/builtin/mailsplit.c @@ -53,14 +53,16 @@ static int keep_cr; */ static int split_one(FILE *mbox, const char *name, int allow_bare) { - FILE *output = NULL; + FILE *output; int fd; int status = 0; int is_bare = !is_from_line(buf.buf, buf.len); - if (is_bare && !allow_bare) - goto corrupt; - + if (is_bare && !allow_bare) { + unlink(name); + fprintf(stderr, "corrupt mailbox\n"); + exit(1); + } fd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0666); if (fd < 0) die_errno("cannot open output file '%s'", name); @@ -91,13 +93,6 @@ static int split_one(FILE *mbox, const char *name, int allow_bare) } fclose(output); return status; - - corrupt: - if (output) - fclose(output); - unlink(name); - fprintf(stderr, "corrupt mailbox\n"); - exit(1); } static int populate_maildir_list(struct string_list *list, const char *path) diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index 61cbde4094..f9ab48597e 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -25,7 +25,7 @@ static void add_merge_entry(struct merge_list *entry) merge_result_end = &entry->next; } -static void merge_trees_recursive(struct tree_desc t[3], const char *base, int df_conflict); +static void merge_trees(struct tree_desc t[3], const char *base); static const char *explanation(struct merge_list *entry) { @@ -195,8 +195,8 @@ static void resolve(const struct traverse_info *info, struct name_entry *ours, s add_merge_entry(final); } -static void unresolved_directory(const struct traverse_info *info, struct name_entry n[3], - int df_conflict) +static void unresolved_directory(const struct traverse_info *info, + struct name_entry n[3]) { char *newbase; struct name_entry *p; @@ -218,7 +218,7 @@ static void unresolved_directory(const struct traverse_info *info, struct name_e buf2 = fill_tree_descriptor(t+2, ENTRY_SHA1(n + 2)); #undef ENTRY_SHA1 - merge_trees_recursive(t, newbase, df_conflict); + merge_trees(t, newbase); free(buf0); free(buf1); @@ -259,7 +259,7 @@ static void unresolved(const struct traverse_info *info, struct name_entry n[3]) dirmask |= (1 << i); } - unresolved_directory(info, n, dirmask && (dirmask != mask)); + unresolved_directory(info, n); if (dirmask == mask) return; @@ -335,21 +335,15 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s return mask; } -static void merge_trees_recursive(struct tree_desc t[3], const char *base, int df_conflict) +static void merge_trees(struct tree_desc t[3], const char *base) { struct traverse_info info; setup_traverse_info(&info, base); - info.data = &df_conflict; info.fn = threeway_callback; traverse_trees(3, t, &info); } -static void merge_trees(struct tree_desc t[3], const char *base) -{ - merge_trees_recursive(t, base, 0); -} - static void *get_tree_descriptor(struct tree_desc *desc, const char *rev) { unsigned char sha1[20]; diff --git a/builtin/merge.c b/builtin/merge.c index 428ca247bd..ec6fa9398f 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -237,11 +237,10 @@ static void drop_save(void) static int save_state(unsigned char *stash) { int len; - struct child_process cp; + struct child_process cp = CHILD_PROCESS_INIT; struct strbuf buffer = STRBUF_INIT; const char *argv[] = {"stash", "create", NULL}; - memset(&cp, 0, sizeof(cp)); cp.argv = argv; cp.out = -1; cp.git_cmd = 1; @@ -657,14 +656,12 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, struct commit_list *remoteheads, struct commit *head, const char *head_arg) { - int index_fd; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); - index_fd = hold_locked_index(lock, 1); + hold_locked_index(lock, 1); refresh_cache(REFRESH_QUIET); if (active_cache_changed && - (write_cache(index_fd, active_cache, active_nr) || - commit_locked_index(lock))) + write_locked_index(&the_index, lock, COMMIT_LOCK)) return error(_("Unable to write index.")); rollback_lock_file(lock); @@ -672,7 +669,6 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, int clean, x; struct commit *result; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); - int index_fd; struct commit_list *reversed = NULL; struct merge_options o; struct commit_list *j; @@ -700,12 +696,11 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, for (j = common; j; j = j->next) commit_list_insert(j->item, &reversed); - index_fd = hold_locked_index(lock, 1); + hold_locked_index(lock, 1); clean = merge_recursive(&o, head, remoteheads->item, reversed, &result); if (active_cache_changed && - (write_cache(index_fd, active_cache, active_nr) || - commit_locked_index(lock))) + write_locked_index(&the_index, lock, COMMIT_LOCK)) die (_("unable to write %s"), get_index_file()); rollback_lock_file(lock); return clean ? 0 : 1; @@ -843,17 +838,15 @@ static void prepare_to_commit(struct commit_list *remoteheads) static int merge_trivial(struct commit *head, struct commit_list *remoteheads) { unsigned char result_tree[20], result_commit[20]; - struct commit_list *parent = xmalloc(sizeof(*parent)); + struct commit_list *parents, **pptr = &parents; write_tree_trivial(result_tree); printf(_("Wonderful.\n")); - parent->item = head; - parent->next = xmalloc(sizeof(*parent->next)); - parent->next->item = remoteheads->item; - parent->next->next = NULL; + pptr = commit_list_append(head, pptr); + pptr = commit_list_append(remoteheads->item, pptr); prepare_to_commit(remoteheads); - if (commit_tree(&merge_msg, result_tree, parent, result_commit, NULL, - sign_commit)) + if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents, + result_commit, NULL, sign_commit)) die(_("failed to write commit object")); finish(head, remoteheads, result_commit, "In-index merge"); drop_save(); @@ -877,8 +870,8 @@ static int finish_automerge(struct commit *head, commit_list_insert(head, &parents); strbuf_addch(&merge_msg, '\n'); prepare_to_commit(remoteheads); - if (commit_tree(&merge_msg, result_tree, parents, result_commit, - NULL, sign_commit)) + if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents, + result_commit, NULL, sign_commit)) die(_("failed to write commit object")); strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy); finish(head, remoteheads, result_commit, buf.buf); @@ -1150,14 +1143,14 @@ int cmd_merge(int argc, const char **argv, const char *prefix) */ if (advice_resolve_conflict) die(_("You have not concluded your merge (MERGE_HEAD exists).\n" - "Please, commit your changes before you can merge.")); + "Please, commit your changes before you merge.")); else die(_("You have not concluded your merge (MERGE_HEAD exists).")); } if (file_exists(git_path("CHERRY_PICK_HEAD"))) { if (advice_resolve_conflict) die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n" - "Please, commit your changes before you can merge.")); + "Please, commit your changes before you merge.")); else die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).")); } @@ -1282,10 +1275,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) printf(_("Commit %s has a good GPG signature by %s\n"), hex, signature_check.signer); - free(signature_check.gpg_output); - free(signature_check.gpg_status); - free(signature_check.signer); - free(signature_check.key); + signature_check_clear(&signature_check); } } diff --git a/builtin/mv.c b/builtin/mv.c index 180ef99127..bf784cb943 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -61,9 +61,49 @@ static const char *add_slash(const char *path) static struct lock_file lock_file; #define SUBMODULE_WITH_GITDIR ((const char *)1) +static void prepare_move_submodule(const char *src, int first, + const char **submodule_gitfile) +{ + struct strbuf submodule_dotgit = STRBUF_INIT; + if (!S_ISGITLINK(active_cache[first]->ce_mode)) + die(_("Directory %s is in index and no submodule?"), src); + if (!is_staging_gitmodules_ok()) + die(_("Please stage your changes to .gitmodules or stash them to proceed")); + strbuf_addf(&submodule_dotgit, "%s/.git", src); + *submodule_gitfile = read_gitfile(submodule_dotgit.buf); + if (*submodule_gitfile) + *submodule_gitfile = xstrdup(*submodule_gitfile); + else + *submodule_gitfile = SUBMODULE_WITH_GITDIR; + strbuf_release(&submodule_dotgit); +} + +static int index_range_of_same_dir(const char *src, int length, + int *first_p, int *last_p) +{ + const char *src_w_slash = add_slash(src); + int first, last, len_w_slash = length + 1; + + first = cache_name_pos(src_w_slash, len_w_slash); + if (first >= 0) + die(_("%.*s is in index"), len_w_slash, src_w_slash); + + first = -1 - first; + for (last = first; last < active_nr; last++) { + const char *path = active_cache[last]->name; + if (strncmp(path, src_w_slash, len_w_slash)) + break; + } + if (src_w_slash != src) + free((char *)src_w_slash); + *first_p = first; + *last_p = last; + return last - first; +} + int cmd_mv(int argc, const char **argv, const char *prefix) { - int i, newfd, gitmodules_modified = 0; + int i, gitmodules_modified = 0; int verbose = 0, show_only = 0, force = 0, ignore_errors = 0; struct option builtin_mv_options[] = { OPT__VERBOSE(&verbose, N_("be verbose")), @@ -85,7 +125,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix) if (--argc < 1) usage_with_options(builtin_mv_usage, builtin_mv_options); - newfd = hold_locked_index(&lock_file, 1); + hold_locked_index(&lock_file, 1); if (read_cache() < 0) die(_("index file corrupt")); @@ -108,7 +148,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix) destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME); } else { if (argc != 1) - die("destination '%s' is not a directory", dest_path[0]); + die(_("destination '%s' is not a directory"), dest_path[0]); destination = dest_path; } @@ -131,75 +171,36 @@ int cmd_mv(int argc, const char **argv, const char *prefix) && lstat(dst, &st) == 0) bad = _("cannot move directory over file"); else if (src_is_dir) { - int first = cache_name_pos(src, length); - if (first >= 0) { - struct strbuf submodule_dotgit = STRBUF_INIT; - if (!S_ISGITLINK(active_cache[first]->ce_mode)) - die (_("Huh? Directory %s is in index and no submodule?"), src); - if (!is_staging_gitmodules_ok()) - die (_("Please, stage your changes to .gitmodules or stash them to proceed")); - strbuf_addf(&submodule_dotgit, "%s/.git", src); - submodule_gitfile[i] = read_gitfile(submodule_dotgit.buf); - if (submodule_gitfile[i]) - submodule_gitfile[i] = xstrdup(submodule_gitfile[i]); - else - submodule_gitfile[i] = SUBMODULE_WITH_GITDIR; - strbuf_release(&submodule_dotgit); - } else { - const char *src_w_slash = add_slash(src); - int last, len_w_slash = length + 1; + int first = cache_name_pos(src, length), last; - modes[i] = WORKING_DIRECTORY; + if (first >= 0) + prepare_move_submodule(src, first, + submodule_gitfile + i); + else if (index_range_of_same_dir(src, length, + &first, &last) < 1) + bad = _("source directory is empty"); + else { /* last - first >= 1 */ + int j, dst_len, n; - first = cache_name_pos(src_w_slash, len_w_slash); - if (first >= 0) - die (_("Huh? %.*s is in index?"), - len_w_slash, src_w_slash); - - first = -1 - first; - for (last = first; last < active_nr; last++) { - const char *path = active_cache[last]->name; - if (strncmp(path, src_w_slash, len_w_slash)) - break; - } - if (src_w_slash != src) - free((char *)src_w_slash); - - if (last - first < 1) - bad = _("source directory is empty"); - else { - int j, dst_len; - - if (last - first > 0) { - source = xrealloc(source, - (argc + last - first) - * sizeof(char *)); - destination = xrealloc(destination, - (argc + last - first) - * sizeof(char *)); - modes = xrealloc(modes, - (argc + last - first) - * sizeof(enum update_mode)); - submodule_gitfile = xrealloc(submodule_gitfile, - (argc + last - first) - * sizeof(char *)); - } + modes[i] = WORKING_DIRECTORY; + n = argc + last - first; + source = xrealloc(source, n * sizeof(char *)); + destination = xrealloc(destination, n * sizeof(char *)); + modes = xrealloc(modes, n * sizeof(enum update_mode)); + submodule_gitfile = xrealloc(submodule_gitfile, n * sizeof(char *)); - dst = add_slash(dst); - dst_len = strlen(dst); + dst = add_slash(dst); + dst_len = strlen(dst); - for (j = 0; j < last - first; j++) { - const char *path = - active_cache[first + j]->name; - source[argc + j] = path; - destination[argc + j] = - prefix_path(dst, dst_len, - path + length + 1); - modes[argc + j] = INDEX; - submodule_gitfile[argc + j] = NULL; - } - argc += last - first; + for (j = 0; j < last - first; j++) { + const char *path = active_cache[first + j]->name; + source[argc + j] = path; + destination[argc + j] = + prefix_path(dst, dst_len, path + length + 1); + modes[argc + j] = INDEX; + submodule_gitfile[argc + j] = NULL; } + argc += last - first; } } else if (cache_name_pos(src, length) < 0) bad = _("not under version control"); @@ -225,24 +226,22 @@ int cmd_mv(int argc, const char **argv, const char *prefix) else string_list_insert(&src_for_dst, dst); - if (bad) { - if (ignore_errors) { - if (--argc > 0) { - memmove(source + i, source + i + 1, - (argc - i) * sizeof(char *)); - memmove(destination + i, - destination + i + 1, - (argc - i) * sizeof(char *)); - memmove(modes + i, modes + i + 1, - (argc - i) * sizeof(enum update_mode)); - memmove(submodule_gitfile + i, - submodule_gitfile + i + 1, - (argc - i) * sizeof(char *)); - i--; - } - } else - die (_("%s, source=%s, destination=%s"), - bad, src, dst); + if (!bad) + continue; + if (!ignore_errors) + die(_("%s, source=%s, destination=%s"), + bad, src, dst); + if (--argc > 0) { + int n = argc - i; + memmove(source + i, source + i + 1, + n * sizeof(char *)); + memmove(destination + i, destination + i + 1, + n * sizeof(char *)); + memmove(modes + i, modes + i + 1, + n * sizeof(enum update_mode)); + memmove(submodule_gitfile + i, submodule_gitfile + i + 1, + n * sizeof(char *)); + i--; } } @@ -254,7 +253,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix) printf(_("Renaming %s to %s\n"), src, dst); if (!show_only && mode != INDEX) { if (rename(src, dst) < 0 && !ignore_errors) - die_errno (_("renaming '%s' failed"), src); + die_errno(_("renaming '%s' failed"), src); if (submodule_gitfile[i]) { if (submodule_gitfile[i] != SUBMODULE_WITH_GITDIR) connect_work_tree_and_git_dir(dst, submodule_gitfile[i]); @@ -275,11 +274,9 @@ int cmd_mv(int argc, const char **argv, const char *prefix) if (gitmodules_modified) stage_updated_gitmodules(); - if (active_cache_changed) { - if (write_cache(newfd, active_cache, active_nr) || - commit_locked_index(&lock_file)) - die(_("Unable to write new index file")); - } + if (active_cache_changed && + write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) + die(_("Unable to write new index file")); return 0; } diff --git a/builtin/name-rev.c b/builtin/name-rev.c index c824d4ec5f..3c8f319be6 100644 --- a/builtin/name-rev.c +++ b/builtin/name-rev.c @@ -33,10 +33,7 @@ static void name_rev(struct commit *commit, return; if (deref) { - char *new_name = xmalloc(strlen(tip_name)+3); - strcpy(new_name, tip_name); - strcat(new_name, "^0"); - tip_name = new_name; + tip_name = xstrfmt("%s^0", tip_name); if (generation) die("generation: %d, but deref?", generation); diff --git a/builtin/notes.c b/builtin/notes.c index 820c34135c..67d0bb14f8 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -122,12 +122,11 @@ static void write_commented_object(int fd, const unsigned char *object) { const char *show_args[5] = {"show", "--stat", "--no-notes", sha1_to_hex(object), NULL}; - struct child_process show; + struct child_process show = CHILD_PROCESS_INIT; struct strbuf buf = STRBUF_INIT; struct strbuf cbuf = STRBUF_INIT; /* Invoke "git show --stat --no-notes $object" */ - memset(&show, 0, sizeof(show)); show.argv = show_args; show.no_stdin = 1; show.out = -1; @@ -211,7 +210,7 @@ static void create_note(const unsigned char *object, struct msg_arg *msg, if (write_sha1_file(msg->buf.buf, msg->buf.len, blob_type, result)) { error(_("unable to write note object")); if (path) - error(_("The note contents has been left in %s"), + error(_("The note contents have been left in %s"), path); exit(128); } diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 238b5021eb..b59f5d895e 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -2494,6 +2494,7 @@ static void get_object_list(int ac, const char **av) if (get_sha1_hex(line + 10, sha1)) die("not an SHA-1 '%s'", line + 10); register_shallow(sha1); + use_bitmap_index = 0; continue; } die("not a rev '%s'", line); diff --git a/builtin/push.c b/builtin/push.c index f8dfea41e1..f50e3d5e77 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -127,11 +127,10 @@ static NORETURN int die_push_simple(struct branch *branch, struct remote *remote * them the big ugly fully qualified ref. */ const char *advice_maybe = ""; - const char *short_upstream = - skip_prefix(branch->merge[0]->src, "refs/heads/"); + const char *short_upstream = branch->merge[0]->src; + + skip_prefix(short_upstream, "refs/heads/", &short_upstream); - if (!short_upstream) - short_upstream = branch->merge[0]->src; /* * Don't show advice for people who explicitly set * push.default. diff --git a/builtin/read-tree.c b/builtin/read-tree.c index 0d7ef847a7..e7e1c33a7f 100644 --- a/builtin/read-tree.c +++ b/builtin/read-tree.c @@ -99,7 +99,7 @@ static struct lock_file lock_file; int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) { - int i, newfd, stage = 0; + int i, stage = 0; unsigned char sha1[20]; struct tree_desc t[MAX_UNPACK_TREES]; struct unpack_trees_options opts; @@ -149,12 +149,21 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) argc = parse_options(argc, argv, unused_prefix, read_tree_options, read_tree_usage, 0); - newfd = hold_locked_index(&lock_file, 1); + hold_locked_index(&lock_file, 1); prefix_set = opts.prefix ? 1 : 0; if (1 < opts.merge + opts.reset + prefix_set) die("Which one? -m, --reset, or --prefix?"); + /* + * NEEDSWORK + * + * The old index should be read anyway even if we're going to + * destroy all index entries because we still need to preserve + * certain information such as index version or split-index + * mode. + */ + if (opts.reset || opts.merge || opts.prefix) { if (read_cache_unmerged() && (opts.prefix || opts.merge)) die("You need to resolve your current index first"); @@ -231,10 +240,9 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) * what came from the tree. */ if (nr_trees == 1 && !opts.prefix) - prime_cache_tree(&active_cache_tree, trees[0]); + prime_cache_tree(&the_index, trees[0]); - if (write_cache(newfd, active_cache, active_nr) || - commit_locked_index(&lock_file)) + if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) die("unable to write new index file"); return 0; } diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index c3230817db..afb8d99264 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -255,7 +255,7 @@ static int copy_to_sideband(int in, int out, void *arg) typedef int (*feed_fn)(void *, const char **, size_t *); static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_state) { - struct child_process proc; + struct child_process proc = CHILD_PROCESS_INIT; struct async muxer; const char *argv[2]; int code; @@ -266,7 +266,6 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_sta argv[1] = NULL; - memset(&proc, 0, sizeof(proc)); proc.argv = argv; proc.in = -1; proc.stdout_to_stderr = 1; @@ -350,7 +349,7 @@ static int run_receive_hook(struct command *commands, const char *hook_name, static int run_update_hook(struct command *cmd) { const char *argv[5]; - struct child_process proc; + struct child_process proc = CHILD_PROCESS_INIT; int code; argv[0] = find_hook("update"); @@ -362,7 +361,6 @@ static int run_update_hook(struct command *cmd) argv[3] = sha1_to_hex(cmd->new_sha1); argv[4] = NULL; - memset(&proc, 0, sizeof(proc)); proc.no_stdin = 1; proc.stdout_to_stderr = 1; proc.err = use_sideband ? -1 : 0; @@ -438,7 +436,7 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si) uint32_t mask = 1 << (cmd->index % 32); int i; - trace_printf_key("GIT_TRACE_SHALLOW", + trace_printf_key(&trace_shallow, "shallow: update_shallow_ref %s\n", cmd->ref_name); for (i = 0; i < si->shallow->nr; i++) if (si->used_shallow[i] && @@ -475,7 +473,6 @@ static const char *update(struct command *cmd, struct shallow_info *si) const char *namespaced_name; unsigned char *old_sha1 = cmd->old_sha1; unsigned char *new_sha1 = cmd->new_sha1; - struct ref_lock *lock; /* only refs/... are allowed */ if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) { @@ -576,19 +573,27 @@ static const char *update(struct command *cmd, struct shallow_info *si) return NULL; /* good */ } else { + struct strbuf err = STRBUF_INIT; + struct ref_transaction *transaction; + if (shallow_update && si->shallow_ref[cmd->index] && update_shallow_ref(cmd, si)) return "shallow error"; - lock = lock_any_ref_for_update(namespaced_name, old_sha1, - 0, NULL); - if (!lock) { - rp_error("failed to lock %s", name); - return "failed to lock"; - } - if (write_ref_sha1(lock, new_sha1, "push")) { - return "failed to write"; /* error() already called */ + transaction = ref_transaction_begin(&err); + if (!transaction || + ref_transaction_update(transaction, namespaced_name, + new_sha1, old_sha1, 0, 1, &err) || + ref_transaction_commit(transaction, "push", &err)) { + ref_transaction_free(transaction); + + rp_error("%s", err.buf); + strbuf_release(&err); + return "failed to update ref"; } + + ref_transaction_free(transaction); + strbuf_release(&err); return NULL; /* good */ } } @@ -598,7 +603,7 @@ static void run_update_post_hook(struct command *commands) struct command *cmd; int argc; const char **argv; - struct child_process proc; + struct child_process proc = CHILD_PROCESS_INIT; char *hook; hook = find_hook("post-update"); @@ -614,17 +619,13 @@ static void run_update_post_hook(struct command *commands) argv[0] = hook; for (argc = 1, cmd = commands; cmd; cmd = cmd->next) { - char *p; if (cmd->error_string || cmd->did_not_exist) continue; - p = xmalloc(strlen(cmd->ref_name) + 1); - strcpy(p, cmd->ref_name); - argv[argc] = p; + argv[argc] = xstrdup(cmd->ref_name); argc++; } argv[argc] = NULL; - memset(&proc, 0, sizeof(proc)); proc.no_stdin = 1; proc.stdout_to_stderr = 1; proc.err = use_sideband ? -1 : 0; @@ -914,7 +915,7 @@ static const char *unpack(int err_fd, struct shallow_info *si) const char *hdr_err; int status; char hdr_arg[38]; - struct child_process child; + struct child_process child = CHILD_PROCESS_INIT; int fsck_objects = (receive_fsck_objects >= 0 ? receive_fsck_objects : transfer_fsck_objects >= 0 @@ -936,7 +937,6 @@ static const char *unpack(int err_fd, struct shallow_info *si) argv_array_pushl(&av, "--shallow-file", alt_shallow_file, NULL); } - memset(&child, 0, sizeof(child)); if (ntohl(hdr.hdr_entries) < unpack_limit) { argv_array_pushl(&av, "unpack-objects", hdr_arg, NULL); if (quiet) @@ -1125,7 +1125,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) int advertise_refs = 0; int stateless_rpc = 0; int i; - char *dir = NULL; + const char *dir = NULL; struct command *commands; struct sha1_array shallow = SHA1_ARRAY_INIT; struct sha1_array ref = SHA1_ARRAY_INIT; @@ -1160,7 +1160,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) } if (dir) usage(receive_pack_usage); - dir = xstrdup(arg); + dir = arg; } if (!dir) usage(receive_pack_usage); diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c index 692c834d9d..d699d28e98 100644 --- a/builtin/remote-ext.c +++ b/builtin/remote-ext.c @@ -179,9 +179,8 @@ static void send_git_request(int stdin_fd, const char *serv, const char *repo, static int run_child(const char *arg, const char *service) { int r; - struct child_process child; + struct child_process child = CHILD_PROCESS_INIT; - memset(&child, 0, sizeof(child)); child.in = -1; child.out = -1; child.err = 0; diff --git a/builtin/remote.c b/builtin/remote.c index c9102e8fe9..9a4640dbf0 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -250,9 +250,7 @@ static struct string_list branch_list; static const char *abbrev_ref(const char *name, const char *prefix) { - const char *abbrev = skip_prefix(name, prefix); - if (abbrev) - return abbrev; + skip_prefix(name, prefix, &name); return name; } #define abbrev_branch(name) abbrev_ref((name), "refs/heads/") @@ -265,16 +263,17 @@ static int config_read_branches(const char *key, const char *value, void *cb) struct string_list_item *item; struct branch_info *info; enum { REMOTE, MERGE, REBASE } type; + size_t key_len; key += 7; - if (ends_with(key, ".remote")) { - name = xstrndup(key, strlen(key) - 7); + if (strip_suffix(key, ".remote", &key_len)) { + name = xmemdupz(key, key_len); type = REMOTE; - } else if (ends_with(key, ".merge")) { - name = xstrndup(key, strlen(key) - 6); + } else if (strip_suffix(key, ".merge", &key_len)) { + name = xmemdupz(key, key_len); type = MERGE; - } else if (ends_with(key, ".rebase")) { - name = xstrndup(key, strlen(key) - 7); + } else if (strip_suffix(key, ".rebase", &key_len)) { + name = xmemdupz(key, key_len); type = REBASE; } else return 0; @@ -755,7 +754,7 @@ static int remove_branches(struct string_list *branches) branch_names = xmalloc(branches->nr * sizeof(*branch_names)); for (i = 0; i < branches->nr; i++) branch_names[i] = branches->items[i].string; - result |= repack_without_refs(branch_names, branches->nr); + result |= repack_without_refs(branch_names, branches->nr, NULL); free(branch_names); for (i = 0; i < branches->nr; i++) { @@ -1333,7 +1332,8 @@ static int prune_remote(const char *remote, int dry_run) for (i = 0; i < states.stale.nr; i++) delete_refs[i] = states.stale.items[i].util; if (!dry_run) - result |= repack_without_refs(delete_refs, states.stale.nr); + result |= repack_without_refs(delete_refs, + states.stale.nr, NULL); free(delete_refs); } diff --git a/builtin/repack.c b/builtin/repack.c index ff2216a7aa..fc088dbe6a 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -83,16 +83,15 @@ static void get_non_kept_pack_filenames(struct string_list *fname_list) DIR *dir; struct dirent *e; char *fname; - size_t len; if (!(dir = opendir(packdir))) return; while ((e = readdir(dir)) != NULL) { - if (!ends_with(e->d_name, ".pack")) + size_t len; + if (!strip_suffix(e->d_name, ".pack", &len)) continue; - len = strlen(e->d_name) - strlen(".pack"); fname = xmemdupz(e->d_name, len); if (!file_exists(mkpath("%s/%s.keep", packdir, fname))) @@ -134,7 +133,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix) {".idx"}, {".bitmap", 1}, }; - struct child_process cmd; + struct child_process cmd = CHILD_PROCESS_INIT; struct string_list_item *item; struct argv_array cmd_args = ARGV_ARRAY_INIT; struct string_list names = STRING_LIST_INIT_DUP; @@ -251,7 +250,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix) argv_array_push(&cmd_args, packtmp); - memset(&cmd, 0, sizeof(cmd)); cmd.argv = cmd_args.argv; cmd.git_cmd = 1; cmd.out = -1; diff --git a/builtin/replace.c b/builtin/replace.c index 1bb491d3c4..8020db8500 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -13,19 +13,21 @@ #include "refs.h" #include "parse-options.h" #include "run-command.h" +#include "tag.h" static const char * const git_replace_usage[] = { N_("git replace [-f] "), N_("git replace [-f] --edit "), + N_("git replace [-f] --graft [...]"), N_("git replace -d ..."), N_("git replace [--format=] [-l []]"), NULL }; enum replace_format { - REPLACE_FORMAT_SHORT, - REPLACE_FORMAT_MEDIUM, - REPLACE_FORMAT_LONG + REPLACE_FORMAT_SHORT, + REPLACE_FORMAT_MEDIUM, + REPLACE_FORMAT_LONG }; struct show_data { @@ -153,7 +155,8 @@ static int replace_object_sha1(const char *object_ref, unsigned char prev[20]; enum object_type obj_type, repl_type; char ref[PATH_MAX]; - struct ref_lock *lock; + struct ref_transaction *transaction; + struct strbuf err = STRBUF_INIT; obj_type = sha1_object_info(object, NULL); repl_type = sha1_object_info(repl, NULL); @@ -166,12 +169,13 @@ static int replace_object_sha1(const char *object_ref, check_ref_valid(object, prev, ref, sizeof(ref), force); - lock = lock_any_ref_for_update(ref, prev, 0, NULL); - if (!lock) - die("%s: cannot lock the ref", ref); - if (write_ref_sha1(lock, repl, NULL) < 0) - die("%s: cannot update the ref", ref); + transaction = ref_transaction_begin(&err); + if (!transaction || + ref_transaction_update(transaction, ref, repl, prev, 0, 1, &err) || + ref_transaction_commit(transaction, NULL, &err)) + die("%s", err.buf); + ref_transaction_free(transaction); return 0; } @@ -188,27 +192,32 @@ static int replace_object(const char *object_ref, const char *replace_ref, int f } /* - * Write the contents of the object named by "sha1" to the file "filename", - * pretty-printed for human editing based on its type. + * Write the contents of the object named by "sha1" to the file "filename". + * If "raw" is true, then the object's raw contents are printed according to + * "type". Otherwise, we pretty-print the contents for human editing. */ -static void export_object(const unsigned char *sha1, const char *filename) +static void export_object(const unsigned char *sha1, enum object_type type, + int raw, const char *filename) { - const char *argv[] = { "--no-replace-objects", "cat-file", "-p", NULL, NULL }; - struct child_process cmd = { argv }; + struct child_process cmd = CHILD_PROCESS_INIT; int fd; fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (fd < 0) die_errno("unable to open %s for writing", filename); - argv[3] = sha1_to_hex(sha1); + argv_array_push(&cmd.args, "--no-replace-objects"); + argv_array_push(&cmd.args, "cat-file"); + if (raw) + argv_array_push(&cmd.args, typename(type)); + else + argv_array_push(&cmd.args, "-p"); + argv_array_push(&cmd.args, sha1_to_hex(sha1)); cmd.git_cmd = 1; cmd.out = fd; if (run_command(&cmd)) die("cat-file reported failure"); - - close(fd); } /* @@ -217,7 +226,7 @@ static void export_object(const unsigned char *sha1, const char *filename) * The sha1 of the written object is returned via sha1. */ static void import_object(unsigned char *sha1, enum object_type type, - const char *filename) + int raw, const char *filename) { int fd; @@ -225,9 +234,9 @@ static void import_object(unsigned char *sha1, enum object_type type, if (fd < 0) die_errno("unable to open %s for reading", filename); - if (type == OBJ_TREE) { + if (!raw && type == OBJ_TREE) { const char *argv[] = { "mktree", NULL }; - struct child_process cmd = { argv }; + struct child_process cmd = CHILD_PROCESS_INIT; struct strbuf result = STRBUF_INIT; cmd.argv = argv; @@ -265,7 +274,7 @@ static void import_object(unsigned char *sha1, enum object_type type, */ } -static int edit_and_replace(const char *object_ref, int force) +static int edit_and_replace(const char *object_ref, int force, int raw) { char *tmpfile = git_pathdup("REPLACE_EDITOBJ"); enum object_type type; @@ -281,10 +290,10 @@ static int edit_and_replace(const char *object_ref, int force) check_ref_valid(old, prev, ref, sizeof(ref), force); - export_object(old, tmpfile); + export_object(old, type, raw, tmpfile); if (launch_editor(tmpfile, NULL, NULL) < 0) die("editing object file failed"); - import_object(new, type, tmpfile); + import_object(new, type, raw, tmpfile); free(tmpfile); @@ -294,22 +303,137 @@ static int edit_and_replace(const char *object_ref, int force) return replace_object_sha1(object_ref, old, "replacement", new, force); } +static void replace_parents(struct strbuf *buf, int argc, const char **argv) +{ + struct strbuf new_parents = STRBUF_INIT; + const char *parent_start, *parent_end; + int i; + + /* find existing parents */ + parent_start = buf->buf; + parent_start += 46; /* "tree " + "hex sha1" + "\n" */ + parent_end = parent_start; + + while (starts_with(parent_end, "parent ")) + parent_end += 48; /* "parent " + "hex sha1" + "\n" */ + + /* prepare new parents */ + for (i = 0; i < argc; i++) { + unsigned char sha1[20]; + if (get_sha1(argv[i], sha1) < 0) + die(_("Not a valid object name: '%s'"), argv[i]); + lookup_commit_or_die(sha1, argv[i]); + strbuf_addf(&new_parents, "parent %s\n", sha1_to_hex(sha1)); + } + + /* replace existing parents with new ones */ + strbuf_splice(buf, parent_start - buf->buf, parent_end - parent_start, + new_parents.buf, new_parents.len); + + strbuf_release(&new_parents); +} + +struct check_mergetag_data { + int argc; + const char **argv; +}; + +static void check_one_mergetag(struct commit *commit, + struct commit_extra_header *extra, + void *data) +{ + struct check_mergetag_data *mergetag_data = (struct check_mergetag_data *)data; + const char *ref = mergetag_data->argv[0]; + unsigned char tag_sha1[20]; + struct tag *tag; + int i; + + hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), tag_sha1); + tag = lookup_tag(tag_sha1); + if (!tag) + die(_("bad mergetag in commit '%s'"), ref); + if (parse_tag_buffer(tag, extra->value, extra->len)) + die(_("malformed mergetag in commit '%s'"), ref); + + /* iterate over new parents */ + for (i = 1; i < mergetag_data->argc; i++) { + unsigned char sha1[20]; + if (get_sha1(mergetag_data->argv[i], sha1) < 0) + die(_("Not a valid object name: '%s'"), mergetag_data->argv[i]); + if (!hashcmp(tag->tagged->sha1, sha1)) + return; /* found */ + } + + die(_("original commit '%s' contains mergetag '%s' that is discarded; " + "use --edit instead of --graft"), ref, sha1_to_hex(tag_sha1)); +} + +static void check_mergetags(struct commit *commit, int argc, const char **argv) +{ + struct check_mergetag_data mergetag_data; + + mergetag_data.argc = argc; + mergetag_data.argv = argv; + for_each_mergetag(check_one_mergetag, commit, &mergetag_data); +} + +static int create_graft(int argc, const char **argv, int force) +{ + unsigned char old[20], new[20]; + const char *old_ref = argv[0]; + struct commit *commit; + struct strbuf buf = STRBUF_INIT; + const char *buffer; + unsigned long size; + + if (get_sha1(old_ref, old) < 0) + die(_("Not a valid object name: '%s'"), old_ref); + commit = lookup_commit_or_die(old, old_ref); + + buffer = get_commit_buffer(commit, &size); + strbuf_add(&buf, buffer, size); + unuse_commit_buffer(commit, buffer); + + replace_parents(&buf, argc - 1, &argv[1]); + + if (remove_signature(&buf)) { + warning(_("the original commit '%s' has a gpg signature."), old_ref); + warning(_("the signature will be removed in the replacement commit!")); + } + + check_mergetags(commit, argc, argv); + + if (write_sha1_file(buf.buf, buf.len, commit_type, new)) + die(_("could not write replacement commit for: '%s'"), old_ref); + + strbuf_release(&buf); + + if (!hashcmp(old, new)) + return error("new commit is the same as the old one: '%s'", sha1_to_hex(old)); + + return replace_object_sha1(old_ref, old, "replacement", new, force); +} + int cmd_replace(int argc, const char **argv, const char *prefix) { int force = 0; + int raw = 0; const char *format = NULL; enum { MODE_UNSPECIFIED = 0, MODE_LIST, MODE_DELETE, MODE_EDIT, + MODE_GRAFT, MODE_REPLACE } cmdmode = MODE_UNSPECIFIED; struct option options[] = { OPT_CMDMODE('l', "list", &cmdmode, N_("list replace refs"), MODE_LIST), OPT_CMDMODE('d', "delete", &cmdmode, N_("delete replace refs"), MODE_DELETE), OPT_CMDMODE('e', "edit", &cmdmode, N_("edit existing object"), MODE_EDIT), + OPT_CMDMODE('g', "graft", &cmdmode, N_("change a commit's parents"), MODE_GRAFT), OPT_BOOL('f', "force", &force, N_("replace the ref if it exists")), + OPT_BOOL(0, "raw", &raw, N_("do not pretty-print contents for --edit")), OPT_STRING(0, "format", &format, N_("format"), N_("use this format")), OPT_END() }; @@ -325,10 +449,17 @@ int cmd_replace(int argc, const char **argv, const char *prefix) usage_msg_opt("--format cannot be used when not listing", git_replace_usage, options); - if (force && cmdmode != MODE_REPLACE && cmdmode != MODE_EDIT) + if (force && + cmdmode != MODE_REPLACE && + cmdmode != MODE_EDIT && + cmdmode != MODE_GRAFT) usage_msg_opt("-f only makes sense when writing a replacement", git_replace_usage, options); + if (raw && cmdmode != MODE_EDIT) + usage_msg_opt("--raw only makes sense with --edit", + git_replace_usage, options); + switch (cmdmode) { case MODE_DELETE: if (argc < 1) @@ -346,7 +477,13 @@ int cmd_replace(int argc, const char **argv, const char *prefix) if (argc != 1) usage_msg_opt("-e needs exactly one argument", git_replace_usage, options); - return edit_and_replace(argv[0], force); + return edit_and_replace(argv[0], force, raw); + + case MODE_GRAFT: + if (argc < 1) + usage_msg_opt("-g needs at least one argument", + git_replace_usage, options); + return create_graft(argc, argv, force); case MODE_LIST: if (argc > 1) diff --git a/builtin/reset.c b/builtin/reset.c index f368266762..855d478e3b 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -84,7 +84,7 @@ static int reset_index(const unsigned char *sha1, int reset_type, int quiet) if (reset_type == MIXED || reset_type == HARD) { tree = parse_tree_indirect(sha1); - prime_cache_tree(&active_cache_tree, tree); + prime_cache_tree(&the_index, tree); } return 0; @@ -93,7 +93,7 @@ static int reset_index(const unsigned char *sha1, int reset_type, int quiet) static void print_new_head_line(struct commit *commit) { const char *hex, *body; - char *msg; + const char *msg; hex = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV); printf(_("HEAD is now at %s"), hex); @@ -109,7 +109,7 @@ static void print_new_head_line(struct commit *commit) } else printf("\n"); - logmsg_free(msg, commit); + unuse_commit_buffer(commit, msg); } static void update_index_from_diff(struct diff_queue_struct *q, @@ -353,7 +353,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) if (reset_type != SOFT) { struct lock_file *lock = xcalloc(1, sizeof(*lock)); - int newfd = hold_locked_index(lock, 1); + hold_locked_index(lock, 1); if (reset_type == MIXED) { int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN; if (read_from_tree(&pathspec, sha1, intent_to_add)) @@ -369,8 +369,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) die(_("Could not reset index file to revision '%s'."), rev); } - if (write_cache(newfd, active_cache, active_nr) || - commit_locked_index(lock)) + if (write_locked_index(&the_index, lock, COMMIT_LOCK)) die(_("Could not write new index file.")); } diff --git a/builtin/rev-list.c b/builtin/rev-list.c index 9f92905379..ff84a825ff 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -106,7 +106,7 @@ static void show_commit(struct commit *commit, void *data) else putchar('\n'); - if (revs->verbose_header && commit->buffer) { + if (revs->verbose_header && get_cached_commit_buffer(commit, NULL)) { struct strbuf buf = STRBUF_INIT; struct pretty_print_context ctx = {0}; ctx.abbrev = revs->abbrev; @@ -173,8 +173,7 @@ static void finish_commit(struct commit *commit, void *data) free_commit_list(commit->parents); commit->parents = NULL; } - free(commit->buffer); - commit->buffer = NULL; + free_commit_buffer(commit); } static void finish_object(struct object *obj, diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 1a6122d3ae..c911b456de 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -11,6 +11,7 @@ #include "parse-options.h" #include "diff.h" #include "revision.h" +#include "split-index.h" #define DO_REVS 1 #define DO_NOREV 2 @@ -150,6 +151,7 @@ static void show_rev(int type, const unsigned char *sha1, const char *name) error("refname '%s' is ambiguous", name); break; } + free(full); } else { show_with_type(type, name); } @@ -734,7 +736,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) } if (!strcmp(arg, "--git-dir")) { const char *gitdir = getenv(GIT_DIR_ENVIRONMENT); - static char cwd[PATH_MAX]; + char *cwd; int len; if (gitdir) { puts(gitdir); @@ -744,10 +746,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) puts(".git"); continue; } - if (!getcwd(cwd, PATH_MAX)) - die_errno("unable to get current working directory"); + cwd = xgetcwd(); len = strlen(cwd); printf("%s%s.git\n", cwd, len && cwd[len-1] != '/' ? "/" : ""); + free(cwd); continue; } if (!strcmp(arg, "--resolve-git-dir")) { @@ -775,6 +777,15 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) : "false"); continue; } + if (!strcmp(arg, "--shared-index-path")) { + if (read_cache() < 0) + die(_("Could not read the index")); + if (the_index.split_index) { + const unsigned char *sha1 = the_index.split_index->base_sha1; + puts(git_path("sharedindex.%s", sha1_to_hex(sha1))); + } + continue; + } if (starts_with(arg, "--since=")) { show_datestring("--max-age=", arg+8); continue; diff --git a/builtin/rm.c b/builtin/rm.c index 960634dd0c..2b61d3bd41 100644 --- a/builtin/rm.c +++ b/builtin/rm.c @@ -65,7 +65,7 @@ static void error_removing_concrete_submodules(struct string_list *files, int *e Q_("the following submodule (or one of its nested " "submodules)\n" "uses a .git directory:", - "the following submodules (or one of its nested " + "the following submodules (or one of their nested " "submodules)\n" "use a .git directory:", files->nr), _("\n(use 'rm -rf' if you really want to remove " @@ -278,7 +278,7 @@ static struct option builtin_rm_options[] = { int cmd_rm(int argc, const char **argv, const char *prefix) { - int i, newfd; + int i; struct pathspec pathspec; char *seen; @@ -293,7 +293,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix) if (!index_only) setup_work_tree(); - newfd = hold_locked_index(&lock_file, 1); + hold_locked_index(&lock_file, 1); if (read_cache() < 0) die(_("index file corrupt")); @@ -427,8 +427,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix) } if (active_cache_changed) { - if (write_cache(newfd, active_cache, active_nr) || - commit_locked_index(&lock_file)) + if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) die(_("Unable to write new index file")); } diff --git a/builtin/send-pack.c b/builtin/send-pack.c index f420b74665..4b1bc0fef7 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -110,6 +110,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) int flags; unsigned int reject_reasons; int progress = -1; + int from_stdin = 0; struct push_cas_option cas = {0}; argv++; @@ -169,6 +170,10 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) args.stateless_rpc = 1; continue; } + if (!strcmp(arg, "--stdin")) { + from_stdin = 1; + continue; + } if (!strcmp(arg, "--helper-status")) { helper_status = 1; continue; @@ -201,6 +206,28 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) } if (!dest) usage(send_pack_usage); + + if (from_stdin) { + struct argv_array all_refspecs = ARGV_ARRAY_INIT; + + for (i = 0; i < nr_refspecs; i++) + argv_array_push(&all_refspecs, refspecs[i]); + + if (args.stateless_rpc) { + const char *buf; + while ((buf = packet_read_line(0, NULL))) + argv_array_push(&all_refspecs, buf); + } else { + struct strbuf line = STRBUF_INIT; + while (strbuf_getline(&line, stdin, '\n') != EOF) + argv_array_push(&all_refspecs, line.buf); + strbuf_release(&line); + } + + refspecs = all_refspecs.argv; + nr_refspecs = all_refspecs.argc; + } + /* * --all and --mirror are incompatible; neither makes sense * with any refspecs. diff --git a/builtin/show-branch.c b/builtin/show-branch.c index d87317290c..298c95e3f8 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -755,7 +755,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) } for (i = 0; i < reflog; i++) { - char *logmsg, *m; + char *logmsg; const char *msg; unsigned long timestamp; int tz; @@ -770,15 +770,14 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) msg = "(none)"; else msg++; - m = xmalloc(strlen(msg) + 200); - sprintf(m, "(%s) %s", - show_date(timestamp, tz, 1), - msg); - reflog_msg[i] = m; + reflog_msg[i] = xstrfmt("(%s) %s", + show_date(timestamp, tz, 1), + msg); free(logmsg); sprintf(nth_desc, "%s@{%d}", *av, base+i); append_ref(nth_desc, sha1, 1); } + free(ref); } else if (all_heads + all_remotes) snarf_refs(all_heads, all_remotes); diff --git a/builtin/tag.c b/builtin/tag.c index c6e8a71127..a81b9e4174 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -32,6 +32,8 @@ static const char * const git_tag_usage[] = { #define SORT_MASK 0x7fff #define REVERSE_SORT 0x8000 +static int tag_sort; + struct tag_filter { const char **patterns; int lines; @@ -83,7 +85,7 @@ static int in_commit_list(const struct commit_list *want, struct commit *c) enum contains_result { CONTAINS_UNKNOWN = -1, CONTAINS_NO = 0, - CONTAINS_YES = 1, + CONTAINS_YES = 1 }; /* @@ -346,9 +348,51 @@ static const char tag_template_nocleanup[] = "Lines starting with '%c' will be kept; you may remove them" " yourself if you want to.\n"); +/* + * Parse a sort string, and return 0 if parsed successfully. Will return + * non-zero when the sort string does not parse into a known type. If var is + * given, the error message becomes a warning and includes information about + * the configuration value. + */ +static int parse_sort_string(const char *var, const char *arg, int *sort) +{ + int type = 0, flags = 0; + + if (skip_prefix(arg, "-", &arg)) + flags |= REVERSE_SORT; + + if (skip_prefix(arg, "version:", &arg) || skip_prefix(arg, "v:", &arg)) + type = VERCMP_SORT; + else + type = STRCMP_SORT; + + if (strcmp(arg, "refname")) { + if (!var) + return error(_("unsupported sort specification '%s'"), arg); + else { + warning(_("unsupported sort specification '%s' in variable '%s'"), + var, arg); + return -1; + } + } + + *sort = (type | flags); + + return 0; +} + static int git_tag_config(const char *var, const char *value, void *cb) { - int status = git_gpg_config(var, value, cb); + int status; + + if (!strcmp(var, "tag.sort")) { + if (!value) + return config_error_nonbool(var); + parse_sort_string(var, value, &tag_sort); + return 0; + } + + status = git_gpg_config(var, value, cb); if (status) return status; if (starts_with(var, "column.")) @@ -522,24 +566,8 @@ static int parse_opt_points_at(const struct option *opt __attribute__((unused)), static int parse_opt_sort(const struct option *opt, const char *arg, int unset) { int *sort = opt->value; - int flags = 0; - if (*arg == '-') { - flags |= REVERSE_SORT; - arg++; - } - if (starts_with(arg, "version:")) { - *sort = VERCMP_SORT; - arg += 8; - } else if (starts_with(arg, "v:")) { - *sort = VERCMP_SORT; - arg += 2; - } else - *sort = STRCMP_SORT; - if (strcmp(arg, "refname")) - die(_("unsupported sort specification %s"), arg); - *sort |= flags; - return 0; + return parse_sort_string(NULL, arg, sort); } int cmd_tag(int argc, const char **argv, const char *prefix) @@ -548,14 +576,15 @@ int cmd_tag(int argc, const char **argv, const char *prefix) struct strbuf ref = STRBUF_INIT; unsigned char object[20], prev[20]; const char *object_ref, *tag; - struct ref_lock *lock; struct create_tag_options opt; char *cleanup_arg = NULL; int annotate = 0, force = 0, lines = -1; - int cmdmode = 0, sort = 0; + int cmdmode = 0; const char *msgfile = NULL, *keyid = NULL; struct msg_arg msg = { 0, STRBUF_INIT }; struct commit_list *with_commit = NULL; + struct ref_transaction *transaction; + struct strbuf err = STRBUF_INIT; struct option options[] = { OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'), { OPTION_INTEGER, 'n', NULL, &lines, N_("n"), @@ -578,7 +607,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) OPT__FORCE(&force, N_("replace the tag if exists")), OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")), { - OPTION_CALLBACK, 0, "sort", &sort, N_("type"), N_("sort tags"), + OPTION_CALLBACK, 0, "sort", &tag_sort, N_("type"), N_("sort tags"), PARSE_OPT_NONEG, parse_opt_sort }, @@ -634,9 +663,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix) copts.padding = 2; run_column_filter(colopts, &copts); } - if (lines != -1 && sort) + if (lines != -1 && tag_sort) die(_("--sort and -n are incompatible")); - ret = list_tags(argv, lines == -1 ? 0 : lines, with_commit, sort); + ret = list_tags(argv, lines == -1 ? 0 : lines, with_commit, tag_sort); if (column_active(colopts)) stop_column_filter(); return ret; @@ -701,14 +730,17 @@ int cmd_tag(int argc, const char **argv, const char *prefix) if (annotate) create_tag(object, tag, &buf, &opt, prev, object); - lock = lock_any_ref_for_update(ref.buf, prev, 0, NULL); - if (!lock) - die(_("%s: cannot lock the ref"), ref.buf); - if (write_ref_sha1(lock, object, NULL) < 0) - die(_("%s: cannot update the ref"), ref.buf); + transaction = ref_transaction_begin(&err); + if (!transaction || + ref_transaction_update(transaction, ref.buf, object, prev, + 0, 1, &err) || + ref_transaction_commit(transaction, NULL, &err)) + die("%s", err.buf); + ref_transaction_free(transaction); if (force && !is_null_sha1(prev) && hashcmp(prev, object)) printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev, DEFAULT_ABBREV)); + strbuf_release(&err); strbuf_release(&buf); strbuf_release(&ref); return 0; diff --git a/builtin/update-index.c b/builtin/update-index.c index ebea285e1b..e8c7fd4d49 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -13,6 +13,7 @@ #include "parse-options.h" #include "pathspec.h" #include "dir.h" +#include "split-index.h" /* * Default to not allowing changes to the list of files. The @@ -55,8 +56,9 @@ static int mark_ce_flags(const char *path, int flag, int mark) active_cache[pos]->ce_flags |= flag; else active_cache[pos]->ce_flags &= ~flag; - cache_tree_invalidate_path(active_cache_tree, path); - active_cache_changed = 1; + active_cache[pos]->ce_flags |= CE_UPDATE_IN_BASE; + cache_tree_invalidate_path(&the_index, path); + active_cache_changed |= CE_ENTRY_CHANGED; return 0; } return -1; @@ -267,8 +269,9 @@ static void chmod_path(int flip, const char *path) default: goto fail; } - cache_tree_invalidate_path(active_cache_tree, path); - active_cache_changed = 1; + cache_tree_invalidate_path(&the_index, path); + ce->ce_flags |= CE_UPDATE_IN_BASE; + active_cache_changed |= CE_ENTRY_CHANGED; report("chmod %cx '%s'", flip, path); return; fail: @@ -743,6 +746,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) char set_executable_bit = 0; struct refresh_params refresh_args = {0, &has_errors}; int lock_error = 0; + int split_index = -1; struct lock_file *lock_file; struct parse_opt_ctx_t ctx; int parseopt_state = PARSE_OPT_UNKNOWN; @@ -825,6 +829,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) resolve_undo_clear_callback}, OPT_INTEGER(0, "index-version", &preferred_index_format, N_("write index in this format")), + OPT_BOOL(0, "split-index", &split_index, + N_("enable or disable split index")), OPT_END() }; @@ -892,7 +898,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) INDEX_FORMAT_LB, INDEX_FORMAT_UB); if (the_index.version != preferred_index_format) - active_cache_changed = 1; + active_cache_changed |= SOMETHING_CHANGED; the_index.version = preferred_index_format; } @@ -918,14 +924,27 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) strbuf_release(&buf); } + if (split_index > 0) { + init_split_index(&the_index); + the_index.cache_changed |= SPLIT_INDEX_ORDERED; + } else if (!split_index && the_index.split_index) { + /* + * can't discard_split_index(&the_index); because that + * will destroy split_index->base->cache[], which may + * be shared with the_index.cache[]. So yeah we're + * leaking a bit here. + */ + the_index.split_index = NULL; + the_index.cache_changed |= SOMETHING_CHANGED; + } + if (active_cache_changed) { if (newfd < 0) { if (refresh_args.flags & REFRESH_QUIET) exit(128); unable_to_lock_index_die(get_index_file(), lock_error); } - if (write_cache(newfd, active_cache, active_nr) || - commit_locked_index(lock_file)) + if (write_locked_index(&the_index, lock_file, COMMIT_LOCK)) die("Unable to write new index file"); } diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 405267f6e2..54a48c0cfa 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -12,8 +12,6 @@ static const char * const git_update_ref_usage[] = { NULL }; -static struct ref_transaction *transaction; - static char line_termination = '\n'; static int update_flags; @@ -176,8 +174,10 @@ static int parse_next_sha1(struct strbuf *input, const char **next, * depending on how line_termination is set. */ -static const char *parse_cmd_update(struct strbuf *input, const char *next) +static const char *parse_cmd_update(struct ref_transaction *transaction, + struct strbuf *input, const char *next) { + struct strbuf err = STRBUF_INIT; char *refname; unsigned char new_sha1[20]; unsigned char old_sha1[20]; @@ -197,17 +197,21 @@ static const char *parse_cmd_update(struct strbuf *input, const char *next) if (*next != line_termination) die("update %s: extra input: %s", refname, next); - ref_transaction_update(transaction, refname, new_sha1, old_sha1, - update_flags, have_old); + if (ref_transaction_update(transaction, refname, new_sha1, old_sha1, + update_flags, have_old, &err)) + die("%s", err.buf); update_flags = 0; free(refname); + strbuf_release(&err); return next; } -static const char *parse_cmd_create(struct strbuf *input, const char *next) +static const char *parse_cmd_create(struct ref_transaction *transaction, + struct strbuf *input, const char *next) { + struct strbuf err = STRBUF_INIT; char *refname; unsigned char new_sha1[20]; @@ -224,16 +228,21 @@ static const char *parse_cmd_create(struct strbuf *input, const char *next) if (*next != line_termination) die("create %s: extra input: %s", refname, next); - ref_transaction_create(transaction, refname, new_sha1, update_flags); + if (ref_transaction_create(transaction, refname, new_sha1, + update_flags, &err)) + die("%s", err.buf); update_flags = 0; free(refname); + strbuf_release(&err); return next; } -static const char *parse_cmd_delete(struct strbuf *input, const char *next) +static const char *parse_cmd_delete(struct ref_transaction *transaction, + struct strbuf *input, const char *next) { + struct strbuf err = STRBUF_INIT; char *refname; unsigned char old_sha1[20]; int have_old; @@ -254,17 +263,21 @@ static const char *parse_cmd_delete(struct strbuf *input, const char *next) if (*next != line_termination) die("delete %s: extra input: %s", refname, next); - ref_transaction_delete(transaction, refname, old_sha1, - update_flags, have_old); + if (ref_transaction_delete(transaction, refname, old_sha1, + update_flags, have_old, &err)) + die("%s", err.buf); update_flags = 0; free(refname); + strbuf_release(&err); return next; } -static const char *parse_cmd_verify(struct strbuf *input, const char *next) +static const char *parse_cmd_verify(struct ref_transaction *transaction, + struct strbuf *input, const char *next) { + struct strbuf err = STRBUF_INIT; char *refname; unsigned char new_sha1[20]; unsigned char old_sha1[20]; @@ -286,11 +299,13 @@ static const char *parse_cmd_verify(struct strbuf *input, const char *next) if (*next != line_termination) die("verify %s: extra input: %s", refname, next); - ref_transaction_update(transaction, refname, new_sha1, old_sha1, - update_flags, have_old); + if (ref_transaction_update(transaction, refname, new_sha1, old_sha1, + update_flags, have_old, &err)) + die("%s", err.buf); update_flags = 0; free(refname); + strbuf_release(&err); return next; } @@ -304,7 +319,7 @@ static const char *parse_cmd_option(struct strbuf *input, const char *next) return next + 8; } -static void update_refs_stdin(void) +static void update_refs_stdin(struct ref_transaction *transaction) { struct strbuf input = STRBUF_INIT; const char *next; @@ -319,13 +334,13 @@ static void update_refs_stdin(void) else if (isspace(*next)) die("whitespace before command: %s", next); else if (starts_with(next, "update ")) - next = parse_cmd_update(&input, next + 7); + next = parse_cmd_update(transaction, &input, next + 7); else if (starts_with(next, "create ")) - next = parse_cmd_create(&input, next + 7); + next = parse_cmd_create(transaction, &input, next + 7); else if (starts_with(next, "delete ")) - next = parse_cmd_delete(&input, next + 7); + next = parse_cmd_delete(transaction, &input, next + 7); else if (starts_with(next, "verify ")) - next = parse_cmd_verify(&input, next + 7); + next = parse_cmd_verify(transaction, &input, next + 7); else if (starts_with(next, "option ")) next = parse_cmd_option(&input, next + 7); else @@ -359,17 +374,22 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix) die("Refusing to perform update with empty message."); if (read_stdin) { - int ret; - transaction = ref_transaction_begin(); + struct strbuf err = STRBUF_INIT; + struct ref_transaction *transaction; + transaction = ref_transaction_begin(&err); + if (!transaction) + die("%s", err.buf); if (delete || no_deref || argc > 0) usage_with_options(git_update_ref_usage, options); if (end_null) line_termination = '\0'; - update_refs_stdin(); - ret = ref_transaction_commit(transaction, msg, - UPDATE_REFS_DIE_ON_ERR); - return ret; + update_refs_stdin(transaction); + if (ref_transaction_commit(transaction, msg, &err)) + die("%s", err.buf); + ref_transaction_free(transaction); + strbuf_release(&err); + return 0; } if (end_null) diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c new file mode 100644 index 0000000000..b0f85042b2 --- /dev/null +++ b/builtin/verify-commit.c @@ -0,0 +1,93 @@ +/* + * Builtin "git commit-commit" + * + * Copyright (c) 2014 Michael J Gruber + * + * Based on git-verify-tag + */ +#include "cache.h" +#include "builtin.h" +#include "commit.h" +#include "run-command.h" +#include +#include "parse-options.h" +#include "gpg-interface.h" + +static const char * const verify_commit_usage[] = { + N_("git verify-commit [-v|--verbose] ..."), + NULL +}; + +static int run_gpg_verify(const unsigned char *sha1, const char *buf, unsigned long size, int verbose) +{ + struct signature_check signature_check; + + memset(&signature_check, 0, sizeof(signature_check)); + + check_commit_signature(lookup_commit(sha1), &signature_check); + + if (verbose && signature_check.payload) + fputs(signature_check.payload, stdout); + + if (signature_check.gpg_output) + fputs(signature_check.gpg_output, stderr); + + signature_check_clear(&signature_check); + return signature_check.result != 'G'; +} + +static int verify_commit(const char *name, int verbose) +{ + enum object_type type; + unsigned char sha1[20]; + char *buf; + unsigned long size; + int ret; + + if (get_sha1(name, sha1)) + return error("commit '%s' not found.", name); + + buf = read_sha1_file(sha1, &type, &size); + if (!buf) + return error("%s: unable to read file.", name); + if (type != OBJ_COMMIT) + return error("%s: cannot verify a non-commit object of type %s.", + name, typename(type)); + + ret = run_gpg_verify(sha1, buf, size, verbose); + + free(buf); + return ret; +} + +static int git_verify_commit_config(const char *var, const char *value, void *cb) +{ + int status = git_gpg_config(var, value, cb); + if (status) + return status; + return git_default_config(var, value, cb); +} + +int cmd_verify_commit(int argc, const char **argv, const char *prefix) +{ + int i = 1, verbose = 0, had_error = 0; + const struct option verify_commit_options[] = { + OPT__VERBOSE(&verbose, N_("print commit contents")), + OPT_END() + }; + + git_config(git_verify_commit_config, NULL); + + argc = parse_options(argc, argv, prefix, verify_commit_options, + verify_commit_usage, PARSE_OPT_KEEP_ARGV0); + if (argc <= i) + usage_with_options(verify_commit_usage, verify_commit_options); + + /* sometimes the program was terminated because this signal + * was received in the process of writing the gpg input: */ + signal(SIGPIPE, SIG_IGN); + while (i < argc) + if (verify_commit(argv[i++], verbose)) + had_error = 1; + return had_error; +} diff --git a/builtin/verify-pack.c b/builtin/verify-pack.c index 66cd2df0f8..7747537beb 100644 --- a/builtin/verify-pack.c +++ b/builtin/verify-pack.c @@ -8,7 +8,7 @@ static int verify_one_pack(const char *path, unsigned int flags) { - struct child_process index_pack; + struct child_process index_pack = CHILD_PROCESS_INIT; const char *argv[] = {"index-pack", NULL, NULL, NULL }; struct strbuf arg = STRBUF_INIT; int verbose = flags & VERIFY_PACK_VERBOSE; @@ -27,13 +27,11 @@ static int verify_one_pack(const char *path, unsigned int flags) * normalize these forms to "foo.pack" for "index-pack --verify". */ strbuf_addstr(&arg, path); - if (has_extension(arg.buf, ".idx")) - strbuf_splice(&arg, arg.len - 3, 3, "pack", 4); - else if (!has_extension(arg.buf, ".pack")) - strbuf_add(&arg, ".pack", 5); + if (strbuf_strip_suffix(&arg, ".idx") || + !ends_with(arg.buf, ".pack")) + strbuf_addstr(&arg, ".pack"); argv[2] = arg.buf; - memset(&index_pack, 0, sizeof(index_pack)); index_pack.argv = argv; index_pack.git_cmd = 1; diff --git a/bundle.c b/bundle.c index 1222952075..b2b89fe862 100644 --- a/bundle.c +++ b/bundle.c @@ -221,8 +221,8 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs) line = memmem(buf, size, "\ntagger ", 8); if (!line++) return 1; - lineend = memchr(line, buf + size - line, '\n'); - line = memchr(line, lineend ? lineend - line : buf + size - line, '>'); + lineend = memchr(line, '\n', buf + size - line); + line = memchr(line, '>', lineend ? lineend - line : buf + size - line); if (!line++) return 1; date = strtoul(line, NULL, 10); @@ -237,12 +237,10 @@ int create_bundle(struct bundle_header *header, const char *path, static struct lock_file lock; int bundle_fd = -1; int bundle_to_stdout; - struct argv_array argv_boundary = ARGV_ARRAY_INIT; - struct argv_array argv_pack = ARGV_ARRAY_INIT; int i, ref_count = 0; struct strbuf buf = STRBUF_INIT; struct rev_info revs; - struct child_process rls; + struct child_process rls = CHILD_PROCESS_INIT; FILE *rls_fout; bundle_to_stdout = !strcmp(path, "-"); @@ -260,14 +258,11 @@ int create_bundle(struct bundle_header *header, const char *path, init_revisions(&revs, NULL); /* write prerequisites */ - argv_array_pushl(&argv_boundary, + argv_array_pushl(&rls.args, "rev-list", "--boundary", "--pretty=oneline", NULL); for (i = 1; i < argc; i++) - argv_array_push(&argv_boundary, argv[i]); - - memset(&rls, 0, sizeof(rls)); - rls.argv = argv_boundary.argv; + argv_array_push(&rls.args, argv[i]); rls.out = -1; rls.git_cmd = 1; if (start_command(&rls)) @@ -382,12 +377,11 @@ int create_bundle(struct bundle_header *header, const char *path, write_or_die(bundle_fd, "\n", 1); /* write pack */ - argv_array_pushl(&argv_pack, + memset(&rls, 0, sizeof(rls)); + argv_array_pushl(&rls.args, "pack-objects", "--all-progress-implied", "--stdout", "--thin", "--delta-base-offset", NULL); - memset(&rls, 0, sizeof(rls)); - rls.argv = argv_pack.argv; rls.in = -1; rls.out = bundle_fd; rls.git_cmd = 1; @@ -422,14 +416,13 @@ int unbundle(struct bundle_header *header, int bundle_fd, int flags) { const char *argv_index_pack[] = {"index-pack", "--fix-thin", "--stdin", NULL, NULL}; - struct child_process ip; + struct child_process ip = CHILD_PROCESS_INIT; if (flags & BUNDLE_VERBOSE) argv_index_pack[3] = "-v"; if (verify_bundle(header, 0)) return -1; - memset(&ip, 0, sizeof(ip)); ip.argv = argv_index_pack; ip.in = bundle_fd; ip.no_stdout = 1; diff --git a/cache-tree.c b/cache-tree.c index 7fa524a113..75a54fdc72 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -98,7 +98,7 @@ struct cache_tree_sub *cache_tree_sub(struct cache_tree *it, const char *path) return find_subtree(it, path, pathlen, 1); } -void cache_tree_invalidate_path(struct cache_tree *it, const char *path) +static int do_invalidate_path(struct cache_tree *it, const char *path) { /* a/b/c * ==> invalidate self @@ -116,7 +116,7 @@ void cache_tree_invalidate_path(struct cache_tree *it, const char *path) #endif if (!it) - return; + return 0; slash = strchrnul(path, '/'); namelen = slash - path; it->entry_count = -1; @@ -137,14 +137,21 @@ void cache_tree_invalidate_path(struct cache_tree *it, const char *path) (it->subtree_nr - pos - 1)); it->subtree_nr--; } - return; + return 1; } down = find_subtree(it, path, namelen, 0); if (down) - cache_tree_invalidate_path(down->cache_tree, slash + 1); + do_invalidate_path(down->cache_tree, slash + 1); + return 1; +} + +void cache_tree_invalidate_path(struct index_state *istate, const char *path) +{ + if (do_invalidate_path(istate->cache_tree, path)) + istate->cache_changed |= CACHE_TREE_CHANGED; } -static int verify_cache(const struct cache_entry * const *cache, +static int verify_cache(struct cache_entry **cache, int entries, int flags) { int i, funny; @@ -229,7 +236,7 @@ int cache_tree_fully_valid(struct cache_tree *it) } static int update_one(struct cache_tree *it, - const struct cache_entry * const *cache, + struct cache_entry **cache, int entries, const char *base, int baselen, @@ -239,9 +246,12 @@ static int update_one(struct cache_tree *it, struct strbuf buffer; int missing_ok = flags & WRITE_TREE_MISSING_OK; int dryrun = flags & WRITE_TREE_DRY_RUN; + int repair = flags & WRITE_TREE_REPAIR; int to_invalidate = 0; int i; + assert(!(dryrun && repair)); + *skip_count = 0; if (0 <= it->entry_count && has_sha1_file(it->sha1)) @@ -313,6 +323,7 @@ static int update_one(struct cache_tree *it, int pathlen, entlen; const unsigned char *sha1; unsigned mode; + int expected_missing = 0; path = ce->name; pathlen = ce_namelen(ce); @@ -329,8 +340,10 @@ static int update_one(struct cache_tree *it, i += sub->count; sha1 = sub->cache_tree->sha1; mode = S_IFDIR; - if (sub->cache_tree->entry_count < 0) + if (sub->cache_tree->entry_count < 0) { to_invalidate = 1; + expected_missing = 1; + } } else { sha1 = ce->sha1; @@ -340,6 +353,8 @@ static int update_one(struct cache_tree *it, } if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) { strbuf_release(&buffer); + if (expected_missing) + return -1; return error("invalid object %06o %s for '%.*s'", mode, sha1_to_hex(sha1), entlen+baselen, path); } @@ -374,7 +389,14 @@ static int update_one(struct cache_tree *it, #endif } - if (dryrun) + if (repair) { + unsigned char sha1[20]; + hash_sha1_file(buffer.buf, buffer.len, tree_type, sha1); + if (has_sha1_file(sha1)) + hashcpy(it->sha1, sha1); + else + to_invalidate = 1; + } else if (dryrun) hash_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1); else if (write_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1)) { strbuf_release(&buffer); @@ -391,18 +413,19 @@ static int update_one(struct cache_tree *it, return i; } -int cache_tree_update(struct cache_tree *it, - const struct cache_entry * const *cache, - int entries, - int flags) +int cache_tree_update(struct index_state *istate, int flags) { - int i, skip; - i = verify_cache(cache, entries, flags); + struct cache_tree *it = istate->cache_tree; + struct cache_entry **cache = istate->cache; + int entries = istate->cache_nr; + int skip, i = verify_cache(cache, entries, flags); + if (i) return i; i = update_one(it, cache, entries, "", 0, &skip, flags); if (i < 0) return i; + istate->cache_changed |= CACHE_TREE_CHANGED; return 0; } @@ -590,13 +613,10 @@ int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix) was_valid = cache_tree_fully_valid(active_cache_tree); if (!was_valid) { - if (cache_tree_update(active_cache_tree, - (const struct cache_entry * const *)active_cache, - active_nr, flags) < 0) + if (cache_tree_update(&the_index, flags) < 0) return WRITE_TREE_UNMERGED_INDEX; if (0 <= newfd) { - if (!write_cache(newfd, active_cache, active_nr) && - !commit_lock_file(lock_file)) + if (!write_locked_index(&the_index, lock_file, COMMIT_LOCK)) newfd = -1; } /* Not being able to write is fine -- we are only interested @@ -649,11 +669,12 @@ static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree) it->entry_count = cnt; } -void prime_cache_tree(struct cache_tree **it, struct tree *tree) +void prime_cache_tree(struct index_state *istate, struct tree *tree) { - cache_tree_free(it); - *it = cache_tree(); - prime_cache_tree_rec(*it, tree); + cache_tree_free(&istate->cache_tree); + istate->cache_tree = cache_tree(); + prime_cache_tree_rec(istate->cache_tree, tree); + istate->cache_changed |= CACHE_TREE_CHANGED; } /* @@ -692,7 +713,5 @@ int update_main_cache_tree(int flags) { if (!the_index.cache_tree) the_index.cache_tree = cache_tree(); - return cache_tree_update(the_index.cache_tree, - (const struct cache_entry * const *)the_index.cache, - the_index.cache_nr, flags); + return cache_tree_update(&the_index, flags); } diff --git a/cache-tree.h b/cache-tree.h index f1923ad1e9..aa7b3e4a0a 100644 --- a/cache-tree.h +++ b/cache-tree.h @@ -23,14 +23,14 @@ struct cache_tree { struct cache_tree *cache_tree(void); void cache_tree_free(struct cache_tree **); -void cache_tree_invalidate_path(struct cache_tree *, const char *); +void cache_tree_invalidate_path(struct index_state *, const char *); struct cache_tree_sub *cache_tree_sub(struct cache_tree *, const char *); void cache_tree_write(struct strbuf *, struct cache_tree *root); struct cache_tree *cache_tree_read(const char *buffer, unsigned long size); int cache_tree_fully_valid(struct cache_tree *); -int cache_tree_update(struct cache_tree *, const struct cache_entry * const *, int, int); +int cache_tree_update(struct index_state *, int); int update_main_cache_tree(int); @@ -39,6 +39,7 @@ int update_main_cache_tree(int); #define WRITE_TREE_IGNORE_CACHE_TREE 2 #define WRITE_TREE_DRY_RUN 4 #define WRITE_TREE_SILENT 8 +#define WRITE_TREE_REPAIR 16 /* error return codes */ #define WRITE_TREE_UNREADABLE_INDEX (-1) @@ -46,7 +47,7 @@ int update_main_cache_tree(int); #define WRITE_TREE_PREFIX_ERROR (-3) int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix); -void prime_cache_tree(struct cache_tree **, struct tree *); +void prime_cache_tree(struct index_state *, struct tree *); extern int cache_tree_matches_traversal(struct cache_tree *, struct name_entry *ent, struct traverse_info *info); diff --git a/cache.h b/cache.h index df65231ac3..db4ccd1cf7 100644 --- a/cache.h +++ b/cache.h @@ -7,6 +7,8 @@ #include "advice.h" #include "gettext.h" #include "convert.h" +#include "trace.h" +#include "string-list.h" #include SHA1_HEADER #ifndef git_SHA_CTX @@ -150,6 +152,7 @@ struct cache_entry { unsigned int ce_mode; unsigned int ce_flags; unsigned int ce_namelen; + unsigned int index; /* for link extension */ unsigned char sha1[20]; char name[FLEX_ARRAY]; /* more */ }; @@ -160,7 +163,7 @@ struct cache_entry { #define CE_STAGESHIFT 12 /* - * Range 0xFFFF0000 in ce_flags is divided into + * Range 0xFFFF0FFF in ce_flags is divided into * two parts: in-memory flags and on-disk ones. * Flags in CE_EXTENDED_FLAGS will get saved on-disk * if you want to save a new flag, add it in @@ -183,6 +186,9 @@ struct cache_entry { /* used to temporarily mark paths matched by pathspecs */ #define CE_MATCHED (1 << 26) +#define CE_UPDATE_IN_BASE (1 << 27) +#define CE_STRIP_NAME (1 << 28) + /* * Extended on-disk flags */ @@ -283,12 +289,22 @@ static inline unsigned int canon_mode(unsigned int mode) #define cache_entry_size(len) (offsetof(struct cache_entry,name) + (len) + 1) +#define SOMETHING_CHANGED (1 << 0) /* unclassified changes go here */ +#define CE_ENTRY_CHANGED (1 << 1) +#define CE_ENTRY_REMOVED (1 << 2) +#define CE_ENTRY_ADDED (1 << 3) +#define RESOLVE_UNDO_CHANGED (1 << 4) +#define CACHE_TREE_CHANGED (1 << 5) +#define SPLIT_INDEX_ORDERED (1 << 6) + +struct split_index; struct index_state { struct cache_entry **cache; unsigned int version; unsigned int cache_nr, cache_alloc, cache_changed; struct string_list *resolve_undo; struct cache_tree *cache_tree; + struct split_index *split_index; struct cache_time timestamp; unsigned name_hash_initialized : 1, initialized : 1; @@ -317,7 +333,6 @@ extern void free_name_hash(struct index_state *istate); #define read_cache_preload(pathspec) read_index_preload(&the_index, (pathspec)) #define is_cache_unborn() is_index_unborn(&the_index) #define read_cache_unmerged() read_index_unmerged(&the_index) -#define write_cache(newfd, cache, entries) write_index(&the_index, (newfd)) #define discard_cache() discard_index(&the_index) #define unmerged_cache() unmerged_index(&the_index) #define cache_name_pos(name, namelen) index_name_pos(&the_index,(name),(namelen)) @@ -472,12 +487,17 @@ extern int daemonize(void); } while (0) /* Initialize and use the cache information */ +struct lock_file; extern int read_index(struct index_state *); extern int read_index_preload(struct index_state *, const struct pathspec *pathspec); +extern int do_read_index(struct index_state *istate, const char *path, + int must_exist); /* for testting only! */ extern int read_index_from(struct index_state *, const char *path); extern int is_index_unborn(struct index_state *); extern int read_index_unmerged(struct index_state *); -extern int write_index(struct index_state *, int newfd); +#define COMMIT_LOCK (1 << 0) +#define CLOSE_LOCK (1 << 1) +extern int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags); extern int discard_index(struct index_state *); extern int unmerged_index(const struct index_state *); extern int verify_path(const char *path); @@ -489,6 +509,7 @@ extern int index_name_pos(const struct index_state *, const char *name, int name #define ADD_CACHE_SKIP_DFCHECK 4 /* Ok to skip DF conflict checks */ #define ADD_CACHE_JUST_APPEND 8 /* Append only; tree.c::read_tree() */ #define ADD_CACHE_NEW_ONLY 16 /* Do not replace existing ones */ +#define ADD_CACHE_KEEP_CACHE_TREE 32 /* Do not invalidate cache-tree */ extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option); extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name); extern int remove_index_entry_at(struct index_state *, int pos); @@ -559,14 +580,16 @@ struct lock_file { #define LOCK_DIE_ON_ERROR 1 #define LOCK_NODEREF 2 extern int unable_to_lock_error(const char *path, int err); +extern void unable_to_lock_message(const char *path, int err, + struct strbuf *buf); extern NORETURN void unable_to_lock_index_die(const char *path, int err); extern int hold_lock_file_for_update(struct lock_file *, const char *path, int); extern int hold_lock_file_for_append(struct lock_file *, const char *path, int); extern int commit_lock_file(struct lock_file *); +extern int reopen_lock_file(struct lock_file *); extern void update_index_if_able(struct index_state *, struct lock_file *); extern int hold_locked_index(struct lock_file *, int); -extern int commit_locked_index(struct lock_file *); extern void set_alternate_index_output(const char *); extern int close_lock_file(struct lock_file *); extern void rollback_lock_file(struct lock_file *); @@ -977,7 +1000,7 @@ extern int read_ref(const char *refname, unsigned char *sha1); * NULL. If more than MAXDEPTH recursive symbolic lookups are needed, * give up and return NULL. * - * errno is sometimes set on errors, but not always. + * errno is set to something meaningful on error. */ extern const char *resolve_ref_unsafe(const char *ref, unsigned char *sha1, int reading, int *flag); extern char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag); @@ -1016,6 +1039,7 @@ enum date_mode { DATE_SHORT, DATE_LOCAL, DATE_ISO8601, + DATE_ISO8601_STRICT, DATE_RFC2822, DATE_RAW }; @@ -1023,10 +1047,10 @@ enum date_mode { const char *show_date(unsigned long time, int timezone, enum date_mode mode); void show_date_relative(unsigned long time, int tz, const struct timeval *now, struct strbuf *timebuf); -int parse_date(const char *date, char *buf, int bufsize); +int parse_date(const char *date, struct strbuf *out); int parse_date_basic(const char *date, unsigned long *timestamp, int *offset); int parse_expiry_date(const char *date, unsigned long *timestamp); -void datestamp(char *buf, int bufsize); +void datestamp(struct strbuf *out); #define approxidate(s) approxidate_careful((s), NULL) unsigned long approxidate_careful(const char *, int *); unsigned long approxidate_relative(const char *date, const struct timeval *now); @@ -1040,6 +1064,7 @@ extern const char *git_author_info(int); extern const char *git_committer_info(int); extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int); extern const char *fmt_name(const char *name, const char *email); +extern const char *ident_default_name(void); extern const char *ident_default_email(void); extern const char *git_editor(void); extern const char *git_pager(int stdout_is_tty); @@ -1078,6 +1103,7 @@ const char *show_ident_date(const struct ident_split *id, enum date_mode mode); extern int ident_cmp(const struct ident_split *, const struct ident_split *); struct checkout { + struct index_state *istate; const char *base_dir; int base_dir_len; unsigned force:1, @@ -1090,12 +1116,16 @@ struct checkout { extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath); struct cache_def { - char path[PATH_MAX + 1]; - int len; + struct strbuf path; int flags; int track_flags; int prefix_len_stat_func; }; +#define CACHE_DEF_INIT { STRBUF_INIT, 0, 0, 0 } +static inline void cache_def_clear(struct cache_def *cache) +{ + strbuf_release(&cache->path); +} extern int has_symlink_leading_path(const char *name, int len); extern int threaded_has_symlink_leading_path(struct cache_def *, const char *, int); @@ -1268,7 +1298,7 @@ extern int git_config_from_buf(config_fn_t fn, const char *name, const char *buf, size_t len, void *data); extern void git_config_push_parameter(const char *text); extern int git_config_from_parameters(config_fn_t fn, void *data); -extern int git_config(config_fn_t fn, void *); +extern void git_config(config_fn_t fn, void *); extern int git_config_with_options(config_fn_t fn, void *, struct git_config_source *config_source, int respect_includes); @@ -1325,6 +1355,69 @@ extern int parse_config_key(const char *var, const char **subsection, int *subsection_len, const char **key); +struct config_set_element { + struct hashmap_entry ent; + char *key; + struct string_list value_list; +}; + +struct configset_list_item { + struct config_set_element *e; + int value_index; +}; + +/* + * the contents of the list are ordered according to their + * position in the config files and order of parsing the files. + * (i.e. key-value pair at the last position of .git/config will + * be at the last item of the list) + */ +struct configset_list { + struct configset_list_item *items; + unsigned int nr, alloc; +}; + +struct config_set { + struct hashmap config_hash; + int hash_initialized; + struct configset_list list; +}; + +extern void git_configset_init(struct config_set *cs); +extern int git_configset_add_file(struct config_set *cs, const char *filename); +extern int git_configset_get_value(struct config_set *cs, const char *key, const char **value); +extern const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key); +extern void git_configset_clear(struct config_set *cs); +extern int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest); +extern int git_configset_get_string(struct config_set *cs, const char *key, char **dest); +extern int git_configset_get_int(struct config_set *cs, const char *key, int *dest); +extern int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest); +extern int git_configset_get_bool(struct config_set *cs, const char *key, int *dest); +extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *is_bool, int *dest); +extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest); +extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest); + +extern int git_config_get_value(const char *key, const char **value); +extern const struct string_list *git_config_get_value_multi(const char *key); +extern void git_config_clear(void); +extern void git_config_iter(config_fn_t fn, void *data); +extern int git_config_get_string_const(const char *key, const char **dest); +extern int git_config_get_string(const char *key, char **dest); +extern int git_config_get_int(const char *key, int *dest); +extern int git_config_get_ulong(const char *key, unsigned long *dest); +extern int git_config_get_bool(const char *key, int *dest); +extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest); +extern int git_config_get_maybe_bool(const char *key, int *dest); +extern int git_config_get_pathname(const char *key, const char **dest); + +struct key_value_info { + const char *filename; + int linenr; +}; + +extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3))); +extern NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr); + extern int committer_ident_sufficiently_given(void); extern int author_ident_sufficiently_given(void); @@ -1376,18 +1469,9 @@ extern void *alloc_commit_node(void); extern void *alloc_tag_node(void); extern void *alloc_object_node(void); extern void alloc_report(void); +extern unsigned int alloc_commit_index(void); -/* trace.c */ -__attribute__((format (printf, 1, 2))) -extern void trace_printf(const char *format, ...); -__attribute__((format (printf, 2, 3))) -extern void trace_argv_printf(const char **argv, const char *format, ...); -extern void trace_repo_setup(const char *prefix); -extern int trace_want(const char *key); -__attribute__((format (printf, 2, 3))) -extern void trace_printf_key(const char *key, const char *fmt, ...); -extern void trace_strbuf(const char *key, const struct strbuf *buf); - +/* pkt-line.c */ void packet_trace_identity(const char *prog); /* add */ diff --git a/column.c b/column.c index 1a468debb4..76b615db5f 100644 --- a/column.c +++ b/column.c @@ -336,8 +336,9 @@ static int column_config(const char *var, const char *value, int git_column_config(const char *var, const char *value, const char *command, unsigned int *colopts) { - const char *it = skip_prefix(var, "column."); - if (!it) + const char *it; + + if (!skip_prefix(var, "column.", &it)) return 0; if (!strcmp(it, "ui")) @@ -366,7 +367,7 @@ int parseopt_column_callback(const struct option *opt, } static int fd_out = -1; -static struct child_process column_process; +static struct child_process column_process = CHILD_PROCESS_INIT; int run_column_filter(int colopts, const struct column_options *opts) { diff --git a/combine-diff.c b/combine-diff.c index f9975d2c2e..91edce58e1 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -12,6 +12,16 @@ #include "sha1-array.h" #include "revision.h" +static int compare_paths(const struct combine_diff_path *one, + const struct diff_filespec *two) +{ + if (!S_ISDIR(one->mode) && !S_ISDIR(two->mode)) + return strcmp(one->path, two->path); + + return base_name_compare(one->path, strlen(one->path), one->mode, + two->path, strlen(two->path), two->mode); +} + static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent) { struct diff_queue_struct *q = &diff_queued_diff; @@ -52,7 +62,7 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, i = 0; while ((p = *tail) != NULL) { cmp = ((i >= q->nr) - ? -1 : strcmp(p->path, q->queue[i]->two->path)); + ? -1 : compare_paths(p, q->queue[i]->two)); if (cmp < 0) { /* p->path not in q->queue[]; drop it */ @@ -1397,7 +1407,8 @@ void diff_tree_combined(const unsigned char *sha1, show_log(rev); if (rev->verbose_header && opt->output_format && - opt->output_format != DIFF_FORMAT_NO_OUTPUT) + opt->output_format != DIFF_FORMAT_NO_OUTPUT && + !commit_format_is_empty(rev->commit_format)) printf("%s%c", diff_line_prefix(opt), opt->line_termination); } diff --git a/command-list.txt b/command-list.txt index cf36c3d71e..a3ff0c9e60 100644 --- a/command-list.txt +++ b/command-list.txt @@ -132,6 +132,7 @@ git-update-server-info synchingrepositories git-upload-archive synchelpers git-upload-pack synchelpers git-var plumbinginterrogators +git-verify-commit ancillaryinterrogators git-verify-pack plumbinginterrogators git-verify-tag ancillaryinterrogators gitweb ancillaryinterrogators diff --git a/commit-slab.h b/commit-slab.h index cc114b53b0..375c9c751a 100644 --- a/commit-slab.h +++ b/commit-slab.h @@ -117,4 +117,16 @@ static int stat_ ##slabname## realloc * catch because GCC silently parses it by default. */ +/* + * Statically initialize a commit slab named "var". Note that this + * evaluates "stride" multiple times! Example: + * + * struct indegree indegrees = COMMIT_SLAB_INIT(1, indegrees); + * + */ +#define COMMIT_SLAB_INIT(stride, var) { \ + COMMIT_SLAB_SIZE / sizeof(**((var).slab)) / (stride), \ + (stride), 0, NULL \ +} + #endif /* COMMIT_SLAB_H */ diff --git a/commit.c b/commit.c index 881be3baa3..9c4439fed6 100644 --- a/commit.c +++ b/commit.c @@ -17,20 +17,6 @@ static struct commit_extra_header *read_commit_extra_header_lines(const char *bu int save_commit_buffer = 1; const char *commit_type = "commit"; -static int commit_count; - -static struct commit *check_commit(struct object *obj, - const unsigned char *sha1, - int quiet) -{ - if (obj->type != OBJ_COMMIT) { - if (!quiet) - error("Object %s is a %s, not a commit", - sha1_to_hex(sha1), typename(obj->type)); - return NULL; - } - return (struct commit *) obj; -} struct commit *lookup_commit_reference_gently(const unsigned char *sha1, int quiet) @@ -39,7 +25,7 @@ struct commit *lookup_commit_reference_gently(const unsigned char *sha1, if (!obj) return NULL; - return check_commit(obj, sha1, quiet); + return object_as_type(obj, OBJ_COMMIT, quiet); } struct commit *lookup_commit_reference(const unsigned char *sha1) @@ -62,14 +48,9 @@ struct commit *lookup_commit_or_die(const unsigned char *sha1, const char *ref_n struct commit *lookup_commit(const unsigned char *sha1) { struct object *obj = lookup_object(sha1); - if (!obj) { - struct commit *c = alloc_commit_node(); - c->index = commit_count++; - return create_object(sha1, OBJ_COMMIT, c); - } - if (!obj->type) - obj->type = OBJ_COMMIT; - return check_commit(obj, sha1, 0); + if (!obj) + return create_object(sha1, alloc_commit_node()); + return object_as_type(obj, OBJ_COMMIT, 0); } struct commit *lookup_commit_reference_by_name(const char *name) @@ -247,6 +228,76 @@ int unregister_shallow(const unsigned char *sha1) return 0; } +struct commit_buffer { + void *buffer; + unsigned long size; +}; +define_commit_slab(buffer_slab, struct commit_buffer); +static struct buffer_slab buffer_slab = COMMIT_SLAB_INIT(1, buffer_slab); + +void set_commit_buffer(struct commit *commit, void *buffer, unsigned long size) +{ + struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); + v->buffer = buffer; + v->size = size; +} + +const void *get_cached_commit_buffer(const struct commit *commit, unsigned long *sizep) +{ + struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); + if (sizep) + *sizep = v->size; + return v->buffer; +} + +const void *get_commit_buffer(const struct commit *commit, unsigned long *sizep) +{ + const void *ret = get_cached_commit_buffer(commit, sizep); + if (!ret) { + enum object_type type; + unsigned long size; + ret = read_sha1_file(commit->object.sha1, &type, &size); + if (!ret) + die("cannot read commit object %s", + sha1_to_hex(commit->object.sha1)); + if (type != OBJ_COMMIT) + die("expected commit for %s, got %s", + sha1_to_hex(commit->object.sha1), typename(type)); + if (sizep) + *sizep = size; + } + return ret; +} + +void unuse_commit_buffer(const struct commit *commit, const void *buffer) +{ + struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); + if (v->buffer != buffer) + free((void *)buffer); +} + +void free_commit_buffer(struct commit *commit) +{ + struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); + free(v->buffer); + v->buffer = NULL; + v->size = 0; +} + +const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep) +{ + struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); + void *ret; + + ret = v->buffer; + if (sizep) + *sizep = v->size; + + v->buffer = NULL; + v->size = 0; + return ret; +} + int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size) { const char *tail = buffer; @@ -324,7 +375,7 @@ int parse_commit(struct commit *item) } ret = parse_commit_buffer(item, buffer, size); if (save_commit_buffer && !ret) { - item->buffer = buffer; + set_commit_buffer(item, buffer, size); return 0; } free(buffer); @@ -379,12 +430,7 @@ struct commit_list *copy_commit_list(struct commit_list *list) struct commit_list *head = NULL; struct commit_list **pp = &head; while (list) { - struct commit_list *new; - new = xmalloc(sizeof(struct commit_list)); - new->item = list->item; - new->next = NULL; - *pp = new; - pp = &new->next; + pp = commit_list_append(list->item, pp); list = list->next; } return head; @@ -538,36 +584,19 @@ define_commit_slab(author_date_slab, unsigned long); static void record_author_date(struct author_date_slab *author_date, struct commit *commit) { - const char *buf, *line_end, *ident_line; - char *buffer = NULL; + const char *buffer = get_commit_buffer(commit, NULL); struct ident_split ident; + const char *ident_line; + size_t ident_len; char *date_end; unsigned long date; - if (!commit->buffer) { - unsigned long size; - enum object_type type; - buffer = read_sha1_file(commit->object.sha1, &type, &size); - if (!buffer) - return; - } - - for (buf = commit->buffer ? commit->buffer : buffer; - buf; - buf = line_end + 1) { - line_end = strchrnul(buf, '\n'); - ident_line = skip_prefix(buf, "author "); - if (!ident_line) { - if (!line_end[0] || line_end[1] == '\n') - return; /* end of header */ - continue; - } - if (split_ident_line(&ident, - ident_line, line_end - ident_line) || - !ident.date_begin || !ident.date_end) - goto fail_exit; /* malformed "author" line */ - break; - } + ident_line = find_commit_header(buffer, "author", &ident_len); + if (!ident_line) + goto fail_exit; /* no author line */ + if (split_ident_line(&ident, ident_line, ident_len) || + !ident.date_begin || !ident.date_end) + goto fail_exit; /* malformed "author" line */ date = strtoul(ident.date_begin, &date_end, 10); if (date_end != ident.date_end) @@ -575,7 +604,7 @@ static void record_author_date(struct author_date_slab *author_date, *(author_date_slab_at(author_date, commit)) = date; fail_exit: - free(buffer); + unuse_commit_buffer(commit, buffer); } static int compare_commits_by_author_date(const void *a_, const void *b_, @@ -729,45 +758,41 @@ void sort_in_topological_order(struct commit_list **list, enum rev_sort_order so static const unsigned all_flags = (PARENT1 | PARENT2 | STALE | RESULT); -static struct commit *interesting(struct commit_list *list) +static int queue_has_nonstale(struct prio_queue *queue) { - while (list) { - struct commit *commit = list->item; - list = list->next; - if (commit->object.flags & STALE) - continue; - return commit; + int i; + for (i = 0; i < queue->nr; i++) { + struct commit *commit = queue->array[i].data; + if (!(commit->object.flags & STALE)) + return 1; } - return NULL; + return 0; } /* all input commits in one and twos[] must have been parsed! */ static struct commit_list *paint_down_to_common(struct commit *one, int n, struct commit **twos) { - struct commit_list *list = NULL; + struct prio_queue queue = { compare_commits_by_commit_date }; struct commit_list *result = NULL; int i; one->object.flags |= PARENT1; - commit_list_insert_by_date(one, &list); - if (!n) - return list; + if (!n) { + commit_list_append(one, &result); + return result; + } + prio_queue_put(&queue, one); + for (i = 0; i < n; i++) { twos[i]->object.flags |= PARENT2; - commit_list_insert_by_date(twos[i], &list); + prio_queue_put(&queue, twos[i]); } - while (interesting(list)) { - struct commit *commit; + while (queue_has_nonstale(&queue)) { + struct commit *commit = prio_queue_get(&queue); struct commit_list *parents; - struct commit_list *next; int flags; - commit = list->item; - next = list->next; - free(list); - list = next; - flags = commit->object.flags & (PARENT1 | PARENT2 | STALE); if (flags == (PARENT1 | PARENT2)) { if (!(commit->object.flags & RESULT)) { @@ -786,11 +811,11 @@ static struct commit_list *paint_down_to_common(struct commit *one, int n, struc if (parse_commit(p)) return NULL; p->object.flags |= flags; - commit_list_insert_by_date(p, &list); + prio_queue_put(&queue, p); } } - free_commit_list(list); + clear_prio_queue(&queue); return result; } @@ -935,12 +960,7 @@ struct commit_list *get_merge_bases_many(struct commit *one, } /* There are more than one */ - cnt = 0; - list = result; - while (list) { - list = list->next; - cnt++; - } + cnt = commit_list_count(result); rslt = xcalloc(cnt, sizeof(*rslt)); for (list = result, i = 0; list; list = list->next) rslt[i++] = list->item; @@ -1080,17 +1100,14 @@ static int do_sign_commit(struct strbuf *buf, const char *keyid) return 0; } -int parse_signed_commit(const unsigned char *sha1, +int parse_signed_commit(const struct commit *commit, struct strbuf *payload, struct strbuf *signature) { + unsigned long size; - enum object_type type; - char *buffer = read_sha1_file(sha1, &type, &size); + const char *buffer = get_commit_buffer(commit, &size); int in_signature, saw_signature = -1; - char *line, *tail; - - if (!buffer || type != OBJ_COMMIT) - goto cleanup; + const char *line, *tail; line = buffer; tail = buffer + size; @@ -1098,7 +1115,7 @@ int parse_signed_commit(const unsigned char *sha1, saw_signature = 0; while (line < tail) { const char *sig = NULL; - char *next = memchr(line, '\n', tail - line); + const char *next = memchr(line, '\n', tail - line); next = next ? next + 1 : tail; if (in_signature && line[0] == ' ') @@ -1119,11 +1136,44 @@ int parse_signed_commit(const unsigned char *sha1, } line = next; } - cleanup: - free(buffer); + unuse_commit_buffer(commit, buffer); return saw_signature; } +int remove_signature(struct strbuf *buf) +{ + const char *line = buf->buf; + const char *tail = buf->buf + buf->len; + int in_signature = 0; + const char *sig_start = NULL; + const char *sig_end = NULL; + + while (line < tail) { + const char *next = memchr(line, '\n', tail - line); + next = next ? next + 1 : tail; + + if (in_signature && line[0] == ' ') + sig_end = next; + else if (starts_with(line, gpg_sig_header) && + line[gpg_sig_header_len] == ' ') { + sig_start = line; + sig_end = next; + in_signature = 1; + } else { + if (*line == '\n') + /* dump the whole remainder of the buffer */ + next = tail; + in_signature = 0; + } + line = next; + } + + if (sig_start) + strbuf_remove(buf, sig_start - buf->buf, sig_end - sig_start); + + return sig_start != NULL; +} + static void handle_signed_tag(struct commit *parent, struct commit_extra_header ***tail) { struct merge_remote_desc *desc; @@ -1183,8 +1233,7 @@ static void parse_gpg_output(struct signature_check *sigc) for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) { const char *found, *next; - found = skip_prefix(buf, sigcheck_gpg_status[i].check + 1); - if (!found) { + if (!skip_prefix(buf, sigcheck_gpg_status[i].check + 1, &found)) { found = strstr(buf, sigcheck_gpg_status[i].check); if (!found) continue; @@ -1201,7 +1250,7 @@ static void parse_gpg_output(struct signature_check *sigc) } } -void check_commit_signature(const struct commit* commit, struct signature_check *sigc) +void check_commit_signature(const struct commit *commit, struct signature_check *sigc) { struct strbuf payload = STRBUF_INIT; struct strbuf signature = STRBUF_INIT; @@ -1211,14 +1260,14 @@ void check_commit_signature(const struct commit* commit, struct signature_check sigc->result = 'N'; - if (parse_signed_commit(commit->object.sha1, - &payload, &signature) <= 0) + if (parse_signed_commit(commit, &payload, &signature) <= 0) goto out; status = verify_signed_buffer(payload.buf, payload.len, signature.buf, signature.len, &gpg_output, &gpg_status); if (status && !gpg_output.len) goto out; + sigc->payload = strbuf_detach(&payload, NULL); sigc->gpg_output = strbuf_detach(&gpg_output, NULL); sigc->gpg_status = strbuf_detach(&gpg_status, NULL); parse_gpg_output(sigc); @@ -1257,14 +1306,25 @@ struct commit_extra_header *read_commit_extra_headers(struct commit *commit, { struct commit_extra_header *extra = NULL; unsigned long size; - enum object_type type; - char *buffer = read_sha1_file(commit->object.sha1, &type, &size); - if (buffer && type == OBJ_COMMIT) - extra = read_commit_extra_header_lines(buffer, size, exclude); - free(buffer); + const char *buffer = get_commit_buffer(commit, &size); + extra = read_commit_extra_header_lines(buffer, size, exclude); + unuse_commit_buffer(commit, buffer); return extra; } +void for_each_mergetag(each_mergetag_fn fn, struct commit *commit, void *data) +{ + struct commit_extra_header *extra, *to_free; + + to_free = read_commit_extra_headers(commit, NULL); + for (extra = to_free; extra; extra = extra->next) { + if (strcmp(extra->key, "mergetag")) + continue; /* not a merge tag */ + fn(commit, extra, data); + } + free_commit_extra_headers(to_free); +} + static inline int standard_header_field(const char *field, size_t len) { return ((len == 4 && !memcmp(field, "tree ", 5)) || @@ -1344,7 +1404,8 @@ void free_commit_extra_headers(struct commit_extra_header *extra) } } -int commit_tree(const struct strbuf *msg, const unsigned char *tree, +int commit_tree(const char *msg, size_t msg_len, + const unsigned char *tree, struct commit_list *parents, unsigned char *ret, const char *author, const char *sign_commit) { @@ -1352,7 +1413,7 @@ int commit_tree(const struct strbuf *msg, const unsigned char *tree, int result; append_merge_tag_headers(parents, &tail); - result = commit_tree_extended(msg, tree, parents, ret, + result = commit_tree_extended(msg, msg_len, tree, parents, ret, author, sign_commit, extra); free_commit_extra_headers(extra); return result; @@ -1473,7 +1534,8 @@ static const char commit_utf8_warn[] = "You may want to amend it after fixing the message, or set the config\n" "variable i18n.commitencoding to the encoding your project uses.\n"; -int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree, +int commit_tree_extended(const char *msg, size_t msg_len, + const unsigned char *tree, struct commit_list *parents, unsigned char *ret, const char *author, const char *sign_commit, struct commit_extra_header *extra) @@ -1484,7 +1546,7 @@ int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree, assert_sha1_type(tree, OBJ_TREE); - if (memchr(msg->buf, '\0', msg->len)) + if (memchr(msg, '\0', msg_len)) return error("a NUL byte in commit log message not allowed."); /* Not having i18n.commitencoding is the same as having utf-8 */ @@ -1523,7 +1585,7 @@ int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree, strbuf_addch(&buffer, '\n'); /* And add the comment */ - strbuf_addbuf(&buffer, msg); + strbuf_add(&buffer, msg, msg_len); /* And check the encoding */ if (encoding_is_utf8 && !verify_utf8(&buffer)) @@ -1592,3 +1654,25 @@ void print_commit_list(struct commit_list *list, printf(format, sha1_to_hex(list->item->object.sha1)); } } + +const char *find_commit_header(const char *msg, const char *key, size_t *out_len) +{ + int key_len = strlen(key); + const char *line = msg; + + while (line) { + const char *eol = strchrnul(line, '\n'); + + if (line == eol) + return NULL; + + if (eol - line > key_len && + !strncmp(line, key, key_len) && + line[key_len] == ' ') { + *out_len = eol - line - key_len - 1; + return line + key_len + 1; + } + line = *eol ? eol + 1 : NULL; + } + return NULL; +} diff --git a/commit.h b/commit.h index a9f177ba48..bc68ccbe69 100644 --- a/commit.h +++ b/commit.h @@ -20,20 +20,31 @@ struct commit { unsigned long date; struct commit_list *parents; struct tree *tree; - char *buffer; }; extern int save_commit_buffer; extern const char *commit_type; /* While we can decorate any object with a name, it's only used for commits.. */ -extern struct decoration name_decoration; struct name_decoration { struct name_decoration *next; int type; - char name[1]; + char name[FLEX_ARRAY]; }; +enum decoration_type { + DECORATION_NONE = 0, + DECORATION_REF_LOCAL, + DECORATION_REF_REMOTE, + DECORATION_REF_TAG, + DECORATION_REF_STASH, + DECORATION_REF_HEAD, + DECORATION_GRAFTED, +}; + +void add_name_decoration(enum decoration_type type, const char *name, struct object *obj); +const struct name_decoration *get_name_decoration(const struct object *obj); + struct commit *lookup_commit(const unsigned char *sha1); struct commit *lookup_commit_reference(const unsigned char *sha1); struct commit *lookup_commit_reference_gently(const unsigned char *sha1, @@ -51,6 +62,44 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s int parse_commit(struct commit *item); void parse_commit_or_die(struct commit *item); +/* + * Associate an object buffer with the commit. The ownership of the + * memory is handed over to the commit, and must be free()-able. + */ +void set_commit_buffer(struct commit *, void *buffer, unsigned long size); + +/* + * Get any cached object buffer associated with the commit. Returns NULL + * if none. The resulting memory should not be freed. + */ +const void *get_cached_commit_buffer(const struct commit *, unsigned long *size); + +/* + * Get the commit's object contents, either from cache or by reading the object + * from disk. The resulting memory should not be modified, and must be given + * to unuse_commit_buffer when the caller is done. + */ +const void *get_commit_buffer(const struct commit *, unsigned long *size); + +/* + * Tell the commit subsytem that we are done with a particular commit buffer. + * The commit and buffer should be the input and return value, respectively, + * from an earlier call to get_commit_buffer. The buffer may or may not be + * freed by this call; callers should not access the memory afterwards. + */ +void unuse_commit_buffer(const struct commit *, const void *buffer); + +/* + * Free any cached object buffer associated with the commit. + */ +void free_commit_buffer(struct commit *); + +/* + * Disassociate any cached object buffer from the commit, but do not free it. + * The buffer (or NULL, if none) is returned. + */ +const void *detach_commit_buffer(struct commit *, unsigned long *sizep); + /* Find beginning and length of commit subject. */ int find_commit_subject(const char *commit_buffer, const char **subject); @@ -115,14 +164,14 @@ struct userformat_want { extern int has_non_ascii(const char *text); struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */ -extern char *logmsg_reencode(const struct commit *commit, - char **commit_encoding, - const char *output_encoding); -extern void logmsg_free(char *msg, const struct commit *commit); +extern const char *logmsg_reencode(const struct commit *commit, + char **commit_encoding, + const char *output_encoding); extern void get_commit_format(const char *arg, struct rev_info *); extern const char *format_subject(struct strbuf *sb, const char *msg, const char *line_separator); extern void userformat_find_requirements(const char *fmt, struct userformat_want *w); +extern int commit_format_is_empty(enum cmit_fmt); extern void format_commit_message(const struct commit *commit, const char *format, struct strbuf *sb, const struct pretty_print_context *context); @@ -235,6 +284,7 @@ extern void assign_shallow_commits_to_refs(struct shallow_info *info, int *ref_status); extern int delayed_reachability_test(struct shallow_info *si, int c); extern void prune_shallow(int show_only); +extern struct trace_key trace_shallow; int is_descendant_of(struct commit *, struct commit_list *); int in_merge_bases(struct commit *, struct commit *); @@ -261,11 +311,13 @@ struct commit_extra_header { extern void append_merge_tag_headers(struct commit_list *parents, struct commit_extra_header ***tail); -extern int commit_tree(const struct strbuf *msg, const unsigned char *tree, +extern int commit_tree(const char *msg, size_t msg_len, + const unsigned char *tree, struct commit_list *parents, unsigned char *ret, const char *author, const char *sign_commit); -extern int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree, +extern int commit_tree_extended(const char *msg, size_t msg_len, + const unsigned char *tree, struct commit_list *parents, unsigned char *ret, const char *author, const char *sign_commit, struct commit_extra_header *); @@ -274,6 +326,22 @@ extern struct commit_extra_header *read_commit_extra_headers(struct commit *, co extern void free_commit_extra_headers(struct commit_extra_header *extra); +/* + * Search the commit object contents given by "msg" for the header "key". + * Returns a pointer to the start of the header contents, or NULL. The length + * of the header, up to the first newline, is returned via out_len. + * + * Note that some headers (like mergetag) may be multi-line. It is the caller's + * responsibility to parse further in this case! + */ +extern const char *find_commit_header(const char *msg, const char *key, + size_t *out_len); + +typedef void (*each_mergetag_fn)(struct commit *commit, struct commit_extra_header *extra, + void *cb_data); + +extern void for_each_mergetag(each_mergetag_fn fn, struct commit *commit, void *data); + struct merge_remote_desc { struct object *obj; /* the named object, could be a tag */ const char *name; @@ -287,8 +355,10 @@ struct merge_remote_desc { */ struct commit *get_merge_parent(const char *name); -extern int parse_signed_commit(const unsigned char *sha1, +extern int parse_signed_commit(const struct commit *commit, struct strbuf *message, struct strbuf *signature); +extern int remove_signature(struct strbuf *buf); + extern void print_commit_list(struct commit_list *list, const char *format_cur, const char *format_last); @@ -300,7 +370,7 @@ extern void print_commit_list(struct commit_list *list, * at all. This may allocate memory for sig->gpg_output, sig->gpg_status, * sig->signer and sig->key. */ -extern void check_commit_signature(const struct commit* commit, struct signature_check *sigc); +extern void check_commit_signature(const struct commit *commit, struct signature_check *sigc); int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused); diff --git a/compat/mingw.c b/compat/mingw.c index a0e13bc862..c5c37e53ce 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1,8 +1,10 @@ #include "../git-compat-util.h" #include "win32.h" #include +#include #include "../strbuf.h" #include "../run-command.h" +#include "../cache.h" static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -198,14 +200,16 @@ static int ask_yes_no_if_possible(const char *format, ...) } } -#undef unlink int mingw_unlink(const char *pathname) { int ret, tries = 0; + wchar_t wpathname[MAX_PATH]; + if (xutftowcs_path(wpathname, pathname) < 0) + return -1; /* read-only files cannot be removed */ - chmod(pathname, 0666); - while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + _wchmod(wpathname, 0666); + while ((ret = _wunlink(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (!is_file_in_use_error(GetLastError())) break; /* @@ -221,45 +225,45 @@ int mingw_unlink(const char *pathname) while (ret == -1 && is_file_in_use_error(GetLastError()) && ask_yes_no_if_possible("Unlink of file '%s' failed. " "Should I try again?", pathname)) - ret = unlink(pathname); + ret = _wunlink(wpathname); return ret; } -static int is_dir_empty(const char *path) +static int is_dir_empty(const wchar_t *wpath) { - struct strbuf buf = STRBUF_INIT; - WIN32_FIND_DATAA findbuf; + WIN32_FIND_DATAW findbuf; HANDLE handle; - - strbuf_addf(&buf, "%s\\*", path); - handle = FindFirstFileA(buf.buf, &findbuf); - if (handle == INVALID_HANDLE_VALUE) { - strbuf_release(&buf); + wchar_t wbuf[MAX_PATH + 2]; + wcscpy(wbuf, wpath); + wcscat(wbuf, L"\\*"); + handle = FindFirstFileW(wbuf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) return GetLastError() == ERROR_NO_MORE_FILES; - } - while (!strcmp(findbuf.cFileName, ".") || - !strcmp(findbuf.cFileName, "..")) - if (!FindNextFile(handle, &findbuf)) { - strbuf_release(&buf); - return GetLastError() == ERROR_NO_MORE_FILES; + while (!wcscmp(findbuf.cFileName, L".") || + !wcscmp(findbuf.cFileName, L"..")) + if (!FindNextFileW(handle, &findbuf)) { + DWORD err = GetLastError(); + FindClose(handle); + return err == ERROR_NO_MORE_FILES; } FindClose(handle); - strbuf_release(&buf); return 0; } -#undef rmdir int mingw_rmdir(const char *pathname) { int ret, tries = 0; + wchar_t wpathname[MAX_PATH]; + if (xutftowcs_path(wpathname, pathname) < 0) + return -1; - while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + while ((ret = _wrmdir(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (!is_file_in_use_error(GetLastError())) errno = err_win_to_posix(GetLastError()); if (errno != EACCES) break; - if (!is_dir_empty(pathname)) { + if (!is_dir_empty(wpathname)) { errno = ENOTEMPTY; break; } @@ -276,16 +280,26 @@ int mingw_rmdir(const char *pathname) while (ret == -1 && errno == EACCES && is_file_in_use_error(GetLastError()) && ask_yes_no_if_possible("Deletion of directory '%s' failed. " "Should I try again?", pathname)) - ret = rmdir(pathname); + ret = _wrmdir(wpathname); + return ret; +} + +int mingw_mkdir(const char *path, int mode) +{ + int ret; + wchar_t wpath[MAX_PATH]; + if (xutftowcs_path(wpath, path) < 0) + return -1; + ret = _wmkdir(wpath); return ret; } -#undef open int mingw_open (const char *filename, int oflags, ...) { va_list args; unsigned mode; int fd; + wchar_t wfilename[MAX_PATH]; va_start(args, oflags); mode = va_arg(args, int); @@ -294,10 +308,12 @@ int mingw_open (const char *filename, int oflags, ...) if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - fd = open(filename, oflags, mode); + if (xutftowcs_path(wfilename, filename) < 0) + return -1; + fd = _wopen(wfilename, oflags, mode); if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) { - DWORD attrs = GetFileAttributes(filename); + DWORD attrs = GetFileAttributesW(wfilename); if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } @@ -332,17 +348,28 @@ int mingw_fgetc(FILE *stream) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + FILE *file; + wchar_t wfilename[MAX_PATH], wotype[4]; if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + if (xutftowcs_path(wfilename, filename) < 0 || + xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0) + return NULL; + file = _wfopen(wfilename, wotype); + return file; } -#undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + FILE *file; + wchar_t wfilename[MAX_PATH], wotype[4]; if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + if (xutftowcs_path(wfilename, filename) < 0 || + xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0) + return NULL; + file = _wfreopen(wfilename, wotype, stream); + return file; } #undef fflush @@ -367,6 +394,31 @@ int mingw_fflush(FILE *stream) return ret; } +int mingw_access(const char *filename, int mode) +{ + wchar_t wfilename[MAX_PATH]; + if (xutftowcs_path(wfilename, filename) < 0) + return -1; + /* X_OK is not supported by the MSVCRT version */ + return _waccess(wfilename, mode & ~X_OK); +} + +int mingw_chdir(const char *dirname) +{ + wchar_t wdirname[MAX_PATH]; + if (xutftowcs_path(wdirname, dirname) < 0) + return -1; + return _wchdir(wdirname); +} + +int mingw_chmod(const char *filename, int mode) +{ + wchar_t wfilename[MAX_PATH]; + if (xutftowcs_path(wfilename, filename) < 0) + return -1; + return _wchmod(wfilename, mode); +} + /* * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC. * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch. @@ -392,10 +444,12 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) */ static int do_lstat(int follow, const char *file_name, struct stat *buf) { - int err; WIN32_FILE_ATTRIBUTE_DATA fdata; + wchar_t wfilename[MAX_PATH]; + if (xutftowcs_path(wfilename, file_name) < 0) + return -1; - if (!(err = get_file_attr(file_name, &fdata))) { + if (GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata)) { buf->st_ino = 0; buf->st_gid = 0; buf->st_uid = 0; @@ -408,8 +462,8 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - WIN32_FIND_DATAA findbuf; - HANDLE handle = FindFirstFileA(file_name, &findbuf); + WIN32_FIND_DATAW findbuf; + HANDLE handle = FindFirstFileW(wfilename, &findbuf); if (handle != INVALID_HANDLE_VALUE) { if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { @@ -428,7 +482,23 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) } return 0; } - errno = err; + switch (GetLastError()) { + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + case ERROR_LOCK_VIOLATION: + case ERROR_SHARING_BUFFER_EXCEEDED: + errno = EACCES; + break; + case ERROR_BUFFER_OVERFLOW: + errno = ENAMETOOLONG; + break; + case ERROR_NOT_ENOUGH_MEMORY: + errno = ENOMEM; + break; + default: + errno = ENOENT; + break; + } return -1; } @@ -441,7 +511,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; - static char alt_name[PATH_MAX]; + char alt_name[PATH_MAX]; if (!do_lstat(follow, file_name, buf)) return 0; @@ -516,16 +586,20 @@ int mingw_utime (const char *file_name, const struct utimbuf *times) { FILETIME mft, aft; int fh, rc; + DWORD attrs; + wchar_t wfilename[MAX_PATH]; + if (xutftowcs_path(wfilename, file_name) < 0) + return -1; /* must have write permission */ - DWORD attrs = GetFileAttributes(file_name); + attrs = GetFileAttributesW(wfilename); if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_READONLY)) { /* ignore errors here; open() will report them */ - SetFileAttributes(file_name, attrs & ~FILE_ATTRIBUTE_READONLY); + SetFileAttributesW(wfilename, attrs & ~FILE_ATTRIBUTE_READONLY); } - if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) { + if ((fh = _wopen(wfilename, O_RDWR | O_BINARY)) < 0) { rc = -1; goto revert_attrs; } @@ -548,7 +622,7 @@ int mingw_utime (const char *file_name, const struct utimbuf *times) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_READONLY)) { /* ignore errors again */ - SetFileAttributes(file_name, attrs); + SetFileAttributesW(wfilename, attrs); } return rc; } @@ -559,6 +633,18 @@ unsigned int sleep (unsigned int seconds) return 0; } +char *mingw_mktemp(char *template) +{ + wchar_t wtemplate[MAX_PATH]; + if (xutftowcs_path(wtemplate, template) < 0) + return NULL; + if (!_wmktemp(wtemplate)) + return NULL; + if (xwcstoutf(template, wtemplate, strlen(template) + 1) < 0) + return NULL; + return template; +} + int mkstemp(char *template) { char *filename = mktemp(template); @@ -617,17 +703,18 @@ struct tm *localtime_r(const time_t *timep, struct tm *result) return result; } -#undef getcwd char *mingw_getcwd(char *pointer, int len) { int i; - char *ret = getcwd(pointer, len); - if (!ret) - return ret; + wchar_t wpointer[MAX_PATH]; + if (!_wgetcwd(wpointer, ARRAY_SIZE(wpointer))) + return NULL; + if (xwcstoutf(pointer, wpointer, len) < 0) + return NULL; for (i = 0; pointer[i]; i++) if (pointer[i] == '\\') pointer[i] = '/'; - return ret; + return pointer; } /* @@ -812,11 +899,44 @@ static char *path_lookup(const char *cmd, char **path, int exe_only) return prog; } -static int env_compare(const void *a, const void *b) +static int do_putenv(char **env, const char *name, int size, int free_old); + +/* used number of elements of environ array, including terminating NULL */ +static int environ_size = 0; +/* allocated size of environ array, in bytes */ +static int environ_alloc = 0; + +/* + * Create environment block suitable for CreateProcess. Merges current + * process environment and the supplied environment changes. + */ +static wchar_t *make_environment_block(char **deltaenv) { - char *const *ea = a; - char *const *eb = b; - return strcasecmp(*ea, *eb); + wchar_t *wenvblk = NULL; + char **tmpenv; + int i = 0, size = environ_size, wenvsz = 0, wenvpos = 0; + + while (deltaenv && deltaenv[i]) + i++; + + /* copy the environment, leaving space for changes */ + tmpenv = xmalloc((size + i) * sizeof(char*)); + memcpy(tmpenv, environ, size * sizeof(char*)); + + /* merge supplied environment changes into the temporary environment */ + for (i = 0; deltaenv && deltaenv[i]; i++) + size = do_putenv(tmpenv, deltaenv[i], size, 0); + + /* create environment block from temporary environment */ + for (i = 0; tmpenv[i]; i++) { + size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */ + ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz); + wenvpos += xutftowcs(&wenvblk[wenvpos], tmpenv[i], size) + 1; + } + /* add final \0 terminator */ + wenvblk[wenvpos] = 0; + free(tmpenv); + return wenvblk; } struct pinfo_t { @@ -827,14 +947,15 @@ struct pinfo_t { static struct pinfo_t *pinfo = NULL; CRITICAL_SECTION pinfo_cs; -static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env, +static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv, const char *dir, int prepend_cmd, int fhin, int fhout, int fherr) { - STARTUPINFO si; + STARTUPINFOW si; PROCESS_INFORMATION pi; - struct strbuf envblk, args; - unsigned flags; + struct strbuf args; + wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL; + unsigned flags = CREATE_UNICODE_ENVIRONMENT; BOOL ret; /* Determine whether or not we are associated to a console */ @@ -851,7 +972,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env, * instead of CREATE_NO_WINDOW to make ssh * recognize that it has no console. */ - flags = DETACHED_PROCESS; + flags |= DETACHED_PROCESS; } else { /* There is already a console. If we specified * DETACHED_PROCESS here, too, Windows would @@ -859,15 +980,19 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env, * The same is true for CREATE_NO_WINDOW. * Go figure! */ - flags = 0; CloseHandle(cons); } memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESTDHANDLES; - si.hStdInput = (HANDLE) _get_osfhandle(fhin); - si.hStdOutput = (HANDLE) _get_osfhandle(fhout); - si.hStdError = (HANDLE) _get_osfhandle(fherr); + si.hStdInput = winansi_get_osfhandle(fhin); + si.hStdOutput = winansi_get_osfhandle(fhout); + si.hStdError = winansi_get_osfhandle(fherr); + + if (xutftowcs_path(wcmd, cmd) < 0) + return -1; + if (dir && xutftowcs_path(wdir, dir) < 0) + return -1; /* concatenate argv, quoting args as we go */ strbuf_init(&args, 0); @@ -886,33 +1011,18 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env, free(quoted); } - if (env) { - int count = 0; - char **e, **sorted_env; - - for (e = env; *e; e++) - count++; - - /* environment must be sorted */ - sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1)); - memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1)); - qsort(sorted_env, count, sizeof(*sorted_env), env_compare); + wargs = xmalloc((2 * args.len + 1) * sizeof(wchar_t)); + xutftowcs(wargs, args.buf, 2 * args.len + 1); + strbuf_release(&args); - strbuf_init(&envblk, 0); - for (e = sorted_env; *e; e++) { - strbuf_addstr(&envblk, *e); - strbuf_addch(&envblk, '\0'); - } - free(sorted_env); - } + wenvblk = make_environment_block(deltaenv); memset(&pi, 0, sizeof(pi)); - ret = CreateProcess(cmd, args.buf, NULL, NULL, TRUE, flags, - env ? envblk.buf : NULL, dir, &si, &pi); + ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags, + wenvblk, dir ? wdir : NULL, &si, &pi); - if (env) - strbuf_release(&envblk); - strbuf_release(&args); + free(wenvblk); + free(wargs); if (!ret) { errno = ENOENT; @@ -941,13 +1051,12 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env, return (pid_t)pi.dwProcessId; } -static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, - int prepend_cmd) +static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd) { - return mingw_spawnve_fd(cmd, argv, env, NULL, prepend_cmd, 0, 1, 2); + return mingw_spawnve_fd(cmd, argv, NULL, NULL, prepend_cmd, 0, 1, 2); } -pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env, +pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv, const char *dir, int fhin, int fhout, int fherr) { @@ -971,14 +1080,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env, pid = -1; } else { - pid = mingw_spawnve_fd(iprog, argv, env, dir, 1, + pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, 1, fhin, fhout, fherr); free(iprog); } argv[0] = argv0; } else - pid = mingw_spawnve_fd(prog, argv, env, dir, 0, + pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, 0, fhin, fhout, fherr); free(prog); } @@ -986,7 +1095,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env, return pid; } -static int try_shell_exec(const char *cmd, char *const *argv, char **env) +static int try_shell_exec(const char *cmd, char *const *argv) { const char *interpr = parse_interpreter(cmd); char **path; @@ -1004,7 +1113,7 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env) argv2 = xmalloc(sizeof(*argv) * (argc+1)); argv2[0] = (char *)cmd; /* full path to the script file */ memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc); - pid = mingw_spawnve(prog, argv2, env, 1); + pid = mingw_spawnv(prog, argv2, 1); if (pid >= 0) { int status; if (waitpid(pid, &status, 0) < 0) @@ -1019,19 +1128,20 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env) return pid; } -static void mingw_execve(const char *cmd, char *const *argv, char *const *env) +int mingw_execv(const char *cmd, char *const *argv) { /* check if git_command is a shell script */ - if (!try_shell_exec(cmd, argv, (char **)env)) { + if (!try_shell_exec(cmd, argv)) { int pid, status; - pid = mingw_spawnve(cmd, (const char **)argv, (char **)env, 0); + pid = mingw_spawnv(cmd, (const char **)argv, 0); if (pid < 0) - return; + return -1; if (waitpid(pid, &status, 0) < 0) status = 255; exit(status); } + return -1; } int mingw_execvp(const char *cmd, char *const *argv) @@ -1040,7 +1150,7 @@ int mingw_execvp(const char *cmd, char *const *argv) char *prog = path_lookup(cmd, path, 0); if (prog) { - mingw_execve(prog, argv, environ); + mingw_execv(prog, argv); free(prog); } else errno = ENOENT; @@ -1049,12 +1159,6 @@ int mingw_execvp(const char *cmd, char *const *argv) return -1; } -int mingw_execv(const char *cmd, char *const *argv) -{ - mingw_execve(cmd, argv, environ); - return -1; -} - int mingw_kill(pid_t pid, int sig) { if (pid > 0 && sig == SIGTERM) { @@ -1080,108 +1184,88 @@ int mingw_kill(pid_t pid, int sig) return -1; } -static char **copy_environ(void) -{ - char **env; - int i = 0; - while (environ[i]) - i++; - env = xmalloc((i+1)*sizeof(*env)); - for (i = 0; environ[i]; i++) - env[i] = xstrdup(environ[i]); - env[i] = NULL; - return env; -} - -void free_environ(char **env) -{ - int i; - for (i = 0; env[i]; i++) - free(env[i]); - free(env); +/* + * Compare environment entries by key (i.e. stopping at '=' or '\0'). + */ +static int compareenv(const void *v1, const void *v2) +{ + const char *e1 = *(const char**)v1; + const char *e2 = *(const char**)v2; + + for (;;) { + int c1 = *e1++; + int c2 = *e2++; + c1 = (c1 == '=') ? 0 : tolower(c1); + c2 = (c2 == '=') ? 0 : tolower(c2); + if (c1 > c2) + return 1; + if (c1 < c2) + return -1; + if (c1 == 0) + return 0; + } } -static int lookup_env(char **env, const char *name, size_t nmln) +static int bsearchenv(char **env, const char *name, size_t size) { - int i; - - for (i = 0; env[i]; i++) { - if (0 == strncmp(env[i], name, nmln) - && '=' == env[i][nmln]) - /* matches */ - return i; + unsigned low = 0, high = size; + while (low < high) { + unsigned mid = low + ((high - low) >> 1); + int cmp = compareenv(&env[mid], &name); + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid; + else + return mid; } - return -1; + return ~low; /* not found, return 1's complement of insert position */ } /* * If name contains '=', then sets the variable, otherwise it unsets it + * Size includes the terminating NULL. Env must have room for size + 1 entries + * (in case of insert). Returns the new size. Optionally frees removed entries. */ -static char **env_setenv(char **env, const char *name) +static int do_putenv(char **env, const char *name, int size, int free_old) { - char *eq = strchrnul(name, '='); - int i = lookup_env(env, name, eq-name); + int i = bsearchenv(env, name, size - 1); - if (i < 0) { - if (*eq) { - for (i = 0; env[i]; i++) - ; - env = xrealloc(env, (i+2)*sizeof(*env)); - env[i] = xstrdup(name); - env[i+1] = NULL; - } - } - else { + /* optionally free removed / replaced entry */ + if (i >= 0 && free_old) free(env[i]); - if (*eq) - env[i] = xstrdup(name); - else - for (; env[i]; i++) - env[i] = env[i+1]; - } - return env; -} - -/* - * Copies global environ and adjusts variables as specified by vars. - */ -char **make_augmented_environ(const char *const *vars) -{ - char **env = copy_environ(); - while (*vars) - env = env_setenv(env, *vars++); - return env; + if (strchr(name, '=')) { + /* if new value ('key=value') is specified, insert or replace entry */ + if (i < 0) { + i = ~i; + memmove(&env[i + 1], &env[i], (size - i) * sizeof(char*)); + size++; + } + env[i] = (char*) name; + } else if (i >= 0) { + /* otherwise ('key') remove existing entry */ + size--; + memmove(&env[i], &env[i + 1], (size - i) * sizeof(char*)); + } + return size; } -#undef getenv - -/* - * The system's getenv looks up the name in a case-insensitive manner. - * This version tries a case-sensitive lookup and falls back to - * case-insensitive if nothing was found. This is necessary because, - * as a prominent example, CMD sets 'Path', but not 'PATH'. - * Warning: not thread-safe. - */ -static char *getenv_cs(const char *name) +char *mingw_getenv(const char *name) { - size_t len = strlen(name); - int i = lookup_env(environ, name, len); - if (i >= 0) - return environ[i] + len + 1; /* skip past name and '=' */ - return getenv(name); + char *value; + int pos = bsearchenv(environ, name, environ_size - 1); + if (pos < 0) + return NULL; + value = strchr(environ[pos], '='); + return value ? &value[1] : NULL; } -char *mingw_getenv(const char *name) +int mingw_putenv(const char *namevalue) { - char *result = getenv_cs(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv_cs("TMP"); - if (!result) - result = getenv_cs("TEMP"); - } - return result; + ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc); + environ_size = do_putenv(environ, namevalue, environ_size, 1); + return 0; } /* @@ -1226,8 +1310,7 @@ static int WSAAPI getaddrinfo_stub(const char *node, const char *service, else ai->ai_canonname = NULL; - sin = xmalloc(ai->ai_addrlen); - memset(sin, 0, ai->ai_addrlen); + sin = xcalloc(1, ai->ai_addrlen); sin->sin_family = AF_INET; /* Note: getaddrinfo is supposed to allow service to be a string, * which should be looked up using getservbyname. This is @@ -1481,33 +1564,36 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; + wchar_t wpold[MAX_PATH], wpnew[MAX_PATH]; + if (xutftowcs_path(wpold, pold) < 0 || xutftowcs_path(wpnew, pnew) < 0) + return -1; /* * Try native rename() first to get errno right. * It is based on MoveFile(), which cannot overwrite existing files. */ - if (!rename(pold, pnew)) + if (!_wrename(wpold, wpnew)) return 0; if (errno != EEXIST) return -1; repeat: - if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) + if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING)) return 0; /* TODO: translate more errors */ gle = GetLastError(); if (gle == ERROR_ACCESS_DENIED && - (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) { + (attrs = GetFileAttributesW(wpnew)) != INVALID_FILE_ATTRIBUTES) { if (attrs & FILE_ATTRIBUTE_DIRECTORY) { errno = EISDIR; return -1; } if ((attrs & FILE_ATTRIBUTE_READONLY) && - SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) { - if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) + SetFileAttributesW(wpnew, attrs & ~FILE_ATTRIBUTE_READONLY)) { + if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING)) return 0; gle = GetLastError(); /* revert file attributes on failure */ - SetFileAttributes(pnew, attrs); + SetFileAttributesW(wpnew, attrs); } } if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) { @@ -1753,11 +1839,16 @@ void mingw_open_html(const char *unixpath) int link(const char *oldpath, const char *newpath) { - typedef BOOL (WINAPI *T)(const char*, const char*, LPSECURITY_ATTRIBUTES); + typedef BOOL (WINAPI *T)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES); static T create_hard_link = NULL; + wchar_t woldpath[MAX_PATH], wnewpath[MAX_PATH]; + if (xutftowcs_path(woldpath, oldpath) < 0 || + xutftowcs_path(wnewpath, newpath) < 0) + return -1; + if (!create_hard_link) { create_hard_link = (T) GetProcAddress( - GetModuleHandle("kernel32.dll"), "CreateHardLinkA"); + GetModuleHandle("kernel32.dll"), "CreateHardLinkW"); if (!create_hard_link) create_hard_link = (T)-1; } @@ -1765,7 +1856,7 @@ int link(const char *oldpath, const char *newpath) errno = ENOSYS; return -1; } - if (!create_hard_link(newpath, oldpath, NULL)) { + if (!create_hard_link(wnewpath, woldpath, NULL)) { errno = err_win_to_posix(GetLastError()); return -1; } @@ -1847,3 +1938,193 @@ int mingw_offset_1st_component(const char *path) return offset + is_dir_sep(path[offset]); } + +int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen) +{ + int upos = 0, wpos = 0; + const unsigned char *utf = (const unsigned char*) utfs; + if (!utf || !wcs || wcslen < 1) { + errno = EINVAL; + return -1; + } + /* reserve space for \0 */ + wcslen--; + if (utflen < 0) + utflen = INT_MAX; + + while (upos < utflen) { + int c = utf[upos++] & 0xff; + if (utflen == INT_MAX && c == 0) + break; + + if (wpos >= wcslen) { + wcs[wpos] = 0; + errno = ERANGE; + return -1; + } + + if (c < 0x80) { + /* ASCII */ + wcs[wpos++] = c; + } else if (c >= 0xc2 && c < 0xe0 && upos < utflen && + (utf[upos] & 0xc0) == 0x80) { + /* 2-byte utf-8 */ + c = ((c & 0x1f) << 6); + c |= (utf[upos++] & 0x3f); + wcs[wpos++] = c; + } else if (c >= 0xe0 && c < 0xf0 && upos + 1 < utflen && + !(c == 0xe0 && utf[upos] < 0xa0) && /* over-long encoding */ + (utf[upos] & 0xc0) == 0x80 && + (utf[upos + 1] & 0xc0) == 0x80) { + /* 3-byte utf-8 */ + c = ((c & 0x0f) << 12); + c |= ((utf[upos++] & 0x3f) << 6); + c |= (utf[upos++] & 0x3f); + wcs[wpos++] = c; + } else if (c >= 0xf0 && c < 0xf5 && upos + 2 < utflen && + wpos + 1 < wcslen && + !(c == 0xf0 && utf[upos] < 0x90) && /* over-long encoding */ + !(c == 0xf4 && utf[upos] >= 0x90) && /* > \u10ffff */ + (utf[upos] & 0xc0) == 0x80 && + (utf[upos + 1] & 0xc0) == 0x80 && + (utf[upos + 2] & 0xc0) == 0x80) { + /* 4-byte utf-8: convert to \ud8xx \udcxx surrogate pair */ + c = ((c & 0x07) << 18); + c |= ((utf[upos++] & 0x3f) << 12); + c |= ((utf[upos++] & 0x3f) << 6); + c |= (utf[upos++] & 0x3f); + c -= 0x10000; + wcs[wpos++] = 0xd800 | (c >> 10); + wcs[wpos++] = 0xdc00 | (c & 0x3ff); + } else if (c >= 0xa0) { + /* invalid utf-8 byte, printable unicode char: convert 1:1 */ + wcs[wpos++] = c; + } else { + /* invalid utf-8 byte, non-printable unicode: convert to hex */ + static const char *hex = "0123456789abcdef"; + wcs[wpos++] = hex[c >> 4]; + if (wpos < wcslen) + wcs[wpos++] = hex[c & 0x0f]; + } + } + wcs[wpos] = 0; + return wpos; +} + +int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen) +{ + if (!wcs || !utf || utflen < 1) { + errno = EINVAL; + return -1; + } + utflen = WideCharToMultiByte(CP_UTF8, 0, wcs, -1, utf, utflen, NULL, NULL); + if (utflen) + return utflen - 1; + errno = ERANGE; + return -1; +} + +/* + * Disable MSVCRT command line wildcard expansion (__getmainargs called from + * mingw startup code, see init.c in mingw runtime). + */ +int _CRT_glob = 0; + +typedef struct { + int newmode; +} _startupinfo; + +extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob, + _startupinfo *si); + +static NORETURN void die_startup() +{ + fputs("fatal: not enough memory for initialization", stderr); + exit(128); +} + +static void *malloc_startup(size_t size) +{ + void *result = malloc(size); + if (!result) + die_startup(); + return result; +} + +static char *wcstoutfdup_startup(char *buffer, const wchar_t *wcs, size_t len) +{ + len = xwcstoutf(buffer, wcs, len) + 1; + return memcpy(malloc_startup(len), buffer, len); +} + +void mingw_startup() +{ + int i, maxlen, argc; + char *buffer; + wchar_t **wenv, **wargv; + _startupinfo si; + + /* get wide char arguments and environment */ + si.newmode = 0; + if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0) + die_startup(); + + /* determine size of argv and environ conversion buffer */ + maxlen = wcslen(_wpgmptr); + for (i = 1; i < argc; i++) + maxlen = max(maxlen, wcslen(wargv[i])); + for (i = 0; wenv[i]; i++) + maxlen = max(maxlen, wcslen(wenv[i])); + + /* + * nedmalloc can't free CRT memory, allocate resizable environment + * list. Note that xmalloc / xmemdupz etc. call getenv, so we cannot + * use it while initializing the environment itself. + */ + environ_size = i + 1; + environ_alloc = alloc_nr(environ_size * sizeof(char*)); + environ = malloc_startup(environ_alloc); + + /* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */ + maxlen = 3 * maxlen + 1; + buffer = malloc_startup(maxlen); + + /* convert command line arguments and environment to UTF-8 */ + __argv[0] = wcstoutfdup_startup(buffer, _wpgmptr, maxlen); + for (i = 1; i < argc; i++) + __argv[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen); + for (i = 0; wenv[i]; i++) + environ[i] = wcstoutfdup_startup(buffer, wenv[i], maxlen); + environ[i] = NULL; + free(buffer); + + /* sort environment for O(log n) getenv / putenv */ + qsort(environ, i, sizeof(char*), compareenv); + + /* fix Windows specific environment settings */ + + /* on Windows it is TMP and TEMP */ + if (!mingw_getenv("TMPDIR")) { + const char *tmp = mingw_getenv("TMP"); + if (!tmp) + tmp = mingw_getenv("TEMP"); + if (tmp) + setenv("TMPDIR", tmp, 1); + } + + /* simulate TERM to enable auto-color (see color.c) */ + if (!getenv("TERM")) + setenv("TERM", "cygwin", 1); + + /* initialize critical section for waitpid pinfo_t list */ + InitializeCriticalSection(&pinfo_cs); + + /* set up default file mode and file modes for stdin/out/err */ + _fmode = _O_BINARY; + _setmode(_fileno(stdin), _O_BINARY); + _setmode(_fileno(stdout), _O_BINARY); + _setmode(_fileno(stderr), _O_BINARY); + + /* initialize Unicode console */ + winansi_init(); +} diff --git a/compat/mingw.h b/compat/mingw.h index 3eaf822e28..df0e3203ab 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -35,6 +35,9 @@ typedef int socklen_t; #ifndef EWOULDBLOCK #define EWOULDBLOCK EAGAIN #endif +#ifndef ELOOP +#define ELOOP EMLINK +#endif #define SHUT_WR SD_SEND #define SIGHUP 1 @@ -118,10 +121,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir #define WNOHANG 1 @@ -192,11 +192,27 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream); int mingw_fflush(FILE *stream); #define fflush mingw_fflush +int mingw_access(const char *filename, int mode); +#undef access +#define access mingw_access + +int mingw_chdir(const char *dirname); +#define chdir mingw_chdir + +int mingw_chmod(const char *filename, int mode); +#define chmod mingw_chmod + +char *mingw_mktemp(char *template); +#define mktemp mingw_mktemp + char *mingw_getcwd(char *pointer, int len); #define getcwd mingw_getcwd char *mingw_getenv(const char *name); #define getenv mingw_getenv +int mingw_putenv(const char *namevalue); +#define putenv mingw_putenv +#define unsetenv mingw_putenv int mingw_gethostname(char *host, int namelen); #define gethostname mingw_gethostname @@ -317,12 +333,8 @@ int mingw_raise(int sig); * ANSI emulation wrappers */ -int winansi_fputs(const char *str, FILE *stream); -int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); -int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); -#define fputs winansi_fputs -#define printf(...) winansi_printf(__VA_ARGS__) -#define fprintf(...) winansi_fprintf(__VA_ARGS__) +void winansi_init(void); +HANDLE winansi_get_osfhandle(int fd); /* * git specific compatibility @@ -348,12 +360,112 @@ int mingw_offset_1st_component(const char *path); void mingw_open_html(const char *path); #define open_html mingw_open_html -/* - * helpers +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + +/** + * Converts UTF-8 encoded string to UTF-16LE. + * + * To support repositories with legacy-encoded file names, invalid UTF-8 bytes + * 0xa0 - 0xff are converted to corresponding printable Unicode chars \u00a0 - + * \u00ff, and invalid UTF-8 bytes 0x80 - 0x9f (which would make non-printable + * Unicode) are converted to hex-code. + * + * Lead-bytes not followed by an appropriate number of trail-bytes, over-long + * encodings and 4-byte encodings > \u10ffff are detected as invalid UTF-8. + * + * Maximum space requirement for the target buffer is two wide chars per UTF-8 + * char (((strlen(utf) * 2) + 1) [* sizeof(wchar_t)]). + * + * The maximum space is needed only if the entire input string consists of + * invalid UTF-8 bytes in range 0x80-0x9f, as per the following table: + * + * | | UTF-8 | UTF-16 | + * Code point | UTF-8 sequence | bytes | words | ratio + * --------------+-------------------+-------+--------+------- + * 000000-00007f | 0-7f | 1 | 1 | 1 + * 000080-0007ff | c2-df + 80-bf | 2 | 1 | 0.5 + * 000800-00ffff | e0-ef + 2 * 80-bf | 3 | 1 | 0.33 + * 010000-10ffff | f0-f4 + 3 * 80-bf | 4 | 2 (a) | 0.5 + * invalid | 80-9f | 1 | 2 (b) | 2 + * invalid | a0-ff | 1 | 1 | 1 + * + * (a) encoded as UTF-16 surrogate pair + * (b) encoded as two hex digits + * + * Note that, while the UTF-8 encoding scheme can be extended to 5-byte, 6-byte + * or even indefinite-byte sequences, the largest valid code point \u10ffff + * encodes as only 4 UTF-8 bytes. + * + * Parameters: + * wcs: wide char target buffer + * utf: string to convert + * wcslen: size of target buffer (in wchar_t's) + * utflen: size of string to convert, or -1 if 0-terminated + * + * Returns: + * length of converted string (_wcslen(wcs)), or -1 on failure + * + * Errors: + * EINVAL: one of the input parameters is invalid (e.g. NULL) + * ERANGE: the output buffer is too small */ +int xutftowcsn(wchar_t *wcs, const char *utf, size_t wcslen, int utflen); -char **make_augmented_environ(const char *const *vars); -void free_environ(char **env); +/** + * Simplified variant of xutftowcsn, assumes input string is \0-terminated. + */ +static inline int xutftowcs(wchar_t *wcs, const char *utf, size_t wcslen) +{ + return xutftowcsn(wcs, utf, wcslen, -1); +} + +/** + * Simplified file system specific variant of xutftowcsn, assumes output + * buffer size is MAX_PATH wide chars and input string is \0-terminated, + * fails with ENAMETOOLONG if input string is too long. + */ +static inline int xutftowcs_path(wchar_t *wcs, const char *utf) +{ + int result = xutftowcsn(wcs, utf, MAX_PATH, -1); + if (result < 0 && errno == ERANGE) + errno = ENAMETOOLONG; + return result; +} + +/** + * Converts UTF-16LE encoded string to UTF-8. + * + * Maximum space requirement for the target buffer is three UTF-8 chars per + * wide char ((_wcslen(wcs) * 3) + 1). + * + * The maximum space is needed only if the entire input string consists of + * UTF-16 words in range 0x0800-0xd7ff or 0xe000-0xffff (i.e. \u0800-\uffff + * modulo surrogate pairs), as per the following table: + * + * | | UTF-16 | UTF-8 | + * Code point | UTF-16 sequence | words | bytes | ratio + * --------------+-----------------------+--------+-------+------- + * 000000-00007f | 0000-007f | 1 | 1 | 1 + * 000080-0007ff | 0080-07ff | 1 | 2 | 2 + * 000800-00ffff | 0800-d7ff / e000-ffff | 1 | 3 | 3 + * 010000-10ffff | d800-dbff + dc00-dfff | 2 | 4 | 2 + * + * Note that invalid code points > 10ffff cannot be represented in UTF-16. + * + * Parameters: + * utf: target buffer + * wcs: wide string to convert + * utflen: size of target buffer + * + * Returns: + * length of converted string, or -1 on failure + * + * Errors: + * EINVAL: one of the input parameters is invalid (e.g. NULL) + * ERANGE: the output buffer is too small + */ +int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen); /* * A critical section used in the implementation of the spawn @@ -363,22 +475,16 @@ void free_environ(char **env); extern CRITICAL_SECTION pinfo_cs; /* - * A replacement of main() that ensures that argv[0] has a path - * and that default fmode and std(in|out|err) are in binary mode + * A replacement of main() that adds win32 specific initialization. */ +void mingw_startup(); #define main(c,v) dummy_decl_mingw_main(); \ static int mingw_main(c,v); \ int main(int argc, char **argv) \ { \ - extern CRITICAL_SECTION pinfo_cs; \ - _fmode = _O_BINARY; \ - _setmode(_fileno(stdin), _O_BINARY); \ - _setmode(_fileno(stdout), _O_BINARY); \ - _setmode(_fileno(stderr), _O_BINARY); \ - argv[0] = xstrdup(_pgmptr); \ - InitializeCriticalSection(&pinfo_cs); \ - return mingw_main(argc, argv); \ + mingw_startup(); \ + return mingw_main(__argc, (void *)__argv); \ } \ static int mingw_main(c,v) diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c index 7a0debe51b..52420ec7d4 100644 --- a/compat/win32/dirent.c +++ b/compat/win32/dirent.c @@ -1,96 +1,81 @@ -#include "../git-compat-util.h" -#include "dirent.h" +#include "../../git-compat-util.h" struct DIR { struct dirent dd_dir; /* includes d_type */ HANDLE dd_handle; /* FindFirstFile handle */ int dd_stat; /* 0-based index */ - char dd_name[1]; /* extend struct */ }; +static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata) +{ + /* convert UTF-16 name to UTF-8 */ + xwcstoutf(ent->d_name, fdata->cFileName, sizeof(ent->d_name)); + + /* Set file type, based on WIN32_FIND_DATA */ + if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + ent->d_type = DT_DIR; + else + ent->d_type = DT_REG; +} + DIR *opendir(const char *name) { - DWORD attrs = GetFileAttributesA(name); + wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */ + WIN32_FIND_DATAW fdata; + HANDLE h; int len; - DIR *p; + DIR *dir; - /* check for valid path */ - if (attrs == INVALID_FILE_ATTRIBUTES) { - errno = ENOENT; + /* convert name to UTF-16 and check length < MAX_PATH */ + if ((len = xutftowcs_path(pattern, name)) < 0) return NULL; - } - /* check if it's a directory */ - if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) { - errno = ENOTDIR; + /* append optional '/' and wildcard '*' */ + if (len && !is_dir_sep(pattern[len - 1])) + pattern[len++] = '/'; + pattern[len++] = '*'; + pattern[len] = 0; + + /* open find handle */ + h = FindFirstFileW(pattern, &fdata); + if (h == INVALID_HANDLE_VALUE) { + DWORD err = GetLastError(); + errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err); return NULL; } - /* check that the pattern won't be too long for FindFirstFileA */ - len = strlen(name); - if (is_dir_sep(name[len - 1])) - len--; - if (len + 2 >= MAX_PATH) { - errno = ENAMETOOLONG; - return NULL; - } - - p = malloc(sizeof(DIR) + len + 2); - if (!p) - return NULL; - - memset(p, 0, sizeof(DIR) + len + 2); - strcpy(p->dd_name, name); - p->dd_name[len] = '/'; - p->dd_name[len+1] = '*'; - - p->dd_handle = INVALID_HANDLE_VALUE; - return p; + /* initialize DIR structure and copy first dir entry */ + dir = xmalloc(sizeof(DIR)); + dir->dd_handle = h; + dir->dd_stat = 0; + finddata2dirent(&dir->dd_dir, &fdata); + return dir; } struct dirent *readdir(DIR *dir) { - WIN32_FIND_DATAA buf; - HANDLE handle; - - if (!dir || !dir->dd_handle) { + if (!dir) { errno = EBADF; /* No set_errno for mingw */ return NULL; } - if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) { - DWORD lasterr; - handle = FindFirstFileA(dir->dd_name, &buf); - lasterr = GetLastError(); - dir->dd_handle = handle; - if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) { - errno = err_win_to_posix(lasterr); + /* if first entry, dirent has already been set up by opendir */ + if (dir->dd_stat) { + /* get next entry and convert from WIN32_FIND_DATA to dirent */ + WIN32_FIND_DATAW fdata; + if (FindNextFileW(dir->dd_handle, &fdata)) { + finddata2dirent(&dir->dd_dir, &fdata); + } else { + DWORD lasterr = GetLastError(); + /* POSIX says you shouldn't set errno when readdir can't + find any more files; so, if another error we leave it set. */ + if (lasterr != ERROR_NO_MORE_FILES) + errno = err_win_to_posix(lasterr); return NULL; } - } else if (dir->dd_handle == INVALID_HANDLE_VALUE) { - return NULL; - } else if (!FindNextFileA(dir->dd_handle, &buf)) { - DWORD lasterr = GetLastError(); - FindClose(dir->dd_handle); - dir->dd_handle = INVALID_HANDLE_VALUE; - /* POSIX says you shouldn't set errno when readdir can't - find any more files; so, if another error we leave it set. */ - if (lasterr != ERROR_NO_MORE_FILES) - errno = err_win_to_posix(lasterr); - return NULL; } - /* We get here if `buf' contains valid data. */ - strcpy(dir->dd_dir.d_name, buf.cFileName); ++dir->dd_stat; - - /* Set file type, based on WIN32_FIND_DATA */ - dir->dd_dir.d_type = 0; - if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - dir->dd_dir.d_type |= DT_DIR; - else - dir->dd_dir.d_type |= DT_REG; - return &dir->dd_dir; } @@ -101,8 +86,7 @@ int closedir(DIR *dir) return -1; } - if (dir->dd_handle != INVALID_HANDLE_VALUE) - FindClose(dir->dd_handle); + FindClose(dir->dd_handle); free(dir); return 0; } diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h index 927a25ca76..058207e4bf 100644 --- a/compat/win32/dirent.h +++ b/compat/win32/dirent.h @@ -9,12 +9,8 @@ typedef struct DIR DIR; #define DT_LNK 3 struct dirent { - long d_ino; /* Always zero. */ - char d_name[FILENAME_MAX]; /* File name. */ - union { - unsigned short d_reclen; /* Always zero. */ - unsigned char d_type; /* Reimplementation adds this */ - }; + unsigned char d_type; /* file type to prevent lstat after readdir */ + char d_name[MAX_PATH * 3]; /* file name (* 3 for UTF-8 conversion) */ }; DIR *opendir(const char *dirname); diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..efc5bb3a4b 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -2,15 +2,10 @@ * Copyright 2008 Peter Harris */ +#undef NOGDI #include "../git-compat-util.h" - -/* - Functions to be wrapped: -*/ -#undef printf -#undef fprintf -#undef fputs -/* TODO: write */ +#include +#include /* ANSI codes used by git: m, K @@ -23,29 +18,114 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static int non_ascii_used = 0; +static HANDLE hthread, hread, hwrite; +static HANDLE hconsole1, hconsole2; + +#ifdef __MINGW32__ +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; +#endif + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress( + GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", + 0, KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) { + const wchar_t *msg = L"\nWarning: Your console font probably " + L"doesn\'t support Unicode. If you experience strange " + L"characters in the output, consider switching to a " + L"TrueType font such as Consolas!\n"; + DWORD dummy; + WriteConsoleW(console, msg, wcslen(msg), &dummy, NULL); + } +} -static void init(void) +static int is_console(int fd) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* get OS handle of the file descriptor */ + hcon = (HANDLE) _get_osfhandle(fd); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - if (!console) - return; + /* check if its a device (i.e. console, printer, serial port) */ + if (GetFileType(hcon) != FILE_TYPE_CHAR) + return 0; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + /* initialize attributes */ + if (!initialized) { + console = hcon; + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } - initialized = 1; + return 1; } +#define BUFFER_SIZE 4096 +#define MAX_PARAMS 16 + +static void write_console(unsigned char *str, size_t len) +{ + /* only called from console_thread, so a static buffer will do */ + static wchar_t wbuf[2 * BUFFER_SIZE + 1]; + DWORD dummy; + + /* convert utf-8 to utf-16 */ + int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len); + + /* write directly to console */ + WriteConsoleW(console, wbuf, wlen, &dummy, NULL); + + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -90,18 +170,13 @@ static void erase_in_line(void) &dummy); } - -static const char *set_attr(const char *str) +static void set_attr(char func, const int *params, int paramlen) { - const char *func; - size_t len = strspn(str, "0123456789;"); - func = str + len; - - switch (*func) { + int i; + switch (func) { case 'm': - do { - long val = strtol(str, (char **)&str, 10); - switch (val) { + for (i = 0; i < paramlen; i++) { + switch (params[i]) { case 0: /* reset */ attr = plain_attr; negative = 0; @@ -224,9 +299,7 @@ static const char *set_attr(const char *str) /* Unsupported code */ break; } - str++; - } while (*(str-1) == ';'); - + } set_console_attr(); break; case 'K': @@ -236,122 +309,271 @@ static const char *set_attr(const char *str) /* Unsupported code */ break; } - - return func + 1; } -static int ansi_emulate(const char *str, FILE *stream) +enum { + TEXT = 0, ESCAPE = 033, BRACKET = '[' +}; + +static DWORD WINAPI console_thread(LPVOID unused) { - int rv = 0; - const char *pos = str; - - while (*pos) { - pos = strstr(str, "\033["); - if (pos) { - size_t len = pos - str; - - if (len) { - size_t out_len = fwrite(str, 1, len, stream); - rv += out_len; - if (out_len < len) - return rv; + unsigned char buffer[BUFFER_SIZE]; + DWORD bytes; + int start, end = 0, c, parampos = 0, state = TEXT; + int params[MAX_PARAMS]; + + while (1) { + /* read next chunk of bytes from the pipe */ + if (!ReadFile(hread, buffer + end, BUFFER_SIZE - end, &bytes, + NULL)) { + /* exit if pipe has been closed or disconnected */ + if (GetLastError() == ERROR_PIPE_NOT_CONNECTED || + GetLastError() == ERROR_BROKEN_PIPE) + break; + /* ignore other errors */ + continue; + } + + /* scan the bytes and handle ANSI control codes */ + bytes += end; + start = end = 0; + while (end < bytes) { + c = buffer[end++]; + switch (state) { + case TEXT: + if (c == ESCAPE) { + /* print text seen so far */ + if (end - 1 > start) + write_console(buffer + start, + end - 1 - start); + + /* then start parsing escape sequence */ + start = end - 1; + memset(params, 0, sizeof(params)); + parampos = 0; + state = ESCAPE; + } + break; + + case ESCAPE: + /* continue if "\033[", otherwise bail out */ + state = (c == BRACKET) ? BRACKET : TEXT; + break; + + case BRACKET: + /* parse [0-9;]* into array of parameters */ + if (c >= '0' && c <= '9') { + params[parampos] *= 10; + params[parampos] += c - '0'; + } else if (c == ';') { + /* + * next parameter, bail out if out of + * bounds + */ + parampos++; + if (parampos >= MAX_PARAMS) + state = TEXT; + } else { + /* + * end of escape sequence, change + * console attributes + */ + set_attr(c, params, parampos + 1); + start = end; + state = TEXT; + } + break; } + } - str = pos + 2; - rv += 2; + /* print remaining text unless parsing an escape sequence */ + if (state == TEXT && end > start) { + /* check for incomplete UTF-8 sequences and fix end */ + if (buffer[end - 1] >= 0x80) { + if (buffer[end -1] >= 0xc0) + end--; + else if (end - 1 > start && + buffer[end - 2] >= 0xe0) + end -= 2; + else if (end - 2 > start && + buffer[end - 3] >= 0xf0) + end -= 3; + } - fflush(stream); + /* print remaining complete UTF-8 sequences */ + if (end > start) + write_console(buffer + start, end - start); - pos = set_attr(str); - rv += pos - str; - str = pos; + /* move remaining bytes to the front */ + if (end < bytes) + memmove(buffer, buffer + end, bytes - end); + end = bytes - end; } else { - rv += strlen(str); - fputs(str, stream); - return rv; + /* all data has been consumed, mark buffer empty */ + end = 0; } } - return rv; + + /* check if the console font supports unicode */ + warn_if_raster_font(); + + CloseHandle(hread); + return 0; } -int winansi_fputs(const char *str, FILE *stream) +static void winansi_exit(void) { - int rv; - - if (!isatty(fileno(stream))) - return fputs(str, stream); + /* flush all streams */ + _flushall(); - init(); + /* signal console thread to exit */ + FlushFileBuffers(hwrite); + DisconnectNamedPipe(hwrite); - if (!console) - return fputs(str, stream); + /* wait for console thread to copy remaining data */ + WaitForSingleObject(hthread, INFINITE); - rv = ansi_emulate(str, stream); + /* cleanup handles... */ + CloseHandle(hwrite); + CloseHandle(hthread); +} - if (rv >= 0) - return 0; - else - return EOF; +static void die_lasterr(const char *fmt, ...) +{ + va_list params; + va_start(params, fmt); + errno = err_win_to_posix(GetLastError()); + die_errno(fmt, params); + va_end(params); } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +static HANDLE duplicate_handle(HANDLE hnd) { - int len, rv; - char small_buf[256]; - char *buf = small_buf; - va_list cp; + HANDLE hresult, hproc = GetCurrentProcess(); + if (!DuplicateHandle(hproc, hnd, hproc, &hresult, 0, TRUE, + DUPLICATE_SAME_ACCESS)) + die_lasterr("DuplicateHandle(%li) failed", (long) hnd); + return hresult; +} - if (!isatty(fileno(stream))) - goto abort; - init(); +/* + * Make MSVCRT's internal file descriptor control structure accessible + * so that we can tweak OS handles and flags directly (we need MSVCRT + * to treat our pipe handle as if it were a console). + * + * We assume that the ioinfo structure (exposed by MSVCRT.dll via + * __pioinfo) starts with the OS handle and the flags. The exact size + * varies between MSVCRT versions, so we try different sizes until + * toggling the FDEV bit of _pioinfo(1)->osflags is reflected in + * isatty(1). + */ +typedef struct { + HANDLE osfhnd; + char osflags; +} ioinfo; - if (!console) - goto abort; +extern __declspec(dllimport) ioinfo *__pioinfo[]; - va_copy(cp, list); - len = vsnprintf(small_buf, sizeof(small_buf), format, cp); - va_end(cp); +static size_t sizeof_ioinfo = 0; - if (len > sizeof(small_buf) - 1) { - buf = malloc(len + 1); - if (!buf) - goto abort; +#define IOINFO_L2E 5 +#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E) - len = vsnprintf(buf, len + 1, format, list); - } +#define FDEV 0x40 - rv = ansi_emulate(buf, stream); +static inline ioinfo* _pioinfo(int fd) +{ + return (ioinfo*)((char*)__pioinfo[fd >> IOINFO_L2E] + + (fd & (IOINFO_ARRAY_ELTS - 1)) * sizeof_ioinfo); +} - if (buf != small_buf) - free(buf); - return rv; +static int init_sizeof_ioinfo() +{ + int istty, wastty; + /* don't init twice */ + if (sizeof_ioinfo) + return sizeof_ioinfo >= 256; + + sizeof_ioinfo = sizeof(ioinfo); + wastty = isatty(1); + while (sizeof_ioinfo < 256) { + /* toggle FDEV flag, check isatty, then toggle back */ + _pioinfo(1)->osflags ^= FDEV; + istty = isatty(1); + _pioinfo(1)->osflags ^= FDEV; + /* return if we found the correct size */ + if (istty != wastty) + return 0; + sizeof_ioinfo += sizeof(void*); + } + error("Tweaking file descriptors doesn't work with this MSVCRT.dll"); + return 1; +} -abort: - rv = vfprintf(stream, format, list); - return rv; +static HANDLE swap_osfhnd(int fd, HANDLE new_handle) +{ + ioinfo *pioinfo; + HANDLE old_handle; + + /* init ioinfo size if we haven't done so */ + if (init_sizeof_ioinfo()) + return INVALID_HANDLE_VALUE; + + /* get ioinfo pointer and change the handles */ + pioinfo = _pioinfo(fd); + old_handle = pioinfo->osfhnd; + pioinfo->osfhnd = new_handle; + return old_handle; } -int winansi_fprintf(FILE *stream, const char *format, ...) +void winansi_init(void) { - va_list list; - int rv; + int con1, con2; + char name[32]; - va_start(list, format); - rv = winansi_vfprintf(stream, format, list); - va_end(list); + /* check if either stdout or stderr is a console output screen buffer */ + con1 = is_console(1); + con2 = is_console(2); + if (!con1 && !con2) + return; - return rv; + /* create a named pipe to communicate with the console thread */ + sprintf(name, "\\\\.\\pipe\\winansi%lu", GetCurrentProcessId()); + hwrite = CreateNamedPipe(name, PIPE_ACCESS_OUTBOUND, + PIPE_TYPE_BYTE | PIPE_WAIT, 1, BUFFER_SIZE, 0, 0, NULL); + if (hwrite == INVALID_HANDLE_VALUE) + die_lasterr("CreateNamedPipe failed"); + + hread = CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + if (hread == INVALID_HANDLE_VALUE) + die_lasterr("CreateFile for named pipe failed"); + + /* start console spool thread on the pipe's read end */ + hthread = CreateThread(NULL, 0, console_thread, NULL, 0, NULL); + if (hthread == INVALID_HANDLE_VALUE) + die_lasterr("CreateThread(console_thread) failed"); + + /* schedule cleanup routine */ + if (atexit(winansi_exit)) + die_errno("atexit(winansi_exit) failed"); + + /* redirect stdout / stderr to the pipe */ + if (con1) + hconsole1 = swap_osfhnd(1, duplicate_handle(hwrite)); + if (con2) + hconsole2 = swap_osfhnd(2, duplicate_handle(hwrite)); } -int winansi_printf(const char *format, ...) +/* + * Returns the real console handle if stdout / stderr is a pipe redirecting + * to the console. Allows spawn / exec to pass the console to the next process. + */ +HANDLE winansi_get_osfhandle(int fd) { - va_list list; - int rv; - - va_start(list, format); - rv = winansi_vfprintf(stdout, format, list); - va_end(list); - - return rv; + HANDLE hnd = (HANDLE) _get_osfhandle(fd); + if ((fd == 1 || fd == 2) && isatty(fd) + && GetFileType(hnd) == FILE_TYPE_PIPE) + return (fd == 1) ? hconsole1 : hconsole2; + return hnd; } diff --git a/config.c b/config.c index a1aef1cf3e..179b681af2 100644 --- a/config.c +++ b/config.c @@ -9,6 +9,8 @@ #include "exec_cmd.h" #include "strbuf.h" #include "quote.h" +#include "hashmap.h" +#include "string-list.h" struct config_source { struct config_source *prev; @@ -37,6 +39,13 @@ static struct config_source *cf; static int zlib_compression_seen; +/* + * Default config_set that contains key-value pairs from the usual set of config + * config files (i.e repo specific .git/config, user wide ~/.gitconfig, XDG + * config file and the global /etc/gitconfig) + */ +static struct config_set the_config_set; + static int config_file_fgetc(struct config_source *conf) { return fgetc(conf->u.file); @@ -127,7 +136,6 @@ static int handle_path_include(const char *path, struct config_include_data *inc int git_config_include(const char *var, const char *value, void *data) { struct config_include_data *inc = data; - const char *type; int ret; /* @@ -138,11 +146,7 @@ int git_config_include(const char *var, const char *value, void *data) if (ret < 0) return ret; - type = skip_prefix(var, "include."); - if (!type) - return ret; - - if (!strcmp(type, "path")) + if (!strcmp(var, "include.path")) ret = handle_path_include(value, inc); return ret; } @@ -163,19 +167,27 @@ void git_config_push_parameter(const char *text) int git_config_parse_parameter(const char *text, config_fn_t fn, void *data) { + const char *value; struct strbuf **pair; + pair = strbuf_split_str(text, '=', 2); if (!pair[0]) return error("bogus config parameter: %s", text); - if (pair[0]->len && pair[0]->buf[pair[0]->len - 1] == '=') + + if (pair[0]->len && pair[0]->buf[pair[0]->len - 1] == '=') { strbuf_setlen(pair[0], pair[0]->len - 1); + value = pair[1] ? pair[1]->buf : ""; + } else { + value = NULL; + } + strbuf_trim(pair[0]); if (!pair[0]->len) { strbuf_list_free(pair); return error("bogus config parameter: %s", text); } strbuf_tolower(pair[0]); - if (fn(pair[0]->buf, pair[1] ? pair[1]->buf : NULL, data) < 0) { + if (fn(pair[0]->buf, value, data) < 0) { strbuf_list_free(pair); return -1; } @@ -230,6 +242,7 @@ static int get_next_char(void) cf->linenr++; if (c == EOF) { cf->eof = 1; + cf->linenr++; c = '\n'; } return c; @@ -305,6 +318,7 @@ static int get_value(config_fn_t fn, void *data, struct strbuf *name) { int c; char *value; + int ret; /* Get the full name */ for (;;) { @@ -327,7 +341,15 @@ static int get_value(config_fn_t fn, void *data, struct strbuf *name) if (!value) return -1; } - return fn(name->buf, value, data); + /* + * We already consumed the \n, but we need linenr to point to + * the line we just parsed during the call to fn to get + * accurate line number in error messages. + */ + cf->linenr--; + ret = fn(name->buf, value, data); + cf->linenr++; + return ret; } static int get_extended_base_var(struct strbuf *name, int c) @@ -443,9 +465,9 @@ static int git_parse_source(config_fn_t fn, void *data) break; } if (cf->die_on_error) - die("bad config file line %d in %s", cf->linenr, cf->name); + die(_("bad config file line %d in %s"), cf->linenr, cf->name); else - return error("bad config file line %d in %s", cf->linenr, cf->name); + return error(_("bad config file line %d in %s"), cf->linenr, cf->name); } static int parse_unit_factor(const char *end, uintmax_t *val) @@ -561,9 +583,9 @@ static void die_bad_number(const char *name, const char *value) value = ""; if (cf && cf->name) - die("bad numeric config value '%s' for '%s' in %s: %s", + die(_("bad numeric config value '%s' for '%s' in %s: %s"), value, name, cf->name, reason); - die("bad numeric config value '%s' for '%s': %s", value, name, reason); + die(_("bad numeric config value '%s' for '%s': %s"), value, name, reason); } int git_config_int(const char *name, const char *value) @@ -648,7 +670,7 @@ int git_config_pathname(const char **dest, const char *var, const char *value) return config_error_nonbool(var); *dest = expand_user_path(value); if (!*dest) - die("Failed to expand user dir in: '%s'", value); + die(_("failed to expand user dir in: '%s'"), value); return 0; } @@ -726,7 +748,7 @@ static int git_default_core_config(const char *var, const char *value) if (level == -1) level = Z_DEFAULT_COMPRESSION; else if (level < 0 || level > Z_BEST_COMPRESSION) - die("bad zlib compression level %d", level); + die(_("bad zlib compression level %d"), level); zlib_compression_level = level; zlib_compression_seen = 1; return 0; @@ -737,7 +759,7 @@ static int git_default_core_config(const char *var, const char *value) if (level == -1) level = Z_DEFAULT_COMPRESSION; else if (level < 0 || level > Z_BEST_COMPRESSION) - die("bad zlib compression level %d", level); + die(_("bad zlib compression level %d"), level); core_compression_level = level; core_compression_seen = 1; if (!zlib_compression_seen) @@ -818,14 +840,12 @@ static int git_default_core_config(const char *var, const char *value) return git_config_string(&editor_program, var, value); if (!strcmp(var, "core.commentchar")) { - const char *comment; - int ret = git_config_string(&comment, var, value); - if (ret) - return ret; - else if (!strcasecmp(comment, "auto")) + if (!value) + return config_error_nonbool(var); + else if (!strcasecmp(value, "auto")) auto_comment_line_char = 1; - else if (comment[0] && !comment[1]) { - comment_line_char = comment[0]; + else if (value[0] && !value[1]) { + comment_line_char = value[0]; auto_comment_line_char = 0; } else return error("core.commentChar should only be one character"); @@ -861,7 +881,7 @@ static int git_default_core_config(const char *var, const char *value) else if (!strcmp(value, "link")) object_creation_mode = OBJECT_CREATION_USES_HARDLINKS; else - die("Invalid mode for object creation: %s", value); + die(_("invalid mode for object creation: %s"), value); return 0; } @@ -1161,7 +1181,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) switch (git_config_from_parameters(fn, data)) { case -1: /* error */ - die("unable to parse command-line config"); + die(_("unable to parse command-line config")); break; case 0: /* found nothing */ break; @@ -1208,9 +1228,365 @@ int git_config_with_options(config_fn_t fn, void *data, return ret; } -int git_config(config_fn_t fn, void *data) +static void git_config_raw(config_fn_t fn, void *data) +{ + if (git_config_with_options(fn, data, NULL, 1) < 0) + /* + * git_config_with_options() normally returns only + * positive values, as most errors are fatal, and + * non-fatal potential errors are guarded by "if" + * statements that are entered only when no error is + * possible. + * + * If we ever encounter a non-fatal error, it means + * something went really wrong and we should stop + * immediately. + */ + die(_("unknown error occured while reading the configuration files")); +} + +static void configset_iter(struct config_set *cs, config_fn_t fn, void *data) +{ + int i, value_index; + struct string_list *values; + struct config_set_element *entry; + struct configset_list *list = &cs->list; + struct key_value_info *kv_info; + + for (i = 0; i < list->nr; i++) { + entry = list->items[i].e; + value_index = list->items[i].value_index; + values = &entry->value_list; + if (fn(entry->key, values->items[value_index].string, data) < 0) { + kv_info = values->items[value_index].util; + git_die_config_linenr(entry->key, kv_info->filename, kv_info->linenr); + } + } +} + +static void git_config_check_init(void); + +void git_config(config_fn_t fn, void *data) +{ + git_config_check_init(); + configset_iter(&the_config_set, fn, data); +} + +static struct config_set_element *configset_find_element(struct config_set *cs, const char *key) +{ + struct config_set_element k; + struct config_set_element *found_entry; + char *normalized_key; + int ret; + /* + * `key` may come from the user, so normalize it before using it + * for querying entries from the hashmap. + */ + ret = git_config_parse_key(key, &normalized_key, NULL); + + if (ret) + return NULL; + + hashmap_entry_init(&k, strhash(normalized_key)); + k.key = normalized_key; + found_entry = hashmap_get(&cs->config_hash, &k, NULL); + free(normalized_key); + return found_entry; +} + +static int configset_add_value(struct config_set *cs, const char *key, const char *value) +{ + struct config_set_element *e; + struct string_list_item *si; + struct configset_list_item *l_item; + struct key_value_info *kv_info = xmalloc(sizeof(*kv_info)); + + e = configset_find_element(cs, key); + /* + * Since the keys are being fed by git_config*() callback mechanism, they + * are already normalized. So simply add them without any further munging. + */ + if (!e) { + e = xmalloc(sizeof(*e)); + hashmap_entry_init(e, strhash(key)); + e->key = xstrdup(key); + string_list_init(&e->value_list, 1); + hashmap_add(&cs->config_hash, e); + } + si = string_list_append_nodup(&e->value_list, value ? xstrdup(value) : NULL); + + ALLOC_GROW(cs->list.items, cs->list.nr + 1, cs->list.alloc); + l_item = &cs->list.items[cs->list.nr++]; + l_item->e = e; + l_item->value_index = e->value_list.nr - 1; + + if (cf) { + kv_info->filename = strintern(cf->name); + kv_info->linenr = cf->linenr; + } else { + /* for values read from `git_config_from_parameters()` */ + kv_info->filename = NULL; + kv_info->linenr = -1; + } + si->util = kv_info; + + return 0; +} + +static int config_set_element_cmp(const struct config_set_element *e1, + const struct config_set_element *e2, const void *unused) +{ + return strcmp(e1->key, e2->key); +} + +void git_configset_init(struct config_set *cs) +{ + hashmap_init(&cs->config_hash, (hashmap_cmp_fn)config_set_element_cmp, 0); + cs->hash_initialized = 1; + cs->list.nr = 0; + cs->list.alloc = 0; + cs->list.items = NULL; +} + +void git_configset_clear(struct config_set *cs) +{ + struct config_set_element *entry; + struct hashmap_iter iter; + if (!cs->hash_initialized) + return; + + hashmap_iter_init(&cs->config_hash, &iter); + while ((entry = hashmap_iter_next(&iter))) { + free(entry->key); + string_list_clear(&entry->value_list, 1); + } + hashmap_free(&cs->config_hash, 1); + cs->hash_initialized = 0; + free(cs->list.items); + cs->list.nr = 0; + cs->list.alloc = 0; + cs->list.items = NULL; +} + +static int config_set_callback(const char *key, const char *value, void *cb) +{ + struct config_set *cs = cb; + configset_add_value(cs, key, value); + return 0; +} + +int git_configset_add_file(struct config_set *cs, const char *filename) +{ + return git_config_from_file(config_set_callback, filename, cs); +} + +int git_configset_get_value(struct config_set *cs, const char *key, const char **value) +{ + const struct string_list *values = NULL; + /* + * Follows "last one wins" semantic, i.e., if there are multiple matches for the + * queried key in the files of the configset, the value returned will be the last + * value in the value list for that key. + */ + values = git_configset_get_value_multi(cs, key); + + if (!values) + return 1; + assert(values->nr > 0); + *value = values->items[values->nr - 1].string; + return 0; +} + +const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key) +{ + struct config_set_element *e = configset_find_element(cs, key); + return e ? &e->value_list : NULL; +} + +int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest) { - return git_config_with_options(fn, data, NULL, 1); + const char *value; + if (!git_configset_get_value(cs, key, &value)) + return git_config_string(dest, key, value); + else + return 1; +} + +int git_configset_get_string(struct config_set *cs, const char *key, char **dest) +{ + return git_configset_get_string_const(cs, key, (const char **)dest); +} + +int git_configset_get_int(struct config_set *cs, const char *key, int *dest) +{ + const char *value; + if (!git_configset_get_value(cs, key, &value)) { + *dest = git_config_int(key, value); + return 0; + } else + return 1; +} + +int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest) +{ + const char *value; + if (!git_configset_get_value(cs, key, &value)) { + *dest = git_config_ulong(key, value); + return 0; + } else + return 1; +} + +int git_configset_get_bool(struct config_set *cs, const char *key, int *dest) +{ + const char *value; + if (!git_configset_get_value(cs, key, &value)) { + *dest = git_config_bool(key, value); + return 0; + } else + return 1; +} + +int git_configset_get_bool_or_int(struct config_set *cs, const char *key, + int *is_bool, int *dest) +{ + const char *value; + if (!git_configset_get_value(cs, key, &value)) { + *dest = git_config_bool_or_int(key, value, is_bool); + return 0; + } else + return 1; +} + +int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest) +{ + const char *value; + if (!git_configset_get_value(cs, key, &value)) { + *dest = git_config_maybe_bool(key, value); + if (*dest == -1) + return -1; + return 0; + } else + return 1; +} + +int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest) +{ + const char *value; + if (!git_configset_get_value(cs, key, &value)) + return git_config_pathname(dest, key, value); + else + return 1; +} + +static void git_config_check_init(void) +{ + if (the_config_set.hash_initialized) + return; + git_configset_init(&the_config_set); + git_config_raw(config_set_callback, &the_config_set); +} + +void git_config_clear(void) +{ + if (!the_config_set.hash_initialized) + return; + git_configset_clear(&the_config_set); +} + +int git_config_get_value(const char *key, const char **value) +{ + git_config_check_init(); + return git_configset_get_value(&the_config_set, key, value); +} + +const struct string_list *git_config_get_value_multi(const char *key) +{ + git_config_check_init(); + return git_configset_get_value_multi(&the_config_set, key); +} + +int git_config_get_string_const(const char *key, const char **dest) +{ + int ret; + git_config_check_init(); + ret = git_configset_get_string_const(&the_config_set, key, dest); + if (ret < 0) + git_die_config(key, NULL); + return ret; +} + +int git_config_get_string(const char *key, char **dest) +{ + git_config_check_init(); + return git_config_get_string_const(key, (const char **)dest); +} + +int git_config_get_int(const char *key, int *dest) +{ + git_config_check_init(); + return git_configset_get_int(&the_config_set, key, dest); +} + +int git_config_get_ulong(const char *key, unsigned long *dest) +{ + git_config_check_init(); + return git_configset_get_ulong(&the_config_set, key, dest); +} + +int git_config_get_bool(const char *key, int *dest) +{ + git_config_check_init(); + return git_configset_get_bool(&the_config_set, key, dest); +} + +int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest) +{ + git_config_check_init(); + return git_configset_get_bool_or_int(&the_config_set, key, is_bool, dest); +} + +int git_config_get_maybe_bool(const char *key, int *dest) +{ + git_config_check_init(); + return git_configset_get_maybe_bool(&the_config_set, key, dest); +} + +int git_config_get_pathname(const char *key, const char **dest) +{ + int ret; + git_config_check_init(); + ret = git_configset_get_pathname(&the_config_set, key, dest); + if (ret < 0) + git_die_config(key, NULL); + return ret; +} + +NORETURN +void git_die_config_linenr(const char *key, const char *filename, int linenr) +{ + if (!filename) + die(_("unable to parse '%s' from command-line config"), key); + else + die(_("bad config variable '%s' in file '%s' at line %d"), + key, filename, linenr); +} + +NORETURN __attribute__((format(printf, 2, 3))) +void git_die_config(const char *key, const char *err, ...) +{ + const struct string_list *values; + struct key_value_info *kv_info; + + if (err) { + va_list params; + va_start(params, err); + vreportf("error: ", err, params); + va_end(params); + } + values = git_config_get_value_multi(key); + kv_info = values->items[values->nr - 1].util; + git_die_config_linenr(key, kv_info->filename, kv_info->linenr); } /* @@ -1246,7 +1622,7 @@ static int store_aux(const char *key, const char *value, void *cb) case KEY_SEEN: if (matches(key, value)) { if (store.seen == 1 && store.multi_replace == 0) { - warning("%s has multiple values", key); + warning(_("%s has multiple values"), key); } ALLOC_GROW(store.offset, store.seen + 1, @@ -1637,8 +2013,8 @@ int git_config_set_multivar_in_file(const char *config_filename, MAP_PRIVATE, in_fd, 0); close(in_fd); - if (fchmod(fd, st.st_mode & 07777) < 0) { - error("fchmod on %s failed: %s", + if (chmod(lock->filename, st.st_mode & 07777) < 0) { + error("chmod on %s failed: %s", lock->filename, strerror(errno)); ret = CONFIG_NO_WRITE; goto out_free; @@ -1708,6 +2084,9 @@ int git_config_set_multivar_in_file(const char *config_filename, lock = NULL; ret = 0; + /* Invalidate the config cache */ + git_config_clear(); + out_free: if (lock) rollback_lock_file(lock); @@ -1816,8 +2195,8 @@ int git_config_rename_section_in_file(const char *config_filename, fstat(fileno(config_file), &st); - if (fchmod(out_fd, st.st_mode & 07777) < 0) { - ret = error("fchmod on %s failed: %s", + if (chmod(lock->filename, st.st_mode & 07777) < 0) { + ret = error("chmod on %s failed: %s", lock->filename, strerror(errno)); goto out; } diff --git a/config.mak.uname b/config.mak.uname index 1ae675b053..a2f380fd8d 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -34,6 +34,7 @@ ifeq ($(uname_S),Linux) HAVE_PATHS_H = YesPlease LIBC_CONTAINS_LIBINTL = YesPlease HAVE_DEV_TTY = YesPlease + HAVE_CLOCK_GETTIME = YesPlease endif ifeq ($(uname_S),GNU/kFreeBSD) HAVE_ALLOCA_H = YesPlease @@ -88,8 +89,13 @@ ifeq ($(uname_S),Darwin) NEEDS_CRYPTO_WITH_SSL = YesPlease NEEDS_SSL_WITH_CRYPTO = YesPlease NEEDS_LIBICONV = YesPlease + # Note: $(uname_R) gives us the underlying Darwin version. + # - MacOS 10.0.* and MacOS 10.1.0 = Darwin 1.* + # - MacOS 10.x.* = Darwin (x+4).* for (1 <= x) + # i.e. "begins with [15678] and a dot" means "10.4.* or older". ifeq ($(shell expr "$(uname_R)" : '[15678]\.'),2) OLD_ICONV = UnfortunatelyYes + NO_APPLE_COMMON_CRYPTO = YesPlease endif ifeq ($(shell expr "$(uname_R)" : '[15]\.'),2) NO_STRLCPY = YesPlease @@ -326,7 +332,6 @@ ifeq ($(uname_S),Windows) NO_IPV6 = YesPlease NO_UNIX_SOCKETS = YesPlease NO_SETENV = YesPlease - NO_UNSETENV = YesPlease NO_STRCASESTR = YesPlease NO_STRLCPY = YesPlease NO_MEMMEM = YesPlease @@ -354,6 +359,7 @@ ifeq ($(uname_S),Windows) NO_POSIX_GOODIES = UnfortunatelyYes NATIVE_CRLF = YesPlease DEFAULT_HELP_FORMAT = html + NO_D_INO_IN_DIRENT = YesPlease CC = compat/vcbuild/scripts/clink.pl AR = compat/vcbuild/scripts/lib.pl @@ -478,7 +484,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_SYMLINK_HEAD = YesPlease NO_UNIX_SOCKETS = YesPlease NO_SETENV = YesPlease - NO_UNSETENV = YesPlease NO_STRCASESTR = YesPlease NO_STRLCPY = YesPlease NO_MEMMEM = YesPlease @@ -503,6 +508,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_INET_NTOP = YesPlease NO_POSIX_GOODIES = UnfortunatelyYes DEFAULT_HELP_FORMAT = html + NO_D_INO_IN_DIRENT = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -D_USE_32BIT_TIME_T -DNOGDI -Icompat -Icompat/win32 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/winansi.o \ diff --git a/connect.c b/connect.c index 94a6650246..d47d0ec604 100644 --- a/connect.c +++ b/connect.c @@ -13,28 +13,24 @@ static char *server_capabilities; static const char *parse_feature_value(const char *, const char *, int *); -static int check_ref(const char *name, int len, unsigned int flags) +static int check_ref(const char *name, unsigned int flags) { if (!flags) return 1; - if (len < 5 || memcmp(name, "refs/", 5)) + if (!skip_prefix(name, "refs/", &name)) return 0; - /* Skip the "refs/" part */ - name += 5; - len -= 5; - /* REF_NORMAL means that we don't want the magic fake tag refs */ if ((flags & REF_NORMAL) && check_refname_format(name, 0)) return 0; /* REF_HEADS means that we want regular branch heads */ - if ((flags & REF_HEADS) && !memcmp(name, "heads/", 6)) + if ((flags & REF_HEADS) && starts_with(name, "heads/")) return 1; /* REF_TAGS means that we want tags */ - if ((flags & REF_TAGS) && !memcmp(name, "tags/", 5)) + if ((flags & REF_TAGS) && starts_with(name, "tags/")) return 1; /* All type bits clear means that we are ok with anything */ @@ -43,7 +39,7 @@ static int check_ref(const char *name, int len, unsigned int flags) int check_ref_type(const struct ref *ref, int flags) { - return check_ref(ref->name, strlen(ref->name), flags); + return check_ref(ref->name, flags); } static void die_initial_contact(int got_at_least_one_head) @@ -64,9 +60,7 @@ static void parse_one_symref_info(struct string_list *symref, const char *val, i if (!len) return; /* just "symref" */ /* e.g. "symref=HEAD:refs/heads/master" */ - sym = xmalloc(len + 1); - memcpy(sym, val, len); - sym[len] = '\0'; + sym = xmemdupz(val, len); target = strchr(sym, ':'); if (!target) /* just "symref=something" */ @@ -129,6 +123,7 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len, char *name; int len, name_len; char *buffer = packet_buffer; + const char *arg; len = packet_read(in, &src_buf, &src_len, packet_buffer, sizeof(packet_buffer), @@ -140,12 +135,12 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len, if (!len) break; - if (len > 4 && starts_with(buffer, "ERR ")) - die("remote error: %s", buffer + 4); + if (len > 4 && skip_prefix(buffer, "ERR ", &arg)) + die("remote error: %s", arg); - if (len == 48 && starts_with(buffer, "shallow ")) { - if (get_sha1_hex(buffer + 8, old_sha1)) - die("protocol error: expected shallow sha-1, got '%s'", buffer + 8); + if (len == 48 && skip_prefix(buffer, "shallow ", &arg)) { + if (get_sha1_hex(arg, old_sha1)) + die("protocol error: expected shallow sha-1, got '%s'", arg); if (!shallow_points) die("repository on the other end cannot be shallow"); sha1_array_append(shallow_points, old_sha1); @@ -168,7 +163,7 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len, continue; } - if (!check_ref(name, name_len, flags)) + if (!check_ref(name, flags)) continue; ref = alloc_ref(buffer + 41); hashcpy(ref->old_sha1, old_sha1); @@ -538,7 +533,8 @@ static struct child_process *git_proxy_connect(int fd[2], char *host) get_host_and_port(&host, &port); - proxy = xcalloc(1, sizeof(*proxy)); + proxy = xmalloc(sizeof(*proxy)); + child_process_init(proxy); argv_array_push(&proxy->args, git_proxy_command); argv_array_push(&proxy->args, host); argv_array_push(&proxy->args, port); @@ -640,7 +636,7 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host, return protocol; } -static struct child_process no_fork; +static struct child_process no_fork = CHILD_PROCESS_INIT; /* * This returns a dummy child_process if the transport protocol does not @@ -695,7 +691,8 @@ struct child_process *git_connect(int fd[2], const char *url, target_host, 0); free(target_host); } else { - conn = xcalloc(1, sizeof(*conn)); + conn = xmalloc(sizeof(*conn)); + child_process_init(conn); strbuf_addstr(&cmd, prog); strbuf_addch(&cmd, ' '); diff --git a/connected.c b/connected.c index be0253e21b..299c56090b 100644 --- a/connected.c +++ b/connected.c @@ -25,12 +25,13 @@ static int check_everything_connected_real(sha1_iterate_fn fn, struct transport *transport, const char *shallow_file) { - struct child_process rev_list; + struct child_process rev_list = CHILD_PROCESS_INIT; const char *argv[9]; char commit[41]; unsigned char sha1[20]; int err = 0, ac = 0; struct packed_git *new_pack = NULL; + size_t base_len; if (fn(cb_data, sha1)) return err; @@ -38,10 +39,9 @@ static int check_everything_connected_real(sha1_iterate_fn fn, if (transport && transport->smart_options && transport->smart_options->self_contained_and_connected && transport->pack_lockfile && - ends_with(transport->pack_lockfile, ".keep")) { + strip_suffix(transport->pack_lockfile, ".keep", &base_len)) { struct strbuf idx_file = STRBUF_INIT; - strbuf_addstr(&idx_file, transport->pack_lockfile); - strbuf_setlen(&idx_file, idx_file.len - 5); /* ".keep" */ + strbuf_add(&idx_file, transport->pack_lockfile, base_len); strbuf_addstr(&idx_file, ".idx"); new_pack = add_packed_git(idx_file.buf, idx_file.len, 1); strbuf_release(&idx_file); @@ -60,7 +60,6 @@ static int check_everything_connected_real(sha1_iterate_fn fn, argv[ac++] = "--quiet"; argv[ac] = NULL; - memset(&rev_list, 0, sizeof(rev_list)); rev_list.argv = argv; rev_list.git_cmd = 1; rev_list.in = -1; diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 7a6e1d797a..06bf262087 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1621,12 +1621,33 @@ _git_pull () __git_push_recurse_submodules="check on-demand" +__git_complete_force_with_lease () +{ + local cur_=$1 + + case "$cur_" in + --*=) + ;; + *:*) + __gitcomp_nl "$(__git_refs)" "" "${cur_#*:}" + ;; + *) + __gitcomp_nl "$(__git_refs)" "" "$cur_" + ;; + esac +} + _git_push () { case "$prev" in --repo) __gitcomp_nl "$(__git_remotes)" return + ;; + --recurse-submodules) + __gitcomp "$__git_push_recurse_submodules" + return + ;; esac case "$cur" in --repo=*) @@ -1637,11 +1658,16 @@ _git_push () __gitcomp "$__git_push_recurse_submodules" "" "${cur##--recurse-submodules=}" return ;; + --force-with-lease=*) + __git_complete_force_with_lease "${cur##--force-with-lease=}" + return + ;; --*) __gitcomp " --all --mirror --tags --dry-run --force --verbose + --quiet --prune --delete --follow-tags --receive-pack= --repo= --set-upstream - --recurse-submodules= + --force-with-lease --force-with-lease= --recurse-submodules= " return ;; diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh index 9d684b10a6..c5473dc8db 100644 --- a/contrib/completion/git-prompt.sh +++ b/contrib/completion/git-prompt.sh @@ -468,7 +468,8 @@ __git_ps1 () fi fi if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ] && - [ -r "$g/refs/stash" ]; then + git rev-parse --verify --quiet refs/stash >/dev/null + then s="$" fi diff --git a/contrib/convert-grafts-to-replace-refs.sh b/contrib/convert-grafts-to-replace-refs.sh new file mode 100755 index 0000000000..0cbc917b8c --- /dev/null +++ b/contrib/convert-grafts-to-replace-refs.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +# You should execute this script in the repository where you +# want to convert grafts to replace refs. + +GRAFTS_FILE="${GIT_DIR:-.git}/info/grafts" + +. $(git --exec-path)/git-sh-setup + +test -f "$GRAFTS_FILE" || die "Could not find graft file: '$GRAFTS_FILE'" + +grep '^[^# ]' "$GRAFTS_FILE" | +while read definition +do + if test -n "$definition" + then + echo "Converting: $definition" + git replace --graft $definition || + die "Conversion failed for: $definition" + fi +done + +mv "$GRAFTS_FILE" "$GRAFTS_FILE.bak" || + die "Could not rename '$GRAFTS_FILE' to '$GRAFTS_FILE.bak'" + +echo "Success!" +echo "All the grafts in '$GRAFTS_FILE' have been converted to replace refs!" +echo "The grafts file '$GRAFTS_FILE' has been renamed: '$GRAFTS_FILE.bak'" diff --git a/contrib/convert-objects/git-convert-objects.txt b/contrib/convert-objects/git-convert-objects.txt index 0565d83fc4..f871880cfb 100644 --- a/contrib/convert-objects/git-convert-objects.txt +++ b/contrib/convert-objects/git-convert-objects.txt @@ -26,4 +26,4 @@ Documentation by David Greaves, Junio C Hamano and the git-list . GIT --- -Part of the gitlink:git[7] suite +Part of the linkgit:git[7] suite diff --git a/contrib/gitview/gitview.txt b/contrib/gitview/gitview.txt index 9e12f97842..7b5f9002b9 100644 --- a/contrib/gitview/gitview.txt +++ b/contrib/gitview/gitview.txt @@ -28,7 +28,7 @@ OPTIONS :: - All the valid option for gitlink:git-rev-list[1]. + All the valid option for linkgit:git-rev-list[1]. Key Bindings ------------ diff --git a/contrib/subtree/Makefile b/contrib/subtree/Makefile index d888d45161..c2bd703ee3 100644 --- a/contrib/subtree/Makefile +++ b/contrib/subtree/Makefile @@ -1,3 +1,6 @@ +# The default target of this Makefile is... +all:: + -include ../../config.mak.autogen -include ../../config.mak @@ -18,6 +21,11 @@ RM ?= rm -f ASCIIDOC = asciidoc XMLTO = xmlto +ifndef SHELL_PATH + SHELL_PATH = /bin/sh +endif +SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) + ASCIIDOC_CONF = ../../Documentation/asciidoc.conf MANPAGE_XSL = ../../Documentation/manpage-normal.xsl @@ -29,10 +37,11 @@ GIT_SUBTREE_XML := git-subtree.xml GIT_SUBTREE_TXT := git-subtree.txt GIT_SUBTREE_HTML := git-subtree.html -all: $(GIT_SUBTREE) +all:: $(GIT_SUBTREE) $(GIT_SUBTREE): $(GIT_SUBTREE_SH) - cp $< $@ && chmod +x $@ + sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' $< >$@ + chmod +x $@ doc: $(GIT_SUBTREE_DOC) $(GIT_SUBTREE_HTML) diff --git a/contrib/svn-fe/Makefile b/contrib/svn-fe/Makefile index 360d8da417..e8651aaf4b 100644 --- a/contrib/svn-fe/Makefile +++ b/contrib/svn-fe/Makefile @@ -1,18 +1,58 @@ all:: svn-fe$X -CC = gcc +CC = cc RM = rm -f MV = mv CFLAGS = -g -O2 -Wall LDFLAGS = -ALL_CFLAGS = $(CFLAGS) -ALL_LDFLAGS = $(LDFLAGS) -EXTLIBS = +EXTLIBS = -lz + +include ../../config.mak.uname +-include ../../config.mak.autogen +-include ../../config.mak + +ifeq ($(uname_S),Darwin) + ifndef NO_FINK + ifeq ($(shell test -d /sw/lib && echo y),y) + CFLAGS += -I/sw/include + LDFLAGS += -L/sw/lib + endif + endif + ifndef NO_DARWIN_PORTS + ifeq ($(shell test -d /opt/local/lib && echo y),y) + CFLAGS += -I/opt/local/include + LDFLAGS += -L/opt/local/lib + endif + endif +endif + +ifndef NO_OPENSSL + EXTLIBS += -lssl + ifdef NEEDS_CRYPTO_WITH_SSL + EXTLIBS += -lcrypto + endif +endif + +ifndef NO_PTHREADS + CFLAGS += $(PTHREADS_CFLAGS) + EXTLIBS += $(PTHREAD_LIBS) +endif + +ifdef HAVE_CLOCK_GETTIME + CFLAGS += -DHAVE_CLOCK_GETTIME + EXTLIBS += -lrt +endif + +ifdef NEEDS_LIBICONV + EXTLIBS += -liconv +endif GIT_LIB = ../../libgit.a VCSSVN_LIB = ../../vcs-svn/lib.a -LIBS = $(VCSSVN_LIB) $(GIT_LIB) $(EXTLIBS) +XDIFF_LIB = ../../xdiff/lib.a + +LIBS = $(VCSSVN_LIB) $(GIT_LIB) $(XDIFF_LIB) QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir QUIET_SUBDIR1 = @@ -33,12 +73,11 @@ ifndef V endif endif -svn-fe$X: svn-fe.o $(VCSSVN_LIB) $(GIT_LIB) - $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ svn-fe.o \ - $(ALL_LDFLAGS) $(LIBS) +svn-fe$X: svn-fe.o $(VCSSVN_LIB) $(XDIFF_LIB) $(GIT_LIB) + $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(EXTLIBS) -o $@ svn-fe.o $(LIBS) svn-fe.o: svn-fe.c ../../vcs-svn/svndump.h - $(QUIET_CC)$(CC) -I../../vcs-svn -o $*.o -c $(ALL_CFLAGS) $< + $(QUIET_CC)$(CC) $(CFLAGS) -I../../vcs-svn -o $*.o -c $< svn-fe.html: svn-fe.txt $(QUIET_SUBDIR0)../../Documentation $(QUIET_SUBDIR1) \ @@ -54,6 +93,9 @@ svn-fe.1: svn-fe.txt ../../vcs-svn/lib.a: FORCE $(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) vcs-svn/lib.a +../../xdiff/lib.a: FORCE + $(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) xdiff/lib.a + ../../libgit.a: FORCE $(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) libgit.a diff --git a/convert.c b/convert.c index ab80b72357..aa7a139bcf 100644 --- a/convert.c +++ b/convert.c @@ -321,7 +321,7 @@ static int filter_buffer(int in, int out, void *data) /* * Spawn cmd and feed the buffer contents through its stdin. */ - struct child_process child_process; + struct child_process child_process = CHILD_PROCESS_INIT; struct filter_params *params = (struct filter_params *)data; int write_err, status; const char *argv[] = { NULL, NULL }; @@ -344,7 +344,6 @@ static int filter_buffer(int in, int out, void *data) argv[0] = cmd.buf; - memset(&child_process, 0, sizeof(child_process)); child_process.argv = argv; child_process.use_shell = 1; child_process.in = -1; @@ -1121,9 +1120,9 @@ static int is_foreign_ident(const char *str) { int i; - if (!starts_with(str, "$Id: ")) + if (!skip_prefix(str, "$Id: ", &str)) return 0; - for (i = 5; str[i]; i++) { + for (i = 0; str[i]; i++) { if (isspace(str[i]) && str[i+1] != '$') return 1; } diff --git a/credential-cache--daemon.c b/credential-cache--daemon.c index 390f194252..3b370ca5e5 100644 --- a/credential-cache--daemon.c +++ b/credential-cache--daemon.c @@ -109,14 +109,12 @@ static int read_request(FILE *fh, struct credential *c, const char *p; strbuf_getline(&item, fh, '\n'); - p = skip_prefix(item.buf, "action="); - if (!p) + if (!skip_prefix(item.buf, "action=", &p)) return error("client sent bogus action line: %s", item.buf); strbuf_addstr(action, p); strbuf_getline(&item, fh, '\n'); - p = skip_prefix(item.buf, "timeout="); - if (!p) + if (!skip_prefix(item.buf, "timeout=", &p)) return error("client sent bogus timeout line: %s", item.buf); *timeout = atoi(p); diff --git a/credential-cache.c b/credential-cache.c index 9a03792c7d..8689a1519a 100644 --- a/credential-cache.c +++ b/credential-cache.c @@ -37,12 +37,11 @@ static int send_request(const char *socket, const struct strbuf *out) static void spawn_daemon(const char *socket) { - struct child_process daemon; + struct child_process daemon = CHILD_PROCESS_INIT; const char *argv[] = { NULL, NULL, NULL }; char buf[128]; int r; - memset(&daemon, 0, sizeof(daemon)); argv[0] = "git-credential-cache--daemon"; argv[1] = socket; daemon.argv = argv; diff --git a/credential.c b/credential.c index e54753c75d..1886ea50b3 100644 --- a/credential.c +++ b/credential.c @@ -40,8 +40,7 @@ static int credential_config_callback(const char *var, const char *value, struct credential *c = data; const char *key, *dot; - key = skip_prefix(var, "credential."); - if (!key) + if (!skip_prefix(var, "credential.", &key)) return 0; if (!value) @@ -206,11 +205,10 @@ static int run_credential_helper(struct credential *c, const char *cmd, int want_output) { - struct child_process helper; + struct child_process helper = CHILD_PROCESS_INIT; const char *argv[] = { NULL, NULL }; FILE *fp; - memset(&helper, 0, sizeof(helper)); argv[0] = cmd; helper.argv = argv; helper.use_shell = 1; diff --git a/daemon.c b/daemon.c index f9c63e9613..4dcfff9352 100644 --- a/daemon.c +++ b/daemon.c @@ -39,8 +39,8 @@ static int strict_paths; static int export_all_trees; /* Take all paths relative to this one if non-NULL */ -static char *base_path; -static char *interpolated_path; +static const char *base_path; +static const char *interpolated_path; static int base_path_relaxed; /* Flag indicating client sent extra args. */ @@ -106,12 +106,12 @@ static void NORETURN daemon_die(const char *err, va_list params) exit(1); } -static const char *path_ok(char *directory) +static const char *path_ok(const char *directory) { static char rpath[PATH_MAX]; static char interp_path[PATH_MAX]; const char *path; - char *dir; + const char *dir; dir = directory; @@ -131,7 +131,7 @@ static const char *path_ok(char *directory) * "~alice/%s/foo". */ int namlen, restlen = strlen(dir); - char *slash = strchr(dir, '/'); + const char *slash = strchr(dir, '/'); if (!slash) slash = dir + restlen; namlen = slash - dir; @@ -230,21 +230,6 @@ struct daemon_service { int overridable; }; -static struct daemon_service *service_looking_at; -static int service_enabled; - -static int git_daemon_config(const char *var, const char *value, void *cb) -{ - if (starts_with(var, "daemon.") && - !strcmp(var + 7, service_looking_at->config_name)) { - service_enabled = git_config_bool(var, value); - return 0; - } - - /* we are not interested in parsing any other configuration here */ - return 0; -} - static int daemon_error(const char *dir, const char *msg) { if (!informative_errors) @@ -253,11 +238,11 @@ static int daemon_error(const char *dir, const char *msg) return -1; } -static char *access_hook; +static const char *access_hook; static int run_access_hook(struct daemon_service *service, const char *dir, const char *path) { - struct child_process child; + struct child_process child = CHILD_PROCESS_INIT; struct strbuf buf = STRBUF_INIT; const char *argv[8]; const char **arg = argv; @@ -275,7 +260,6 @@ static int run_access_hook(struct daemon_service *service, const char *dir, cons *arg = NULL; #undef STRARG - memset(&child, 0, sizeof(child)); child.use_shell = 1; child.argv = argv; child.no_stdin = 1; @@ -318,10 +302,11 @@ static int run_access_hook(struct daemon_service *service, const char *dir, cons return -1; } -static int run_service(char *dir, struct daemon_service *service) +static int run_service(const char *dir, struct daemon_service *service) { const char *path; int enabled = service->enabled; + struct strbuf var = STRBUF_INIT; loginfo("Request %s for '%s'", service->name, dir); @@ -352,11 +337,9 @@ static int run_service(char *dir, struct daemon_service *service) } if (service->overridable) { - service_looking_at = service; - service_enabled = -1; - git_config(git_daemon_config, NULL); - if (0 <= service_enabled) - enabled = service_enabled; + strbuf_addf(&var, "daemon.%s", service->config_name); + git_config_get_bool(var.buf, &enabled); + strbuf_release(&var); } if (!enabled) { logerror("'%s': service not enabled for '%s'", @@ -404,9 +387,8 @@ static void copy_to_log(int fd) static int run_service_command(const char **argv) { - struct child_process cld; + struct child_process cld = CHILD_PROCESS_INIT; - memset(&cld, 0, sizeof(cld)); cld.argv = argv; cld.git_cmd = 1; cld.err = -1; @@ -624,15 +606,16 @@ static int execute(void) for (i = 0; i < ARRAY_SIZE(daemon_service); i++) { struct daemon_service *s = &(daemon_service[i]); - int namelen = strlen(s->name); - if (starts_with(line, "git-") && - !strncmp(s->name, line + 4, namelen) && - line[namelen + 4] == ' ') { + const char *arg; + + if (skip_prefix(line, "git-", &arg) && + skip_prefix(arg, s->name, &arg) && + *arg++ == ' ') { /* * Note: The directory here is probably context sensitive, * and might depend on the actual service being performed. */ - return run_service(line + namelen + 5, s); + return run_service(arg, s); } } @@ -730,7 +713,7 @@ static void check_dead_children(void) static char **cld_argv; static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen) { - struct child_process cld = { NULL }; + struct child_process cld = CHILD_PROCESS_INIT; char addrbuf[300] = "REMOTE_ADDR=", portbuf[300]; char *env[] = { addrbuf, portbuf, NULL }; @@ -775,7 +758,6 @@ static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen) logerror("unable to fork"); else add_child(&cld, addr, addrlen); - close(incoming); } static void child_handler(int signo) @@ -1133,16 +1115,17 @@ int main(int argc, char **argv) for (i = 1; i < argc; i++) { char *arg = argv[i]; + const char *v; - if (starts_with(arg, "--listen=")) { - string_list_append(&listen_addr, xstrdup_tolower(arg + 9)); + if (skip_prefix(arg, "--listen=", &v)) { + string_list_append(&listen_addr, xstrdup_tolower(v)); continue; } - if (starts_with(arg, "--port=")) { + if (skip_prefix(arg, "--port=", &v)) { char *end; unsigned long n; - n = strtoul(arg+7, &end, 0); - if (arg[7] && !*end) { + n = strtoul(v, &end, 0); + if (*v && !*end) { listen_port = n; continue; } @@ -1168,20 +1151,20 @@ int main(int argc, char **argv) export_all_trees = 1; continue; } - if (starts_with(arg, "--access-hook=")) { - access_hook = arg + 14; + if (skip_prefix(arg, "--access-hook=", &v)) { + access_hook = v; continue; } - if (starts_with(arg, "--timeout=")) { - timeout = atoi(arg+10); + if (skip_prefix(arg, "--timeout=", &v)) { + timeout = atoi(v); continue; } - if (starts_with(arg, "--init-timeout=")) { - init_timeout = atoi(arg+15); + if (skip_prefix(arg, "--init-timeout=", &v)) { + init_timeout = atoi(v); continue; } - if (starts_with(arg, "--max-connections=")) { - max_connections = atoi(arg+18); + if (skip_prefix(arg, "--max-connections=", &v)) { + max_connections = atoi(v); if (max_connections < 0) max_connections = 0; /* unlimited */ continue; @@ -1190,16 +1173,16 @@ int main(int argc, char **argv) strict_paths = 1; continue; } - if (starts_with(arg, "--base-path=")) { - base_path = arg+12; + if (skip_prefix(arg, "--base-path=", &v)) { + base_path = v; continue; } if (!strcmp(arg, "--base-path-relaxed")) { base_path_relaxed = 1; continue; } - if (starts_with(arg, "--interpolated-path=")) { - interpolated_path = arg+20; + if (skip_prefix(arg, "--interpolated-path=", &v)) { + interpolated_path = v; continue; } if (!strcmp(arg, "--reuseaddr")) { @@ -1210,12 +1193,12 @@ int main(int argc, char **argv) user_path = ""; continue; } - if (starts_with(arg, "--user-path=")) { - user_path = arg + 12; + if (skip_prefix(arg, "--user-path=", &v)) { + user_path = v; continue; } - if (starts_with(arg, "--pid-file=")) { - pid_file = arg + 11; + if (skip_prefix(arg, "--pid-file=", &v)) { + pid_file = v; continue; } if (!strcmp(arg, "--detach")) { @@ -1223,28 +1206,28 @@ int main(int argc, char **argv) log_syslog = 1; continue; } - if (starts_with(arg, "--user=")) { - user_name = arg + 7; + if (skip_prefix(arg, "--user=", &v)) { + user_name = v; continue; } - if (starts_with(arg, "--group=")) { - group_name = arg + 8; + if (skip_prefix(arg, "--group=", &v)) { + group_name = v; continue; } - if (starts_with(arg, "--enable=")) { - enable_service(arg + 9, 1); + if (skip_prefix(arg, "--enable=", &v)) { + enable_service(v, 1); continue; } - if (starts_with(arg, "--disable=")) { - enable_service(arg + 10, 0); + if (skip_prefix(arg, "--disable=", &v)) { + enable_service(v, 0); continue; } - if (starts_with(arg, "--allow-override=")) { - make_service_overridable(arg + 17, 1); + if (skip_prefix(arg, "--allow-override=", &v)) { + make_service_overridable(v, 1); continue; } - if (starts_with(arg, "--forbid-override=")) { - make_service_overridable(arg + 18, 0); + if (skip_prefix(arg, "--forbid-override=", &v)) { + make_service_overridable(v, 0); continue; } if (!strcmp(arg, "--informative-errors")) { diff --git a/date.c b/date.c index 782de95d90..59dfe579c6 100644 --- a/date.c +++ b/date.c @@ -200,7 +200,16 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode) tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, tz); - else if (mode == DATE_RFC2822) + else if (mode == DATE_ISO8601_STRICT) { + char sign = (tz >= 0) ? '+' : '-'; + tz = abs(tz); + strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", + tm->tm_year + 1900, + tm->tm_mon + 1, + tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, + sign, tz / 100, tz % 100); + } else if (mode == DATE_RFC2822) strbuf_addf(&timebuf, "%.3s, %d %.3s %d %02d:%02d:%02d %+05d", weekday_names[tm->tm_wday], tm->tm_mday, month_names[tm->tm_mon], tm->tm_year + 1900, @@ -605,7 +614,7 @@ static int match_tz(const char *date, int *offp) return end - date; } -static int date_string(unsigned long date, int offset, char *buf, int len) +static void date_string(unsigned long date, int offset, struct strbuf *buf) { int sign = '+'; @@ -613,7 +622,7 @@ static int date_string(unsigned long date, int offset, char *buf, int len) offset = -offset; sign = '-'; } - return snprintf(buf, len, "%lu %c%02d%02d", date, sign, offset / 60, offset % 60); + strbuf_addf(buf, "%lu %c%02d%02d", date, sign, offset / 60, offset % 60); } /* @@ -735,13 +744,14 @@ int parse_expiry_date(const char *date, unsigned long *timestamp) return errors; } -int parse_date(const char *date, char *result, int maxlen) +int parse_date(const char *date, struct strbuf *result) { unsigned long timestamp; int offset; if (parse_date_basic(date, ×tamp, &offset)) return -1; - return date_string(timestamp, offset, result, maxlen); + date_string(timestamp, offset, result); + return 0; } enum date_mode parse_date_format(const char *format) @@ -751,6 +761,9 @@ enum date_mode parse_date_format(const char *format) else if (!strcmp(format, "iso8601") || !strcmp(format, "iso")) return DATE_ISO8601; + else if (!strcmp(format, "iso8601-strict") || + !strcmp(format, "iso-strict")) + return DATE_ISO8601_STRICT; else if (!strcmp(format, "rfc2822") || !strcmp(format, "rfc")) return DATE_RFC2822; @@ -766,7 +779,7 @@ enum date_mode parse_date_format(const char *format) die("unknown date format %s", format); } -void datestamp(char *buf, int bufsize) +void datestamp(struct strbuf *out) { time_t now; int offset; @@ -776,7 +789,7 @@ void datestamp(char *buf, int bufsize) offset = tm_to_time_t(localtime(&now)) - now; offset /= 60; - date_string(now, offset, buf, bufsize); + date_string(now, offset, out); } /* diff --git a/decorate.c b/decorate.c index 7cb5d29a89..b2aac90c26 100644 --- a/decorate.c +++ b/decorate.c @@ -8,10 +8,7 @@ static unsigned int hash_obj(const struct object *obj, unsigned int n) { - unsigned int hash; - - memcpy(&hash, obj->sha1, sizeof(unsigned int)); - return hash % n; + return sha1hash(obj->sha1) % n; } static void *insert_decoration(struct decoration *n, const struct object *base, void *decoration) diff --git a/diff.c b/diff.c index bba9a558a6..d7a5c81bb8 100644 --- a/diff.c +++ b/diff.c @@ -52,23 +52,23 @@ static char diff_colors[][COLOR_MAXLEN] = { GIT_COLOR_NORMAL, /* FUNCINFO */ }; -static int parse_diff_color_slot(const char *var, int ofs) +static int parse_diff_color_slot(const char *var) { - if (!strcasecmp(var+ofs, "plain")) + if (!strcasecmp(var, "plain")) return DIFF_PLAIN; - if (!strcasecmp(var+ofs, "meta")) + if (!strcasecmp(var, "meta")) return DIFF_METAINFO; - if (!strcasecmp(var+ofs, "frag")) + if (!strcasecmp(var, "frag")) return DIFF_FRAGINFO; - if (!strcasecmp(var+ofs, "old")) + if (!strcasecmp(var, "old")) return DIFF_FILE_OLD; - if (!strcasecmp(var+ofs, "new")) + if (!strcasecmp(var, "new")) return DIFF_FILE_NEW; - if (!strcasecmp(var+ofs, "commit")) + if (!strcasecmp(var, "commit")) return DIFF_COMMIT; - if (!strcasecmp(var+ofs, "whitespace")) + if (!strcasecmp(var, "whitespace")) return DIFF_WHITESPACE; - if (!strcasecmp(var+ofs, "func")) + if (!strcasecmp(var, "func")) return DIFF_FUNCINFO; return -1; } @@ -231,6 +231,8 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) int git_diff_basic_config(const char *var, const char *value, void *cb) { + const char *name; + if (!strcmp(var, "diff.renamelimit")) { diff_rename_limit_default = git_config_int(var, value); return 0; @@ -239,8 +241,9 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) if (userdiff_config(var, value) < 0) return -1; - if (starts_with(var, "diff.color.") || starts_with(var, "color.diff.")) { - int slot = parse_diff_color_slot(var, 11); + if (skip_prefix(var, "diff.color.", &name) || + skip_prefix(var, "color.diff.", &name)) { + int slot = parse_diff_color_slot(name); if (slot < 0) return 0; if (!value) @@ -373,7 +376,7 @@ static unsigned long diff_filespec_size(struct diff_filespec *one) { if (!DIFF_FILE_VALID(one)) return 0; - diff_populate_filespec(one, 1); + diff_populate_filespec(one, CHECK_SIZE_ONLY); return one->size; } @@ -522,9 +525,9 @@ static void emit_hunk_header(struct emit_callback *ecbdata, ep += 2; /* skip over @@ */ /* The hunk header in fraginfo color */ - strbuf_add(&msgbuf, frag, strlen(frag)); + strbuf_addstr(&msgbuf, frag); strbuf_add(&msgbuf, line, ep - line); - strbuf_add(&msgbuf, reset, strlen(reset)); + strbuf_addstr(&msgbuf, reset); /* * trailing "\r\n" @@ -538,15 +541,15 @@ static void emit_hunk_header(struct emit_callback *ecbdata, if (*ep != ' ' && *ep != '\t') break; if (ep != cp) { - strbuf_add(&msgbuf, plain, strlen(plain)); + strbuf_addstr(&msgbuf, plain); strbuf_add(&msgbuf, cp, ep - cp); - strbuf_add(&msgbuf, reset, strlen(reset)); + strbuf_addstr(&msgbuf, reset); } if (ep < line + len) { - strbuf_add(&msgbuf, func, strlen(func)); + strbuf_addstr(&msgbuf, func); strbuf_add(&msgbuf, ep, line + len - ep); - strbuf_add(&msgbuf, reset, strlen(reset)); + strbuf_addstr(&msgbuf, reset); } strbuf_add(&msgbuf, line + len, org_len - len); @@ -1907,11 +1910,11 @@ static void show_dirstat(struct diff_options *options) diff_free_filespec_data(p->one); diff_free_filespec_data(p->two); } else if (DIFF_FILE_VALID(p->one)) { - diff_populate_filespec(p->one, 1); + diff_populate_filespec(p->one, CHECK_SIZE_ONLY); copied = added = 0; diff_free_filespec_data(p->one); } else if (DIFF_FILE_VALID(p->two)) { - diff_populate_filespec(p->two, 1); + diff_populate_filespec(p->two, CHECK_SIZE_ONLY); copied = 0; added = p->two->size; diff_free_filespec_data(p->two); @@ -2185,8 +2188,8 @@ int diff_filespec_is_binary(struct diff_filespec *one) one->is_binary = one->driver->binary; else { if (!one->data && DIFF_FILE_VALID(one)) - diff_populate_filespec(one, 0); - if (one->data) + diff_populate_filespec(one, CHECK_BINARY); + if (one->is_binary == -1 && one->data) one->is_binary = buffer_is_binary(one->data, one->size); if (one->is_binary == -1) @@ -2321,6 +2324,19 @@ static void builtin_diff(const char *name_a, } else if (!DIFF_OPT_TST(o, TEXT) && ( (!textconv_one && diff_filespec_is_binary(one)) || (!textconv_two && diff_filespec_is_binary(two)) )) { + if (!one->data && !two->data && + S_ISREG(one->mode) && S_ISREG(two->mode) && + !DIFF_OPT_TST(o, BINARY)) { + if (!hashcmp(one->sha1, two->sha1)) { + if (must_show_header) + fprintf(o->file, "%s", header.buf); + goto free_ab_and_return; + } + fprintf(o->file, "%s", header.buf); + fprintf(o->file, "%sBinary files %s and %s differ\n", + line_prefix, lbl[0], lbl[1]); + goto free_ab_and_return; + } if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) die("unable to read files to diff"); /* Quite common confusing case */ @@ -2341,6 +2357,7 @@ static void builtin_diff(const char *name_a, } else { /* Crazy xdl interfaces.. */ const char *diffopts = getenv("GIT_DIFF_OPTS"); + const char *v; xpparam_t xpp; xdemitconf_t xecfg; struct emit_callback ecbdata; @@ -2379,10 +2396,10 @@ static void builtin_diff(const char *name_a, xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags); if (!diffopts) ; - else if (starts_with(diffopts, "--unified=")) - xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10); - else if (starts_with(diffopts, "-u")) - xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10); + else if (skip_prefix(diffopts, "--unified=", &v)) + xecfg.ctxlen = strtoul(v, NULL, 10); + else if (skip_prefix(diffopts, "-u", &v)) + xecfg.ctxlen = strtoul(v, NULL, 10); if (o->word_diff) init_diff_words_data(&ecbdata, o, one, two); xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata, @@ -2664,8 +2681,9 @@ static int diff_populate_gitlink(struct diff_filespec *s, int size_only) * grab the data for the blob (or file) for our own in-core comparison. * diff_filespec has data and size fields for this purpose. */ -int diff_populate_filespec(struct diff_filespec *s, int size_only) +int diff_populate_filespec(struct diff_filespec *s, unsigned int flags) { + int size_only = flags & CHECK_SIZE_ONLY; int err = 0; /* * demote FAIL to WARN to allow inspecting the situation @@ -2720,6 +2738,11 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only) } if (size_only) return 0; + if ((flags & CHECK_BINARY) && + s->size > big_file_threshold && s->is_binary == -1) { + s->is_binary = 1; + return 0; + } fd = open(s->path, O_RDONLY); if (fd < 0) goto err_empty; @@ -2741,16 +2764,21 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only) } else { enum object_type type; - if (size_only) { + if (size_only || (flags & CHECK_BINARY)) { type = sha1_object_info(s->sha1, &s->size); if (type < 0) die("unable to read %s", sha1_to_hex(s->sha1)); - } else { - s->data = read_sha1_file(s->sha1, &type, &s->size); - if (!s->data) - die("unable to read %s", sha1_to_hex(s->sha1)); - s->should_free = 1; + if (size_only) + return 0; + if (s->size > big_file_threshold && s->is_binary == -1) { + s->is_binary = 1; + return 0; + } } + s->data = read_sha1_file(s->sha1, &type, &s->size); + if (!s->data) + die("unable to read %s", sha1_to_hex(s->sha1)); + s->should_free = 1; } return 0; } @@ -3391,12 +3419,10 @@ int parse_long_opt(const char *opt, const char **argv, const char **optarg) { const char *arg = argv[0]; - if (arg[0] != '-' || arg[1] != '-') + if (!skip_prefix(arg, "--", &arg)) return 0; - arg += strlen("--"); - if (!starts_with(arg, opt)) + if (!skip_prefix(arg, opt, &arg)) return 0; - arg += strlen(opt); if (*arg == '=') { /* stuck form: --option=value */ *optarg = arg + 1; return 1; @@ -3420,13 +3446,13 @@ static int stat_opt(struct diff_options *options, const char **av) int count = options->stat_count; int argcount = 1; - arg += strlen("--stat"); + if (!skip_prefix(arg, "--stat", &arg)) + die("BUG: stat option does not begin with --stat: %s", arg); end = (char *)arg; switch (*arg) { case '-': - if (starts_with(arg, "-width")) { - arg += strlen("-width"); + if (skip_prefix(arg, "-width", &arg)) { if (*arg == '=') width = strtoul(arg + 1, &end, 10); else if (!*arg && !av[1]) @@ -3435,8 +3461,7 @@ static int stat_opt(struct diff_options *options, const char **av) width = strtoul(av[1], &end, 10); argcount = 2; } - } else if (starts_with(arg, "-name-width")) { - arg += strlen("-name-width"); + } else if (skip_prefix(arg, "-name-width", &arg)) { if (*arg == '=') name_width = strtoul(arg + 1, &end, 10); else if (!*arg && !av[1]) @@ -3445,8 +3470,7 @@ static int stat_opt(struct diff_options *options, const char **av) name_width = strtoul(av[1], &end, 10); argcount = 2; } - } else if (starts_with(arg, "-graph-width")) { - arg += strlen("-graph-width"); + } else if (skip_prefix(arg, "-graph-width", &arg)) { if (*arg == '=') graph_width = strtoul(arg + 1, &end, 10); else if (!*arg && !av[1]) @@ -3455,8 +3479,7 @@ static int stat_opt(struct diff_options *options, const char **av) graph_width = strtoul(av[1], &end, 10); argcount = 2; } - } else if (starts_with(arg, "-count")) { - arg += strlen("-count"); + } else if (skip_prefix(arg, "-count", &arg)) { if (*arg == '=') count = strtoul(arg + 1, &end, 10); else if (!*arg && !av[1]) @@ -3609,17 +3632,17 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) options->output_format |= DIFF_FORMAT_SHORTSTAT; else if (!strcmp(arg, "-X") || !strcmp(arg, "--dirstat")) return parse_dirstat_opt(options, ""); - else if (starts_with(arg, "-X")) - return parse_dirstat_opt(options, arg + 2); - else if (starts_with(arg, "--dirstat=")) - return parse_dirstat_opt(options, arg + 10); + else if (skip_prefix(arg, "-X", &arg)) + return parse_dirstat_opt(options, arg); + else if (skip_prefix(arg, "--dirstat=", &arg)) + return parse_dirstat_opt(options, arg); else if (!strcmp(arg, "--cumulative")) return parse_dirstat_opt(options, "cumulative"); else if (!strcmp(arg, "--dirstat-by-file")) return parse_dirstat_opt(options, "files"); - else if (starts_with(arg, "--dirstat-by-file=")) { + else if (skip_prefix(arg, "--dirstat-by-file=", &arg)) { parse_dirstat_opt(options, "files"); - return parse_dirstat_opt(options, arg + 18); + return parse_dirstat_opt(options, arg); } else if (!strcmp(arg, "--check")) options->output_format |= DIFF_FORMAT_CHECKDIFF; @@ -3669,9 +3692,9 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) DIFF_OPT_CLR(options, RENAME_EMPTY); else if (!strcmp(arg, "--relative")) DIFF_OPT_SET(options, RELATIVE_NAME); - else if (starts_with(arg, "--relative=")) { + else if (skip_prefix(arg, "--relative=", &arg)) { DIFF_OPT_SET(options, RELATIVE_NAME); - options->prefix = arg + 11; + options->prefix = arg; } /* xdiff options */ @@ -3722,8 +3745,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) DIFF_OPT_CLR(options, FOLLOW_RENAMES); else if (!strcmp(arg, "--color")) options->use_color = 1; - else if (starts_with(arg, "--color=")) { - int value = git_config_colorbool(NULL, arg+8); + else if (skip_prefix(arg, "--color=", &arg)) { + int value = git_config_colorbool(NULL, arg); if (value < 0) return error("option `color' expects \"always\", \"auto\", or \"never\""); options->use_color = value; @@ -3734,29 +3757,28 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) options->use_color = 1; options->word_diff = DIFF_WORDS_COLOR; } - else if (starts_with(arg, "--color-words=")) { + else if (skip_prefix(arg, "--color-words=", &arg)) { options->use_color = 1; options->word_diff = DIFF_WORDS_COLOR; - options->word_regex = arg + 14; + options->word_regex = arg; } else if (!strcmp(arg, "--word-diff")) { if (options->word_diff == DIFF_WORDS_NONE) options->word_diff = DIFF_WORDS_PLAIN; } - else if (starts_with(arg, "--word-diff=")) { - const char *type = arg + 12; - if (!strcmp(type, "plain")) + else if (skip_prefix(arg, "--word-diff=", &arg)) { + if (!strcmp(arg, "plain")) options->word_diff = DIFF_WORDS_PLAIN; - else if (!strcmp(type, "color")) { + else if (!strcmp(arg, "color")) { options->use_color = 1; options->word_diff = DIFF_WORDS_COLOR; } - else if (!strcmp(type, "porcelain")) + else if (!strcmp(arg, "porcelain")) options->word_diff = DIFF_WORDS_PORCELAIN; - else if (!strcmp(type, "none")) + else if (!strcmp(arg, "none")) options->word_diff = DIFF_WORDS_NONE; else - die("bad --word-diff argument: %s", type); + die("bad --word-diff argument: %s", arg); } else if ((argcount = parse_long_opt("word-diff-regex", av, &optarg))) { if (options->word_diff == DIFF_WORDS_NONE) @@ -3779,13 +3801,13 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) else if (!strcmp(arg, "--ignore-submodules")) { DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG); handle_ignore_submodules_arg(options, "all"); - } else if (starts_with(arg, "--ignore-submodules=")) { + } else if (skip_prefix(arg, "--ignore-submodules=", &arg)) { DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG); - handle_ignore_submodules_arg(options, arg + 20); + handle_ignore_submodules_arg(options, arg); } else if (!strcmp(arg, "--submodule")) DIFF_OPT_SET(options, SUBMODULE_LOG); - else if (starts_with(arg, "--submodule=")) - return parse_submodule_opt(options, arg + 12); + else if (skip_prefix(arg, "--submodule=", &arg)) + return parse_submodule_opt(options, arg); /* misc options */ else if (!strcmp(arg, "-z")) @@ -3820,8 +3842,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) } else if (!strcmp(arg, "--abbrev")) options->abbrev = DEFAULT_ABBREV; - else if (starts_with(arg, "--abbrev=")) { - options->abbrev = strtoul(arg + 9, NULL, 10); + else if (skip_prefix(arg, "--abbrev=", &arg)) { + options->abbrev = strtoul(arg, NULL, 10); if (options->abbrev < MINIMUM_ABBREV) options->abbrev = MINIMUM_ABBREV; else if (40 < options->abbrev) @@ -3902,16 +3924,13 @@ static int diff_scoreopt_parse(const char *opt) cmd = *opt++; if (cmd == '-') { /* convert the long-form arguments into short-form versions */ - if (starts_with(opt, "break-rewrites")) { - opt += strlen("break-rewrites"); + if (skip_prefix(opt, "break-rewrites", &opt)) { if (*opt == 0 || *opt++ == '=') cmd = 'B'; - } else if (starts_with(opt, "find-copies")) { - opt += strlen("find-copies"); + } else if (skip_prefix(opt, "find-copies", &opt)) { if (*opt == 0 || *opt++ == '=') cmd = 'C'; - } else if (starts_with(opt, "find-renames")) { - opt += strlen("find-renames"); + } else if (skip_prefix(opt, "find-renames", &opt)) { if (*opt == 0 || *opt++ == '=') cmd = 'M'; } @@ -4693,8 +4712,8 @@ static int diff_filespec_check_stat_unmatch(struct diff_filepair *p) !DIFF_FILE_VALID(p->two) || (p->one->sha1_valid && p->two->sha1_valid) || (p->one->mode != p->two->mode) || - diff_populate_filespec(p->one, 1) || - diff_populate_filespec(p->two, 1) || + diff_populate_filespec(p->one, CHECK_SIZE_ONLY) || + diff_populate_filespec(p->two, CHECK_SIZE_ONLY) || (p->one->size != p->two->size) || !diff_filespec_is_identical(p->one, p->two)) /* (2) */ p->skip_stat_unmatch_result = 1; @@ -4936,7 +4955,7 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec, struct diff_tempfile *temp; const char *argv[3]; const char **arg = argv; - struct child_process child; + struct child_process child = CHILD_PROCESS_INIT; struct strbuf buf = STRBUF_INIT; int err = 0; @@ -4945,7 +4964,6 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec, *arg++ = temp->name; *arg = NULL; - memset(&child, 0, sizeof(child)); child.use_shell = 1; child.argv = argv; child.out = -1; diff --git a/diffcore-rename.c b/diffcore-rename.c index 749a35d2c2..4e132f1fdb 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -147,9 +147,11 @@ static int estimate_similarity(struct diff_filespec *src, * is a possible size - we really should have a flag to * say whether the size is valid or not!) */ - if (!src->cnt_data && diff_populate_filespec(src, 1)) + if (!src->cnt_data && + diff_populate_filespec(src, CHECK_SIZE_ONLY)) return 0; - if (!dst->cnt_data && diff_populate_filespec(dst, 1)) + if (!dst->cnt_data && + diff_populate_filespec(dst, CHECK_SIZE_ONLY)) return 0; max_size = ((src->size > dst->size) ? src->size : dst->size); @@ -242,14 +244,12 @@ struct file_similarity { static unsigned int hash_filespec(struct diff_filespec *filespec) { - unsigned int hash; if (!filespec->sha1_valid) { if (diff_populate_filespec(filespec, 0)) return 0; hash_sha1_file(filespec->data, filespec->size, "blob", filespec->sha1); } - memcpy(&hash, filespec->sha1, sizeof(hash)); - return hash; + return sha1hash(filespec->sha1); } static int find_identical_files(struct hashmap *srcs, @@ -259,15 +259,14 @@ static int find_identical_files(struct hashmap *srcs, int renames = 0; struct diff_filespec *target = rename_dst[dst_index].two; - struct file_similarity *p, *best, dst; + struct file_similarity *p, *best = NULL; int i = 100, best_score = -1; /* * Find the best source match for specified destination. */ - best = NULL; - hashmap_entry_init(&dst, hash_filespec(target)); - for (p = hashmap_get(srcs, &dst, NULL); p; p = hashmap_get_next(srcs, p)) { + p = hashmap_get_from_hash(srcs, hash_filespec(target), NULL); + for (; p; p = hashmap_get_next(srcs, p)) { int score; struct diff_filespec *source = p->filespec; diff --git a/diffcore.h b/diffcore.h index c876dac71a..33ea2de348 100644 --- a/diffcore.h +++ b/diffcore.h @@ -55,7 +55,9 @@ extern void free_filespec(struct diff_filespec *); extern void fill_filespec(struct diff_filespec *, const unsigned char *, int, unsigned short); -extern int diff_populate_filespec(struct diff_filespec *, int); +#define CHECK_SIZE_ONLY 1 +#define CHECK_BINARY 2 +extern int diff_populate_filespec(struct diff_filespec *, unsigned int); extern void diff_free_filespec_data(struct diff_filespec *); extern void diff_free_filespec_blob(struct diff_filespec *); extern int diff_filespec_is_binary(struct diff_filespec *); diff --git a/dir.c b/dir.c index e65888dfad..bd274a73f1 100644 --- a/dir.c +++ b/dir.c @@ -557,8 +557,7 @@ int add_excludes_from_file_to_list(const char *fname, buf = xrealloc(buf, size+1); buf[size++] = '\n'; } - } - else { + } else { size = xsize_t(st.st_size); if (size == 0) { close(fd); @@ -793,17 +792,19 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen) group = &dir->exclude_list_group[EXC_DIRS]; - /* Pop the exclude lists from the EXCL_DIRS exclude_list_group + /* + * Pop the exclude lists from the EXCL_DIRS exclude_list_group * which originate from directories not in the prefix of the - * path being checked. */ + * path being checked. + */ while ((stk = dir->exclude_stack) != NULL) { if (stk->baselen <= baselen && - !strncmp(dir->basebuf, base, stk->baselen)) + !strncmp(dir->basebuf.buf, base, stk->baselen)) break; el = &group->el[dir->exclude_stack->exclude_ix]; dir->exclude_stack = stk->prev; dir->exclude = NULL; - free((char *)el->src); /* see strdup() below */ + free((char *)el->src); /* see strbuf_detach() below */ clear_exclude_list(el); free(stk); group->nr--; @@ -813,8 +814,17 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen) if (dir->exclude) return; + /* + * Lazy initialization. All call sites currently just + * memset(dir, 0, sizeof(*dir)) before use. Changing all of + * them seems lots of work for little benefit. + */ + if (!dir->basebuf.buf) + strbuf_init(&dir->basebuf, PATH_MAX); + /* Read from the parent directories and push them down. */ current = stk ? stk->baselen : -1; + strbuf_setlen(&dir->basebuf, current < 0 ? 0 : current); while (current < baselen) { struct exclude_stack *stk = xcalloc(1, sizeof(*stk)); const char *cp; @@ -822,8 +832,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen) if (current < 0) { cp = base; current = 0; - } - else { + } else { cp = strchr(base + current + 1, '/'); if (!cp) die("oops in prep_exclude"); @@ -833,48 +842,47 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen) stk->baselen = cp - base; stk->exclude_ix = group->nr; el = add_exclude_list(dir, EXC_DIRS, NULL); - memcpy(dir->basebuf + current, base + current, - stk->baselen - current); + strbuf_add(&dir->basebuf, base + current, stk->baselen - current); + assert(stk->baselen == dir->basebuf.len); /* Abort if the directory is excluded */ if (stk->baselen) { int dt = DT_DIR; - dir->basebuf[stk->baselen - 1] = 0; + dir->basebuf.buf[stk->baselen - 1] = 0; dir->exclude = last_exclude_matching_from_lists(dir, - dir->basebuf, stk->baselen - 1, - dir->basebuf + current, &dt); - dir->basebuf[stk->baselen - 1] = '/'; + dir->basebuf.buf, stk->baselen - 1, + dir->basebuf.buf + current, &dt); + dir->basebuf.buf[stk->baselen - 1] = '/'; if (dir->exclude && dir->exclude->flags & EXC_FLAG_NEGATIVE) dir->exclude = NULL; if (dir->exclude) { - dir->basebuf[stk->baselen] = 0; dir->exclude_stack = stk; return; } } - /* Try to read per-directory file unless path is too long */ - if (dir->exclude_per_dir && - stk->baselen + strlen(dir->exclude_per_dir) < PATH_MAX) { - strcpy(dir->basebuf + stk->baselen, - dir->exclude_per_dir); + /* Try to read per-directory file */ + if (dir->exclude_per_dir) { /* * dir->basebuf gets reused by the traversal, but we * need fname to remain unchanged to ensure the src * member of each struct exclude correctly * back-references its source file. Other invocations * of add_exclude_list provide stable strings, so we - * strdup() and free() here in the caller. + * strbuf_detach() and free() here in the caller. */ - el->src = strdup(dir->basebuf); - add_excludes_from_file_to_list(dir->basebuf, - dir->basebuf, stk->baselen, el, 1); + struct strbuf sb = STRBUF_INIT; + strbuf_addbuf(&sb, &dir->basebuf); + strbuf_addstr(&sb, dir->exclude_per_dir); + el->src = strbuf_detach(&sb, NULL); + add_excludes_from_file_to_list(el->src, el->src, + stk->baselen, el, 1); } dir->exclude_stack = stk; current = stk->baselen; } - dir->basebuf[baselen] = '\0'; + strbuf_setlen(&dir->basebuf, baselen); } /* @@ -1499,12 +1507,16 @@ int dir_inside_of(const char *subdir, const char *dir) int is_inside_dir(const char *dir) { - char cwd[PATH_MAX]; + char *cwd; + int rc; + if (!dir) return 0; - if (!getcwd(cwd, sizeof(cwd))) - die_errno("can't find the current directory"); - return dir_inside_of(cwd, dir) >= 0; + + cwd = xgetcwd(); + rc = (dir_inside_of(cwd, dir) >= 0); + free(cwd); + return rc; } int is_empty_dir(const char *path) @@ -1671,4 +1683,5 @@ void clear_directory(struct dir_struct *dir) free(stk); stk = prev; } + strbuf_release(&dir->basebuf); } diff --git a/dir.h b/dir.h index 55e53456af..6c45e9d4b9 100644 --- a/dir.h +++ b/dir.h @@ -15,6 +15,27 @@ struct dir_entry { #define EXC_FLAG_MUSTBEDIR 8 #define EXC_FLAG_NEGATIVE 16 +struct exclude { + /* + * This allows callers of last_exclude_matching() etc. + * to determine the origin of the matching pattern. + */ + struct exclude_list *el; + + const char *pattern; + int patternlen; + int nowildcardlen; + const char *base; + int baselen; + int flags; + + /* + * Counting starts from 1 for line numbers in ignore files, + * and from -1 decrementing for patterns from CLI args. + */ + int srcpos; +}; + /* * Each excludes file will be parsed into a fresh exclude_list which * is appended to the relevant exclude_list_group (either EXC_DIRS or @@ -32,26 +53,7 @@ struct exclude_list { /* origin of list, e.g. path to filename, or descriptive string */ const char *src; - struct exclude { - /* - * This allows callers of last_exclude_matching() etc. - * to determine the origin of the matching pattern. - */ - struct exclude_list *el; - - const char *pattern; - int patternlen; - int nowildcardlen; - const char *base; - int baselen; - int flags; - - /* - * Counting starts from 1 for line numbers in ignore files, - * and from -1 decrementing for patterns from CLI args. - */ - int srcpos; - } **excludes; + struct exclude **excludes; }; /* @@ -117,7 +119,7 @@ struct dir_struct { */ struct exclude_stack *exclude_stack; struct exclude *exclude; - char basebuf[PATH_MAX]; + struct strbuf basebuf; }; /* diff --git a/editor.c b/editor.c index 0abbd8dc3a..01c644cddb 100644 --- a/editor.c +++ b/editor.c @@ -38,10 +38,9 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en if (strcmp(editor, ":")) { const char *args[] = { editor, real_path(path), NULL }; - struct child_process p; + struct child_process p = CHILD_PROCESS_INIT; int ret, sig; - memset(&p, 0, sizeof(p)); p.argv = args; p.env = env; p.use_shell = 1; diff --git a/entry.c b/entry.c index 77c6882624..1eda8e9471 100644 --- a/entry.c +++ b/entry.c @@ -210,9 +210,12 @@ static int write_entry(struct cache_entry *ce, finish: if (state->refresh_cache) { + assert(state->istate); if (!fstat_done) lstat(ce->name, &st); fill_stat_cache_info(ce, &st); + ce->ce_flags |= CE_UPDATE_IN_BASE; + state->istate->cache_changed |= CE_ENTRY_CHANGED; } return 0; } diff --git a/environment.c b/environment.c index 4dac5e9edd..565f65293b 100644 --- a/environment.c +++ b/environment.c @@ -124,6 +124,12 @@ static char *expand_namespace(const char *raw_namespace) return strbuf_detach(&buf, NULL); } +static char *git_path_from_env(const char *envvar, const char *path) +{ + const char *value = getenv(envvar); + return value ? xstrdup(value) : git_pathdup("%s", path); +} + static void setup_git_env(void) { const char *gitfile; @@ -134,19 +140,9 @@ static void setup_git_env(void) git_dir = DEFAULT_GIT_DIR_ENVIRONMENT; gitfile = read_gitfile(git_dir); git_dir = xstrdup(gitfile ? gitfile : git_dir); - git_object_dir = getenv(DB_ENVIRONMENT); - if (!git_object_dir) { - git_object_dir = xmalloc(strlen(git_dir) + 9); - sprintf(git_object_dir, "%s/objects", git_dir); - } - git_index_file = getenv(INDEX_ENVIRONMENT); - if (!git_index_file) { - git_index_file = xmalloc(strlen(git_dir) + 7); - sprintf(git_index_file, "%s/index", git_dir); - } - git_graft_file = getenv(GRAFT_ENVIRONMENT); - if (!git_graft_file) - git_graft_file = git_pathdup("info/grafts"); + git_object_dir = git_path_from_env(DB_ENVIRONMENT, "objects"); + git_index_file = git_path_from_env(INDEX_ENVIRONMENT, "index"); + git_graft_file = git_path_from_env(GRAFT_ENVIRONMENT, "info/grafts"); if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT)) check_replace_refs = 0; namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT)); diff --git a/ewah/ewah_io.c b/ewah/ewah_io.c index f7f700ef51..1c2d7afd4c 100644 --- a/ewah/ewah_io.c +++ b/ewah/ewah_io.c @@ -110,9 +110,9 @@ int ewah_serialize(struct ewah_bitmap *self, int fd) return ewah_serialize_to(self, write_helper, (void *)(intptr_t)fd); } -int ewah_read_mmap(struct ewah_bitmap *self, void *map, size_t len) +int ewah_read_mmap(struct ewah_bitmap *self, const void *map, size_t len) { - uint8_t *ptr = map; + const uint8_t *ptr = map; size_t i; self->bit_size = get_be32(ptr); diff --git a/ewah/ewok.h b/ewah/ewok.h index 43adeb5c68..f6ad190a03 100644 --- a/ewah/ewok.h +++ b/ewah/ewok.h @@ -99,8 +99,7 @@ int ewah_serialize(struct ewah_bitmap *self, int fd); int ewah_serialize_native(struct ewah_bitmap *self, int fd); int ewah_deserialize(struct ewah_bitmap *self, int fd); -int ewah_read_mmap(struct ewah_bitmap *self, void *map, size_t len); -int ewah_read_mmap_native(struct ewah_bitmap *self, void *map, size_t len); +int ewah_read_mmap(struct ewah_bitmap *self, const void *map, size_t len); uint32_t ewah_checksum(struct ewah_bitmap *self); diff --git a/exec_cmd.c b/exec_cmd.c index 125fa6fabf..698e7526c4 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -86,11 +86,7 @@ const char *git_exec_path(void) static void add_path(struct strbuf *out, const char *path) { if (path && *path) { - if (is_absolute_path(path)) - strbuf_addstr(out, path); - else - strbuf_addstr(out, absolute_path(path)); - + strbuf_add_absolute_path(out, path); strbuf_addch(out, PATH_SEP); } } diff --git a/fast-import.c b/fast-import.c index 6707a66471..487f1f81ac 100644 --- a/fast-import.c +++ b/fast-import.c @@ -371,8 +371,8 @@ static volatile sig_atomic_t checkpoint_requested; static int cat_blob_fd = STDOUT_FILENO; static void parse_argv(void); -static void parse_cat_blob(void); -static void parse_ls(struct branch *b); +static void parse_cat_blob(const char *p); +static void parse_ls(const char *p, struct branch *b); static void write_branch_report(FILE *rpt, struct branch *b) { @@ -946,10 +946,12 @@ static void unkeep_all_packs(void) static void end_packfile(void) { - struct packed_git *old_p = pack_data, *new_p; + if (!pack_data) + return; clear_delta_base_cache(); if (object_count) { + struct packed_git *new_p; unsigned char cur_pack_sha1[20]; char *idx_name; int i; @@ -991,10 +993,11 @@ static void end_packfile(void) pack_id++; } else { - close(old_p->pack_fd); - unlink_or_warn(old_p->pack_name); + close(pack_data->pack_fd); + unlink_or_warn(pack_data->pack_name); } - free(old_p); + free(pack_data); + pack_data = NULL; /* We can't carry a delta across packfiles. */ strbuf_release(&last_blob.data); @@ -1419,7 +1422,7 @@ static void mktree(struct tree_content *t, int v, struct strbuf *b) static void store_tree(struct tree_entry *root) { - struct tree_content *t = root->tree; + struct tree_content *t; unsigned int i, j, del; struct last_object lo = { STRBUF_INIT, 0, 0, /* no_swap */ 1 }; struct object_entry *le = NULL; @@ -1427,6 +1430,10 @@ static void store_tree(struct tree_entry *root) if (!is_null_sha1(root->versions[1].sha1)) return; + if (!root->tree) + load_tree(root); + t = root->tree; + for (i = 0; i < t->entry_count; i++) { if (t->entries[i]->tree) store_tree(t->entries[i]); @@ -1679,8 +1686,9 @@ static int tree_content_get( static int update_branch(struct branch *b) { static const char *msg = "fast-import"; - struct ref_lock *lock; + struct ref_transaction *transaction; unsigned char old_sha1[20]; + struct strbuf err = STRBUF_INIT; if (read_ref(b->name, old_sha1)) hashclr(old_sha1); @@ -1689,29 +1697,33 @@ static int update_branch(struct branch *b) delete_ref(b->name, old_sha1, 0); return 0; } - lock = lock_any_ref_for_update(b->name, old_sha1, 0, NULL); - if (!lock) - return error("Unable to lock %s", b->name); if (!force_update && !is_null_sha1(old_sha1)) { struct commit *old_cmit, *new_cmit; old_cmit = lookup_commit_reference_gently(old_sha1, 0); new_cmit = lookup_commit_reference_gently(b->sha1, 0); - if (!old_cmit || !new_cmit) { - unlock_ref(lock); + if (!old_cmit || !new_cmit) return error("Branch %s is missing commits.", b->name); - } if (!in_merge_bases(old_cmit, new_cmit)) { - unlock_ref(lock); warning("Not updating %s" " (new tip %s does not contain %s)", b->name, sha1_to_hex(b->sha1), sha1_to_hex(old_sha1)); return -1; } } - if (write_ref_sha1(lock, b->sha1, msg) < 0) - return error("Unable to update %s", b->name); + transaction = ref_transaction_begin(&err); + if (!transaction || + ref_transaction_update(transaction, b->name, b->sha1, old_sha1, + 0, 1, &err) || + ref_transaction_commit(transaction, msg, &err)) { + ref_transaction_free(transaction); + error("%s", err.buf); + strbuf_release(&err); + return -1; + } + ref_transaction_free(transaction); + strbuf_release(&err); return 0; } @@ -1730,15 +1742,32 @@ static void dump_tags(void) { static const char *msg = "fast-import"; struct tag *t; - struct ref_lock *lock; - char ref_name[PATH_MAX]; + struct strbuf ref_name = STRBUF_INIT; + struct strbuf err = STRBUF_INIT; + struct ref_transaction *transaction; + transaction = ref_transaction_begin(&err); + if (!transaction) { + failure |= error("%s", err.buf); + goto cleanup; + } for (t = first_tag; t; t = t->next_tag) { - sprintf(ref_name, "tags/%s", t->name); - lock = lock_ref_sha1(ref_name, NULL); - if (!lock || write_ref_sha1(lock, t->sha1, msg) < 0) - failure |= error("Unable to update %s", ref_name); + strbuf_reset(&ref_name); + strbuf_addf(&ref_name, "refs/tags/%s", t->name); + + if (ref_transaction_update(transaction, ref_name.buf, t->sha1, + NULL, 0, 0, &err)) { + failure |= error("%s", err.buf); + goto cleanup; + } } + if (ref_transaction_commit(transaction, msg, &err)) + failure |= error("%s", err.buf); + + cleanup: + ref_transaction_free(transaction); + strbuf_release(&ref_name); + strbuf_release(&err); } static void dump_marks_helper(FILE *f, @@ -1861,6 +1890,8 @@ static int read_next_command(void) } for (;;) { + const char *p; + if (unread_command_buf) { unread_command_buf = 0; } else { @@ -1893,8 +1924,8 @@ static int read_next_command(void) rc->prev->next = rc; cmd_tail = rc; } - if (starts_with(command_buf.buf, "cat-blob ")) { - parse_cat_blob(); + if (skip_prefix(command_buf.buf, "cat-blob ", &p)) { + parse_cat_blob(p); continue; } if (command_buf.buf[0] == '#') @@ -1912,8 +1943,9 @@ static void skip_optional_lf(void) static void parse_mark(void) { - if (starts_with(command_buf.buf, "mark :")) { - next_mark = strtoumax(command_buf.buf + 6, NULL, 10); + const char *v; + if (skip_prefix(command_buf.buf, "mark :", &v)) { + next_mark = strtoumax(v, NULL, 10); read_next_command(); } else @@ -1922,14 +1954,15 @@ static void parse_mark(void) static int parse_data(struct strbuf *sb, uintmax_t limit, uintmax_t *len_res) { + const char *data; strbuf_reset(sb); - if (!starts_with(command_buf.buf, "data ")) + if (!skip_prefix(command_buf.buf, "data ", &data)) die("Expected 'data n' command, found: %s", command_buf.buf); - if (starts_with(command_buf.buf + 5, "<<")) { - char *term = xstrdup(command_buf.buf + 5 + 2); - size_t term_len = command_buf.len - 5 - 2; + if (skip_prefix(data, "<<", &data)) { + char *term = xstrdup(data); + size_t term_len = command_buf.len - (data - command_buf.buf); strbuf_detach(&command_buf, NULL); for (;;) { @@ -1944,7 +1977,7 @@ static int parse_data(struct strbuf *sb, uintmax_t limit, uintmax_t *len_res) free(term); } else { - uintmax_t len = strtoumax(command_buf.buf + 5, NULL, 10); + uintmax_t len = strtoumax(data, NULL, 10); size_t n = 0, length = (size_t)len; if (limit && limit < len) { @@ -1967,7 +2000,7 @@ static int parse_data(struct strbuf *sb, uintmax_t limit, uintmax_t *len_res) return 1; } -static int validate_raw_date(const char *src, char *result, int maxlen) +static int validate_raw_date(const char *src, struct strbuf *result) { const char *orig_src = src; char *endp; @@ -1985,11 +2018,10 @@ static int validate_raw_date(const char *src, char *result, int maxlen) return -1; num = strtoul(src + 1, &endp, 10); - if (errno || endp == src + 1 || *endp || (endp - orig_src) >= maxlen || - 1400 < num) + if (errno || endp == src + 1 || *endp || 1400 < num) return -1; - strcpy(result, orig_src); + strbuf_addstr(result, orig_src); return 0; } @@ -1997,7 +2029,7 @@ static char *parse_ident(const char *buf) { const char *ltgt; size_t name_len; - char *ident; + struct strbuf ident = STRBUF_INIT; /* ensure there is a space delimiter even if there is no name */ if (*buf == '<') @@ -2016,26 +2048,25 @@ static char *parse_ident(const char *buf) die("Missing space after > in ident string: %s", buf); ltgt++; name_len = ltgt - buf; - ident = xmalloc(name_len + 24); - strncpy(ident, buf, name_len); + strbuf_add(&ident, buf, name_len); switch (whenspec) { case WHENSPEC_RAW: - if (validate_raw_date(ltgt, ident + name_len, 24) < 0) + if (validate_raw_date(ltgt, &ident) < 0) die("Invalid raw date \"%s\" in ident: %s", ltgt, buf); break; case WHENSPEC_RFC2822: - if (parse_date(ltgt, ident + name_len, 24) < 0) + if (parse_date(ltgt, &ident) < 0) die("Invalid rfc2822 date \"%s\" in ident: %s", ltgt, buf); break; case WHENSPEC_NOW: if (strcmp("now", ltgt)) die("Date in ident must be 'now': %s", buf); - datestamp(ident + name_len, 24); + datestamp(&ident); break; } - return ident; + return strbuf_detach(&ident, NULL); } static void parse_and_store_blob( @@ -2265,15 +2296,14 @@ static uintmax_t parse_mark_ref_space(const char **p) char *end; mark = parse_mark_ref(*p, &end); - if (*end != ' ') + if (*end++ != ' ') die("Missing space after mark: %s", command_buf.buf); *p = end; return mark; } -static void file_change_m(struct branch *b) +static void file_change_m(const char *p, struct branch *b) { - const char *p = command_buf.buf + 2; static struct strbuf uq = STRBUF_INIT; const char *endp; struct object_entry *oe; @@ -2301,20 +2331,17 @@ static void file_change_m(struct branch *b) if (*p == ':') { oe = find_mark(parse_mark_ref_space(&p)); hashcpy(sha1, oe->idx.sha1); - } else if (starts_with(p, "inline ")) { + } else if (skip_prefix(p, "inline ", &p)) { inline_data = 1; oe = NULL; /* not used with inline_data, but makes gcc happy */ - p += strlen("inline"); /* advance to space */ } else { if (get_sha1_hex(p, sha1)) die("Invalid dataref: %s", command_buf.buf); oe = find_object(sha1); p += 40; - if (*p != ' ') + if (*p++ != ' ') die("Missing space after SHA1: %s", command_buf.buf); } - assert(*p == ' '); - p++; /* skip space */ strbuf_reset(&uq); if (!unquote_c_style(&uq, p, &endp)) { @@ -2324,7 +2351,7 @@ static void file_change_m(struct branch *b) } /* Git does not track empty, non-toplevel directories. */ - if (S_ISDIR(mode) && !memcmp(sha1, EMPTY_TREE_SHA1_BIN, 20) && *p) { + if (S_ISDIR(mode) && !hashcmp(sha1, EMPTY_TREE_SHA1_BIN) && *p) { tree_content_remove(&b->branch_tree, p, NULL, 0); return; } @@ -2374,9 +2401,8 @@ static void file_change_m(struct branch *b) tree_content_set(&b->branch_tree, p, sha1, mode, NULL); } -static void file_change_d(struct branch *b) +static void file_change_d(const char *p, struct branch *b) { - const char *p = command_buf.buf + 2; static struct strbuf uq = STRBUF_INIT; const char *endp; @@ -2389,15 +2415,14 @@ static void file_change_d(struct branch *b) tree_content_remove(&b->branch_tree, p, NULL, 1); } -static void file_change_cr(struct branch *b, int rename) +static void file_change_cr(const char *s, struct branch *b, int rename) { - const char *s, *d; + const char *d; static struct strbuf s_uq = STRBUF_INIT; static struct strbuf d_uq = STRBUF_INIT; const char *endp; struct tree_entry leaf; - s = command_buf.buf + 2; strbuf_reset(&s_uq); if (!unquote_c_style(&s_uq, s, &endp)) { if (*endp != ' ') @@ -2442,9 +2467,8 @@ static void file_change_cr(struct branch *b, int rename) leaf.tree); } -static void note_change_n(struct branch *b, unsigned char *old_fanout) +static void note_change_n(const char *p, struct branch *b, unsigned char *old_fanout) { - const char *p = command_buf.buf + 2; static struct strbuf uq = STRBUF_INIT; struct object_entry *oe; struct branch *s; @@ -2474,20 +2498,17 @@ static void note_change_n(struct branch *b, unsigned char *old_fanout) if (*p == ':') { oe = find_mark(parse_mark_ref_space(&p)); hashcpy(sha1, oe->idx.sha1); - } else if (starts_with(p, "inline ")) { + } else if (skip_prefix(p, "inline ", &p)) { inline_data = 1; oe = NULL; /* not used with inline_data, but makes gcc happy */ - p += strlen("inline"); /* advance to space */ } else { if (get_sha1_hex(p, sha1)) die("Invalid dataref: %s", command_buf.buf); oe = find_object(sha1); p += 40; - if (*p != ' ') + if (*p++ != ' ') die("Missing space after SHA1: %s", command_buf.buf); } - assert(*p == ' '); - p++; /* skip space */ /* */ s = lookup_branch(p); @@ -2585,7 +2606,7 @@ static int parse_from(struct branch *b) const char *from; struct branch *s; - if (!starts_with(command_buf.buf, "from ")) + if (!skip_prefix(command_buf.buf, "from ", &from)) return 0; if (b->branch_tree.tree) { @@ -2593,7 +2614,6 @@ static int parse_from(struct branch *b) b->branch_tree.tree = NULL; } - from = strchr(command_buf.buf, ' ') + 1; s = lookup_branch(from); if (b == s) die("Can't create a branch from itself: %s", b->name); @@ -2634,8 +2654,7 @@ static struct hash_list *parse_merge(unsigned int *count) struct branch *s; *count = 0; - while (starts_with(command_buf.buf, "merge ")) { - from = strchr(command_buf.buf, ' ') + 1; + while (skip_prefix(command_buf.buf, "merge ", &from)) { n = xmalloc(sizeof(*n)); s = lookup_branch(from); if (s) @@ -2666,31 +2685,29 @@ static struct hash_list *parse_merge(unsigned int *count) return list; } -static void parse_new_commit(void) +static void parse_new_commit(const char *arg) { static struct strbuf msg = STRBUF_INIT; struct branch *b; - char *sp; char *author = NULL; char *committer = NULL; struct hash_list *merge_list = NULL; unsigned int merge_count; unsigned char prev_fanout, new_fanout; + const char *v; - /* Obtain the branch name from the rest of our command */ - sp = strchr(command_buf.buf, ' ') + 1; - b = lookup_branch(sp); + b = lookup_branch(arg); if (!b) - b = new_branch(sp); + b = new_branch(arg); read_next_command(); parse_mark(); - if (starts_with(command_buf.buf, "author ")) { - author = parse_ident(command_buf.buf + 7); + if (skip_prefix(command_buf.buf, "author ", &v)) { + author = parse_ident(v); read_next_command(); } - if (starts_with(command_buf.buf, "committer ")) { - committer = parse_ident(command_buf.buf + 10); + if (skip_prefix(command_buf.buf, "committer ", &v)) { + committer = parse_ident(v); read_next_command(); } if (!committer) @@ -2710,20 +2727,20 @@ static void parse_new_commit(void) /* file_change* */ while (command_buf.len > 0) { - if (starts_with(command_buf.buf, "M ")) - file_change_m(b); - else if (starts_with(command_buf.buf, "D ")) - file_change_d(b); - else if (starts_with(command_buf.buf, "R ")) - file_change_cr(b, 1); - else if (starts_with(command_buf.buf, "C ")) - file_change_cr(b, 0); - else if (starts_with(command_buf.buf, "N ")) - note_change_n(b, &prev_fanout); + if (skip_prefix(command_buf.buf, "M ", &v)) + file_change_m(v, b); + else if (skip_prefix(command_buf.buf, "D ", &v)) + file_change_d(v, b); + else if (skip_prefix(command_buf.buf, "R ", &v)) + file_change_cr(v, b, 1); + else if (skip_prefix(command_buf.buf, "C ", &v)) + file_change_cr(v, b, 0); + else if (skip_prefix(command_buf.buf, "N ", &v)) + note_change_n(v, b, &prev_fanout); else if (!strcmp("deleteall", command_buf.buf)) file_change_deleteall(b); - else if (starts_with(command_buf.buf, "ls ")) - parse_ls(b); + else if (skip_prefix(command_buf.buf, "ls ", &v)) + parse_ls(v, b); else { unread_command_buf = 1; break; @@ -2766,10 +2783,9 @@ static void parse_new_commit(void) b->last_commit = object_count_by_type[OBJ_COMMIT]; } -static void parse_new_tag(void) +static void parse_new_tag(const char *arg) { static struct strbuf msg = STRBUF_INIT; - char *sp; const char *from; char *tagger; struct branch *s; @@ -2777,12 +2793,11 @@ static void parse_new_tag(void) uintmax_t from_mark = 0; unsigned char sha1[20]; enum object_type type; + const char *v; - /* Obtain the new tag name from the rest of our command */ - sp = strchr(command_buf.buf, ' ') + 1; t = pool_alloc(sizeof(struct tag)); memset(t, 0, sizeof(struct tag)); - t->name = pool_strdup(sp); + t->name = pool_strdup(arg); if (last_tag) last_tag->next_tag = t; else @@ -2791,9 +2806,8 @@ static void parse_new_tag(void) read_next_command(); /* from ... */ - if (!starts_with(command_buf.buf, "from ")) + if (!skip_prefix(command_buf.buf, "from ", &from)) die("Expected from command, got %s", command_buf.buf); - from = strchr(command_buf.buf, ' ') + 1; s = lookup_branch(from); if (s) { if (is_null_sha1(s->sha1)) @@ -2819,8 +2833,8 @@ static void parse_new_tag(void) read_next_command(); /* tagger ... */ - if (starts_with(command_buf.buf, "tagger ")) { - tagger = parse_ident(command_buf.buf + 7); + if (skip_prefix(command_buf.buf, "tagger ", &v)) { + tagger = parse_ident(v); read_next_command(); } else tagger = NULL; @@ -2849,14 +2863,11 @@ static void parse_new_tag(void) t->pack_id = pack_id; } -static void parse_reset_branch(void) +static void parse_reset_branch(const char *arg) { struct branch *b; - char *sp; - /* Obtain the branch name from the rest of our command */ - sp = strchr(command_buf.buf, ' ') + 1; - b = lookup_branch(sp); + b = lookup_branch(arg); if (b) { hashclr(b->sha1); hashclr(b->branch_tree.versions[0].sha1); @@ -2867,7 +2878,7 @@ static void parse_reset_branch(void) } } else - b = new_branch(sp); + b = new_branch(arg); read_next_command(); parse_from(b); if (command_buf.len > 0) @@ -2925,14 +2936,12 @@ static void cat_blob(struct object_entry *oe, unsigned char sha1[20]) free(buf); } -static void parse_cat_blob(void) +static void parse_cat_blob(const char *p) { - const char *p; struct object_entry *oe = oe; unsigned char sha1[20]; /* cat-blob SP LF */ - p = command_buf.buf + strlen("cat-blob "); if (*p == ':') { oe = find_mark(parse_mark_ref_eol(p)); if (!oe) @@ -3015,6 +3024,8 @@ static struct object_entry *parse_treeish_dataref(const char **p) die("Invalid dataref: %s", command_buf.buf); e = find_object(sha1); *p += 40; + if (*(*p)++ != ' ') + die("Missing space after tree-ish: %s", command_buf.buf); } while (!e || e->type != OBJ_TREE) @@ -3049,14 +3060,12 @@ static void print_ls(int mode, const unsigned char *sha1, const char *path) cat_blob_write(line.buf, line.len); } -static void parse_ls(struct branch *b) +static void parse_ls(const char *p, struct branch *b) { - const char *p; struct tree_entry *root = NULL; struct tree_entry leaf = {NULL}; /* ls SP ( SP)? */ - p = command_buf.buf + strlen("ls "); if (*p == '"') { if (!b) die("Not in a commit: %s", command_buf.buf); @@ -3068,8 +3077,6 @@ static void parse_ls(struct branch *b) if (!is_null_sha1(root->versions[1].sha1)) root->versions[1].mode = S_IFDIR; load_tree(root); - if (*p++ != ' ') - die("Missing space after tree-ish: %s", command_buf.buf); } if (*p == '"') { static struct strbuf uq = STRBUF_INIT; @@ -3207,9 +3214,9 @@ static void option_export_pack_edges(const char *edges) static int parse_one_option(const char *option) { - if (starts_with(option, "max-pack-size=")) { + if (skip_prefix(option, "max-pack-size=", &option)) { unsigned long v; - if (!git_parse_ulong(option + 14, &v)) + if (!git_parse_ulong(option, &v)) return 0; if (v < 8192) { warning("max-pack-size is now in bytes, assuming --max-pack-size=%lum", v); @@ -3219,17 +3226,17 @@ static int parse_one_option(const char *option) v = 1024 * 1024; } max_packsize = v; - } else if (starts_with(option, "big-file-threshold=")) { + } else if (skip_prefix(option, "big-file-threshold=", &option)) { unsigned long v; - if (!git_parse_ulong(option + 19, &v)) + if (!git_parse_ulong(option, &v)) return 0; big_file_threshold = v; - } else if (starts_with(option, "depth=")) { - option_depth(option + 6); - } else if (starts_with(option, "active-branches=")) { - option_active_branches(option + 16); - } else if (starts_with(option, "export-pack-edges=")) { - option_export_pack_edges(option + 18); + } else if (skip_prefix(option, "depth=", &option)) { + option_depth(option); + } else if (skip_prefix(option, "active-branches=", &option)) { + option_active_branches(option); + } else if (skip_prefix(option, "export-pack-edges=", &option)) { + option_export_pack_edges(option); } else if (starts_with(option, "quiet")) { show_stats = 0; } else if (starts_with(option, "stats")) { @@ -3243,15 +3250,16 @@ static int parse_one_option(const char *option) static int parse_one_feature(const char *feature, int from_stream) { - if (starts_with(feature, "date-format=")) { - option_date_format(feature + 12); - } else if (starts_with(feature, "import-marks=")) { - option_import_marks(feature + 13, from_stream, 0); - } else if (starts_with(feature, "import-marks-if-exists=")) { - option_import_marks(feature + strlen("import-marks-if-exists="), - from_stream, 1); - } else if (starts_with(feature, "export-marks=")) { - option_export_marks(feature + 13); + const char *arg; + + if (skip_prefix(feature, "date-format=", &arg)) { + option_date_format(arg); + } else if (skip_prefix(feature, "import-marks=", &arg)) { + option_import_marks(arg, from_stream, 0); + } else if (skip_prefix(feature, "import-marks-if-exists=", &arg)) { + option_import_marks(arg, from_stream, 1); + } else if (skip_prefix(feature, "export-marks=", &arg)) { + option_export_marks(arg); } else if (!strcmp(feature, "cat-blob")) { ; /* Don't die - this feature is supported */ } else if (!strcmp(feature, "relative-marks")) { @@ -3271,10 +3279,8 @@ static int parse_one_feature(const char *feature, int from_stream) return 1; } -static void parse_feature(void) +static void parse_feature(const char *feature) { - char *feature = command_buf.buf + 8; - if (seen_data_command) die("Got feature command '%s' after data command", feature); @@ -3284,10 +3290,8 @@ static void parse_feature(void) die("This version of fast-import does not support feature %s.", feature); } -static void parse_option(void) +static void parse_option(const char *option) { - char *option = command_buf.buf + 11; - if (seen_data_command) die("Got option command '%s' after data command", option); @@ -3297,36 +3301,34 @@ static void parse_option(void) die("This version of fast-import does not support option: %s", option); } -static int git_pack_config(const char *k, const char *v, void *cb) +static void git_pack_config(void) { - if (!strcmp(k, "pack.depth")) { - max_depth = git_config_int(k, v); + int indexversion_value; + unsigned long packsizelimit_value; + + if (!git_config_get_ulong("pack.depth", &max_depth)) { if (max_depth > MAX_DEPTH) max_depth = MAX_DEPTH; - return 0; } - if (!strcmp(k, "pack.compression")) { - int level = git_config_int(k, v); - if (level == -1) - level = Z_DEFAULT_COMPRESSION; - else if (level < 0 || level > Z_BEST_COMPRESSION) - die("bad pack compression level %d", level); - pack_compression_level = level; + if (!git_config_get_int("pack.compression", &pack_compression_level)) { + if (pack_compression_level == -1) + pack_compression_level = Z_DEFAULT_COMPRESSION; + else if (pack_compression_level < 0 || + pack_compression_level > Z_BEST_COMPRESSION) + git_die_config("pack.compression", + "bad pack compression level %d", pack_compression_level); pack_compression_seen = 1; - return 0; } - if (!strcmp(k, "pack.indexversion")) { - pack_idx_opts.version = git_config_int(k, v); + if (!git_config_get_int("pack.indexversion", &indexversion_value)) { + pack_idx_opts.version = indexversion_value; if (pack_idx_opts.version > 2) - die("bad pack.indexversion=%"PRIu32, - pack_idx_opts.version); - return 0; + git_die_config("pack.indexversion", + "bad pack.indexversion=%"PRIu32, pack_idx_opts.version); } - if (!strcmp(k, "pack.packsizelimit")) { - max_packsize = git_config_ulong(k, v); - return 0; - } - return git_default_config(k, v, cb); + if (!git_config_get_ulong("pack.packsizelimit", &packsizelimit_value)) + max_packsize = packsizelimit_value; + + git_config(git_default_config, NULL); } static const char fast_import_usage[] = @@ -3342,18 +3344,21 @@ static void parse_argv(void) if (*a != '-' || !strcmp(a, "--")) break; - if (parse_one_option(a + 2)) + if (!skip_prefix(a, "--", &a)) + die("unknown option %s", a); + + if (parse_one_option(a)) continue; - if (parse_one_feature(a + 2, 0)) + if (parse_one_feature(a, 0)) continue; - if (starts_with(a + 2, "cat-blob-fd=")) { - option_cat_blob_fd(a + 2 + strlen("cat-blob-fd=")); + if (skip_prefix(a, "cat-blob-fd=", &a)) { + option_cat_blob_fd(a); continue; } - die("unknown option %s", a); + die("unknown option --%s", a); } if (i != global_argc) usage(fast_import_usage); @@ -3376,7 +3381,7 @@ int main(int argc, char **argv) setup_git_directory(); reset_pack_idx_option(&pack_idx_opts); - git_config(git_pack_config, NULL); + git_pack_config(); if (!pack_compression_seen && core_compression_seen) pack_compression_level = core_compression_level; @@ -3400,26 +3405,27 @@ int main(int argc, char **argv) set_die_routine(die_nicely); set_checkpoint_signal(); while (read_next_command() != EOF) { + const char *v; if (!strcmp("blob", command_buf.buf)) parse_new_blob(); - else if (starts_with(command_buf.buf, "ls ")) - parse_ls(NULL); - else if (starts_with(command_buf.buf, "commit ")) - parse_new_commit(); - else if (starts_with(command_buf.buf, "tag ")) - parse_new_tag(); - else if (starts_with(command_buf.buf, "reset ")) - parse_reset_branch(); + else if (skip_prefix(command_buf.buf, "ls ", &v)) + parse_ls(v, NULL); + else if (skip_prefix(command_buf.buf, "commit ", &v)) + parse_new_commit(v); + else if (skip_prefix(command_buf.buf, "tag ", &v)) + parse_new_tag(v); + else if (skip_prefix(command_buf.buf, "reset ", &v)) + parse_reset_branch(v); else if (!strcmp("checkpoint", command_buf.buf)) parse_checkpoint(); else if (!strcmp("done", command_buf.buf)) break; else if (starts_with(command_buf.buf, "progress ")) parse_progress(); - else if (starts_with(command_buf.buf, "feature ")) - parse_feature(); - else if (starts_with(command_buf.buf, "option git ")) - parse_option(); + else if (skip_prefix(command_buf.buf, "feature ", &v)) + parse_feature(v); + else if (skip_prefix(command_buf.buf, "option git ", &v)) + parse_option(v); else if (starts_with(command_buf.buf, "option ")) /* ignore non-git options*/; else diff --git a/fetch-pack.c b/fetch-pack.c index b12bd4c59a..7487aa7306 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -189,20 +189,23 @@ static enum ack_type get_ack(int fd, unsigned char *result_sha1) { int len; char *line = packet_read_line(fd, &len); + const char *arg; if (!len) die("git fetch-pack: expected ACK/NAK, got EOF"); if (!strcmp(line, "NAK")) return NAK; - if (starts_with(line, "ACK ")) { - if (!get_sha1_hex(line+4, result_sha1)) { - if (len < 45) + if (skip_prefix(line, "ACK ", &arg)) { + if (!get_sha1_hex(arg, result_sha1)) { + arg += 40; + len -= arg - line; + if (len < 1) return ACK; - if (strstr(line+45, "continue")) + if (strstr(arg, "continue")) return ACK_continue; - if (strstr(line+45, "common")) + if (strstr(arg, "common")) return ACK_common; - if (strstr(line+45, "ready")) + if (strstr(arg, "ready")) return ACK_ready; return ACK; } @@ -319,18 +322,19 @@ static int find_common(struct fetch_pack_args *args, if (args->depth > 0) { char *line; + const char *arg; unsigned char sha1[20]; send_request(args, fd[1], &req_buf); while ((line = packet_read_line(fd[0], NULL))) { - if (starts_with(line, "shallow ")) { - if (get_sha1_hex(line + 8, sha1)) + if (skip_prefix(line, "shallow ", &arg)) { + if (get_sha1_hex(arg, sha1)) die("invalid shallow line: %s", line); register_shallow(sha1); continue; } - if (starts_with(line, "unshallow ")) { - if (get_sha1_hex(line + 10, sha1)) + if (skip_prefix(line, "unshallow ", &arg)) { + if (get_sha1_hex(arg, sha1)) die("invalid unshallow line: %s", line); if (!lookup_object(sha1)) die("object not found: %s", line); @@ -662,7 +666,7 @@ static int get_pack(struct fetch_pack_args *args, char hdr_arg[256]; const char **av, *cmd_name; int do_keep = args->keep_pack; - struct child_process cmd; + struct child_process cmd = CHILD_PROCESS_INIT; int ret; memset(&demux, 0, sizeof(demux)); @@ -681,7 +685,6 @@ static int get_pack(struct fetch_pack_args *args, else demux.out = xd[0]; - memset(&cmd, 0, sizeof(cmd)); cmd.argv = argv; av = argv; *hdr_arg = 0; @@ -865,34 +868,15 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, return ref; } -static int fetch_pack_config(const char *var, const char *value, void *cb) +static void fetch_pack_config(void) { - if (strcmp(var, "fetch.unpacklimit") == 0) { - fetch_unpack_limit = git_config_int(var, value); - return 0; - } - - if (strcmp(var, "transfer.unpacklimit") == 0) { - transfer_unpack_limit = git_config_int(var, value); - return 0; - } - - if (strcmp(var, "repack.usedeltabaseoffset") == 0) { - prefer_ofs_delta = git_config_bool(var, value); - return 0; - } - - if (!strcmp(var, "fetch.fsckobjects")) { - fetch_fsck_objects = git_config_bool(var, value); - return 0; - } - - if (!strcmp(var, "transfer.fsckobjects")) { - transfer_fsck_objects = git_config_bool(var, value); - return 0; - } + git_config_get_int("fetch.unpacklimit", &fetch_unpack_limit); + git_config_get_int("transfer.unpacklimit", &transfer_unpack_limit); + git_config_get_bool("repack.usedeltabaseoffset", &prefer_ofs_delta); + git_config_get_bool("fetch.fsckobjects", &fetch_fsck_objects); + git_config_get_bool("transfer.fsckobjects", &transfer_fsck_objects); - return git_default_config(var, value, cb); + git_config(git_default_config, NULL); } static void fetch_pack_setup(void) @@ -900,7 +884,7 @@ static void fetch_pack_setup(void) static int did_setup; if (did_setup) return; - git_config(fetch_pack_config, NULL); + fetch_pack_config(); if (0 <= transfer_unpack_limit) unpack_limit = transfer_unpack_limit; else if (0 <= fetch_unpack_limit) diff --git a/fsck.c b/fsck.c index abed62bac7..56156fff44 100644 --- a/fsck.c +++ b/fsck.c @@ -276,56 +276,42 @@ static int fsck_ident(const char **ident, struct object *obj, fsck_error error_f return 0; } -static int fsck_commit(struct commit *commit, fsck_error error_func) +static int fsck_commit_buffer(struct commit *commit, const char *buffer, + fsck_error error_func) { - const char *buffer = commit->buffer, *tmp; unsigned char tree_sha1[20], sha1[20]; struct commit_graft *graft; - int parents = 0; + unsigned parent_count, parent_line_count = 0; int err; - buffer = skip_prefix(buffer, "tree "); - if (!buffer) + if (!skip_prefix(buffer, "tree ", &buffer)) return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'tree' line"); if (get_sha1_hex(buffer, tree_sha1) || buffer[40] != '\n') return error_func(&commit->object, FSCK_ERROR, "invalid 'tree' line format - bad sha1"); buffer += 41; - while ((tmp = skip_prefix(buffer, "parent "))) { - buffer = tmp; + while (skip_prefix(buffer, "parent ", &buffer)) { if (get_sha1_hex(buffer, sha1) || buffer[40] != '\n') return error_func(&commit->object, FSCK_ERROR, "invalid 'parent' line format - bad sha1"); buffer += 41; - parents++; + parent_line_count++; } graft = lookup_commit_graft(commit->object.sha1); + parent_count = commit_list_count(commit->parents); if (graft) { - struct commit_list *p = commit->parents; - parents = 0; - while (p) { - p = p->next; - parents++; - } - if (graft->nr_parent == -1 && !parents) + if (graft->nr_parent == -1 && !parent_count) ; /* shallow commit */ - else if (graft->nr_parent != parents) + else if (graft->nr_parent != parent_count) return error_func(&commit->object, FSCK_ERROR, "graft objects missing"); } else { - struct commit_list *p = commit->parents; - while (p && parents) { - p = p->next; - parents--; - } - if (p || parents) + if (parent_count != parent_line_count) return error_func(&commit->object, FSCK_ERROR, "parent objects missing"); } - buffer = skip_prefix(buffer, "author "); - if (!buffer) + if (!skip_prefix(buffer, "author ", &buffer)) return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'author' line"); err = fsck_ident(&buffer, &commit->object, error_func); if (err) return err; - buffer = skip_prefix(buffer, "committer "); - if (!buffer) + if (!skip_prefix(buffer, "committer ", &buffer)) return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'committer' line"); err = fsck_ident(&buffer, &commit->object, error_func); if (err) @@ -336,6 +322,14 @@ static int fsck_commit(struct commit *commit, fsck_error error_func) return 0; } +static int fsck_commit(struct commit *commit, fsck_error error_func) +{ + const char *buffer = get_commit_buffer(commit, NULL); + int ret = fsck_commit_buffer(commit, buffer, error_func); + unuse_commit_buffer(commit, buffer); + return ret; +} + static int fsck_tag(struct tag *tag, fsck_error error_func) { struct object *tagged = tag->tagged; diff --git a/git-bisect.sh b/git-bisect.sh index 1e0d602f4b..6cda2b5a60 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -286,11 +286,11 @@ bisect_next_check() { if test -s "$GIT_DIR/BISECT_START" then - gettextln "You need to give me at least one good and one bad revisions. + gettextln "You need to give me at least one good and one bad revision. (You can use \"git bisect bad\" and \"git bisect good\" for that.)" >&2 else gettextln "You need to start by \"git bisect start\". -You then need to give me at least one good and one bad revisions. +You then need to give me at least one good and one bad revision. (You can use \"git bisect bad\" and \"git bisect good\" for that.)" >&2 fi exit 1 ;; diff --git a/git-compat-util.h b/git-compat-util.h index b6f03b36dc..4e7e3f8726 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -264,19 +264,35 @@ extern char *gitbasename(char *); #endif #ifndef has_dos_drive_prefix -#define has_dos_drive_prefix(path) 0 +static inline int git_has_dos_drive_prefix(const char *path) +{ + return 0; +} +#define has_dos_drive_prefix git_has_dos_drive_prefix #endif -#ifndef offset_1st_component -#define offset_1st_component(path) (is_dir_sep((path)[0])) +#ifndef is_dir_sep +static inline int git_is_dir_sep(int c) +{ + return c == '/'; +} +#define is_dir_sep git_is_dir_sep #endif -#ifndef is_dir_sep -#define is_dir_sep(c) ((c) == '/') +#ifndef offset_1st_component +static inline int git_offset_1st_component(const char *path) +{ + return is_dir_sep(path[0]); +} +#define offset_1st_component git_offset_1st_component #endif #ifndef find_last_dir_sep -#define find_last_dir_sep(path) strrchr(path, '/') +static inline char *git_find_last_dir_sep(const char *path) +{ + return strrchr(path, '/'); +} +#define find_last_dir_sep git_find_last_dir_sep #endif #if defined(__HP_cc) && (__HP_cc >= 61000) @@ -291,10 +307,12 @@ extern char *gitbasename(char *); #else #define NORETURN #define NORETURN_PTR +#ifndef __GNUC__ #ifndef __attribute__ #define __attribute__(x) #endif #endif +#endif /* The sentinel attribute is valid from gcc version 4.0 */ #if defined(__GNUC__) && (__GNUC__ >= 4) @@ -347,15 +365,66 @@ extern void set_error_routine(void (*routine)(const char *err, va_list params)); extern void set_die_is_recursing_routine(int (*routine)(void)); extern int starts_with(const char *str, const char *prefix); -extern int ends_with(const char *str, const char *suffix); -static inline const char *skip_prefix(const char *str, const char *prefix) +/* + * If the string "str" begins with the string found in "prefix", return 1. + * The "out" parameter is set to "str + strlen(prefix)" (i.e., to the point in + * the string right after the prefix). + * + * Otherwise, return 0 and leave "out" untouched. + * + * Examples: + * + * [extract branch name, fail if not a branch] + * if (!skip_prefix(ref, "refs/heads/", &branch) + * return -1; + * + * [skip prefix if present, otherwise use whole string] + * skip_prefix(name, "refs/heads/", &name); + */ +static inline int skip_prefix(const char *str, const char *prefix, + const char **out) { do { - if (!*prefix) - return str; + if (!*prefix) { + *out = str; + return 1; + } } while (*str++ == *prefix++); - return NULL; + return 0; +} + +/* + * If buf ends with suffix, return 1 and subtract the length of the suffix + * from *len. Otherwise, return 0 and leave *len untouched. + */ +static inline int strip_suffix_mem(const char *buf, size_t *len, + const char *suffix) +{ + size_t suflen = strlen(suffix); + if (*len < suflen || memcmp(buf + (*len - suflen), suffix, suflen)) + return 0; + *len -= suflen; + return 1; +} + +/* + * If str ends with suffix, return 1 and set *len to the size of the string + * without the suffix. Otherwise, return 0 and set *len to the size of the + * string. + * + * Note that we do _not_ NUL-terminate str to the new length. + */ +static inline int strip_suffix(const char *str, const char *suffix, size_t *len) +{ + *len = strlen(str); + return strip_suffix_mem(str, len, suffix); +} + +static inline int ends_with(const char *str, const char *suffix) +{ + size_t len; + return strip_suffix(str, suffix, &len); } #if defined(NO_MMAP) || defined(USE_WIN32_MMAP) @@ -540,6 +609,7 @@ extern try_to_free_t set_try_to_free_routine(try_to_free_t); extern char *xstrdup(const char *str); extern void *xmalloc(size_t size); extern void *xmallocz(size_t size); +extern void *xmallocz_gently(size_t size); extern void *xmemdupz(const void *data, size_t len); extern char *xstrndup(const char *str, size_t len); extern void *xrealloc(void *ptr, size_t size); @@ -554,6 +624,7 @@ extern int xmkstemp(char *template); extern int xmkstemp_mode(char *template, int mode); extern int odb_mkstemp(char *template, size_t limit, const char *pattern); extern int odb_pack_keep(char *name, size_t namesz, const unsigned char *sha1); +extern char *xgetcwd(void); static inline size_t xsize_t(off_t len) { @@ -562,13 +633,6 @@ static inline size_t xsize_t(off_t len) return (size_t)len; } -static inline int has_extension(const char *filename, const char *ext) -{ - size_t len = strlen(filename); - size_t extlen = strlen(ext); - return len > extlen && !memcmp(filename + len - extlen, ext, extlen); -} - /* in ctype.c, for kwset users */ extern const char tolower_trans_tbl[256]; @@ -704,6 +768,10 @@ void git_qsort(void *base, size_t nmemb, size_t size, #endif #endif +#if defined(__GNUC__) || (_MSC_VER >= 1400) +#define HAVE_VARIADIC_MACROS 1 +#endif + /* * Preserves errno, prints a message, but gives no warning for ENOENT. * Always returns the return value of unlink(2). diff --git a/git-filter-branch.sh b/git-filter-branch.sh index 86d6994619..e6e99f5bb5 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -332,7 +332,13 @@ while read commit parents; do parentstr= for parent in $parents; do for reparent in $(map "$parent"); do - parentstr="$parentstr -p $reparent" + case "$parentstr " in + *" -p $reparent "*) + ;; + *) + parentstr="$parentstr -p $reparent" + ;; + esac done done if [ "$filter_parent" ]; then diff --git a/git-pull.sh b/git-pull.sh index 18a394fcc4..4d4fc77b05 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -20,7 +20,7 @@ die_conflict () { if [ $(git config --bool --get advice.resolveConflict || echo true) = "true" ]; then die "$(gettext "Pull is not possible because you have unmerged files. Please, fix them up in the work tree, and then use 'git add/rm ' -as appropriate to mark resolution, or use 'git commit -a'.")" +as appropriate to mark resolution and make a commit.")" else die "$(gettext "Pull is not possible because you have unmerged files.")" fi diff --git a/git-rebase--am.sh b/git-rebase--am.sh index ca20e1e66f..f923732333 100644 --- a/git-rebase--am.sh +++ b/git-rebase--am.sh @@ -29,7 +29,13 @@ skip) ;; esac -test -n "$rebase_root" && root_flag=--root +if test -z "$rebase_root" + # this is now equivalent to ! -z "$upstream" +then + revisions=$upstream...$orig_head +else + revisions=$onto...$orig_head +fi ret=0 if test -n "$keep_empty" @@ -38,14 +44,17 @@ then # empty commits and even if it didn't the format doesn't really lend # itself well to recording empty patches. fortunately, cherry-pick # makes this easy - git cherry-pick ${gpg_sign_opt:+"$gpg_sign_opt"} --allow-empty "$revisions" + git cherry-pick ${gpg_sign_opt:+"$gpg_sign_opt"} --allow-empty \ + --right-only "$revisions" \ + ${restrict_revision+^$restrict_revision} ret=$? else rm -f "$GIT_DIR/rebased-patches" - git format-patch -k --stdout --full-index --ignore-if-in-upstream \ + git format-patch -k --stdout --full-index --cherry-pick --right-only \ --src-prefix=a/ --dst-prefix=b/ --no-renames --no-cover-letter \ - $root_flag "$revisions" >"$GIT_DIR/rebased-patches" + "$revisions" ${restrict_revision+^$restrict_revision} \ + >"$GIT_DIR/rebased-patches" ret=$? if test 0 != $ret diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 7e1eda0088..b64dd28acf 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -963,7 +963,7 @@ else fi git rev-list $merges_option --pretty=oneline --abbrev-commit \ --abbrev=7 --reverse --left-right --topo-order \ - $revisions | \ + $revisions ${restrict_revision+^$restrict_revision} | \ sed -n "s/^>//p" | while read -r shortsha1 rest do diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh index 6d77b3ca91..d3fb67d75b 100644 --- a/git-rebase--merge.sh +++ b/git-rebase--merge.sh @@ -53,11 +53,12 @@ continue_merge () { } call_merge () { - cmt="$(cat "$state_dir/cmt.$1")" + msgnum="$1" + echo "$msgnum" >"$state_dir/msgnum" + cmt="$(cat "$state_dir/cmt.$msgnum")" echo "$cmt" > "$state_dir/current" hd=$(git rev-parse --verify HEAD) cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD) - msgnum=$(cat "$state_dir/msgnum") eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"' eval GITHEAD_$hd='$onto_name' export GITHEAD_$cmt GITHEAD_$hd diff --git a/git-rebase.sh b/git-rebase.sh index 06c810b64f..55da9db818 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -59,6 +59,7 @@ If you prefer to skip this patch, run "git rebase --skip" instead. To check out the original branch and stop rebasing, run "git rebase --abort".') " unset onto +unset restrict_revision cmd= strategy= strategy_opts= @@ -546,7 +547,7 @@ then "${switch_to:-HEAD}") if test -n "$new_upstream" then - upstream=$new_upstream + restrict_revision=$new_upstream fi fi @@ -572,7 +573,7 @@ require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")" # and if this is not an interactive rebase. mb=$(git merge-base "$onto" "$orig_head") if test "$type" != interactive && test "$upstream" = "$onto" && - test "$mb" = "$onto" && + test "$mb" = "$onto" && test -z "$restrict_revision" && # linear history? ! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > /dev/null then @@ -626,7 +627,7 @@ if test -n "$rebase_root" then revisions="$onto..$orig_head" else - revisions="$upstream..$orig_head" + revisions="${restrict_revision-$upstream}..$orig_head" fi run_specific_rebase diff --git a/git-stash.sh b/git-stash.sh index bcc757b390..0158c73386 100755 --- a/git-stash.sh +++ b/git-stash.sh @@ -297,7 +297,7 @@ have_stash () { list_stash () { have_stash || return 0 - git log --format="%gd: %gs" -g "$@" $ref_stash -- + git log --format="%gd: %gs" -g --first-parent -m "$@" $ref_stash -- } show_stash () { @@ -394,7 +394,7 @@ parse_flags_and_rev() REV=$(git rev-parse --quiet --symbolic --verify "$1" 2>/dev/null) || { reference="$1" - die "$(eval_gettext "\$reference is not valid reference")" + die "$(eval_gettext "\$reference is not a valid reference")" } i_commit=$(git rev-parse --quiet --verify "$REV^2" 2>/dev/null) && diff --git a/git-svn.perl b/git-svn.perl index 0a323722a6..b6e2186cef 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -260,8 +260,8 @@ sub _req_svn { } ], 'find-rev' => [ \&cmd_find_rev, "Translate between SVN revision numbers and tree-ish", - { 'before' => \$_before, - 'after' => \$_after } ], + { 'B|before' => \$_before, + 'A|after' => \$_after } ], 'rebase' => [ \&cmd_rebase, "Fetch and rebase your working directory", { 'merge|m|M' => \$_merge, 'verbose|v' => \$_verbose, @@ -306,13 +306,16 @@ sub readline { } package main; -my $term = eval { - $ENV{"GIT_SVN_NOTTY"} - ? new Term::ReadLine 'git-svn', \*STDIN, \*STDOUT - : new Term::ReadLine 'git-svn'; -}; -if ($@) { - $term = new FakeTerm "$@: going non-interactive"; +my $term; +sub term_init { + $term = eval { + $ENV{"GIT_SVN_NOTTY"} + ? new Term::ReadLine 'git-svn', \*STDIN, \*STDOUT + : new Term::ReadLine 'git-svn'; + }; + if ($@) { + $term = new FakeTerm "$@: going non-interactive"; + } } my $cmd; @@ -424,6 +427,7 @@ sub ask { my $default = $arg{default}; my $resp; my $i = 0; + term_init() unless $term; if ( !( defined($term->IN) && defined( fileno($term->IN) ) @@ -1161,7 +1165,9 @@ sub cmd_branch { ::_req_svn(); my $ctx = SVN::Client->new( - auth => Git::SVN::Ra::_auth_providers(), + config => SVN::Core::config_get_config( + $Git::SVN::Ra::config_dir + ), log_msg => sub { ${ $_[0] } = defined $_message ? $_message @@ -1475,10 +1481,37 @@ sub cmd_commit_diff { } } - sub cmd_info { - my $path = canonicalize_path(defined($_[0]) ? $_[0] : "."); - my $fullpath = canonicalize_path($cmd_dir_prefix . $path); + my $path_arg = defined($_[0]) ? $_[0] : '.'; + my $path = $path_arg; + if (File::Spec->file_name_is_absolute($path)) { + $path = canonicalize_path($path); + + my $toplevel = eval { + my @cmd = qw/rev-parse --show-toplevel/; + command_oneline(\@cmd, STDERR => 0); + }; + + # remove $toplevel from the absolute path: + my ($vol, $dirs, $file) = File::Spec->splitpath($path); + my (undef, $tdirs, $tfile) = File::Spec->splitpath($toplevel); + my @dirs = File::Spec->splitdir($dirs); + my @tdirs = File::Spec->splitdir($tdirs); + pop @dirs if $dirs[-1] eq ''; + pop @tdirs if $tdirs[-1] eq ''; + push @dirs, $file; + push @tdirs, $tfile; + while (@tdirs && @dirs && $tdirs[0] eq $dirs[0]) { + shift @dirs; + shift @tdirs; + } + $dirs = File::Spec->catdir(@dirs); + $path = File::Spec->catpath($vol, $dirs); + + $path = canonicalize_path($path); + } else { + $path = canonicalize_path($cmd_dir_prefix . $path); + } if (exists $_[1]) { die "Too many arguments specified\n"; } @@ -1499,14 +1532,14 @@ sub cmd_info { # canonicalize_path() will return "" to make libsvn 1.5.x happy, $path = "." if $path eq ""; - my $full_url = canonicalize_url( add_path_to_url( $url, $fullpath ) ); + my $full_url = canonicalize_url( add_path_to_url( $url, $path ) ); if ($_url) { print "$full_url\n"; return; } - my $result = "Path: $path\n"; + my $result = "Path: $path_arg\n"; $result .= "Name: " . basename($path) . "\n" if $file_type ne "dir"; $result .= "URL: $full_url\n"; @@ -1537,7 +1570,7 @@ sub cmd_info { } my ($lc_author, $lc_rev, $lc_date_utc); - my @args = Git::SVN::Log::git_svn_log_cmd($rev, $rev, "--", $fullpath); + my @args = Git::SVN::Log::git_svn_log_cmd($rev, $rev, "--", $path); my $log = command_output_pipe(@args); my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/; while (<$log>) { diff --git a/git.c b/git.c index d6b4a5543f..523768da61 100644 --- a/git.c +++ b/git.c @@ -14,13 +14,13 @@ const char git_usage_string[] = " []"; const char git_more_info_string[] = - N_("'git help -a' and 'git help -g' lists available subcommands and some\n" + N_("'git help -a' and 'git help -g' list available subcommands and some\n" "concept guides. See 'git help ' or 'git help '\n" "to read about a specific subcommand or concept."); static struct startup_info git_startup_info; static int use_pager = -1; -static char orig_cwd[PATH_MAX]; +static char *orig_cwd; static const char *env_names[] = { GIT_DIR_ENVIRONMENT, GIT_WORK_TREE_ENVIRONMENT, @@ -36,8 +36,7 @@ static void save_env(void) if (saved_environment) return; saved_environment = 1; - if (!getcwd(orig_cwd, sizeof(orig_cwd))) - die_errno("cannot getcwd"); + orig_cwd = xgetcwd(); for (i = 0; i < ARRAY_SIZE(env_names); i++) { orig_env[i] = getenv(env_names[i]); if (orig_env[i]) @@ -48,8 +47,9 @@ static void save_env(void) static void restore_env(void) { int i; - if (*orig_cwd && chdir(orig_cwd)) + if (orig_cwd && chdir(orig_cwd)) die_errno("could not move to %s", orig_cwd); + free(orig_cwd); for (i = 0; i < ARRAY_SIZE(env_names); i++) { if (orig_env[i]) setenv(env_names[i], orig_env[i], 1); @@ -91,8 +91,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) /* * Check remaining flags. */ - if (starts_with(cmd, "--exec-path")) { - cmd += 11; + if (skip_prefix(cmd, "--exec-path", &cmd)) { if (*cmd == '=') git_set_argv_exec_path(cmd + 1); else { @@ -129,8 +128,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) *envchanged = 1; (*argv)++; (*argc)--; - } else if (starts_with(cmd, "--git-dir=")) { - setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1); + } else if (skip_prefix(cmd, "--git-dir=", &cmd)) { + setenv(GIT_DIR_ENVIRONMENT, cmd, 1); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--namespace")) { @@ -143,8 +142,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) *envchanged = 1; (*argv)++; (*argc)--; - } else if (starts_with(cmd, "--namespace=")) { - setenv(GIT_NAMESPACE_ENVIRONMENT, cmd + 12, 1); + } else if (skip_prefix(cmd, "--namespace=", &cmd)) { + setenv(GIT_NAMESPACE_ENVIRONMENT, cmd, 1); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--work-tree")) { @@ -157,14 +156,15 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) *envchanged = 1; (*argv)++; (*argc)--; - } else if (starts_with(cmd, "--work-tree=")) { - setenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1); + } else if (skip_prefix(cmd, "--work-tree=", &cmd)) { + setenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--bare")) { - static char git_dir[PATH_MAX+1]; + char *cwd = xgetcwd(); is_bare_repository_cfg = 1; - setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 0); + setenv(GIT_DIR_ENVIRONMENT, cwd, 0); + free(cwd); setenv(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, "0", 1); if (envchanged) *envchanged = 1; @@ -479,6 +479,7 @@ static struct cmd_struct commands[] = { { "upload-archive", cmd_upload_archive }, { "upload-archive--writer", cmd_upload_archive_writer }, { "var", cmd_var, RUN_SETUP_GENTLY }, + { "verify-commit", cmd_verify_commit, RUN_SETUP }, { "verify-pack", cmd_verify_pack }, { "verify-tag", cmd_verify_tag, RUN_SETUP }, { "version", cmd_version }, @@ -613,6 +614,8 @@ int main(int argc, char **av) git_setup_gettext(); + trace_command_performance(argv); + /* * "git-xxxx" is the same as "git xxxx", but we obviously: * @@ -623,8 +626,7 @@ int main(int argc, char **av) * So we just directly call the builtin handler, and die if * that one cannot handle it. */ - if (starts_with(cmd, "git-")) { - cmd += 4; + if (skip_prefix(cmd, "git-", &cmd)) { argv[0] = cmd; handle_builtin(argc, argv); die("cannot handle %s as a builtin", cmd); @@ -635,8 +637,8 @@ int main(int argc, char **av) argc--; handle_options(&argv, &argc, NULL); if (argc > 0) { - if (starts_with(argv[0], "--")) - argv[0] += 2; + /* translate --help and --version into commands */ + skip_prefix(argv[0], "--", &argv[0]); } else { /* The user didn't specify a command; give them help */ commit_pager_choice(); diff --git a/gitk-git/gitk b/gitk-git/gitk index c8df35dee5..3520bdaebc 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -2594,6 +2594,9 @@ proc makewindow {} { bind $ctext $ctxbut {pop_diff_menu %W %X %Y %x %y} bind $ctext {focus %W} bind $ctext <> rehighlight_search_results + for {set i 1} {$i < 10} {incr i} { + bind . <$M1B-Key-$i> [list go_to_parent $i] + } set maincursor [. cget -cursor] set textcursor [$ctext cget -cursor] @@ -3017,6 +3020,7 @@ proc keys {} { [mc ", n, j Move down one commit"] [mc ", z, h Go back in history list"] [mc ", x, l Go forward in history list"] +[mc "<%s-n> Go to n-th parent of current commit in history list" $M1T] [mc " Move up one page in commit list"] [mc " Move down one page in commit list"] [mc "<%s-Home> Scroll to top of commit list" $M1T] @@ -7497,6 +7501,14 @@ proc goforw {} { } } +proc go_to_parent {i} { + global parents curview targetid + set ps $parents($curview,$targetid) + if {[llength $ps] >= $i} { + selbyid [lindex $ps [expr $i - 1]] + } +} + proc gettree {id} { global treefilelist treeidlist diffids diffmergeid treepending global nullid nullid2 diff --git a/gitk-git/po/bg.po b/gitk-git/po/bg.po index 782397e6b5..f86a161129 100644 --- a/gitk-git/po/bg.po +++ b/gitk-git/po/bg.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: gitk master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-01-26 15:47-0800\n" -"PO-Revision-Date: 2014-01-08 08:03+0200\n" +"POT-Creation-Date: 2014-08-03 11:17+0300\n" +"PO-Revision-Date: 2014-07-28 07:32+0300\n" "Last-Translator: Alexander Shopov \n" "Language-Team: Bulgarian \n" "Language: bg\n" @@ -22,11 +22,11 @@ msgstr "" msgid "Couldn't get list of unmerged files:" msgstr "Списъкът с неслети файлове не може да бъде получен:" -#: gitk:212 gitk:2353 +#: gitk:212 gitk:2379 msgid "Color words" msgstr "Оцветяване на думите" -#: gitk:217 gitk:2353 gitk:8103 gitk:8136 +#: gitk:217 gitk:2379 gitk:8155 gitk:8188 msgid "Markup words" msgstr "Отбелязване на думите" @@ -40,13 +40,16 @@ msgstr "Грешка при изпълнение на командата с „- #: gitk:391 msgid "No files selected: --merge specified but no files are unmerged." -msgstr "Не са избрани файлове — указана е опцията „--merge“, но няма неслети файлове." +msgstr "" +"Не са избрани файлове — указана е опцията „--merge“, но няма неслети файлове." #: gitk:394 msgid "" "No files selected: --merge specified but no unmerged files are within file " "limit." -msgstr "Не са избрани файлове — указана е опцията „--merge“, но няма неслети файлове в ограниченията." +msgstr "" +"Не са избрани файлове — указана е опцията „--merge“, но няма неслети файлове " +"в ограниченията." #: gitk:416 gitk:564 msgid "Error executing git log:" @@ -56,11 +59,11 @@ msgstr "Грешка при изпълнение на „git log“:" msgid "Reading" msgstr "Прочитане" -#: gitk:494 gitk:4429 +#: gitk:494 gitk:4470 msgid "Reading commits..." msgstr "Прочитане на подаванията…" -#: gitk:497 gitk:1635 gitk:4432 +#: gitk:497 gitk:1635 gitk:4473 msgid "No commits selected" msgstr "Не са избрани подавания" @@ -76,12 +79,12 @@ msgstr "Липсва информация за подавания" msgid "mc" msgstr "mc" -#: gitk:1930 gitk:4222 gitk:9552 gitk:11122 gitk:11401 +#: gitk:1930 gitk:4263 gitk:9604 gitk:11174 gitk:11453 msgid "OK" msgstr "Добре" -#: gitk:1932 gitk:4224 gitk:9079 gitk:9158 gitk:9274 gitk:9323 gitk:9554 -#: gitk:11123 gitk:11402 +#: gitk:1932 gitk:4265 gitk:9131 gitk:9210 gitk:9326 gitk:9375 gitk:9606 +#: gitk:11175 gitk:11454 msgid "Cancel" msgstr "Отказ" @@ -103,7 +106,7 @@ msgstr "Изброяване на указателите" #: gitk:2072 msgid "Start git gui" -msgstr "Стартиране на git gui" +msgstr "Стартиране на „git gui“" #: gitk:2074 msgid "Quit" @@ -137,11 +140,11 @@ msgstr "Изтриване на изгледа" msgid "All files" msgstr "Всички файлове" -#: gitk:2081 gitk:3975 +#: gitk:2081 gitk:4016 msgid "View" msgstr "Изглед" -#: gitk:2091 gitk:2101 gitk:2945 +#: gitk:2091 gitk:2101 gitk:2976 msgid "About gitk" msgstr "Относно gitk" @@ -153,7 +156,7 @@ msgstr "Клавишни комбинации" msgid "Help" msgstr "Помощ" -#: gitk:2183 gitk:8535 +#: gitk:2183 gitk:8587 msgid "SHA1 ID:" msgstr "SHA1:" @@ -165,708 +168,706 @@ msgstr "Ред" msgid "Find" msgstr "Търсене" -#: gitk:2266 -msgid "next" -msgstr "следващо" - -#: gitk:2267 -msgid "prev" -msgstr "предишно" - -#: gitk:2268 +#: gitk:2293 msgid "commit" msgstr "подаване" -#: gitk:2271 gitk:2273 gitk:4590 gitk:4613 gitk:4637 gitk:6653 gitk:6725 -#: gitk:6810 +#: gitk:2297 gitk:2299 gitk:4631 gitk:4654 gitk:4678 gitk:6698 gitk:6770 +#: gitk:6855 msgid "containing:" msgstr "съдържащо:" -#: gitk:2274 gitk:3457 gitk:3462 gitk:4666 +#: gitk:2300 gitk:3488 gitk:3493 gitk:4707 msgid "touching paths:" msgstr "засягащо пътищата:" -#: gitk:2275 gitk:4680 +#: gitk:2301 gitk:4721 msgid "adding/removing string:" msgstr "добавящо/премахващо низ" -#: gitk:2276 gitk:4682 +#: gitk:2302 gitk:4723 msgid "changing lines matching:" msgstr "променящо редове напасващи:" -#: gitk:2285 gitk:2287 gitk:4669 +#: gitk:2311 gitk:2313 gitk:4710 msgid "Exact" msgstr "Точно" -#: gitk:2287 gitk:4757 gitk:6621 +#: gitk:2313 gitk:4798 gitk:6666 msgid "IgnCase" msgstr "Без регистър" -#: gitk:2287 gitk:4639 gitk:4755 gitk:6617 +#: gitk:2313 gitk:4680 gitk:4796 gitk:6662 msgid "Regexp" -msgstr "Рег. изр." +msgstr "Рег. израз" -#: gitk:2289 gitk:2290 gitk:4777 gitk:4807 gitk:4814 gitk:6746 gitk:6814 +#: gitk:2315 gitk:2316 gitk:4818 gitk:4848 gitk:4855 gitk:6791 gitk:6859 msgid "All fields" msgstr "Всички полета" -#: gitk:2290 gitk:4774 gitk:4807 gitk:6684 +#: gitk:2316 gitk:4815 gitk:4848 gitk:6729 msgid "Headline" msgstr "Първи ред" -#: gitk:2291 gitk:4774 gitk:6684 gitk:6814 gitk:7283 +#: gitk:2317 gitk:4815 gitk:6729 gitk:6859 gitk:7332 msgid "Comments" msgstr "Коментари" -#: gitk:2291 gitk:4774 gitk:4779 gitk:4814 gitk:6684 gitk:7218 gitk:8713 -#: gitk:8728 +#: gitk:2317 gitk:4815 gitk:4820 gitk:4855 gitk:6729 gitk:7267 gitk:8765 +#: gitk:8780 msgid "Author" msgstr "Автор" -#: gitk:2291 gitk:4774 gitk:6684 gitk:7220 +#: gitk:2317 gitk:4815 gitk:6729 gitk:7269 msgid "Committer" msgstr "Подаващ" -#: gitk:2322 +#: gitk:2348 msgid "Search" msgstr "Търсене" -#: gitk:2330 +#: gitk:2356 msgid "Diff" msgstr "Разлики" -#: gitk:2332 +#: gitk:2358 msgid "Old version" msgstr "Стара версия" -#: gitk:2334 +#: gitk:2360 msgid "New version" msgstr "Нова версия" -#: gitk:2336 +#: gitk:2362 msgid "Lines of context" msgstr "Контекст в редове" -#: gitk:2346 +#: gitk:2372 msgid "Ignore space change" msgstr "Празните знаци без значение" -#: gitk:2350 gitk:2352 gitk:7842 gitk:8089 +#: gitk:2376 gitk:2378 gitk:7894 gitk:8141 msgid "Line diff" msgstr "Поредови разлики" -#: gitk:2417 +#: gitk:2443 msgid "Patch" msgstr "Кръпка" -#: gitk:2419 +#: gitk:2445 msgid "Tree" msgstr "Дърво" -#: gitk:2577 gitk:2597 +#: gitk:2604 gitk:2624 msgid "Diff this -> selected" msgstr "Разлики между това и избраното" -#: gitk:2578 gitk:2598 +#: gitk:2605 gitk:2625 msgid "Diff selected -> this" msgstr "Разлики между избраното и това" -#: gitk:2579 gitk:2599 +#: gitk:2606 gitk:2626 msgid "Make patch" msgstr "Създаване на кръпка" -#: gitk:2580 gitk:9137 +#: gitk:2607 gitk:9189 msgid "Create tag" msgstr "Създаване на етикет" -#: gitk:2581 gitk:9254 +#: gitk:2608 gitk:9306 msgid "Write commit to file" msgstr "Запазване на подаването във файл" -#: gitk:2582 gitk:9311 +#: gitk:2609 gitk:9363 msgid "Create new branch" msgstr "Създаване на нов клон" -#: gitk:2583 +#: gitk:2610 msgid "Cherry-pick this commit" msgstr "Отбиране на това подаване" -#: gitk:2584 +#: gitk:2611 msgid "Reset HEAD branch to here" msgstr "Привеждане на върха на клона към текущото подаване" -#: gitk:2585 +#: gitk:2612 msgid "Mark this commit" msgstr "Отбелязване на това подаване" -#: gitk:2586 +#: gitk:2613 msgid "Return to mark" msgstr "Връщане към отбелязаното подаване" -#: gitk:2587 +#: gitk:2614 msgid "Find descendant of this and mark" msgstr "Откриване и отбелязване на наследниците" -#: gitk:2588 +#: gitk:2615 msgid "Compare with marked commit" msgstr "Сравнение с отбелязаното подаване" -#: gitk:2589 gitk:2600 +#: gitk:2616 gitk:2627 msgid "Diff this -> marked commit" msgstr "Разлики между това и отбелязаното" -#: gitk:2590 gitk:2601 +#: gitk:2617 gitk:2628 msgid "Diff marked commit -> this" msgstr "Разлики между отбелязаното и това" -#: gitk:2591 +#: gitk:2618 msgid "Revert this commit" msgstr "Отмяна на това подаване" -#: gitk:2607 +#: gitk:2634 msgid "Check out this branch" msgstr "Изтегляне на този клон" -#: gitk:2608 +#: gitk:2635 msgid "Remove this branch" msgstr "Изтриване на този клон" -#: gitk:2615 +#: gitk:2642 msgid "Highlight this too" msgstr "Отбелязване и на това" -#: gitk:2616 +#: gitk:2643 msgid "Highlight this only" msgstr "Отбелязване само на това" -#: gitk:2617 +#: gitk:2644 msgid "External diff" msgstr "Външна програма за разлики" -#: gitk:2618 +#: gitk:2645 msgid "Blame parent commit" msgstr "Анотиране на родителското подаване" -#: gitk:2625 +#: gitk:2652 msgid "Show origin of this line" msgstr "Показване на произхода на този ред" -#: gitk:2626 +#: gitk:2653 msgid "Run git gui blame on this line" msgstr "Изпълнение на „git gui blame“ върху този ред" -#: gitk:2947 +#: gitk:2978 msgid "" "\n" "Gitk - a commit viewer for git\n" "\n" -"Copyright © 2005-2011 Paul Mackerras\n" +"Copyright © 2005-2014 Paul Mackerras\n" "\n" "Use and redistribute under the terms of the GNU General Public License" msgstr "" "\n" "Gitk — визуализация на подаванията в Git\n" "\n" -"Авторски права: © 2005-2011 Paul Mackerras\n" +"Авторски права: © 2005-2014 Paul Mackerras\n" "\n" "Използвайте и разпространявайте при условията на ОПЛ на ГНУ" -#: gitk:2955 gitk:3020 gitk:9738 +#: gitk:2986 gitk:3051 gitk:9790 msgid "Close" msgstr "Затваряне" -#: gitk:2976 +#: gitk:3007 msgid "Gitk key bindings" msgstr "Клавишни комбинации" -#: gitk:2979 +#: gitk:3010 msgid "Gitk key bindings:" msgstr "Клавишни комбинации:" -#: gitk:2981 +#: gitk:3012 #, tcl-format msgid "<%s-Q>\t\tQuit" msgstr "<%s-Q>\t\tСпиране на програмата" -#: gitk:2982 +#: gitk:3013 #, tcl-format msgid "<%s-W>\t\tClose window" msgstr "<%s-W>\t\tЗатваряне на прозореца" -#: gitk:2983 +#: gitk:3014 msgid "\t\tMove to first commit" msgstr "\t\tКъм първото подаване" -#: gitk:2984 +#: gitk:3015 msgid "\t\tMove to last commit" msgstr "\t\tКъм последното подаване" -#: gitk:2985 +#: gitk:3016 msgid ", p, k\tMove up one commit" msgstr ", p, k\tЕдно подаване нагоре" -#: gitk:2986 +#: gitk:3017 msgid ", n, j\tMove down one commit" msgstr ", n, j\tЕдно подаване надолу" -#: gitk:2987 +#: gitk:3018 msgid ", z, h\tGo back in history list" msgstr ", z, h\tНазад в историята" -#: gitk:2988 +#: gitk:3019 msgid ", x, l\tGo forward in history list" msgstr ", x, l\tНапред в историята" -#: gitk:2989 +#: gitk:3020 msgid "\tMove up one page in commit list" -msgstr "\tЕдна страница нагоре в списъка с подаванията" +msgstr "\tСтраница нагоре в списъка с подаванията" -#: gitk:2990 +#: gitk:3021 msgid "\tMove down one page in commit list" -msgstr "\tЕдна страница надолу в списъка с подаванията" +msgstr "\tСтраница надолу в списъка с подаванията" -#: gitk:2991 +#: gitk:3022 #, tcl-format msgid "<%s-Home>\tScroll to top of commit list" msgstr "<%s-Home>\tКъм началото на списъка с подаванията" -#: gitk:2992 +#: gitk:3023 #, tcl-format msgid "<%s-End>\tScroll to bottom of commit list" msgstr "<%s-End>\tКъм края на списъка с подаванията" -#: gitk:2993 +#: gitk:3024 #, tcl-format msgid "<%s-Up>\tScroll commit list up one line" -msgstr "<%s-Up>\tПридвижване на списъка с подавания с един ред нагоре" +msgstr "<%s-Up>\tРед нагоре в списъка с подавания" -#: gitk:2994 +#: gitk:3025 #, tcl-format msgid "<%s-Down>\tScroll commit list down one line" -msgstr "<%s-Down>\tПридвижване на списъка с подавания с един ред надолу" +msgstr "<%s-Down>\tРед надолу в списъка с подавания" -#: gitk:2995 +#: gitk:3026 #, tcl-format msgid "<%s-PageUp>\tScroll commit list up one page" -msgstr "<%s-PageUp>\tПридвижване на списъка с подавания с една страница нагоре" +msgstr "<%s-PageUp>\tСтраница нагоре в списъка с подавания" -#: gitk:2996 +#: gitk:3027 #, tcl-format msgid "<%s-PageDown>\tScroll commit list down one page" -msgstr "<%s-PageDown>\tПридвижване на списъка с подавания с една страница надолу" +msgstr "<%s-PageDown>\tСтраница надолу в списъка с подавания" -#: gitk:2997 +#: gitk:3028 msgid "\tFind backwards (upwards, later commits)" msgstr "\tТърсене назад (визуално нагоре, исторически — последващи)" -#: gitk:2998 +#: gitk:3029 msgid "\tFind forwards (downwards, earlier commits)" -msgstr "\tТърсене напред (визуално надолу, исторически — предхождащи)" +msgstr "" +"\tТърсене напред (визуално надолу, исторически — предхождащи)" -#: gitk:2999 +#: gitk:3030 msgid ", b\tScroll diff view up one page" -msgstr ", b\tПридвижване на изгледа за разлики една страница нагоре" +msgstr ", b\tСтраница нагоре в изгледа за разлики" -#: gitk:3000 +#: gitk:3031 msgid "\tScroll diff view up one page" -msgstr "\tПридвижване на изгледа за разлики една страница нагоре" +msgstr "\tСтраница надолу в изгледа за разлики" -#: gitk:3001 +#: gitk:3032 msgid "\t\tScroll diff view down one page" -msgstr "\t\tПридвижване на изгледа за разлики една страница надолу" +msgstr "\t\tСтраница надолу в изгледа за разлики" -#: gitk:3002 +#: gitk:3033 msgid "u\t\tScroll diff view up 18 lines" -msgstr "u\t\tПридвижване на изгледа за разлики 18 реда нагоре" +msgstr "u\t\t18 реда нагоре в изгледа за разлики" -#: gitk:3003 +#: gitk:3034 msgid "d\t\tScroll diff view down 18 lines" -msgstr "d\t\tПридвижване на изгледа за разлики 18 реда надолу" +msgstr "d\t\t18 реда надолу в изгледа за разлики" -#: gitk:3004 +#: gitk:3035 #, tcl-format msgid "<%s-F>\t\tFind" msgstr "<%s-F>\t\tТърсене" -#: gitk:3005 +#: gitk:3036 #, tcl-format msgid "<%s-G>\t\tMove to next find hit" msgstr "<%s-G>\t\tКъм следващата поява" -#: gitk:3006 +#: gitk:3037 msgid "\tMove to next find hit" msgstr "\tКъм следващата поява" -#: gitk:3007 +#: gitk:3038 msgid "/\t\tFocus the search box" msgstr "/\t\tФокус върху полето за търсене" -#: gitk:3008 +#: gitk:3039 msgid "?\t\tMove to previous find hit" msgstr "?\t\tКъм предишната поява" -#: gitk:3009 +#: gitk:3040 msgid "f\t\tScroll diff view to next file" -msgstr "f\t\tПридвижване на изгледа за разлики към следващия ред" +msgstr "f\t\tСледващ файл в изгледа за разлики" -#: gitk:3010 +#: gitk:3041 #, tcl-format msgid "<%s-S>\t\tSearch for next hit in diff view" msgstr "<%s-S>\t\tТърсене на следващата поява в изгледа за разлики" -#: gitk:3011 +#: gitk:3042 #, tcl-format msgid "<%s-R>\t\tSearch for previous hit in diff view" msgstr "<%s-R>\t\tТърсене на предишната поява в изгледа за разлики" -#: gitk:3012 +#: gitk:3043 #, tcl-format msgid "<%s-KP+>\tIncrease font size" msgstr "<%s-KP+>\tПо-голям размер на шрифта" -#: gitk:3013 +#: gitk:3044 #, tcl-format msgid "<%s-plus>\tIncrease font size" msgstr "<%s-plus>\tПо-голям размер на шрифта" -#: gitk:3014 +#: gitk:3045 #, tcl-format msgid "<%s-KP->\tDecrease font size" msgstr "<%s-KP->\tПо-малък размер на шрифта" -#: gitk:3015 +#: gitk:3046 #, tcl-format msgid "<%s-minus>\tDecrease font size" msgstr "<%s-minus>\tПо-малък размер на шрифта" -#: gitk:3016 +#: gitk:3047 msgid "\t\tUpdate" msgstr "\t\tОбновяване" -#: gitk:3471 gitk:3480 +#: gitk:3512 gitk:3521 #, tcl-format msgid "Error creating temporary directory %s:" msgstr "Грешка при създаването на временната директория „%s“:" -#: gitk:3493 +#: gitk:3534 #, tcl-format msgid "Error getting \"%s\" from %s:" msgstr "Грешка при получаването на „%s“ от %s:" -#: gitk:3556 +#: gitk:3597 msgid "command failed:" msgstr "неуспешно изпълнение на команда:" -#: gitk:3705 +#: gitk:3746 msgid "No such commit" msgstr "Такова подаване няма" -#: gitk:3719 +#: gitk:3760 msgid "git gui blame: command failed:" -msgstr "git gui blame: неуспешно изпълнение на команда:" +msgstr "„git gui blame“: неуспешно изпълнение на команда:" -#: gitk:3750 +#: gitk:3791 #, tcl-format msgid "Couldn't read merge head: %s" msgstr "Върхът за сливане не може да бъде прочетен: %s" -#: gitk:3758 +#: gitk:3799 #, tcl-format msgid "Error reading index: %s" msgstr "Грешка при прочитане на индекса: %s" -#: gitk:3783 +#: gitk:3824 #, tcl-format msgid "Couldn't start git blame: %s" msgstr "Командата „git blame“ не може да бъде стартирана: %s" -#: gitk:3786 gitk:6652 +#: gitk:3827 gitk:6697 msgid "Searching" msgstr "Търсене" -#: gitk:3818 +#: gitk:3859 #, tcl-format msgid "Error running git blame: %s" msgstr "Грешка при изпълнението на „git blame“: %s" -#: gitk:3846 +#: gitk:3887 #, tcl-format msgid "That line comes from commit %s, which is not in this view" msgstr "Този ред идва от подаването %s, което не е в изгледа" -#: gitk:3860 +#: gitk:3901 msgid "External diff viewer failed:" msgstr "Неуспешно изпълнение на външната програма за разлики:" -#: gitk:3978 +#: gitk:4019 msgid "Gitk view definition" msgstr "Дефиниция на изглед в Gitk" -#: gitk:3982 +#: gitk:4023 msgid "Remember this view" msgstr "Запазване на този изглед" -#: gitk:3983 +#: gitk:4024 msgid "References (space separated list):" msgstr "Указатели (списък с разделител интервал):" -#: gitk:3984 +#: gitk:4025 msgid "Branches & tags:" msgstr "Клони и етикети:" -#: gitk:3985 +#: gitk:4026 msgid "All refs" msgstr "Всички указатели" -#: gitk:3986 +#: gitk:4027 msgid "All (local) branches" msgstr "Всички (локални) клони" -#: gitk:3987 +#: gitk:4028 msgid "All tags" msgstr "Всички етикети" -#: gitk:3988 +#: gitk:4029 msgid "All remote-tracking branches" msgstr "Всички следящи клони" -#: gitk:3989 +#: gitk:4030 msgid "Commit Info (regular expressions):" msgstr "Информация за подаване (рег. изр.):" -#: gitk:3990 +#: gitk:4031 msgid "Author:" msgstr "Автор:" -#: gitk:3991 +#: gitk:4032 msgid "Committer:" msgstr "Подал:" -#: gitk:3992 +#: gitk:4033 msgid "Commit Message:" msgstr "Съобщение при подаване:" -#: gitk:3993 +#: gitk:4034 msgid "Matches all Commit Info criteria" msgstr "Съвпадение по коя да е информация за подаването" -#: gitk:3994 +#: gitk:4035 msgid "Changes to Files:" msgstr "Промени по файловете:" -#: gitk:3995 +#: gitk:4036 msgid "Fixed String" msgstr "Дословен низ" -#: gitk:3996 +#: gitk:4037 msgid "Regular Expression" msgstr "Регулярен израз" -#: gitk:3997 +#: gitk:4038 msgid "Search string:" msgstr "Низ за търсене:" -#: gitk:3998 +#: gitk:4039 msgid "" "Commit Dates (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 " "15:27:38\"):" -msgstr "Дата на подаване („2 weeks ago“ (преди 2 седмици), „2009-03-17 15:27:38“, „March 17, 2009 15:27:38“):" +msgstr "" +"Дата на подаване („2 weeks ago“ (преди 2 седмици), „2009-03-17 15:27:38“, " +"„March 17, 2009 15:27:38“):" -#: gitk:3999 +#: gitk:4040 msgid "Since:" msgstr "От:" -#: gitk:4000 +#: gitk:4041 msgid "Until:" msgstr "До:" -#: gitk:4001 +#: gitk:4042 msgid "Limit and/or skip a number of revisions (positive integer):" -msgstr "Ограничаване и/или прескачане на определен брой версии (неотрицателно цяло число):" +msgstr "" +"Ограничаване и/или прескачане на определен брой версии (неотрицателно цяло " +"число):" -#: gitk:4002 +#: gitk:4043 msgid "Number to show:" msgstr "Брой показани:" -#: gitk:4003 +#: gitk:4044 msgid "Number to skip:" msgstr "Брой прескочени:" -#: gitk:4004 +#: gitk:4045 msgid "Miscellaneous options:" msgstr "Разни:" -#: gitk:4005 +#: gitk:4046 msgid "Strictly sort by date" msgstr "Подреждане по дата" -#: gitk:4006 +#: gitk:4047 msgid "Mark branch sides" msgstr "Отбелязване на страните по клона" -#: gitk:4007 +#: gitk:4048 msgid "Limit to first parent" -msgstr "Само първият родител" +msgstr "Само първия родител" -#: gitk:4008 +#: gitk:4049 msgid "Simple history" msgstr "Опростена история" -#: gitk:4009 +#: gitk:4050 msgid "Additional arguments to git log:" msgstr "Допълнителни аргументи към „git log“:" -#: gitk:4010 +#: gitk:4051 msgid "Enter files and directories to include, one per line:" msgstr "Въведете файловете и директориите за включване, по елемент на ред" -#: gitk:4011 +#: gitk:4052 msgid "Command to generate more commits to include:" -msgstr "Команда за генерирането на допълнителни подавания, които да бъдат включени:" +msgstr "" +"Команда за генерирането на допълнителни подавания, които да бъдат включени:" -#: gitk:4135 +#: gitk:4176 msgid "Gitk: edit view" msgstr "Gitk: редактиране на изглед" -#: gitk:4143 +#: gitk:4184 msgid "-- criteria for selecting revisions" msgstr "— критерии за избор на версии" -#: gitk:4148 +#: gitk:4189 msgid "View Name" msgstr "Име на изглед" -#: gitk:4223 +#: gitk:4264 msgid "Apply (F5)" msgstr "Прилагане (F5)" -#: gitk:4261 +#: gitk:4302 msgid "Error in commit selection arguments:" msgstr "Грешка в аргументите за избор на подавания:" -#: gitk:4314 gitk:4366 gitk:4827 gitk:4841 gitk:6107 gitk:12184 gitk:12185 +#: gitk:4355 gitk:4407 gitk:4868 gitk:4882 gitk:6152 gitk:12281 gitk:12282 msgid "None" msgstr "Няма" -#: gitk:4924 gitk:4929 +#: gitk:4965 gitk:4970 msgid "Descendant" msgstr "Наследник" -#: gitk:4925 +#: gitk:4966 msgid "Not descendant" msgstr "Не е наследник" -#: gitk:4932 gitk:4937 +#: gitk:4973 gitk:4978 msgid "Ancestor" msgstr "Предшественик" -#: gitk:4933 +#: gitk:4974 msgid "Not ancestor" msgstr "Не е предшественик" -#: gitk:5223 +#: gitk:5268 msgid "Local changes checked in to index but not committed" msgstr "Локални промени добавени към индекса, но неподадени" -#: gitk:5259 +#: gitk:5304 msgid "Local uncommitted changes, not checked in to index" msgstr "Локални промени извън индекса" -#: gitk:7032 +#: gitk:7077 msgid "and many more" msgstr "и още много" -#: gitk:7035 +#: gitk:7080 msgid "many" msgstr "много" -#: gitk:7222 +#: gitk:7271 msgid "Tags:" msgstr "Етикети:" -#: gitk:7239 gitk:7245 gitk:8708 +#: gitk:7288 gitk:7294 gitk:8760 msgid "Parent" msgstr "Родител" -#: gitk:7250 +#: gitk:7299 msgid "Child" msgstr "Дете" -#: gitk:7259 +#: gitk:7308 msgid "Branch" msgstr "Клон" -#: gitk:7262 +#: gitk:7311 msgid "Follows" msgstr "Следва" -#: gitk:7265 +#: gitk:7314 msgid "Precedes" msgstr "Предшества" -#: gitk:7849 +#: gitk:7901 #, tcl-format msgid "Error getting diffs: %s" msgstr "Грешка при получаването на разликите: %s" -#: gitk:8533 +#: gitk:8585 msgid "Goto:" msgstr "Към ред:" -#: gitk:8554 +#: gitk:8606 #, tcl-format msgid "Short SHA1 id %s is ambiguous" -msgstr "Съкратената SHA1 %s не е еднозначна" +msgstr "Съкратената сума по SHA1 %s не е еднозначна" -#: gitk:8561 +#: gitk:8613 #, tcl-format msgid "Revision %s is not known" msgstr "Непозната версия %s" -#: gitk:8571 +#: gitk:8623 #, tcl-format msgid "SHA1 id %s is not known" -msgstr "Непозната SHA1 %s" +msgstr "Непозната сума по SHA1 %s" -#: gitk:8573 +#: gitk:8625 #, tcl-format msgid "Revision %s is not in the current view" msgstr "Версия %s не е в текущия изглед" -#: gitk:8715 gitk:8730 +#: gitk:8767 gitk:8782 msgid "Date" msgstr "Дата" -#: gitk:8718 +#: gitk:8770 msgid "Children" msgstr "Деца" -#: gitk:8781 +#: gitk:8833 #, tcl-format msgid "Reset %s branch to here" msgstr "Зануляване на клона „%s“ към текущото подаване" -#: gitk:8783 +#: gitk:8835 msgid "Detached head: can't reset" msgstr "Несвързан връх: невъзможно зануляване" -#: gitk:8888 gitk:8894 +#: gitk:8940 gitk:8946 msgid "Skipping merge commit " msgstr "Пропускане на подаването на сливането" -#: gitk:8903 gitk:8908 +#: gitk:8955 gitk:8960 msgid "Error getting patch ID for " msgstr "Грешка при получаването на идентификатора на " -#: gitk:8904 gitk:8909 +#: gitk:8956 gitk:8961 msgid " - stopping\n" msgstr " — спиране\n" -#: gitk:8914 gitk:8917 gitk:8925 gitk:8939 gitk:8948 +#: gitk:8966 gitk:8969 gitk:8977 gitk:8991 gitk:9000 msgid "Commit " msgstr "Подаване" -#: gitk:8918 +#: gitk:8970 msgid "" " is the same patch as\n" " " @@ -874,7 +875,7 @@ msgstr "" " е същата кръпка като\n" " " -#: gitk:8926 +#: gitk:8978 msgid "" " differs from\n" " " @@ -882,135 +883,138 @@ msgstr "" " се различава от\n" " " -#: gitk:8928 +#: gitk:8980 msgid "" "Diff of commits:\n" "\n" -msgstr "Разлика между подаванията:\n\n" +msgstr "" +"Разлика между подаванията:\n" +"\n" -#: gitk:8940 gitk:8949 +#: gitk:8992 gitk:9001 #, tcl-format msgid " has %s children - stopping\n" msgstr " има %s деца — спиране\n" -#: gitk:8968 +#: gitk:9020 #, tcl-format msgid "Error writing commit to file: %s" msgstr "Грешка при запазването на подаването във файл: %s" -#: gitk:8974 +#: gitk:9026 #, tcl-format msgid "Error diffing commits: %s" msgstr "Грешка при изчисляването на разликите между подаванията: %s" -#: gitk:9020 +#: gitk:9072 msgid "Top" msgstr "Най-горе" -#: gitk:9021 +#: gitk:9073 msgid "From" msgstr "От" -#: gitk:9026 +#: gitk:9078 msgid "To" msgstr "До" -#: gitk:9050 +#: gitk:9102 msgid "Generate patch" msgstr "Генериране на кръпка" -#: gitk:9052 +#: gitk:9104 msgid "From:" msgstr "От:" -#: gitk:9061 +#: gitk:9113 msgid "To:" msgstr "До:" -#: gitk:9070 +#: gitk:9122 msgid "Reverse" msgstr "Обръщане" -#: gitk:9072 gitk:9268 +#: gitk:9124 gitk:9320 msgid "Output file:" msgstr "Запазване във файла:" -#: gitk:9078 +#: gitk:9130 msgid "Generate" msgstr "Генериране" -#: gitk:9116 +#: gitk:9168 msgid "Error creating patch:" msgstr "Грешка при създаването на кръпка:" -#: gitk:9139 gitk:9256 gitk:9313 +#: gitk:9191 gitk:9308 gitk:9365 msgid "ID:" msgstr "Идентификатор:" -#: gitk:9148 +#: gitk:9200 msgid "Tag name:" msgstr "Име на етикет:" -#: gitk:9151 +#: gitk:9203 msgid "Tag message is optional" msgstr "Съобщението за етикет е незадължително" -#: gitk:9153 +#: gitk:9205 msgid "Tag message:" msgstr "Съобщение за етикет:" -#: gitk:9157 gitk:9322 +#: gitk:9209 gitk:9374 msgid "Create" msgstr "Създаване" -#: gitk:9175 +#: gitk:9227 msgid "No tag name specified" msgstr "Липсва име на етикет" -#: gitk:9179 +#: gitk:9231 #, tcl-format msgid "Tag \"%s\" already exists" msgstr "Етикетът „%s“ вече съществува" -#: gitk:9189 +#: gitk:9241 msgid "Error creating tag:" msgstr "Грешка при създаването на етикет:" -#: gitk:9265 +#: gitk:9317 msgid "Command:" msgstr "Команда:" -#: gitk:9273 +#: gitk:9325 msgid "Write" -msgstr "Pdmdpldke" +msgstr "Запазване" -#: gitk:9291 +#: gitk:9343 msgid "Error writing commit:" msgstr "Грешка при запазването на подаването:" -#: gitk:9318 +#: gitk:9370 msgid "Name:" msgstr "Име:" -#: gitk:9341 +#: gitk:9393 msgid "Please specify a name for the new branch" msgstr "Укажете име за новия клон" -#: gitk:9346 +#: gitk:9398 #, tcl-format msgid "Branch '%s' already exists. Overwrite?" msgstr "Клонът „%s“ вече съществува. Да бъде ли презаписан?" -#: gitk:9413 +#: gitk:9465 #, tcl-format msgid "Commit %s is already included in branch %s -- really re-apply it?" -msgstr "Подаването „%s“ вече е включено в клона „%s“ — да бъде ли приложено отново?" +msgstr "" +"Подаването „%s“ вече е включено в клона „%s“ — да бъде ли приложено отново?" -#: gitk:9418 +#: gitk:9470 msgid "Cherry-picking" msgstr "Отбиране" -#: gitk:9427 +#: gitk:9479 #, tcl-format msgid "" "Cherry-pick failed because of local changes to file '%s'.\n" @@ -1019,7 +1023,7 @@ msgstr "" "Неуспешно отбиране, защото във файла „%s“ има локални промени.\n" "Подайте, занулете или ги скатайте и пробвайте отново." -#: gitk:9433 +#: gitk:9485 msgid "" "Cherry-pick failed because of merge conflict.\n" "Do you wish to run git citool to resolve it?" @@ -1027,20 +1031,20 @@ msgstr "" "Неуспешно отбиране поради конфликти при сливане.\n" "Искате ли да ги коригирате чрез „git citool“?" -#: gitk:9449 gitk:9507 +#: gitk:9501 gitk:9559 msgid "No changes committed" msgstr "Не са подадени промени" -#: gitk:9476 +#: gitk:9528 #, tcl-format msgid "Commit %s is not included in branch %s -- really revert it?" msgstr "Подаването „%s“ не е включено в клона „%s“. Да бъде ли отменено?" -#: gitk:9481 +#: gitk:9533 msgid "Reverting" msgstr "Отмяна" -#: gitk:9489 +#: gitk:9541 #, tcl-format msgid "" "Revert failed because of local changes to the following files:%s Please " @@ -1049,7 +1053,7 @@ msgstr "" "Неуспешна отмяна, защото във файла „%s“ има локални промени.\n" "Подайте, занулете или ги скатайте и пробвайте отново.<" -#: gitk:9493 +#: gitk:9545 msgid "" "Revert failed because of merge conflict.\n" " Do you wish to run git citool to resolve it?" @@ -1057,28 +1061,28 @@ msgstr "" "Неуспешно отмяна поради конфликти при сливане.\n" "Искате ли да ги коригирате чрез „git citool“?" -#: gitk:9536 +#: gitk:9588 msgid "Confirm reset" msgstr "Потвърждаване на зануляването" -#: gitk:9538 +#: gitk:9590 #, tcl-format msgid "Reset branch %s to %s?" -msgstr "Да се занули ли клона „%s“ към „%s“?" +msgstr "Да се занули ли клонът „%s“ към „%s“?" -#: gitk:9540 +#: gitk:9592 msgid "Reset type:" msgstr "Вид зануляване:" -#: gitk:9543 +#: gitk:9595 msgid "Soft: Leave working tree and index untouched" msgstr "Слабо: работното дърво и индекса остават същите" -#: gitk:9546 +#: gitk:9598 msgid "Mixed: Leave working tree untouched, reset index" msgstr "Смесено: работното дърво остава същото, индексът се занулява" -#: gitk:9549 +#: gitk:9601 msgid "" "Hard: Reset working tree and index\n" "(discard ALL local changes)" @@ -1086,249 +1090,251 @@ msgstr "" "Силно: зануляване и на работното дърво, и на индекса\n" "(*ВСИЧКИ* локални промени ще бъдат безвъзвратно загубени)" -#: gitk:9566 +#: gitk:9618 msgid "Resetting" msgstr "Зануляване" -#: gitk:9626 +#: gitk:9678 msgid "Checking out" msgstr "Изтегляне" -#: gitk:9679 +#: gitk:9731 msgid "Cannot delete the currently checked-out branch" msgstr "Текущо изтегленият клон не може да бъде изтрит" -#: gitk:9685 +#: gitk:9737 #, tcl-format msgid "" "The commits on branch %s aren't on any other branch.\n" "Really delete branch %s?" msgstr "" "Подаванията на клона „%s“ не са на никой друг клон.\n" -"Наистина ли да се изтрие клона „%s“?" +"Наистина ли да се изтрие клонът „%s“?" -#: gitk:9716 +#: gitk:9768 #, tcl-format msgid "Tags and heads: %s" msgstr "Етикети и върхове: %s" -#: gitk:9731 +#: gitk:9783 msgid "Filter" msgstr "Филтриране" -#: gitk:10027 +#: gitk:10079 msgid "" "Error reading commit topology information; branch and preceding/following " "tag information will be incomplete." -msgstr "Грешка при прочитането на топологията на подаванията. Информацията за клона и предшестващите/следващите етикети ще е непълна." +msgstr "" +"Грешка при прочитането на топологията на подаванията. Информацията за клона " +"и предшестващите/следващите етикети ще е непълна." -#: gitk:11004 +#: gitk:11056 msgid "Tag" msgstr "Етикет" -#: gitk:11008 +#: gitk:11060 msgid "Id" msgstr "Идентификатор" -#: gitk:11091 +#: gitk:11143 msgid "Gitk font chooser" msgstr "Избор на шрифт за Gitk" -#: gitk:11108 +#: gitk:11160 msgid "B" msgstr "Ч" -#: gitk:11111 +#: gitk:11163 msgid "I" msgstr "К" -#: gitk:11229 +#: gitk:11281 msgid "Commit list display options" msgstr "Настройки на списъка с подавания" -#: gitk:11232 +#: gitk:11284 msgid "Maximum graph width (lines)" msgstr "Максимална широчина на графа (в редове)" -#: gitk:11235 +#: gitk:11287 #, tcl-format msgid "Maximum graph width (% of pane)" msgstr "Максимална широчина на графа (% от панела)" -#: gitk:11238 +#: gitk:11290 msgid "Show local changes" msgstr "Показване на локалните промени" -#: gitk:11241 +#: gitk:11293 msgid "Auto-select SHA1 (length)" msgstr "Автоматично избиране на SHA1 (дължина)" -#: gitk:11245 +#: gitk:11297 msgid "Hide remote refs" msgstr "Скриване на отдалечените указатели" -#: gitk:11249 +#: gitk:11301 msgid "Diff display options" msgstr "Настройки на показването на разликите" -#: gitk:11251 +#: gitk:11303 msgid "Tab spacing" msgstr "Широчина на табулатора" -#: gitk:11254 +#: gitk:11306 msgid "Display nearby tags/heads" msgstr "Извеждане на близките етикети и върхове" -#: gitk:11257 +#: gitk:11309 msgid "Maximum # tags/heads to show" msgstr "Максимален брой етикети/върхове за показване" -#: gitk:11260 +#: gitk:11312 msgid "Limit diffs to listed paths" msgstr "Разлика само в избраните пътища" -#: gitk:11263 +#: gitk:11315 msgid "Support per-file encodings" msgstr "Поддръжка на различни кодирания за всеки файл" -#: gitk:11269 gitk:11416 +#: gitk:11321 gitk:11468 msgid "External diff tool" msgstr "Външен инструмент за разлики" -#: gitk:11270 +#: gitk:11322 msgid "Choose..." msgstr "Избор…" -#: gitk:11275 +#: gitk:11327 msgid "General options" msgstr "Общи настройки" -#: gitk:11278 +#: gitk:11330 msgid "Use themed widgets" msgstr "Използване на тема за графичните обекти" -#: gitk:11280 +#: gitk:11332 msgid "(change requires restart)" msgstr "(промяната изисква рестартиране на Gitk)" -#: gitk:11282 +#: gitk:11334 msgid "(currently unavailable)" msgstr "(в момента недостъпно)" -#: gitk:11293 +#: gitk:11345 msgid "Colors: press to choose" msgstr "Цветове: избира се с натискане" -#: gitk:11296 +#: gitk:11348 msgid "Interface" msgstr "Интерфейс" -#: gitk:11297 +#: gitk:11349 msgid "interface" msgstr "интерфейс" -#: gitk:11300 +#: gitk:11352 msgid "Background" msgstr "Фон" -#: gitk:11301 gitk:11331 +#: gitk:11353 gitk:11383 msgid "background" -msgstr "Фон" +msgstr "фон" -#: gitk:11304 +#: gitk:11356 msgid "Foreground" msgstr "Знаци" -#: gitk:11305 +#: gitk:11357 msgid "foreground" msgstr "знаци" -#: gitk:11308 +#: gitk:11360 msgid "Diff: old lines" msgstr "Разлика: стари редове" -#: gitk:11309 +#: gitk:11361 msgid "diff old lines" msgstr "разлика, стари редове" -#: gitk:11313 +#: gitk:11365 msgid "Diff: new lines" msgstr "Разлика: нови редове" -#: gitk:11314 +#: gitk:11366 msgid "diff new lines" msgstr "разлика, нови редове" -#: gitk:11318 +#: gitk:11370 msgid "Diff: hunk header" msgstr "Разлика: начало на парче" -#: gitk:11320 +#: gitk:11372 msgid "diff hunk header" msgstr "разлика, начало на парче" -#: gitk:11324 +#: gitk:11376 msgid "Marked line bg" msgstr "Фон на отбелязан ред" -#: gitk:11326 +#: gitk:11378 msgid "marked line background" -msgstr "Фон на отбелязан ред" +msgstr "фон на отбелязан ред" -#: gitk:11330 +#: gitk:11382 msgid "Select bg" msgstr "Избор на фон" -#: gitk:11339 +#: gitk:11391 msgid "Fonts: press to choose" msgstr "Шрифтове: избира се с натискане" -#: gitk:11341 +#: gitk:11393 msgid "Main font" msgstr "Основен шрифт" -#: gitk:11342 +#: gitk:11394 msgid "Diff display font" msgstr "Шрифт за разликите" -#: gitk:11343 +#: gitk:11395 msgid "User interface font" msgstr "Шрифт на интерфейса" -#: gitk:11365 +#: gitk:11417 msgid "Gitk preferences" msgstr "Настройки на Gitk" -#: gitk:11374 +#: gitk:11426 msgid "General" msgstr "Общи" -#: gitk:11375 +#: gitk:11427 msgid "Colors" msgstr "Цветове" -#: gitk:11376 +#: gitk:11428 msgid "Fonts" msgstr "Шрифтове" -#: gitk:11426 +#: gitk:11478 #, tcl-format msgid "Gitk: choose color for %s" -msgstr "Gitk: избор на цвят на %s" +msgstr "Gitk: избор на цвят на „%s“" -#: gitk:12080 +#: gitk:12177 msgid "Cannot find a git repository here." msgstr "Тук липсва хранилище на Git." -#: gitk:12127 +#: gitk:12224 #, tcl-format msgid "Ambiguous argument '%s': both revision and filename" msgstr "Нееднозначен аргумент „%s“: има и такава версия, и такъв файл" -#: gitk:12139 +#: gitk:12236 msgid "Bad arguments to gitk:" msgstr "Неправилни аргументи на gitk:" -#: gitk:12242 +#: gitk:12339 msgid "Command line" msgstr "Команден ред" diff --git a/gpg-interface.c b/gpg-interface.c index 8b0e87436b..1ef73fb7df 100644 --- a/gpg-interface.c +++ b/gpg-interface.c @@ -7,6 +7,20 @@ static char *configured_signing_key; static const char *gpg_program = "gpg"; +void signature_check_clear(struct signature_check *sigc) +{ + free(sigc->payload); + free(sigc->gpg_output); + free(sigc->gpg_status); + free(sigc->signer); + free(sigc->key); + sigc->payload = NULL; + sigc->gpg_output = NULL; + sigc->gpg_status = NULL; + sigc->signer = NULL; + sigc->key = NULL; +} + void set_signing_key(const char *key) { free(configured_signing_key); @@ -41,12 +55,11 @@ const char *get_signing_key(void) */ int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key) { - struct child_process gpg; + struct child_process gpg = CHILD_PROCESS_INIT; const char *args[4]; ssize_t len; size_t i, j, bottom; - memset(&gpg, 0, sizeof(gpg)); gpg.argv = args; gpg.in = -1; gpg.out = -1; @@ -102,7 +115,7 @@ int verify_signed_buffer(const char *payload, size_t payload_size, const char *signature, size_t signature_size, struct strbuf *gpg_output, struct strbuf *gpg_status) { - struct child_process gpg; + struct child_process gpg = CHILD_PROCESS_INIT; const char *args_gpg[] = {NULL, "--status-fd=1", "--verify", "FILE", "-", NULL}; char path[PATH_MAX]; int fd, ret; @@ -119,7 +132,6 @@ int verify_signed_buffer(const char *payload, size_t payload_size, path, strerror(errno)); close(fd); - memset(&gpg, 0, sizeof(gpg)); gpg.argv = args_gpg; gpg.in = -1; gpg.out = -1; diff --git a/gpg-interface.h b/gpg-interface.h index a85cb5bc97..37c23daff0 100644 --- a/gpg-interface.h +++ b/gpg-interface.h @@ -2,6 +2,7 @@ #define GPG_INTERFACE_H struct signature_check { + char *payload; char *gpg_output; char *gpg_status; char result; /* 0 (not checked), @@ -13,6 +14,7 @@ struct signature_check { char *key; }; +extern void signature_check_clear(struct signature_check *sigc); extern int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key); extern int verify_signed_buffer(const char *payload, size_t payload_size, const char *signature, size_t signature_size, struct strbuf *gpg_output, struct strbuf *gpg_status); extern int git_gpg_config(const char *, const char *, void *); diff --git a/hashmap.c b/hashmap.c index d1b8056d8d..f693839cb4 100644 --- a/hashmap.c +++ b/hashmap.c @@ -226,3 +226,41 @@ void *hashmap_iter_next(struct hashmap_iter *iter) current = iter->map->table[iter->tablepos++]; } } + +struct pool_entry { + struct hashmap_entry ent; + size_t len; + unsigned char data[FLEX_ARRAY]; +}; + +static int pool_entry_cmp(const struct pool_entry *e1, + const struct pool_entry *e2, + const unsigned char *keydata) +{ + return e1->data != keydata && + (e1->len != e2->len || memcmp(e1->data, keydata, e1->len)); +} + +const void *memintern(const void *data, size_t len) +{ + static struct hashmap map; + struct pool_entry key, *e; + + /* initialize string pool hashmap */ + if (!map.tablesize) + hashmap_init(&map, (hashmap_cmp_fn) pool_entry_cmp, 0); + + /* lookup interned string in pool */ + hashmap_entry_init(&key, memhash(data, len)); + key.len = len; + e = hashmap_get(&map, &key, data); + if (!e) { + /* not found: create it */ + e = xmallocz(sizeof(struct pool_entry) + len); + hashmap_entry_init(e, key.ent.hash); + e->len = len; + memcpy(e->data, data, len); + hashmap_add(&map, e); + } + return e->data; +} diff --git a/hashmap.h b/hashmap.h index a816ad47b1..ab7958ae33 100644 --- a/hashmap.h +++ b/hashmap.h @@ -13,6 +13,17 @@ extern unsigned int strihash(const char *buf); extern unsigned int memhash(const void *buf, size_t len); extern unsigned int memihash(const void *buf, size_t len); +static inline unsigned int sha1hash(const unsigned char *sha1) +{ + /* + * Equivalent to 'return *(unsigned int *)sha1;', but safe on + * platforms that don't support unaligned reads. + */ + unsigned int hash; + memcpy(&hash, sha1, sizeof(hash)); + return hash; +} + /* data structures */ struct hashmap_entry { @@ -57,6 +68,14 @@ extern void *hashmap_put(struct hashmap *map, void *entry); extern void *hashmap_remove(struct hashmap *map, const void *key, const void *keydata); +static inline void *hashmap_get_from_hash(const struct hashmap *map, + unsigned int hash, const void *keydata) +{ + struct hashmap_entry key; + hashmap_entry_init(&key, hash); + return hashmap_get(map, &key, keydata); +} + /* hashmap_iter functions */ extern void hashmap_iter_init(struct hashmap *map, struct hashmap_iter *iter); @@ -68,4 +87,12 @@ static inline void *hashmap_iter_first(struct hashmap *map, return hashmap_iter_next(iter); } +/* string interning */ + +extern const void *memintern(const void *data, size_t len); +static inline const char *strintern(const char *string) +{ + return memintern(string, strlen(string)); +} + #endif diff --git a/help.c b/help.c index b266b09320..7af65e205e 100644 --- a/help.c +++ b/help.c @@ -129,7 +129,6 @@ static void list_commands_in_dir(struct cmdnames *cmds, const char *path, const char *prefix) { - int prefix_len; DIR *dir = opendir(path); struct dirent *de; struct strbuf buf = STRBUF_INIT; @@ -139,15 +138,15 @@ static void list_commands_in_dir(struct cmdnames *cmds, return; if (!prefix) prefix = "git-"; - prefix_len = strlen(prefix); strbuf_addf(&buf, "%s/", path); len = buf.len; while ((de = readdir(dir)) != NULL) { - int entlen; + const char *ent; + size_t entlen; - if (!starts_with(de->d_name, prefix)) + if (!skip_prefix(de->d_name, prefix, &ent)) continue; strbuf_setlen(&buf, len); @@ -155,11 +154,10 @@ static void list_commands_in_dir(struct cmdnames *cmds, if (!is_executable(buf.buf)) continue; - entlen = strlen(de->d_name) - prefix_len; - if (has_extension(de->d_name, ".exe")) - entlen -= 4; + entlen = strlen(ent); + strip_suffix(ent, ".exe", &entlen); - add_cmdname(cmds, de->d_name + prefix_len, entlen); + add_cmdname(cmds, ent, entlen); } closedir(dir); strbuf_release(&buf); @@ -251,11 +249,13 @@ static struct cmdnames aliases; static int git_unknown_cmd_config(const char *var, const char *value, void *cb) { + const char *p; + if (!strcmp(var, "help.autocorrect")) autocorrect = git_config_int(var,value); /* Also use aliases for command lookup */ - if (starts_with(var, "alias.")) - add_cmdname(&aliases, var + 6, strlen(var + 6)); + if (skip_prefix(var, "alias.", &p)) + add_cmdname(&aliases, p, strlen(p)); return git_default_config(var, value, cb); } @@ -412,11 +412,12 @@ static int append_similar_ref(const char *refname, const unsigned char *sha1, { struct similar_ref_cb *cb = (struct similar_ref_cb *)(cb_data); char *branch = strrchr(refname, '/') + 1; + const char *remote; + /* A remote branch of the same name is deemed similar */ - if (starts_with(refname, "refs/remotes/") && + if (skip_prefix(refname, "refs/remotes/", &remote) && !strcmp(branch, cb->base_ref)) - string_list_append(cb->similar_refs, - refname + strlen("refs/remotes/")); + string_list_append(cb->similar_refs, remote); return 0; } diff --git a/http-backend.c b/http-backend.c index d2c0a625ce..404e682593 100644 --- a/http-backend.c +++ b/http-backend.c @@ -219,40 +219,36 @@ static void get_idx_file(char *name) send_local_file("application/x-git-packed-objects-toc", name); } -static int http_config(const char *var, const char *value, void *cb) +static void http_config(void) { - if (!strcmp(var, "http.getanyfile")) { - getanyfile = git_config_bool(var, value); - return 0; - } + int i, value = 0; + struct strbuf var = STRBUF_INIT; - if (starts_with(var, "http.")) { - int i; + git_config_get_bool("http.getanyfile", &getanyfile); - for (i = 0; i < ARRAY_SIZE(rpc_service); i++) { - struct rpc_service *svc = &rpc_service[i]; - if (!strcmp(var + 5, svc->config_name)) { - svc->enabled = git_config_bool(var, value); - return 0; - } - } + for (i = 0; i < ARRAY_SIZE(rpc_service); i++) { + struct rpc_service *svc = &rpc_service[i]; + strbuf_addf(&var, "http.%s", svc->config_name); + if (!git_config_get_bool(var.buf, &value)) + svc->enabled = value; + strbuf_reset(&var); } - /* we are not interested in parsing any other configuration here */ - return 0; + strbuf_release(&var); } static struct rpc_service *select_service(const char *name) { + const char *svc_name; struct rpc_service *svc = NULL; int i; - if (!starts_with(name, "git-")) + if (!skip_prefix(name, "git-", &svc_name)) forbidden("Unsupported service: '%s'", name); for (i = 0; i < ARRAY_SIZE(rpc_service); i++) { struct rpc_service *s = &rpc_service[i]; - if (!strcmp(s->name, name + 4)) { + if (!strcmp(s->name, svc_name)) { svc = s; break; } @@ -320,7 +316,7 @@ static void run_service(const char **argv) const char *host = getenv("REMOTE_ADDR"); struct argv_array env = ARGV_ARRAY_INIT; int gzipped_request = 0; - struct child_process cld; + struct child_process cld = CHILD_PROCESS_INIT; if (encoding && !strcmp(encoding, "gzip")) gzipped_request = 1; @@ -338,7 +334,6 @@ static void run_service(const char **argv) argv_array_pushf(&env, "GIT_COMMITTER_EMAIL=%s@http.%s", user, host); - memset(&cld, 0, sizeof(cld)); cld.argv = argv; cld.env = env.argv; if (gzipped_request) @@ -607,9 +602,7 @@ int main(int argc, char **argv) cmd = c; n = out[0].rm_eo - out[0].rm_so; - cmd_arg = xmalloc(n); - memcpy(cmd_arg, dir + out[0].rm_so + 1, n-1); - cmd_arg[n-1] = '\0'; + cmd_arg = xmemdupz(dir + out[0].rm_so + 1, n - 1); dir[out[0].rm_so] = 0; break; } @@ -626,7 +619,7 @@ int main(int argc, char **argv) access("git-daemon-export-ok", F_OK) ) not_found("Repository not exported: '%s'", dir); - git_config(http_config, NULL); + http_config(); cmd->imp(cmd_arg); return 0; } diff --git a/http-push.c b/http-push.c index de00d1693a..952f8ede49 100644 --- a/http-push.c +++ b/http-push.c @@ -199,7 +199,7 @@ static void curl_setup_http(CURL *curl, const char *url, curl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer); #ifndef NO_CURL_IOCTL curl_easy_setopt(curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer); - curl_easy_setopt(curl, CURLOPT_IOCTLDATA, &buffer); + curl_easy_setopt(curl, CURLOPT_IOCTLDATA, buffer); #endif curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_fn); curl_easy_setopt(curl, CURLOPT_NOBODY, 0); @@ -719,14 +719,10 @@ static int fetch_indices(void) return ret; } -static void one_remote_object(const char *hex) +static void one_remote_object(const unsigned char *sha1) { - unsigned char sha1[20]; struct object *obj; - if (get_sha1_hex(hex, sha1) != 0) - return; - obj = lookup_object(sha1); if (!obj) obj = parse_object(sha1); @@ -767,15 +763,13 @@ static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed) if (tag_closed && ctx->cdata) { if (!strcmp(ctx->name, DAV_ACTIVELOCK_OWNER)) { - lock->owner = xmalloc(strlen(ctx->cdata) + 1); - strcpy(lock->owner, ctx->cdata); + lock->owner = xstrdup(ctx->cdata); } else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TIMEOUT)) { - if (starts_with(ctx->cdata, "Second-")) - lock->timeout = - strtol(ctx->cdata + 7, NULL, 10); + const char *arg; + if (skip_prefix(ctx->cdata, "Second-", &arg)) + lock->timeout = strtol(arg, NULL, 10); } else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TOKEN)) { - lock->token = xmalloc(strlen(ctx->cdata) + 1); - strcpy(lock->token, ctx->cdata); + lock->token = xstrdup(ctx->cdata); git_SHA1_Init(&sha_ctx); git_SHA1_Update(&sha_ctx, lock->token, strlen(lock->token)); @@ -856,8 +850,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout) struct xml_ctx ctx; char *escaped; - url = xmalloc(strlen(repo->url) + strlen(path) + 1); - sprintf(url, "%s%s", repo->url, path); + url = xstrfmt("%s%s", repo->url, path); /* Make sure leading directories exist for the remote ref */ ep = strchr(url + strlen(repo->url) + 1, '/'); @@ -1020,26 +1013,38 @@ static void remote_ls(const char *path, int flags, void (*userFunc)(struct remote_ls_ctx *ls), void *userData); +/* extract hex from sharded "xx/x{40}" filename */ +static int get_sha1_hex_from_objpath(const char *path, unsigned char *sha1) +{ + char hex[40]; + + if (strlen(path) != 41) + return -1; + + memcpy(hex, path, 2); + path += 2; + path++; /* skip '/' */ + memcpy(hex, path, 38); + + return get_sha1_hex(hex, sha1); +} + static void process_ls_object(struct remote_ls_ctx *ls) { unsigned int *parent = (unsigned int *)ls->userData; - char *path = ls->dentry_name; - char *obj_hex; + const char *path = ls->dentry_name; + unsigned char sha1[20]; if (!strcmp(ls->path, ls->dentry_name) && (ls->flags & IS_DIR)) { remote_dir_exists[*parent] = 1; return; } - if (strlen(path) != 49) + if (!skip_prefix(path, "objects/", &path) || + get_sha1_hex_from_objpath(path, sha1)) return; - path += 8; - obj_hex = xmalloc(strlen(path)); - /* NB: path is not null-terminated, can not use strlcpy here */ - memcpy(obj_hex, path, 2); - strcpy(obj_hex + 2, path + 3); - one_remote_object(obj_hex); - free(obj_hex); + + one_remote_object(sha1); } static void process_ls_ref(struct remote_ls_ctx *ls) @@ -1117,7 +1122,7 @@ static void remote_ls(const char *path, int flags, void (*userFunc)(struct remote_ls_ctx *ls), void *userData) { - char *url = xmalloc(strlen(repo->url) + strlen(path) + 1); + char *url = xstrfmt("%s%s", repo->url, path); struct active_request_slot *slot; struct slot_results results; struct strbuf in_buffer = STRBUF_INIT; @@ -1133,8 +1138,6 @@ static void remote_ls(const char *path, int flags, ls.userData = userData; ls.userFunc = userFunc; - sprintf(url, "%s%s", repo->url, path); - strbuf_addf(&out_buffer.buf, PROPFIND_ALL_REQUEST); dav_headers = curl_slist_append(dav_headers, "Depth: 1"); @@ -1536,10 +1539,9 @@ static void update_remote_info_refs(struct remote_lock *lock) static int remote_exists(const char *path) { - char *url = xmalloc(strlen(repo->url) + strlen(path) + 1); + char *url = xstrfmt("%s%s", repo->url, path); int ret; - sprintf(url, "%s%s", repo->url, path); switch (http_get_strbuf(url, NULL, NULL)) { case HTTP_OK: @@ -1559,11 +1561,9 @@ static int remote_exists(const char *path) static void fetch_symref(const char *path, char **symref, unsigned char *sha1) { - char *url; + char *url = xstrfmt("%s%s", repo->url, path); struct strbuf buffer = STRBUF_INIT; - - url = xmalloc(strlen(repo->url) + strlen(path) + 1); - sprintf(url, "%s%s", repo->url, path); + const char *name; if (http_get_strbuf(url, &buffer, NULL) != HTTP_OK) die("Couldn't get %s for remote symref\n%s", url, @@ -1578,8 +1578,8 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1) return; /* If it's a symref, set the refname; otherwise try for a sha1 */ - if (starts_with((char *)buffer.buf, "ref: ")) { - *symref = xmemdupz((char *)buffer.buf + 5, buffer.len - 6); + if (skip_prefix(buffer.buf, "ref: ", &name)) { + *symref = xmemdupz(name, buffer.len - (name - buffer.buf)); } else { get_sha1_hex(buffer.buf, sha1); } @@ -1673,8 +1673,7 @@ static int delete_remote_branch(const char *pattern, int force) fprintf(stderr, "Removing remote branch '%s'\n", remote_ref->name); if (dry_run) return 0; - url = xmalloc(strlen(repo->url) + strlen(remote_ref->name) + 1); - sprintf(url, "%s%s", repo->url, remote_ref->name); + url = xstrfmt("%s%s", repo->url, remote_ref->name); slot = get_active_slot(); slot->results = &results; curl_setup_http_get(slot->curl, url, DAV_DELETE); diff --git a/http-walker.c b/http-walker.c index 1516c5eb29..88da5468e7 100644 --- a/http-walker.c +++ b/http-walker.c @@ -230,7 +230,6 @@ static void process_alternates_response(void *callback_data) int okay = 0; int serverlen = 0; struct alt_base *newalt; - char *target = NULL; if (data[i] == '/') { /* * This counts @@ -287,17 +286,15 @@ static void process_alternates_response(void *callback_data) } /* skip "objects\n" at end */ if (okay) { - target = xmalloc(serverlen + posn - i - 6); - memcpy(target, base, serverlen); - memcpy(target + serverlen, data + i, - posn - i - 7); - target[serverlen + posn - i - 7] = 0; + struct strbuf target = STRBUF_INIT; + strbuf_add(&target, base, serverlen); + strbuf_add(&target, data + i, posn - i - 7); if (walker->get_verbosely) - fprintf(stderr, - "Also look at %s\n", target); + fprintf(stderr, "Also look at %s\n", + target.buf); newalt = xmalloc(sizeof(*newalt)); newalt->next = NULL; - newalt->base = target; + newalt->base = strbuf_detach(&target, NULL); newalt->got_indices = 0; newalt->packs = NULL; @@ -341,8 +338,7 @@ static void fetch_alternates(struct walker *walker, const char *base) if (walker->get_verbosely) fprintf(stderr, "Getting alternates list for %s\n", base); - url = xmalloc(strlen(base) + 31); - sprintf(url, "%s/objects/info/http-alternates", base); + url = xstrfmt("%s/objects/info/http-alternates", base); /* * Use a callback to process the result, since another request @@ -566,8 +562,7 @@ struct walker *get_http_walker(const char *url) struct walker *walker = xmalloc(sizeof(struct walker)); data->alt = xmalloc(sizeof(*data->alt)); - data->alt->base = xmalloc(strlen(url) + 1); - strcpy(data->alt->base, url); + data->alt->base = xstrdup(url); for (s = data->alt->base + strlen(data->alt->base) - 1; *s == '/'; --s) *s = 0; diff --git a/http.c b/http.c index 2b4f6a357c..0adcec4683 100644 --- a/http.c +++ b/http.c @@ -300,6 +300,9 @@ static CURL *get_curl_handle(void) { CURL *result = curl_easy_init(); + if (!result) + die("curl_easy_init failed"); + if (!curl_ssl_verify) { curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 0); @@ -399,7 +402,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth) git_config(urlmatch_config_entry, &config); free(normalized_url); - curl_global_init(CURL_GLOBAL_ALL); + if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) + die("curl_global_init failed"); http_proactive_auth = proactive_auth; @@ -417,10 +421,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth) } curlm = curl_multi_init(); - if (curlm == NULL) { - fprintf(stderr, "Error creating curl multi handle.\n"); - exit(1); - } + if (!curlm) + die("curl_multi_init failed"); #endif if (getenv("GIT_SSL_NO_VERIFY")) @@ -927,7 +929,7 @@ static int extract_param(const char *raw, const char *name, return -1; raw++; - while (*raw && !isspace(*raw)) + while (*raw && !isspace(*raw) && *raw != ';') strbuf_addch(out, *raw++); return 0; } @@ -971,7 +973,7 @@ static void extract_content_type(struct strbuf *raw, struct strbuf *type, strbuf_reset(charset); while (*p) { - while (isspace(*p)) + while (isspace(*p) || *p == ';') p++; if (!extract_param(p, "charset", charset)) return; @@ -1087,11 +1089,10 @@ static int update_url_from_redirect(struct strbuf *base, if (!strcmp(asked, got->buf)) return 0; - if (!starts_with(asked, base->buf)) + if (!skip_prefix(asked, base->buf, &tail)) die("BUG: update_url_from_redirect: %s is not a superset of %s", asked, base->buf); - tail = asked + base->len; tail_len = strlen(tail); if (got->len < tail_len || @@ -1333,7 +1334,7 @@ int finish_http_pack_request(struct http_pack_request *preq) struct packed_git **lst; struct packed_git *p = preq->target; char *tmp_idx; - struct child_process ip; + struct child_process ip = CHILD_PROCESS_INIT; const char *ip_argv[8]; close_pack_index(p); @@ -1356,7 +1357,6 @@ int finish_http_pack_request(struct http_pack_request *preq) ip_argv[3] = preq->tmpfile; ip_argv[4] = NULL; - memset(&ip, 0, sizeof(ip)); ip.argv = ip_argv; ip.git_cmd = 1; ip.no_stdin = 1; diff --git a/ident.c b/ident.c index 1d9b6e770d..5ff1aadaaa 100644 --- a/ident.c +++ b/ident.c @@ -9,7 +9,7 @@ static struct strbuf git_default_name = STRBUF_INIT; static struct strbuf git_default_email = STRBUF_INIT; -static char git_default_date[50]; +static struct strbuf git_default_date = STRBUF_INIT; #define IDENT_NAME_GIVEN 01 #define IDENT_MAIL_GIVEN 02 @@ -102,7 +102,7 @@ static void copy_email(const struct passwd *pw, struct strbuf *email) add_domainname(email); } -static const char *ident_default_name(void) +const char *ident_default_name(void) { if (!git_default_name.len) { copy_gecos(xgetpwuid_self(), &git_default_name); @@ -129,9 +129,9 @@ const char *ident_default_email(void) static const char *ident_default_date(void) { - if (!git_default_date[0]) - datestamp(git_default_date, sizeof(git_default_date)); - return git_default_date; + if (!git_default_date.len) + datestamp(&git_default_date); + return git_default_date.buf; } static int crud(unsigned char c) @@ -292,7 +292,6 @@ const char *fmt_ident(const char *name, const char *email, const char *date_str, int flag) { static struct strbuf ident = STRBUF_INIT; - char date[50]; int strict = (flag & IDENT_STRICT); int want_date = !(flag & IDENT_NO_DATE); int want_name = !(flag & IDENT_NO_NAME); @@ -320,15 +319,6 @@ const char *fmt_ident(const char *name, const char *email, die("unable to auto-detect email address (got '%s')", email); } - if (want_date) { - if (date_str && date_str[0]) { - if (parse_date(date_str, date, sizeof(date)) < 0) - die("invalid date format: %s", date_str); - } - else - strcpy(date, ident_default_date()); - } - strbuf_reset(&ident); if (want_name) { strbuf_addstr_without_crud(&ident, name); @@ -339,8 +329,14 @@ const char *fmt_ident(const char *name, const char *email, strbuf_addch(&ident, '>'); if (want_date) { strbuf_addch(&ident, ' '); - strbuf_addstr_without_crud(&ident, date); + if (date_str && date_str[0]) { + if (parse_date(date_str, &ident) < 0) + die("invalid date format: %s", date_str); + } + else + strbuf_addstr(&ident, ident_default_date()); } + return ident.buf; } diff --git a/imap-send.c b/imap-send.c index 83a6ed2ac3..f33e56dba1 100644 --- a/imap-send.c +++ b/imap-send.c @@ -69,6 +69,7 @@ struct imap_server_conf { char *tunnel; char *host; int port; + char *folder; char *user; char *pass; int use_ssl; @@ -82,6 +83,7 @@ static struct imap_server_conf server = { NULL, /* tunnel */ NULL, /* host */ 0, /* port */ + NULL, /* folder */ NULL, /* user */ NULL, /* pass */ 0, /* use_ssl */ @@ -128,7 +130,6 @@ struct imap_cmd_cb { char *data; int dlen; int uid; - unsigned create:1, trycreate:1; }; struct imap_cmd { @@ -493,9 +494,9 @@ static int nfsnprintf(char *buf, int blen, const char *fmt, ...) return ret; } -static struct imap_cmd *v_issue_imap_cmd(struct imap_store *ctx, - struct imap_cmd_cb *cb, - const char *fmt, va_list ap) +static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx, + struct imap_cmd_cb *cb, + const char *fmt, va_list ap) { struct imap *imap = ctx->imap; struct imap_cmd *cmd; @@ -524,7 +525,7 @@ static struct imap_cmd *v_issue_imap_cmd(struct imap_store *ctx, if (Verbose) { if (imap->num_in_progress) printf("(%d in progress) ", imap->num_in_progress); - if (memcmp(cmd->cmd, "LOGIN", 5)) + if (!starts_with(cmd->cmd, "LOGIN")) printf(">>> %s", buf); else printf(">>> %d LOGIN \n", cmd->tag); @@ -558,20 +559,6 @@ static struct imap_cmd *v_issue_imap_cmd(struct imap_store *ctx, return cmd; } -__attribute__((format (printf, 3, 4))) -static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx, - struct imap_cmd_cb *cb, - const char *fmt, ...) -{ - struct imap_cmd *ret; - va_list ap; - - va_start(ap, fmt); - ret = v_issue_imap_cmd(ctx, cb, fmt, ap); - va_end(ap); - return ret; -} - __attribute__((format (printf, 3, 4))) static int imap_exec(struct imap_store *ctx, struct imap_cmd_cb *cb, const char *fmt, ...) @@ -580,7 +567,7 @@ static int imap_exec(struct imap_store *ctx, struct imap_cmd_cb *cb, struct imap_cmd *cmdp; va_start(ap, fmt); - cmdp = v_issue_imap_cmd(ctx, cb, fmt, ap); + cmdp = issue_imap_cmd(ctx, cb, fmt, ap); va_end(ap); if (!cmdp) return RESP_BAD; @@ -596,7 +583,7 @@ static int imap_exec_m(struct imap_store *ctx, struct imap_cmd_cb *cb, struct imap_cmd *cmdp; va_start(ap, fmt); - cmdp = v_issue_imap_cmd(ctx, cb, fmt, ap); + cmdp = issue_imap_cmd(ctx, cb, fmt, ap); va_end(ap); if (!cmdp) return DRV_STORE_BAD; @@ -714,8 +701,8 @@ static int parse_response_code(struct imap_store *ctx, struct imap_cmd_cb *cb, static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd) { struct imap *imap = ctx->imap; - struct imap_cmd *cmdp, **pcmdp, *ncmdp; - char *cmd, *arg, *arg1, *p; + struct imap_cmd *cmdp, **pcmdp; + char *cmd, *arg, *arg1; int n, resp, resp2, tag; for (;;) { @@ -801,39 +788,17 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd) if (!strcmp("OK", arg)) resp = DRV_OK; else { - if (!strcmp("NO", arg)) { - if (cmdp->cb.create && cmd && (cmdp->cb.trycreate || !memcmp(cmd, "[TRYCREATE]", 11))) { /* SELECT, APPEND or UID COPY */ - p = strchr(cmdp->cmd, '"'); - if (!issue_imap_cmd(ctx, NULL, "CREATE \"%.*s\"", (int)(strchr(p + 1, '"') - p + 1), p)) { - resp = RESP_BAD; - goto normal; - } - /* not waiting here violates the spec, but a server that does not - grok this nonetheless violates it too. */ - cmdp->cb.create = 0; - if (!(ncmdp = issue_imap_cmd(ctx, &cmdp->cb, "%s", cmdp->cmd))) { - resp = RESP_BAD; - goto normal; - } - free(cmdp->cmd); - free(cmdp); - if (!tcmd) - return 0; /* ignored */ - if (cmdp == tcmd) - tcmd = ncmdp; - continue; - } + if (!strcmp("NO", arg)) resp = RESP_NO; - } else /*if (!strcmp("BAD", arg))*/ + else /*if (!strcmp("BAD", arg))*/ resp = RESP_BAD; fprintf(stderr, "IMAP command '%s' returned response (%s) - %s\n", - memcmp(cmdp->cmd, "LOGIN", 5) ? + !starts_with(cmdp->cmd, "LOGIN") ? cmdp->cmd : "LOGIN ", arg, cmd ? cmd : ""); } if ((resp2 = parse_response_code(ctx, &cmdp->cb, cmd)) > resp) resp = resp2; - normal: if (cmdp->cb.done) cmdp->cb.done(ctx, cmdp, resp); free(cmdp->cb.data); @@ -944,7 +909,7 @@ static int auth_cram_md5(struct imap_store *ctx, struct imap_cmd *cmd, const cha return 0; } -static struct imap_store *imap_open_store(struct imap_server_conf *srvc) +static struct imap_store *imap_open_store(struct imap_server_conf *srvc, char *folder) { struct credential cred = CREDENTIAL_INIT; struct imap_store *ctx; @@ -961,17 +926,16 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc) /* open connection to IMAP server */ if (srvc->tunnel) { - const char *argv[] = { srvc->tunnel, NULL }; - struct child_process tunnel = {NULL}; + struct child_process tunnel = CHILD_PROCESS_INIT; imap_info("Starting tunnel '%s'... ", srvc->tunnel); - tunnel.argv = argv; + argv_array_push(&tunnel.args, srvc->tunnel); tunnel.use_shell = 1; tunnel.in = -1; tunnel.out = -1; if (start_command(&tunnel)) - die("cannot start proxy %s", argv[0]); + die("cannot start proxy %s", srvc->tunnel); imap->buf.sock.fd[0] = tunnel.out; imap->buf.sock.fd[1] = tunnel.in; @@ -1156,6 +1120,25 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc) credential_approve(&cred); credential_clear(&cred); + /* check the target mailbox exists */ + ctx->name = folder; + switch (imap_exec(ctx, NULL, "EXAMINE \"%s\"", ctx->name)) { + case RESP_OK: + /* ok */ + break; + case RESP_BAD: + fprintf(stderr, "IMAP error: could not check mailbox\n"); + goto out; + case RESP_NO: + if (imap_exec(ctx, NULL, "CREATE \"%s\"", ctx->name) == RESP_OK) { + imap_info("Created missing mailbox\n"); + } else { + fprintf(stderr, "IMAP error: could not create missing mailbox\n"); + goto out; + } + break; + } + ctx->prefix = ""; return ctx; @@ -1164,6 +1147,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc) credential_reject(&cred); credential_clear(&cred); + out: imap_close_store(ctx); return NULL; } @@ -1219,7 +1203,6 @@ static int imap_store_msg(struct imap_store *ctx, struct strbuf *msg) box = ctx->name; prefix = !strcmp(box, "INBOX") ? "" : ctx->prefix; - cb.create = 0; ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\" ", prefix, box); imap->caps = imap->rcaps; if (ret != DRV_OK) @@ -1324,49 +1307,35 @@ static int split_msg(struct strbuf *all_msgs, struct strbuf *msg, int *ofs) return 1; } -static char *imap_folder; - -static int git_imap_config(const char *key, const char *val, void *cb) +static void git_imap_config(void) { - char imap_key[] = "imap."; + const char *val = NULL; - if (strncmp(key, imap_key, sizeof imap_key - 1)) - return 0; + git_config_get_bool("imap.sslverify", &server.ssl_verify); + git_config_get_bool("imap.preformattedhtml", &server.use_html); + git_config_get_string("imap.folder", &server.folder); - key += sizeof imap_key - 1; - - /* check booleans first, and barf on others */ - if (!strcmp("sslverify", key)) - server.ssl_verify = git_config_bool(key, val); - else if (!strcmp("preformattedhtml", key)) - server.use_html = git_config_bool(key, val); - else if (!val) - return config_error_nonbool(key); - - if (!strcmp("folder", key)) { - imap_folder = xstrdup(val); - } else if (!strcmp("host", key)) { - if (starts_with(val, "imap:")) - val += 5; - else if (starts_with(val, "imaps:")) { - val += 6; - server.use_ssl = 1; + if (!git_config_get_value("imap.host", &val)) { + if (!val) { + git_die_config("imap.host", "Missing value for 'imap.host'"); + } else { + if (starts_with(val, "imap:")) + val += 5; + else if (starts_with(val, "imaps:")) { + val += 6; + server.use_ssl = 1; + } + if (starts_with(val, "//")) + val += 2; + server.host = xstrdup(val); } - if (starts_with(val, "//")) - val += 2; - server.host = xstrdup(val); - } else if (!strcmp("user", key)) - server.user = xstrdup(val); - else if (!strcmp("pass", key)) - server.pass = xstrdup(val); - else if (!strcmp("port", key)) - server.port = git_config_int(key, val); - else if (!strcmp("tunnel", key)) - server.tunnel = xstrdup(val); - else if (!strcmp("authmethod", key)) - server.auth_method = xstrdup(val); + } - return 0; + git_config_get_string("imap.user", &server.user); + git_config_get_string("imap.pass", &server.pass); + git_config_get_int("imap.port", &server.port); + git_config_get_string("imap.tunnel", &server.tunnel); + git_config_get_string("imap.authmethod", &server.auth_method); } int main(int argc, char **argv) @@ -1387,12 +1356,12 @@ int main(int argc, char **argv) usage(imap_send_usage); setup_git_directory_gently(&nongit_ok); - git_config(git_imap_config, NULL); + git_imap_config(); if (!server.port) server.port = server.use_ssl ? 993 : 143; - if (!imap_folder) { + if (!server.folder) { fprintf(stderr, "no imap store specified\n"); return 1; } @@ -1422,14 +1391,13 @@ int main(int argc, char **argv) } /* write it to the imap server */ - ctx = imap_open_store(&server); + ctx = imap_open_store(&server, server.folder); if (!ctx) { fprintf(stderr, "failed to open store\n"); return 1; } fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : ""); - ctx->name = imap_folder; while (1) { unsigned percent = n * 100 / total; diff --git a/khash.h b/khash.h index 57ff6038c5..06c7906549 100644 --- a/khash.h +++ b/khash.h @@ -320,19 +320,12 @@ static const double __ac_HASH_UPPER = 0.77; code; \ } } -static inline khint_t __kh_oid_hash(const unsigned char *oid) -{ - khint_t hash; - memcpy(&hash, oid, sizeof(hash)); - return hash; -} - #define __kh_oid_cmp(a, b) (hashcmp(a, b) == 0) -KHASH_INIT(sha1, const unsigned char *, void *, 1, __kh_oid_hash, __kh_oid_cmp) +KHASH_INIT(sha1, const unsigned char *, void *, 1, sha1hash, __kh_oid_cmp) typedef kh_sha1_t khash_sha1; -KHASH_INIT(sha1_pos, const unsigned char *, int, 1, __kh_oid_hash, __kh_oid_cmp) +KHASH_INIT(sha1_pos, const unsigned char *, int, 1, sha1hash, __kh_oid_cmp) typedef kh_sha1_pos_t khash_sha1_pos; #endif /* __AC_KHASH_H */ diff --git a/line-log.c b/line-log.c index 1500101058..1008e72258 100644 --- a/line-log.c +++ b/line-log.c @@ -766,17 +766,6 @@ void line_log_init(struct rev_info *rev, const char *prefix, struct string_list } } -static int count_parents(struct commit *commit) -{ - struct commit_list *parents = commit->parents; - int count = 0; - while (parents) { - count++; - parents = parents->next; - } - return count; -} - static void move_diff_queue(struct diff_queue_struct *dst, struct diff_queue_struct *src) { @@ -1150,7 +1139,7 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm struct commit **parents; struct commit_list *p; int i; - int nparents = count_parents(commit); + int nparents = commit_list_count(commit->parents); diffqueues = xmalloc(nparents * sizeof(*diffqueues)); cand = xmalloc(nparents * sizeof(*cand)); @@ -1174,9 +1163,7 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm */ add_line_range(rev, parents[i], cand[i]); clear_commit_line_range(rev, commit); - commit->parents = xmalloc(sizeof(struct commit_list)); - commit->parents->item = parents[i]; - commit->parents->next = NULL; + commit_list_append(parents[i], &commit->parents); free(parents); free(cand); free_diffqueues(nparents, diffqueues); diff --git a/ll-merge.c b/ll-merge.c index fb61ea66a1..8ea03e536a 100644 --- a/ll-merge.c +++ b/ll-merge.c @@ -225,11 +225,8 @@ static int read_merge_config(const char *var, const char *value, void *cb) const char *key, *name; int namelen; - if (!strcmp(var, "merge.default")) { - if (value) - default_ll_merge = xstrdup(value); - return 0; - } + if (!strcmp(var, "merge.default")) + return git_config_string(&default_ll_merge, var, value); /* * We are not interested in anything but "merge..variable"; @@ -254,12 +251,8 @@ static int read_merge_config(const char *var, const char *value, void *cb) ll_user_merge_tail = &(fn->next); } - if (!strcmp("name", key)) { - if (!value) - return error("%s: lacks value", var); - fn->description = xstrdup(value); - return 0; - } + if (!strcmp("name", key)) + return git_config_string(&fn->description, var, value); if (!strcmp("driver", key)) { if (!value) @@ -285,12 +278,8 @@ static int read_merge_config(const char *var, const char *value, void *cb) return 0; } - if (!strcmp("recursive", key)) { - if (!value) - return error("%s: lacks value", var); - fn->recursive = xstrdup(value); - return 0; - } + if (!strcmp("recursive", key)) + return git_config_string(&fn->recursive, var, value); return 0; } diff --git a/lockfile.c b/lockfile.c index 8fbcb6a98a..2a800cef33 100644 --- a/lockfile.c +++ b/lockfile.c @@ -5,7 +5,6 @@ #include "sigchain.h" static struct lock_file *lock_file_list; -static const char *alternate_index_output; static void remove_lock_file(void) { @@ -121,7 +120,7 @@ static char *resolve_symlink(char *p, size_t s) return p; } - +/* Make sure errno contains a meaningful value on error */ static int lock_file(struct lock_file *lk, const char *path, int flags) { /* @@ -130,8 +129,10 @@ static int lock_file(struct lock_file *lk, const char *path, int flags) */ static const size_t max_path_len = sizeof(lk->filename) - 5; - if (strlen(path) >= max_path_len) + if (strlen(path) >= max_path_len) { + errno = ENAMETOOLONG; return -1; + } strcpy(lk->filename, path); if (!(flags & LOCK_NODEREF)) resolve_symlink(lk->filename, max_path_len); @@ -148,44 +149,51 @@ static int lock_file(struct lock_file *lk, const char *path, int flags) lock_file_list = lk; lk->on_list = 1; } - if (adjust_shared_perm(lk->filename)) - return error("cannot fix permission bits on %s", - lk->filename); + if (adjust_shared_perm(lk->filename)) { + int save_errno = errno; + error("cannot fix permission bits on %s", + lk->filename); + errno = save_errno; + return -1; + } } else lk->filename[0] = 0; return lk->fd; } -static char *unable_to_lock_message(const char *path, int err) +void unable_to_lock_message(const char *path, int err, struct strbuf *buf) { - struct strbuf buf = STRBUF_INIT; - if (err == EEXIST) { - strbuf_addf(&buf, "Unable to create '%s.lock': %s.\n\n" + strbuf_addf(buf, "Unable to create '%s.lock': %s.\n\n" "If no other git process is currently running, this probably means a\n" "git process crashed in this repository earlier. Make sure no other git\n" "process is running and remove the file manually to continue.", absolute_path(path), strerror(err)); } else - strbuf_addf(&buf, "Unable to create '%s.lock': %s", + strbuf_addf(buf, "Unable to create '%s.lock': %s", absolute_path(path), strerror(err)); - return strbuf_detach(&buf, NULL); } int unable_to_lock_error(const char *path, int err) { - char *msg = unable_to_lock_message(path, err); - error("%s", msg); - free(msg); + struct strbuf buf = STRBUF_INIT; + + unable_to_lock_message(path, err, &buf); + error("%s", buf.buf); + strbuf_release(&buf); return -1; } NORETURN void unable_to_lock_index_die(const char *path, int err) { - die("%s", unable_to_lock_message(path, err)); + struct strbuf buf = STRBUF_INIT; + + unable_to_lock_message(path, err, &buf); + die("%s", buf.buf); } +/* This should return a meaningful errno on failure */ int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags) { int fd = lock_file(lk, path, flags); @@ -229,6 +237,16 @@ int close_lock_file(struct lock_file *lk) return close(fd); } +int reopen_lock_file(struct lock_file *lk) +{ + if (0 <= lk->fd) + die(_("BUG: reopen a lockfile that is still open")); + if (!lk->filename[0]) + die(_("BUG: reopen a lockfile that has been committed")); + lk->fd = open(lk->filename, O_WRONLY); + return lk->fd; +} + int commit_lock_file(struct lock_file *lk) { char result_file[PATH_MAX]; @@ -252,25 +270,6 @@ int hold_locked_index(struct lock_file *lk, int die_on_error) : 0); } -void set_alternate_index_output(const char *name) -{ - alternate_index_output = name; -} - -int commit_locked_index(struct lock_file *lk) -{ - if (alternate_index_output) { - if (lk->fd >= 0 && close_lock_file(lk)) - return -1; - if (rename(lk->filename, alternate_index_output)) - return -1; - lk->filename[0] = 0; - return 0; - } - else - return commit_lock_file(lk); -} - void rollback_lock_file(struct lock_file *lk) { if (lk->filename[0]) { diff --git a/log-tree.c b/log-tree.c index cf2f86c866..bcee7c5966 100644 --- a/log-tree.c +++ b/log-tree.c @@ -12,17 +12,7 @@ #include "sequencer.h" #include "line-log.h" -struct decoration name_decoration = { "object names" }; - -enum decoration_type { - DECORATION_NONE = 0, - DECORATION_REF_LOCAL, - DECORATION_REF_REMOTE, - DECORATION_REF_TAG, - DECORATION_REF_STASH, - DECORATION_REF_HEAD, - DECORATION_GRAFTED, -}; +static struct decoration name_decoration = { "object names" }; static char decoration_colors[][COLOR_MAXLEN] = { GIT_COLOR_RESET, @@ -84,15 +74,20 @@ int parse_decorate_color_config(const char *var, const int ofs, const char *valu #define decorate_get_color_opt(o, ix) \ decorate_get_color((o)->use_color, ix) -static void add_name_decoration(enum decoration_type type, const char *name, struct object *obj) +void add_name_decoration(enum decoration_type type, const char *name, struct object *obj) { int nlen = strlen(name); - struct name_decoration *res = xmalloc(sizeof(struct name_decoration) + nlen); + struct name_decoration *res = xmalloc(sizeof(*res) + nlen + 1); memcpy(res->name, name, nlen + 1); res->type = type; res->next = add_decoration(&name_decoration, obj, res); } +const struct name_decoration *get_name_decoration(const struct object *obj) +{ + return lookup_decoration(&name_decoration, obj); +} + static int add_ref_decoration(const char *refname, const unsigned char *sha1, int flags, void *cb_data) { struct object *obj; @@ -187,13 +182,13 @@ void format_decorations(struct strbuf *sb, int use_color) { const char *prefix; - struct name_decoration *decoration; + const struct name_decoration *decoration; const char *color_commit = diff_get_color(use_color, DIFF_COMMIT); const char *color_reset = decorate_get_color(use_color, DECORATION_NONE); - decoration = lookup_decoration(&name_decoration, &commit->object); + decoration = get_name_decoration(&commit->object); if (!decoration) return; prefix = " ("; @@ -365,6 +360,7 @@ static void show_sig_lines(struct rev_info *opt, int status, const char *bol) eol = strchrnul(bol, '\n'); printf("%s%.*s%s%s", color, (int)(eol - bol), bol, reset, *eol ? "\n" : ""); + graph_show_oneline(opt->graph); bol = (*eol) ? (eol + 1) : eol; } } @@ -376,7 +372,7 @@ static void show_signature(struct rev_info *opt, struct commit *commit) struct strbuf gpg_output = STRBUF_INIT; int status; - if (parse_signed_commit(commit->object.sha1, &payload, &signature) <= 0) + if (parse_signed_commit(commit, &payload, &signature) <= 0) goto out; status = verify_signed_buffer(payload.buf, payload.len, @@ -413,10 +409,11 @@ static int is_common_merge(const struct commit *commit) && !commit->parents->next->next); } -static void show_one_mergetag(struct rev_info *opt, +static void show_one_mergetag(struct commit *commit, struct commit_extra_header *extra, - struct commit *commit) + void *data) { + struct rev_info *opt = (struct rev_info *)data; unsigned char sha1[20]; struct tag *tag; struct strbuf verify_message; @@ -446,16 +443,17 @@ static void show_one_mergetag(struct rev_info *opt, payload_size = parse_signature(extra->value, extra->len); status = -1; - if (extra->len > payload_size) - if (verify_signed_buffer(extra->value, payload_size, - extra->value + payload_size, - extra->len - payload_size, - &verify_message, NULL)) { - if (verify_message.len <= gpg_message_offset) - strbuf_addstr(&verify_message, "No signature\n"); - else - status = 0; - } + if (extra->len > payload_size) { + /* could have a good signature */ + if (!verify_signed_buffer(extra->value, payload_size, + extra->value + payload_size, + extra->len - payload_size, + &verify_message, NULL)) + status = 0; /* good */ + else if (verify_message.len <= gpg_message_offset) + strbuf_addstr(&verify_message, "No signature\n"); + /* otherwise we couldn't verify, which is shown as bad */ + } show_sig_lines(opt, status, verify_message.buf); strbuf_release(&verify_message); @@ -463,15 +461,7 @@ static void show_one_mergetag(struct rev_info *opt, static void show_mergetag(struct rev_info *opt, struct commit *commit) { - struct commit_extra_header *extra, *to_free; - - to_free = read_commit_extra_headers(commit, NULL); - for (extra = to_free; extra; extra = extra->next) { - if (strcmp(extra->key, "mergetag")) - continue; /* not a merge tag */ - show_one_mergetag(opt, extra, commit); - } - free_commit_extra_headers(to_free); + for_each_mergetag(show_one_mergetag, commit, opt); } void show_log(struct rev_info *opt) @@ -588,7 +578,7 @@ void show_log(struct rev_info *opt) show_mergetag(opt, commit); } - if (!commit->buffer) + if (!get_cached_commit_buffer(commit, NULL)) return; if (opt->show_notes) { @@ -654,7 +644,7 @@ void show_log(struct rev_info *opt) graph_show_commit_msg(opt->graph, &msgbuf); else fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); - if (opt->use_terminator) { + if (opt->use_terminator && !commit_format_is_empty(opt->commit_format)) { if (!opt->missing_newline) graph_show_padding(opt->graph); putchar(opt->diffopt.line_termination); @@ -681,7 +671,8 @@ int log_tree_diff_flush(struct rev_info *opt) show_log(opt); if ((opt->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT) && opt->verbose_header && - opt->commit_format != CMIT_FMT_ONELINE) { + opt->commit_format != CMIT_FMT_ONELINE && + !commit_format_is_empty(opt->commit_format)) { /* * When showing a verbose header (i.e. log message), * and not in --pretty=oneline format, we would want diff --git a/match-trees.c b/match-trees.c index e80b4af354..1ce0954a3e 100644 --- a/match-trees.c +++ b/match-trees.c @@ -140,17 +140,12 @@ static void match_trees(const unsigned char *hash1, goto next; score = score_trees(elem, hash2); if (*best_score < score) { - char *newpath; - newpath = xmalloc(strlen(base) + strlen(path) + 1); - sprintf(newpath, "%s%s", base, path); free(*best_match); - *best_match = newpath; + *best_match = xstrfmt("%s%s", base, path); *best_score = score; } if (recurse_limit) { - char *newbase; - newbase = xmalloc(strlen(base) + strlen(path) + 2); - sprintf(newbase, "%s%s/", base, path); + char *newbase = xstrfmt("%s%s/", base, path); match_trees(elem, hash2, best_score, best_match, newbase, recurse_limit - 1); free(newbase); diff --git a/merge-recursive.c b/merge-recursive.c index cab16fafb5..8ab944c44c 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -40,7 +40,7 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two, static struct commit *make_virtual_commit(struct tree *tree, const char *comment) { - struct commit *commit = xcalloc(1, sizeof(struct commit)); + struct commit *commit = alloc_commit_node(); struct merge_remote_desc *desc = xmalloc(sizeof(*desc)); desc->name = comment; @@ -171,7 +171,7 @@ static void output(struct merge_options *o, int v, const char *fmt, ...) strbuf_vaddf(&o->obuf, fmt, ap); va_end(ap); - strbuf_add(&o->obuf, "\n", 1); + strbuf_addch(&o->obuf, '\n'); if (!o->buffer_output) flush_output(o); } @@ -190,9 +190,11 @@ static void output_commit_title(struct merge_options *o, struct commit *commit) printf(_("(bad commit)\n")); else { const char *title; - int len = find_commit_subject(commit->buffer, &title); + const char *msg = get_commit_buffer(commit, NULL); + int len = find_commit_subject(msg, &title); if (len) printf("%.*s\n", len, title); + unuse_commit_buffer(commit, msg); } } } @@ -265,9 +267,7 @@ struct tree *write_tree_from_memory(struct merge_options *o) active_cache_tree = cache_tree(); if (!cache_tree_fully_valid(active_cache_tree) && - cache_tree_update(active_cache_tree, - (const struct cache_entry * const *)active_cache, - active_nr, 0) < 0) + cache_tree_update(&the_index, 0) < 0) die(_("error building trees")); result = lookup_tree(active_cache_tree->sha1); @@ -601,25 +601,36 @@ static int remove_file(struct merge_options *o, int clean, return 0; } +/* add a string to a strbuf, but converting "/" to "_" */ +static void add_flattened_path(struct strbuf *out, const char *s) +{ + size_t i = out->len; + strbuf_addstr(out, s); + for (; i < out->len; i++) + if (out->buf[i] == '/') + out->buf[i] = '_'; +} + static char *unique_path(struct merge_options *o, const char *path, const char *branch) { - char *newpath = xmalloc(strlen(path) + 1 + strlen(branch) + 8 + 1); + struct strbuf newpath = STRBUF_INIT; int suffix = 0; struct stat st; - char *p = newpath + strlen(path); - strcpy(newpath, path); - *(p++) = '~'; - strcpy(p, branch); - for (; *p; ++p) - if ('/' == *p) - *p = '_'; - while (string_list_has_string(&o->current_file_set, newpath) || - string_list_has_string(&o->current_directory_set, newpath) || - lstat(newpath, &st) == 0) - sprintf(p, "_%d", suffix++); - - string_list_insert(&o->current_file_set, newpath); - return newpath; + size_t base_len; + + strbuf_addf(&newpath, "%s~", path); + add_flattened_path(&newpath, branch); + + base_len = newpath.len; + while (string_list_has_string(&o->current_file_set, newpath.buf) || + string_list_has_string(&o->current_directory_set, newpath.buf) || + lstat(newpath.buf, &st) == 0) { + strbuf_setlen(&newpath, base_len); + strbuf_addf(&newpath, "_%d", suffix++); + } + + string_list_insert(&o->current_file_set, newpath.buf); + return strbuf_detach(&newpath, NULL); } static int dir_in_way(const char *path, int check_working_copy) @@ -969,14 +980,10 @@ merge_file_special_markers(struct merge_options *o, char *side2 = NULL; struct merge_file_info mfi; - if (filename1) { - side1 = xmalloc(strlen(branch1) + strlen(filename1) + 2); - sprintf(side1, "%s:%s", branch1, filename1); - } - if (filename2) { - side2 = xmalloc(strlen(branch2) + strlen(filename2) + 2); - sprintf(side2, "%s:%s", branch2, filename2); - } + if (filename1) + side1 = xstrfmt("%s:%s", branch1, filename1); + if (filename2) + side2 = xstrfmt("%s:%s", branch2, filename2); mfi = merge_file_1(o, one, a, b, side1 ? side1 : branch1, side2 ? side2 : branch2); @@ -1992,7 +1999,7 @@ int merge_recursive_generic(struct merge_options *o, const unsigned char **base_list, struct commit **result) { - int clean, index_fd; + int clean; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); struct commit *head_commit = get_ref(head, o->branch1); struct commit *next_commit = get_ref(merge, o->branch2); @@ -2009,33 +2016,22 @@ int merge_recursive_generic(struct merge_options *o, } } - index_fd = hold_locked_index(lock, 1); + hold_locked_index(lock, 1); clean = merge_recursive(o, head_commit, next_commit, ca, result); if (active_cache_changed && - (write_cache(index_fd, active_cache, active_nr) || - commit_locked_index(lock))) + write_locked_index(&the_index, lock, COMMIT_LOCK)) return error(_("Unable to write index.")); return clean ? 0 : 1; } -static int merge_recursive_config(const char *var, const char *value, void *cb) +static void merge_recursive_config(struct merge_options *o) { - struct merge_options *o = cb; - if (!strcmp(var, "merge.verbosity")) { - o->verbosity = git_config_int(var, value); - return 0; - } - if (!strcmp(var, "diff.renamelimit")) { - o->diff_rename_limit = git_config_int(var, value); - return 0; - } - if (!strcmp(var, "merge.renamelimit")) { - o->merge_rename_limit = git_config_int(var, value); - return 0; - } - return git_xmerge_config(var, value, cb); + git_config_get_int("merge.verbosity", &o->verbosity); + git_config_get_int("diff.renamelimit", &o->diff_rename_limit); + git_config_get_int("merge.renamelimit", &o->merge_rename_limit); + git_config(git_xmerge_config, NULL); } void init_merge_options(struct merge_options *o) @@ -2046,23 +2042,22 @@ void init_merge_options(struct merge_options *o) o->diff_rename_limit = -1; o->merge_rename_limit = -1; o->renormalize = 0; - git_config(merge_recursive_config, o); + merge_recursive_config(o); if (getenv("GIT_MERGE_VERBOSITY")) o->verbosity = strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10); if (o->verbosity >= 5) o->buffer_output = 0; strbuf_init(&o->obuf, 0); - memset(&o->current_file_set, 0, sizeof(struct string_list)); - o->current_file_set.strdup_strings = 1; - memset(&o->current_directory_set, 0, sizeof(struct string_list)); - o->current_directory_set.strdup_strings = 1; - memset(&o->df_conflict_file_set, 0, sizeof(struct string_list)); - o->df_conflict_file_set.strdup_strings = 1; + string_list_init(&o->current_file_set, 1); + string_list_init(&o->current_directory_set, 1); + string_list_init(&o->df_conflict_file_set, 1); } int parse_merge_opt(struct merge_options *o, const char *s) { + const char *arg; + if (!s || !*s) return -1; if (!strcmp(s, "ours")) @@ -2071,14 +2066,14 @@ int parse_merge_opt(struct merge_options *o, const char *s) o->recursive_variant = MERGE_RECURSIVE_THEIRS; else if (!strcmp(s, "subtree")) o->subtree_shift = ""; - else if (starts_with(s, "subtree=")) - o->subtree_shift = s + strlen("subtree="); + else if (skip_prefix(s, "subtree=", &arg)) + o->subtree_shift = arg; else if (!strcmp(s, "patience")) o->xdl_opts = DIFF_WITH_ALG(o, PATIENCE_DIFF); else if (!strcmp(s, "histogram")) o->xdl_opts = DIFF_WITH_ALG(o, HISTOGRAM_DIFF); - else if (starts_with(s, "diff-algorithm=")) { - long value = parse_algorithm_value(s + strlen("diff-algorithm=")); + else if (skip_prefix(s, "diff-algorithm=", &arg)) { + long value = parse_algorithm_value(arg); if (value < 0) return -1; /* clear out previous settings */ @@ -2096,9 +2091,8 @@ int parse_merge_opt(struct merge_options *o, const char *s) o->renormalize = 1; else if (!strcmp(s, "no-renormalize")) o->renormalize = 0; - else if (starts_with(s, "rename-threshold=")) { - const char *score = s + strlen("rename-threshold="); - if ((o->rename_score = parse_rename_score(&score)) == -1 || *score != 0) + else if (skip_prefix(s, "rename-threshold=", &arg)) { + if ((o->rename_score = parse_rename_score(&arg)) == -1 || *arg != 0) return -1; } else diff --git a/merge.c b/merge.c index 70f1000fcb..74ced7f70b 100644 --- a/merge.c +++ b/merge.c @@ -18,39 +18,23 @@ int try_merge_command(const char *strategy, size_t xopts_nr, const char **xopts, struct commit_list *common, const char *head_arg, struct commit_list *remotes) { - const char **args; - int i = 0, x = 0, ret; + struct argv_array args = ARGV_ARRAY_INIT; + int i, ret; struct commit_list *j; - struct strbuf buf = STRBUF_INIT; - args = xmalloc((4 + xopts_nr + commit_list_count(common) + - commit_list_count(remotes)) * sizeof(char *)); - strbuf_addf(&buf, "merge-%s", strategy); - args[i++] = buf.buf; - for (x = 0; x < xopts_nr; x++) { - char *s = xmalloc(strlen(xopts[x])+2+1); - strcpy(s, "--"); - strcpy(s+2, xopts[x]); - args[i++] = s; - } - for (j = common; j; j = j->next) - args[i++] = xstrdup(merge_argument(j->item)); - args[i++] = "--"; - args[i++] = head_arg; - for (j = remotes; j; j = j->next) - args[i++] = xstrdup(merge_argument(j->item)); - args[i] = NULL; - ret = run_command_v_opt(args, RUN_GIT_CMD); - strbuf_release(&buf); - i = 1; - for (x = 0; x < xopts_nr; x++) - free((void *)args[i++]); + argv_array_pushf(&args, "merge-%s", strategy); + for (i = 0; i < xopts_nr; i++) + argv_array_pushf(&args, "--%s", xopts[i]); for (j = common; j; j = j->next) - free((void *)args[i++]); - i += 2; + argv_array_push(&args, merge_argument(j->item)); + argv_array_push(&args, "--"); + argv_array_push(&args, head_arg); for (j = remotes; j; j = j->next) - free((void *)args[i++]); - free(args); + argv_array_push(&args, merge_argument(j->item)); + + ret = run_command_v_opt(args.argv, RUN_GIT_CMD); + argv_array_clear(&args); + discard_cache(); if (read_cache() < 0) die(_("failed to read the cache")); @@ -66,13 +50,13 @@ int checkout_fast_forward(const unsigned char *head, struct tree *trees[MAX_UNPACK_TREES]; struct unpack_trees_options opts; struct tree_desc t[MAX_UNPACK_TREES]; - int i, fd, nr_trees = 0; + int i, nr_trees = 0; struct dir_struct dir; struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); refresh_cache(REFRESH_QUIET); - fd = hold_locked_index(lock_file, 1); + hold_locked_index(lock_file, 1); memset(&trees, 0, sizeof(trees)); memset(&opts, 0, sizeof(opts)); @@ -105,8 +89,7 @@ int checkout_fast_forward(const unsigned char *head, } if (unpack_trees(nr_trees, t, &opts)) return -1; - if (write_cache(fd, active_cache, active_nr) || - commit_locked_index(lock_file)) + if (write_locked_index(&the_index, lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); return 0; } diff --git a/name-hash.c b/name-hash.c index 49fd508317..702cd0518f 100644 --- a/name-hash.c +++ b/name-hash.c @@ -213,12 +213,11 @@ struct cache_entry *index_dir_exists(struct index_state *istate, const char *nam struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int icase) { struct cache_entry *ce; - struct hashmap_entry key; lazy_init_name_hash(istate); - hashmap_entry_init(&key, memihash(name, namelen)); - ce = hashmap_get(&istate->name_hash, &key, NULL); + ce = hashmap_get_from_hash(&istate->name_hash, + memihash(name, namelen), NULL); while (ce) { if (same_name(ce, name, namelen, icase)) return ce; diff --git a/notes-cache.c b/notes-cache.c index 97dfd63c9b..c4e9bb7f6c 100644 --- a/notes-cache.c +++ b/notes-cache.c @@ -48,7 +48,6 @@ int notes_cache_write(struct notes_cache *c) { unsigned char tree_sha1[20]; unsigned char commit_sha1[20]; - struct strbuf msg = STRBUF_INIT; if (!c || !c->tree.initialized || !c->tree.ref || !*c->tree.ref) return -1; @@ -57,9 +56,8 @@ int notes_cache_write(struct notes_cache *c) if (write_notes_tree(&c->tree, tree_sha1)) return -1; - strbuf_attach(&msg, c->validity, - strlen(c->validity), strlen(c->validity) + 1); - if (commit_tree(&msg, tree_sha1, NULL, commit_sha1, NULL, NULL) < 0) + if (commit_tree(c->validity, strlen(c->validity), tree_sha1, NULL, + commit_sha1, NULL, NULL) < 0) return -1; if (update_ref("update notes cache", c->tree.ref, commit_sha1, NULL, 0, UPDATE_REFS_QUIET_ON_ERR) < 0) diff --git a/notes-merge.c b/notes-merge.c index 94a1a8ae46..fd5fae255d 100644 --- a/notes-merge.c +++ b/notes-merge.c @@ -644,7 +644,8 @@ int notes_merge(struct notes_merge_options *o, struct commit_list *parents = NULL; commit_list_insert(remote, &parents); /* LIFO order */ commit_list_insert(local, &parents); - create_notes_commit(local_tree, parents, &o->commit_msg, + create_notes_commit(local_tree, parents, + o->commit_msg.buf, o->commit_msg.len, result_sha1); } @@ -671,8 +672,8 @@ int notes_merge_commit(struct notes_merge_options *o, DIR *dir; struct dirent *e; struct strbuf path = STRBUF_INIT; - char *msg = strstr(partial_commit->buffer, "\n\n"); - struct strbuf sb_msg = STRBUF_INIT; + const char *buffer = get_commit_buffer(partial_commit, NULL); + const char *msg = strstr(buffer, "\n\n"); int baselen; strbuf_addstr(&path, git_path(NOTES_MERGE_WORKTREE)); @@ -719,9 +720,9 @@ int notes_merge_commit(struct notes_merge_options *o, strbuf_setlen(&path, baselen); } - strbuf_attach(&sb_msg, msg, strlen(msg), strlen(msg) + 1); - create_notes_commit(partial_tree, partial_commit->parents, &sb_msg, - result_sha1); + create_notes_commit(partial_tree, partial_commit->parents, + msg, strlen(msg), result_sha1); + unuse_commit_buffer(partial_commit, buffer); if (o->verbosity >= 4) printf("Finalized notes merge commit: %s\n", sha1_to_hex(result_sha1)); diff --git a/notes-utils.c b/notes-utils.c index a0b1d7be98..b64dc1b021 100644 --- a/notes-utils.c +++ b/notes-utils.c @@ -4,7 +4,8 @@ #include "notes-utils.h" void create_notes_commit(struct notes_tree *t, struct commit_list *parents, - const struct strbuf *msg, unsigned char *result_sha1) + const char *msg, size_t msg_len, + unsigned char *result_sha1) { unsigned char tree_sha1[20]; @@ -25,7 +26,7 @@ void create_notes_commit(struct notes_tree *t, struct commit_list *parents, /* else: t->ref points to nothing, assume root/orphan commit */ } - if (commit_tree(msg, tree_sha1, parents, result_sha1, NULL, NULL)) + if (commit_tree(msg, msg_len, tree_sha1, parents, result_sha1, NULL, NULL)) die("Failed to commit notes tree to database"); } @@ -46,7 +47,7 @@ void commit_notes(struct notes_tree *t, const char *msg) if (buf.buf[buf.len - 1] != '\n') strbuf_addch(&buf, '\n'); /* Make sure msg ends with newline */ - create_notes_commit(t, NULL, &buf, commit_sha1); + create_notes_commit(t, NULL, buf.buf, buf.len, commit_sha1); strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */ update_ref(buf.buf, t->ref, commit_sha1, NULL, 0, UPDATE_REFS_DIE_ON_ERR); diff --git a/notes-utils.h b/notes-utils.h index 564e30cccd..890ddb33e1 100644 --- a/notes-utils.h +++ b/notes-utils.h @@ -15,7 +15,7 @@ * The resulting commit SHA1 is stored in result_sha1. */ void create_notes_commit(struct notes_tree *t, struct commit_list *parents, - const struct strbuf *msg, unsigned char *result_sha1); + const char *msg, size_t msg_len, unsigned char *result_sha1); void commit_notes(struct notes_tree *t, const char *msg); diff --git a/object.c b/object.c index 57a0890a87..a16b9f9e93 100644 --- a/object.c +++ b/object.c @@ -50,18 +50,7 @@ int type_from_string(const char *str) */ static unsigned int hash_obj(const unsigned char *sha1, unsigned int n) { - unsigned int hash; - - /* - * Since the sha1 is essentially random, we just take the - * required number of bits directly from the first - * sizeof(unsigned int) bytes of sha1. First we have to copy - * the bytes into a properly aligned integer. If we cared - * about getting consistent results across architectures, we - * would have to call ntohl() here, too. - */ - memcpy(&hash, sha1, sizeof(unsigned int)); - return hash & (n - 1); + return sha1hash(sha1) & (n - 1); } /* @@ -141,13 +130,12 @@ static void grow_object_hash(void) obj_hash_size = new_hash_size; } -void *create_object(const unsigned char *sha1, int type, void *o) +void *create_object(const unsigned char *sha1, void *o) { struct object *obj = o; obj->parsed = 0; obj->used = 0; - obj->type = type; obj->flags = 0; hashcpy(obj->sha1, sha1); @@ -159,11 +147,30 @@ void *create_object(const unsigned char *sha1, int type, void *o) return obj; } +void *object_as_type(struct object *obj, enum object_type type, int quiet) +{ + if (obj->type == type) + return obj; + else if (obj->type == OBJ_NONE) { + if (type == OBJ_COMMIT) + ((struct commit *)obj)->index = alloc_commit_index(); + obj->type = type; + return obj; + } + else { + if (!quiet) + error("object %s is a %s, not a %s", + sha1_to_hex(obj->sha1), + typename(obj->type), typename(type)); + return NULL; + } +} + struct object *lookup_unknown_object(const unsigned char *sha1) { struct object *obj = lookup_object(sha1); if (!obj) - obj = create_object(sha1, OBJ_NONE, alloc_object_node()); + obj = create_object(sha1, alloc_object_node()); return obj; } @@ -197,8 +204,8 @@ struct object *parse_object_buffer(const unsigned char *sha1, enum object_type t if (commit) { if (parse_commit_buffer(commit, buffer, size)) return NULL; - if (!commit->buffer) { - commit->buffer = buffer; + if (!get_cached_commit_buffer(commit, NULL)) { + set_commit_buffer(commit, buffer, size); *eaten_p = 1; } obj = &commit->object; @@ -214,8 +221,6 @@ struct object *parse_object_buffer(const unsigned char *sha1, enum object_type t warning("object %s has unknown type id %d", sha1_to_hex(sha1), type); obj = NULL; } - if (obj && obj->type == OBJ_NONE) - obj->type = type; return obj; } diff --git a/object.h b/object.h index 6e12f2c7f4..5e8d8ee548 100644 --- a/object.h +++ b/object.h @@ -79,7 +79,9 @@ extern struct object *get_indexed_object(unsigned int); */ struct object *lookup_object(const unsigned char *sha1); -extern void *create_object(const unsigned char *sha1, int type, void *obj); +extern void *create_object(const unsigned char *sha1, void *obj); + +void *object_as_type(struct object *obj, enum object_type type, int quiet); /* * Returns the object, having parsed it to find out what it is. diff --git a/pack-objects.c b/pack-objects.c index 4f36c32045..9992f3ecf2 100644 --- a/pack-objects.c +++ b/pack-objects.c @@ -7,10 +7,9 @@ static uint32_t locate_object_entry_hash(struct packing_data *pdata, const unsigned char *sha1, int *found) { - uint32_t i, hash, mask = (pdata->index_size - 1); + uint32_t i, mask = (pdata->index_size - 1); - memcpy(&hash, sha1, sizeof(uint32_t)); - i = hash & mask; + i = sha1hash(sha1) & mask; while (pdata->index[i] > 0) { uint32_t pos = pdata->index[i] - 1; diff --git a/pack-write.c b/pack-write.c index 9ccf80419b..33293ce2a6 100644 --- a/pack-write.c +++ b/pack-write.c @@ -288,13 +288,12 @@ char *index_pack_lockfile(int ip_out) * case, we need it to remove the corresponding .keep file * later on. If we don't get that then tough luck with it. */ - if (read_in_full(ip_out, packname, 46) == 46 && packname[45] == '\n' && - memcmp(packname, "keep\t", 5) == 0) { - char path[PATH_MAX]; + if (read_in_full(ip_out, packname, 46) == 46 && packname[45] == '\n') { + const char *name; packname[45] = 0; - snprintf(path, sizeof(path), "%s/pack/pack-%s.keep", - get_object_directory(), packname + 5); - return xstrdup(path); + if (skip_prefix(packname, "keep\t", &name)) + return xstrfmt("%s/pack/pack-%s.keep", + get_object_directory(), name); } return NULL; } diff --git a/pager.c b/pager.c index 8b5cbc56e4..b2b805af98 100644 --- a/pager.c +++ b/pager.c @@ -6,19 +6,13 @@ #define DEFAULT_PAGER "less" #endif -struct pager_config { - const char *cmd; - int want; - char *value; -}; - /* * This is split up from the rest of git so that we can do * something different on Windows. */ static const char *pager_argv[] = { NULL, NULL }; -static struct child_process pager_process; +static struct child_process pager_process = CHILD_PROCESS_INIT; static void wait_for_pager(void) { @@ -155,30 +149,22 @@ int decimal_width(int number) return width; } -static int pager_command_config(const char *var, const char *value, void *data) +/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */ +int check_pager_config(const char *cmd) { - struct pager_config *c = data; - if (starts_with(var, "pager.") && !strcmp(var + 6, c->cmd)) { - int b = git_config_maybe_bool(var, value); + int want = -1; + struct strbuf key = STRBUF_INIT; + const char *value = NULL; + strbuf_addf(&key, "pager.%s", cmd); + if (!git_config_get_value(key.buf, &value)) { + int b = git_config_maybe_bool(key.buf, value); if (b >= 0) - c->want = b; + want = b; else { - c->want = 1; - c->value = xstrdup(value); + want = 1; + pager_program = xstrdup(value); } } - return 0; -} - -/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */ -int check_pager_config(const char *cmd) -{ - struct pager_config c; - c.cmd = cmd; - c.want = -1; - c.value = NULL; - git_config(pager_command_config, &c); - if (c.value) - pager_program = c.value; - return c.want; + strbuf_release(&key); + return want; } diff --git a/parse-options.c b/parse-options.c index b536896f26..e7dafa80d5 100644 --- a/parse-options.c +++ b/parse-options.c @@ -231,7 +231,8 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, continue; again: - rest = skip_prefix(arg, long_name); + if (!skip_prefix(arg, long_name, &rest)) + rest = NULL; if (options->type == OPTION_ARGUMENT) { if (!rest) continue; @@ -280,12 +281,13 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, continue; } flags |= OPT_UNSET; - rest = skip_prefix(arg + 3, long_name); - /* abbreviated and negated? */ - if (!rest && starts_with(long_name, arg + 3)) - goto is_abbreviated; - if (!rest) - continue; + if (!skip_prefix(arg + 3, long_name, &rest)) { + /* abbreviated and negated? */ + if (starts_with(long_name, arg + 3)) + goto is_abbreviated; + else + continue; + } } if (*rest) { if (*rest != '=') diff --git a/path.c b/path.c index bc804a31b3..f68df0cf88 100644 --- a/path.c +++ b/path.c @@ -148,10 +148,12 @@ void home_config_paths(char **global, char **xdg, char *file) *global = mkpathdup("%s/.gitconfig", home); } - if (!xdg_home) - *xdg = NULL; - else - *xdg = mkpathdup("%s/git/%s", xdg_home, file); + if (xdg) { + if (!xdg_home) + *xdg = NULL; + else + *xdg = mkpathdup("%s/git/%s", xdg_home, file); + } free(to_free); } @@ -249,9 +251,7 @@ int validate_headref(const char *path) static struct passwd *getpw_str(const char *username, size_t len) { struct passwd *pw; - char *username_z = xmalloc(len + 1); - memcpy(username_z, username, len); - username_z[len] = '\0'; + char *username_z = xmemdupz(username, len); pw = getpwnam(username_z); free(username_z); return pw; @@ -277,16 +277,16 @@ char *expand_user_path(const char *path) const char *home = getenv("HOME"); if (!home) goto return_null; - strbuf_add(&user_path, home, strlen(home)); + strbuf_addstr(&user_path, home); } else { struct passwd *pw = getpw_str(username, username_len); if (!pw) goto return_null; - strbuf_add(&user_path, pw->pw_dir, strlen(pw->pw_dir)); + strbuf_addstr(&user_path, pw->pw_dir); } to_copy = first_slash; } - strbuf_add(&user_path, to_copy, strlen(to_copy)); + strbuf_addstr(&user_path, to_copy); return strbuf_detach(&user_path, NULL); return_null: strbuf_release(&user_path); diff --git a/pathspec.c b/pathspec.c index 8043099955..9304ee33d7 100644 --- a/pathspec.c +++ b/pathspec.c @@ -338,7 +338,7 @@ static void NORETURN unsupported_magic(const char *pattern, if (!(magic & m->bit)) continue; if (sb.len) - strbuf_addstr(&sb, " "); + strbuf_addch(&sb, ' '); if (short_magic & m->bit) strbuf_addf(&sb, "'%c'", m->mnemonic); else @@ -389,8 +389,7 @@ void parse_pathspec(struct pathspec *pathspec, if (!(flags & PATHSPEC_PREFER_CWD)) die("BUG: PATHSPEC_PREFER_CWD requires arguments"); - pathspec->items = item = xmalloc(sizeof(*item)); - memset(item, 0, sizeof(*item)); + pathspec->items = item = xcalloc(1, sizeof(*item)); item->match = prefix; item->original = prefix; item->nowildcard_len = item->len = strlen(prefix); diff --git a/pkt-line.c b/pkt-line.c index bc63b3b80e..8bc89b1e0c 100644 --- a/pkt-line.c +++ b/pkt-line.c @@ -3,7 +3,7 @@ char packet_buffer[LARGE_PACKET_MAX]; static const char *packet_trace_prefix = "git"; -static const char trace_key[] = "GIT_TRACE_PACKET"; +static struct trace_key trace_packet = TRACE_KEY_INIT(PACKET); void packet_trace_identity(const char *prog) { @@ -15,7 +15,7 @@ static void packet_trace(const char *buf, unsigned int len, int write) int i; struct strbuf out; - if (!trace_want(trace_key)) + if (!trace_want(&trace_packet)) return; /* +32 is just a guess for header + quoting */ @@ -27,7 +27,7 @@ static void packet_trace(const char *buf, unsigned int len, int write) if ((len >= 4 && starts_with(buf, "PACK")) || (len >= 5 && starts_with(buf+1, "PACK"))) { strbuf_addstr(&out, "PACK ..."); - unsetenv(trace_key); + trace_disable(&trace_packet); } else { /* XXX we should really handle printable utf8 */ @@ -43,7 +43,7 @@ static void packet_trace(const char *buf, unsigned int len, int write) } strbuf_addch(&out, '\n'); - trace_strbuf(trace_key, &out); + trace_strbuf(&trace_packet, &out); strbuf_release(&out); } diff --git a/po/TEAMS b/po/TEAMS index f75a1743eb..461cc14354 100644 --- a/po/TEAMS +++ b/po/TEAMS @@ -5,12 +5,18 @@ Language: bg (Bulgarian) Repository: https://github.com/git-l10n/git-po Leader: Alexander Shopov +Language: ca (Catalan) +Repository: https://github.com/alexhenrie/git-po +Leader: Alex Henrie + Language: de (German) Repository: https://github.com/ralfth/git-po-de Leader: Ralf Thielow Members: Thomas Rast Jan Krüger Christian Stimming + Phillip Szelat + Matthias Rüster Language: fr (French) Repository: https://github.com/jnavila/git diff --git a/po/bg.po b/po/bg.po index e862e10604..ef97185321 100644 --- a/po/bg.po +++ b/po/bg.po @@ -18,7 +18,7 @@ # root commit начално подаване # fixup вкарвам подаване в предното без следа # remote-tracking branch следящ клон -# git bundle архив на git +# git bundle пратка на git # bisect двоично търсене # am прилагам поредица от кръпки # working directory/tree — винаги работно дърво, git следи цялото дърво, а не директории @@ -39,16 +39,41 @@ # sequence последователност/поредица # whitespace symbol знаци за интервали # shortlog съкратения журнал +# backing store мястото за съхранение +# reject отхвърлено парче +# topic branch тематичен клон +# empty head връх без история +# tree-ish указател към дърво +# three-way merge тройно сливане +# dirty нечист, мръсен (файл, индекс) +# fallback резервен вариант +# pathspec magic опция за магически пътища +# bitmap index индекс на база битови маски +# mark маркер +# plumbing команди от системно ниво +# porcelain команди от потребителско ниво +# pack [noun] пакетен файл - fixme in glossary +# mainline базово подаване - при cherry-pick на merge - към коя версия да се изчислява разликата +# # ---- # FAILED to parse неуспешен анализ на... -> неразпозната стойност на -# +# blob обект BLOB # ======================== -# „“…— +# „“…— ●≫ѝ→ +# +# stressed a +# форма̀та +# delta - разлика или делта +# consistency between stdout - standard output/ stdin - standard input/ stderr - standard error +# mergetag етикет при сливане +# # ======================== # RECHECK # ------------------------ +# FIXME # HEAD as a reference vs head of a branch -# +# git update-index -h извежда само един ред, а не цялата помощ за опциите +# git fetch --al работи подобно на --all # ======================== # GENERATE STATS # ------------------------ @@ -67,7 +92,7 @@ # ======================== # STRINGS statistics # ------------------------ -# 1307t,0f,921u +# 2228t # # ======================== # MOST IMPORTANT name asc ordering @@ -75,40 +100,37 @@ # add, blame, branch, checkout, clone, commit, common-cmds, config, diff, fetch, fsck, gc, git-rebase, git-stash, grep, log, mv, parse-options, push, reflog, remote, reset, revert, rm, wt-status # # ======================== -# IMPORTANT strings desc, name asc ordering +# IMPORTANT strings, name asc ordering # ------------------------ -# 111 apply 54 git-submodule 30 git-am 13 check-ignore 10 merge-file -# 97 merge 39 init-db 30 describe 12 pathspec 10 merge-base -# 64 tag 35 archive 29 git-bisect 12 name-rev 10 ls-tree -# 55 merge-recursive 32 clean 14 show-ref 11 date 10 hash-object +# apply, archive, check-ignore, clean, date, describe, git-am, git-bisect, git-submodule, hash-object, init-db, ls-tree, merge, merge-base, merge-file, merge-recursive, name-rev, pathspec, show-ref, tag # # ======================== # WHOLE STATISTICS strings desc, name asc ordering # ------------------------ -# 144 [remote] 47 [push] 26 [revert] 12 checkout-index 6 [prune] 2 [verify-tag] -# 137 [commit] 46 pack-objects 24 [mv] 11 date 6 [gpg-interface] 2 [update-server-info] -# 114 [branch] 41 [help] 23 repack 11 column 6 [check-attr] 2 [run-command] -# 111 apply 39 init-db 21 [rm] 10 urlmatch 5 [write-tree] 2 [rerere] -# 101 notes 36 [add] 21 [common-cmds] 10 shortlog 5 [sha1_name] 2 [read-cache] -# 100 [wt-status] 35 [reset] 19 [show-branch] 10 merge-file 5 [rev-parse] 2 [obstack] -# 97 merge 35 archive 19 read-tree 10 merge-base 4 [wrapper] 2 [advice] -# 78 [checkout] 34 [config] 19 bundle 10 ls-tree 4 [prune-packed] 1 [unpack-trees] -# 77 [log] 32 clean 16 [parse-options] 10 hash-object 4 [notes-utils] 1 [unpack-objects] -# 69 [clone] 30 git-am 15 [fsck] 10 for-each-ref 4 [mktree] 1 [progress] -# 68 index-pack 30 describe 14 show-ref 10 cat-file 4 [check-mailmap] 1 [precompose_utf8] +# 144 [remote] 47 [push] 26 [revert] 12 [checkout-index] 6 [prune] 2 [verify-tag] +# 137 [commit] 46 [pack-objects] 24 [mv] 11 [date] 6 [gpg-interface] 2 [update-server-info] +# 114 [branch] 41 [help] 23 [repack] 11 [column] 6 [check-attr] 2 [run-command] +# 111 [apply] 39 [init-db] 21 [rm] 10 [urlmatch] 5 [write-tree] 2 [rerere] +# 101 [notes] 36 [add] 21 [common-cmds] 10 [shortlog] 5 [sha1_name] 2 [read-cache] +# 100 [wt-status] 35 [reset] 19 [show-branch] 10 [merge-file] 5 [rev-parse] 2 [obstack] +# 97 [merge] 35 [archive] 19 [read-tree] 10 [merge-base] 4 [wrapper] 2 [advice] +# 78 [checkout] 34 [config] 19 [bundle] 10 [ls-tree] 4 [prune-packed] 1 [unpack-trees] +# 77 [log] 32 [clean] 16 [parse-options] 10 [hash-object] 4 [notes-utils] 1 [unpack-objects] +# 69 [clone] 30 [git-am] 15 [fsck] 10 [for-each-ref] 4 [mktree] 1 [progress] +# 68 [index-pack] 30 [describe] 14 [show-ref] 10 [cat-file] 4 [check-mailmap] 1 [precompose_utf8] # 68 [fetch] 29 [git-stash] 14 [gc] 9 [update-ref] 3 [verify-pack] 1 [object] -# 64 tag 29 git-bisect 14 fast-export 9 [submodule] 3 [reflog] 1 [git] -# 64 [grep] 28 update-index 13 [diff] 8 [replace] 3 [pack-refs] 1 [diffcore-rename] -# 56 sequencer 28 [blame] 13 check-ignore 8 [git-pull] 3 [count-objects] 1 [diffcore-order] -# 55 merge-recursive 27 ls-files 12 pathspec 8 [fmt-merge-msg] 3 [connected] 1 [attr] -# 54 git-submodule 27 [git-rebase] 12 name-rev 7 [symbolic-ref] 3 [bisect--helper] +# 64 [tag] 29 [git-bisect] 14 [fast-export] 9 [submodule] 3 [reflog] 1 [git] +# 64 [grep] 28 [update-index] 13 [diff] 8 [replace] 3 [pack-refs] 1 [diffcore-rename] +# 56 [sequencer] 28 [blame] 13 [check-ignore] 8 [git-pull] 3 [count-objects] 1 [diffcore-order] +# 55 [merge-recursive] 27 [ls-files] 12 [pathspec] 8 [fmt-merge-msg] 3 [connected] 1 [attr] +# 54 [git-submodule] 27 [git-rebase] 12 [name-rev] 7 [symbolic-ref] 3 [bisect--helper] # msgid "" msgstr "" "Project-Id-Version: git master\n" "Report-Msgid-Bugs-To: Git Mailing List \n" -"POT-Creation-Date: 2014-04-19 12:50+0800\n" -"PO-Revision-Date: 2014-05-11 17:06+0300\n" +"POT-Creation-Date: 2014-08-04 14:48+0800\n" +"PO-Revision-Date: 2014-08-03 13:01+0300\n" "Last-Translator: Alexander Shopov \n" "Language-Team: Bulgarian \n" "Language: bg\n" @@ -122,59 +144,60 @@ msgstr "" msgid "hint: %.*s\n" msgstr "Подсказка: %.*s\n" -#: advice.c:85 +# TRANSFER +#: advice.c:88 msgid "" -"Fix them up in the work tree,\n" -"and then use 'git add/rm ' as\n" -"appropriate to mark resolution and make a commit,\n" -"or use 'git commit -a'." +"Fix them up in the work tree, and then use 'git add/rm '\n" +"as appropriate to mark resolution and make a commit, or use\n" +"'git commit -a'." msgstr "" -"Редактирайте ги в работното дърво,\n" -"и тогава ползвайте „git add/rm “,\n" -"за да отбележите коригирането им и ги\n" -"подадете или просто ползвайте „git commit -a“." +"Редактирайте ги в работното дърво, и тогава ползвайте „git add/rm ФАЙЛ“\n" +"за да отбележите коригирането им и ги подадете или просто ползвайте:\n" +"„git commit -a“" #: archive.c:10 msgid "git archive [options] [...]" -msgstr "" +msgstr "git archive [ОПЦИЯ…] УКАЗАТЕЛ_КЪМ_ДЪРВО [ПЪТ…]" #: archive.c:11 msgid "git archive --list" -msgstr "" +msgstr "git archive --list" #: archive.c:12 msgid "" "git archive --remote [--exec ] [options] [...]" msgstr "" +"git archive --remote ХРАНИЛИЩЕ [--exec КОМАНДА] [ОПЦИЯ…] УКАЗАТЕЛ_КЪМ_ДЪРВО " +"[ПЪТ…]" #: archive.c:13 msgid "git archive --remote [--exec ] --list" -msgstr "" +msgstr "git archive --remote ХРАНИЛИЩЕ [--exec КОМАНДА] --list" -#: archive.c:243 builtin/add.c:136 builtin/add.c:428 builtin/rm.c:328 +#: archive.c:243 builtin/add.c:136 builtin/add.c:427 builtin/rm.c:328 #, c-format msgid "pathspec '%s' did not match any files" msgstr "пътят „%s“ не съвпада с никой файл" #: archive.c:328 msgid "fmt" -msgstr "" +msgstr "ФОРМАТ" #: archive.c:328 msgid "archive format" -msgstr "" +msgstr "ФОРМАТ на архива" -#: archive.c:329 builtin/log.c:1193 +#: archive.c:329 builtin/log.c:1201 msgid "prefix" msgstr "префикс" #: archive.c:330 msgid "prepend prefix to each pathname in the archive" -msgstr "" +msgstr "добавяне на този префикс към всеки път в архива" -#: archive.c:331 builtin/archive.c:88 builtin/blame.c:2258 -#: builtin/blame.c:2259 builtin/config.c:57 builtin/fast-export.c:680 -#: builtin/fast-export.c:682 builtin/grep.c:714 builtin/hash-object.c:77 +#: archive.c:331 builtin/archive.c:88 builtin/blame.c:2517 +#: builtin/blame.c:2518 builtin/config.c:57 builtin/fast-export.c:709 +#: builtin/fast-export.c:711 builtin/grep.c:712 builtin/hash-object.c:77 #: builtin/ls-files.c:489 builtin/ls-files.c:492 builtin/notes.c:412 #: builtin/notes.c:569 builtin/read-tree.c:108 parse-options.h:151 msgid "file" @@ -182,31 +205,31 @@ msgstr "файл" #: archive.c:332 builtin/archive.c:89 msgid "write the archive to this file" -msgstr "" +msgstr "запазване на архива в този файл" #: archive.c:334 msgid "read .gitattributes in working directory" -msgstr "" +msgstr "изчитане на „.gitattributes“ в работната директория" #: archive.c:335 msgid "report archived files on stderr" -msgstr "" +msgstr "извеждане на архивираните файлове на стандартната грешка" #: archive.c:336 msgid "store only" -msgstr "" +msgstr "само съхранение без компресиране" #: archive.c:337 msgid "compress faster" -msgstr "" +msgstr "бързо компресиране" #: archive.c:345 msgid "compress better" -msgstr "" +msgstr "добро компресиране" #: archive.c:348 msgid "list supported archive formats" -msgstr "" +msgstr "извеждане на списъка с поддържаните формати" #: archive.c:350 builtin/archive.c:90 builtin/clone.c:84 msgid "repo" @@ -214,15 +237,15 @@ msgstr "хранилище" #: archive.c:351 builtin/archive.c:91 msgid "retrieve the archive from remote repository " -msgstr "" +msgstr "изтегляне на архива от отдалеченото ХРАНИЛИЩЕ" #: archive.c:352 builtin/archive.c:92 builtin/notes.c:491 msgid "command" -msgstr "" +msgstr "команда" #: archive.c:353 builtin/archive.c:93 msgid "path to the remote git-upload-archive command" -msgstr "" +msgstr "път към отдалечената команда „git-upload-archive“" #: attr.c:259 msgid "" @@ -355,24 +378,24 @@ msgstr "Указателят не може да бъде записан" #: bundle.c:33 #, c-format msgid "'%s' does not look like a v2 bundle file" -msgstr "Файлът „%s“ не изглежда да е архив на git версия 2" +msgstr "Файлът „%s“ не изглежда да е пратка на git версия 2" #: bundle.c:60 #, c-format msgid "unrecognized header: %s%s (%d)" -msgstr "" +msgstr "непозната заглавна част: %s%s (%d)" -#: bundle.c:86 builtin/commit.c:706 +#: bundle.c:86 builtin/commit.c:755 #, c-format msgid "could not open '%s'" msgstr "„%s“ не може да се отвори" #: bundle.c:138 msgid "Repository lacks these prerequisite commits:" -msgstr "" +msgstr "В хранилището липсват следните необходими подавания:" -#: bundle.c:162 sequencer.c:669 sequencer.c:1123 builtin/log.c:332 -#: builtin/log.c:821 builtin/log.c:1418 builtin/log.c:1644 builtin/merge.c:357 +#: bundle.c:162 sequencer.c:630 sequencer.c:1085 builtin/log.c:330 +#: builtin/log.c:821 builtin/log.c:1428 builtin/log.c:1665 builtin/merge.c:357 #: builtin/shortlog.c:158 msgid "revision walk setup failed" msgstr "неуспешно настройване на обхождането на версиите" @@ -381,61 +404,65 @@ msgstr "неуспешно настройване на обхождането н #, c-format msgid "The bundle contains this ref:" msgid_plural "The bundle contains these %d refs:" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Пратката съдържа следния указател:" +msgstr[1] "Пратката съдържа следните %d указатели:" #: bundle.c:191 msgid "The bundle records a complete history." -msgstr "" +msgstr "Пратката съдържа пълна история." #: bundle.c:193 #, c-format msgid "The bundle requires this ref:" msgid_plural "The bundle requires these %d refs:" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Пратката изисква следния указател:" +msgstr[1] "Пратката изисква следните %d указатели:" -#: bundle.c:293 +# FIXME better message +#: bundle.c:289 msgid "rev-list died" -msgstr "" +msgstr "Командата „git rev-list“ не завърши успешно" -#: bundle.c:299 builtin/log.c:1329 builtin/shortlog.c:261 +#: bundle.c:295 builtin/log.c:1339 builtin/shortlog.c:261 #, c-format msgid "unrecognized argument: %s" msgstr "непознат аргумент: %s" -#: bundle.c:334 +#: bundle.c:330 #, c-format msgid "ref '%s' is excluded by the rev-list options" msgstr "" +"указателят „%s“ не е бил включен поради опциите зададени на „git rev-list“" -#: bundle.c:379 +#: bundle.c:375 msgid "Refusing to create empty bundle." -msgstr "" +msgstr "Създаването на празна пратка е невъзможно." -#: bundle.c:395 +#: bundle.c:390 msgid "Could not spawn pack-objects" -msgstr "" +msgstr "Командата „git pack-objects“ не може да бъде стартирана" -#: bundle.c:413 +# FIXME better message +#: bundle.c:408 msgid "pack-objects died" -msgstr "" +msgstr "Командата „git pack-objects“ не завърши успешно" -#: bundle.c:416 +#: bundle.c:411 #, c-format msgid "cannot create '%s'" -msgstr "" +msgstr "Файлът „%s“ не може да бъде създаден" -#: bundle.c:438 +# FIXME better message +#: bundle.c:433 msgid "index-pack died" -msgstr "" +msgstr "Командата „git index-pack“ не завърши успешно" -#: commit.c:54 +#: commit.c:40 #, c-format msgid "could not parse %s" msgstr "„%s“ не може да се анализира" -#: commit.c:56 +#: commit.c:42 #, c-format msgid "%s %s is not a commit!" msgstr "%s %s не е подаване!" @@ -451,7 +478,7 @@ msgstr "Командата „git rev-list“ не може да бъде изп #: connected.c:90 #, c-format msgid "failed write to rev-list: %s" -msgstr "неуспешен запис в списъка с версиите: %s" +msgstr "неуспешен запис на списъка с версиите: %s" #: connected.c:98 #, c-format @@ -460,99 +487,99 @@ msgstr "стандартният вход на списъка с версиит #: date.c:95 msgid "in the future" -msgstr "" +msgstr "в бъдещето" #: date.c:101 #, c-format msgid "%lu second ago" msgid_plural "%lu seconds ago" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "преди %lu секунда" +msgstr[1] "преди %lu секунди" #: date.c:108 #, c-format msgid "%lu minute ago" msgid_plural "%lu minutes ago" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "преди %lu минута" +msgstr[1] "преди %lu минути" #: date.c:115 #, c-format msgid "%lu hour ago" msgid_plural "%lu hours ago" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "преди %lu час" +msgstr[1] "преди %lu часа" #: date.c:122 #, c-format msgid "%lu day ago" msgid_plural "%lu days ago" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "преди %lu ден" +msgstr[1] "преди %lu дена" #: date.c:128 #, c-format msgid "%lu week ago" msgid_plural "%lu weeks ago" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "преди %lu седмица" +msgstr[1] "преди %lu седмици" #: date.c:135 #, c-format msgid "%lu month ago" msgid_plural "%lu months ago" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "преди %lu месец" +msgstr[1] "преди %lu месеца" #: date.c:146 #, c-format msgid "%lu year" msgid_plural "%lu years" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%lu година" +msgstr[1] "%lu години" #. TRANSLATORS: "%s" is " years" #: date.c:149 #, c-format msgid "%s, %lu month ago" msgid_plural "%s, %lu months ago" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "преди %s и %lu месец" +msgstr[1] "преди %s и %lu месеца" #: date.c:154 date.c:159 #, c-format msgid "%lu year ago" msgid_plural "%lu years ago" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "преди %lu година" +msgstr[1] "преди %lu години" #: diffcore-order.c:24 #, c-format msgid "failed to read orderfile '%s'" msgstr "файлът с подредбата на съответствията „%s“ не може да бъде прочетен" -#: diffcore-rename.c:517 +#: diffcore-rename.c:514 msgid "Performing inexact rename detection" msgstr "Търсене на преименувания на обекти съчетани с промени" -#: diff.c:113 +#: diff.c:114 #, c-format msgid " Failed to parse dirstat cut-off percentage '%s'\n" msgstr "" " Неуспешно разпознаване на „%s“ като процент-праг за статистиката по " "директории\n" -#: diff.c:118 +#: diff.c:119 #, c-format msgid " Unknown dirstat parameter '%s'\n" msgstr " Непознат параметър „%s“ за статистиката по директории'\n" -#: diff.c:213 +#: diff.c:214 #, c-format msgid "Unknown value for 'diff.submodule' config variable: '%s'" msgstr "Непозната стойност „%s“ за настройката „diff.submodule“" -#: diff.c:263 +#: diff.c:267 #, c-format msgid "" "Found errors in 'diff.dirstat' config variable:\n" @@ -561,7 +588,17 @@ msgstr "" "Грешки в настройката „diff.dirstat“:\n" "%s" -#: diff.c:3495 +#: diff.c:2934 +#, c-format +msgid "external diff died, stopping at %s" +msgstr "" +"външната програма за разлики завърши неуспешно. Спиране на работата при „%s“" + +#: diff.c:3329 +msgid "--follow requires exactly one pathspec" +msgstr "Опцията „--follow“ изисква точно един път" + +#: diff.c:3492 #, c-format msgid "" "Failed to parse --dirstat/-X option parameter:\n" @@ -570,58 +607,58 @@ msgstr "" "Неразпознат параметър към опцията „--dirstat/-X“:\n" "%s" -#: diff.c:3509 +#: diff.c:3506 #, c-format msgid "Failed to parse --submodule option parameter: '%s'" msgstr "Неразпознат параметър към опцията „--submodule“: „%s“" -#: gpg-interface.c:59 gpg-interface.c:131 +#: gpg-interface.c:73 gpg-interface.c:145 msgid "could not run gpg." msgstr "Програмата „gpg“ не може да бъде стартирана." -#: gpg-interface.c:71 +#: gpg-interface.c:85 msgid "gpg did not accept the data" msgstr "Програмата „gpg“ не прие подадените данни." -#: gpg-interface.c:82 +#: gpg-interface.c:96 msgid "gpg failed to sign the data" msgstr "Програмата „gpg“ не подписа данните." -#: gpg-interface.c:115 +#: gpg-interface.c:129 #, c-format msgid "could not create temporary file '%s': %s" msgstr "Програмата „gpg“ не успя да създаде временния файл „%s“: %s" -#: gpg-interface.c:118 +#: gpg-interface.c:132 #, c-format msgid "failed writing detached signature to '%s': %s" msgstr "Програмата „gpg“ не успя да запише самостоятелния подпис към „%s“: %s" -#: grep.c:1698 +#: grep.c:1703 #, c-format msgid "'%s': unable to read %s" msgstr "„%s“: файлът сочен от „%s“ не може да бъде прочетен" -#: grep.c:1715 +#: grep.c:1720 #, c-format msgid "'%s': %s" msgstr "„%s“: „%s“" -#: grep.c:1726 +#: grep.c:1731 #, c-format msgid "'%s': short read %s" msgstr "„%s“: изчитането на „%s“ върна по-малко байтове от заявените" -#: help.c:209 +#: help.c:207 #, c-format msgid "available git commands in '%s'" msgstr "налични команди на git от „%s“" -#: help.c:216 +#: help.c:214 msgid "git commands available from elsewhere on your $PATH" -msgstr "команди на git от други директории от пътя „$PATH“" +msgstr "команди на git от други директории от „$PATH“" -#: help.c:232 +#: help.c:230 msgid "The most commonly used git commands are:" msgstr "Най-често употребяваните команди на git са:" @@ -660,7 +697,7 @@ msgstr "след %0.1f секунди…" msgid "git: '%s' is not a git command. See 'git --help'." msgstr "git: „%s“ не е команда на git. Вижте изхода от „git --help“." -#: help.c:384 help.c:443 +#: help.c:384 help.c:444 msgid "" "\n" "Did you mean this?" @@ -674,16 +711,16 @@ msgstr[1] "" "\n" "Команди с подобно име са:" -#: help.c:439 +#: help.c:440 #, c-format msgid "%s: %s - %s" msgstr "%s: %s — %s" -#: merge.c:56 +#: merge.c:40 msgid "failed to read the cache" -msgstr "" +msgstr "кешът не може да бъде прочетен" -#: merge.c:110 builtin/checkout.c:357 builtin/checkout.c:558 +#: merge.c:93 builtin/checkout.c:356 builtin/checkout.c:556 #: builtin/clone.c:661 msgid "unable to write new index file" msgstr "неуспешно записване на новия индекс" @@ -691,258 +728,274 @@ msgstr "неуспешно записване на новия индекс" #: merge-recursive.c:190 #, c-format msgid "(bad commit)\n" -msgstr "" +msgstr "(лошо подаване)\n" -#: merge-recursive.c:208 +#: merge-recursive.c:210 #, c-format msgid "addinfo_cache failed for path '%s'" -msgstr "" +msgstr "неуспешно изпълнение на „addinfo_cache“ за пътя „%s“" #: merge-recursive.c:271 msgid "error building trees" -msgstr "" +msgstr "грешка при изграждане на дърветата" -#: merge-recursive.c:675 +#: merge-recursive.c:692 #, c-format msgid "failed to create path '%s'%s" -msgstr "" +msgstr "грешка при създаването на пътя „%s“%s" -#: merge-recursive.c:686 +#: merge-recursive.c:703 #, c-format msgid "Removing %s to make room for subdirectory\n" -msgstr "" +msgstr "Изтриване на „%s“, за да се освободи място за поддиректория\n" -#: merge-recursive.c:700 merge-recursive.c:721 +# FIXME better message +#: merge-recursive.c:717 merge-recursive.c:738 msgid ": perhaps a D/F conflict?" -msgstr "" +msgstr ": възможно е да има конфликт директория/файл." -#: merge-recursive.c:711 +#: merge-recursive.c:728 #, c-format msgid "refusing to lose untracked file at '%s'" msgstr "" +"преустановяване на действието, за да не се изтрие неследеният файл „%s“" -#: merge-recursive.c:751 +#: merge-recursive.c:768 #, c-format msgid "cannot read object %s '%s'" -msgstr "" +msgstr "обектът „%s“ (%s) не може да бъде прочетен" -#: merge-recursive.c:753 +#: merge-recursive.c:770 #, c-format msgid "blob expected for %s '%s'" -msgstr "" +msgstr "обектът „%s“ (%s) се очакваше да е BLOB, а не е" -#: merge-recursive.c:776 builtin/clone.c:317 +#: merge-recursive.c:793 builtin/clone.c:317 #, c-format msgid "failed to open '%s'" msgstr "директорията „%s“ не може да бъде отворена" -#: merge-recursive.c:784 +#: merge-recursive.c:801 #, c-format msgid "failed to symlink '%s'" -msgstr "" +msgstr "неуспешно създаване на символната връзка „%s“" -#: merge-recursive.c:787 +#: merge-recursive.c:804 #, c-format msgid "do not know what to do with %06o %s '%s'" msgstr "" +"не е ясно какво да се прави с обекта „%2$s“ (%3$s) с права за достъп „%1$06o“" -#: merge-recursive.c:925 +#: merge-recursive.c:942 msgid "Failed to execute internal merge" -msgstr "" +msgstr "Неуспешно вътрешно сливане" -#: merge-recursive.c:929 +#: merge-recursive.c:946 #, c-format msgid "Unable to add %s to database" -msgstr "" +msgstr "„%s“ не може да се добави в базата с данни" -#: merge-recursive.c:945 +#: merge-recursive.c:962 msgid "unsupported object type in the tree" -msgstr "" +msgstr "в дървото има неподдържан вид обект" -#: merge-recursive.c:1024 merge-recursive.c:1038 +#: merge-recursive.c:1037 merge-recursive.c:1051 #, c-format msgid "" "CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " "in tree." msgstr "" +"КОНФЛИКТ (%s/изтриване): „%s“ е изтрит в %s, а „%s“ в %s. Версия %s на „%s“ " +"е оставена в дървото." -#: merge-recursive.c:1030 merge-recursive.c:1043 +#: merge-recursive.c:1043 merge-recursive.c:1056 #, c-format msgid "" "CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " "in tree at %s." msgstr "" +"КОНФЛИКТ (%s/изтриване): „%s“ е изтрит в %s, а „%s“ в %s. Версия %s на „%s“ " +"е оставена в дървото: %s." -#: merge-recursive.c:1084 +#: merge-recursive.c:1097 msgid "rename" -msgstr "" +msgstr "преименуване" -#: merge-recursive.c:1084 +#: merge-recursive.c:1097 msgid "renamed" msgstr "преименуван" -#: merge-recursive.c:1140 +#: merge-recursive.c:1153 #, c-format msgid "%s is a directory in %s adding as %s instead" -msgstr "" +msgstr "„%s“ е директория в „%s“, затова се добавя като „%s“" -#: merge-recursive.c:1162 +#: merge-recursive.c:1175 #, c-format msgid "" "CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s" "\"->\"%s\" in \"%s\"%s" msgstr "" +"КОНФЛИКТ (преименуване/преименуване): „%s“ е преименуван на „%s“ в клон " +"„%s“, а „%s“ е преименуван на „%s“ в „%s“/%s." -#: merge-recursive.c:1167 +#: merge-recursive.c:1180 msgid " (left unresolved)" -msgstr "" +msgstr " (некоригиран конфликт)" -#: merge-recursive.c:1221 +#: merge-recursive.c:1234 #, c-format msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s" msgstr "" +"КОНФЛИКТ (преименуване/преименуване): „%s“ е преименуван на „%s“ в клон " +"„%s“, а „%s“ е преименуван на „%s“ в „%s“" -#: merge-recursive.c:1251 +#: merge-recursive.c:1264 #, c-format msgid "Renaming %s to %s and %s to %s instead" -msgstr "" +msgstr "Преименуване на „%s“ на „%s“, а „%s“ на „%s“" -#: merge-recursive.c:1450 +#: merge-recursive.c:1463 #, c-format msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s" msgstr "" +"КОНФЛИКТ (преименуване/добавяне): „%s“ е преименуван на „%s“ в клон „%s“, а " +"„%s“ е добавен в „%s“" -#: merge-recursive.c:1460 +#: merge-recursive.c:1473 #, c-format msgid "Adding merged %s" -msgstr "" +msgstr "Добавяне на слетия „%s“" -#: merge-recursive.c:1465 merge-recursive.c:1663 +#: merge-recursive.c:1478 merge-recursive.c:1676 #, c-format msgid "Adding as %s instead" -msgstr "" +msgstr "Добавяне като „%s“" -#: merge-recursive.c:1516 +#: merge-recursive.c:1529 #, c-format msgid "cannot read object %s" -msgstr "" +msgstr "обектът „%s“ не може да се прочете" -#: merge-recursive.c:1519 +#: merge-recursive.c:1532 #, c-format msgid "object %s is not a blob" -msgstr "" +msgstr "обектът „%s“ не е BLOB" -#: merge-recursive.c:1567 +#: merge-recursive.c:1580 msgid "modify" -msgstr "" +msgstr "промяна" -#: merge-recursive.c:1567 +#: merge-recursive.c:1580 msgid "modified" msgstr "променен" -#: merge-recursive.c:1577 +#: merge-recursive.c:1590 msgid "content" -msgstr "" +msgstr "съдържание" -#: merge-recursive.c:1584 +#: merge-recursive.c:1597 msgid "add/add" -msgstr "" +msgstr "добавяне/добавяне" -#: merge-recursive.c:1618 +#: merge-recursive.c:1631 #, c-format msgid "Skipped %s (merged same as existing)" -msgstr "" +msgstr "Прескачане на „%s“ (слетият резултат е идентичен със сегашния)" -#: merge-recursive.c:1632 +#: merge-recursive.c:1645 #, c-format msgid "Auto-merging %s" -msgstr "" +msgstr "Автоматично сливане на „%s“" -#: merge-recursive.c:1636 git-submodule.sh:1149 +#: merge-recursive.c:1649 git-submodule.sh:1150 msgid "submodule" msgstr "ПОДМОДУЛ" -#: merge-recursive.c:1637 +#: merge-recursive.c:1650 #, c-format msgid "CONFLICT (%s): Merge conflict in %s" -msgstr "" +msgstr "КОНФЛИКТ (%s): Конфликт при сливане на „%s“" -#: merge-recursive.c:1727 +#: merge-recursive.c:1740 #, c-format msgid "Removing %s" msgstr "Изтриване на „%s“" -#: merge-recursive.c:1752 +#: merge-recursive.c:1765 msgid "file/directory" -msgstr "" +msgstr "файл/директория" -#: merge-recursive.c:1758 +#: merge-recursive.c:1771 msgid "directory/file" -msgstr "" +msgstr "директория/файл" -#: merge-recursive.c:1763 +#: merge-recursive.c:1776 #, c-format msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s" msgstr "" +"КОНФЛИКТ (%s): Съществува директория на име „%s“ в „%s“. Добавяне на „%s“ " +"като „%s“" -#: merge-recursive.c:1773 +#: merge-recursive.c:1786 #, c-format msgid "Adding %s" -msgstr "" +msgstr "Добавяне на „%s“" -#: merge-recursive.c:1790 +#: merge-recursive.c:1803 msgid "Fatal merge failure, shouldn't happen." -msgstr "" +msgstr "Фатална грешка при сливане, а такава не трябва да възниква!" -#: merge-recursive.c:1809 +#: merge-recursive.c:1822 msgid "Already up-to-date!" -msgstr "" +msgstr "Вече е обновено!" -#: merge-recursive.c:1818 +#: merge-recursive.c:1831 #, c-format msgid "merging of trees %s and %s failed" -msgstr "" +msgstr "неуспешно сливане на дърветата „%s“ и „%s“" -#: merge-recursive.c:1848 +# FIXME message +#: merge-recursive.c:1861 #, c-format msgid "Unprocessed path??? %s" -msgstr "" +msgstr "Пътят „%s“ не е обработен, това е грешка в Git." -#: merge-recursive.c:1893 +#: merge-recursive.c:1906 msgid "Merging:" -msgstr "" +msgstr "Сливане:" -#: merge-recursive.c:1906 +#: merge-recursive.c:1919 #, c-format msgid "found %u common ancestor:" msgid_plural "found %u common ancestors:" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "открит е %u общ предшественик:" +msgstr[1] "открити са %u общи предшественици:" -#: merge-recursive.c:1943 +#: merge-recursive.c:1956 msgid "merge returned no commit" -msgstr "" +msgstr "сливането не върна подаване" -#: merge-recursive.c:2000 +#: merge-recursive.c:2013 #, c-format msgid "Could not parse object '%s'" -msgstr "" +msgstr "Неуспешен анализ на обекта „%s“" -#: merge-recursive.c:2012 builtin/merge.c:668 +#: merge-recursive.c:2024 builtin/merge.c:666 msgid "Unable to write index." -msgstr "" +msgstr "Индексът не може да бъде прочетен" -#: notes-utils.c:40 +#: notes-utils.c:41 msgid "Cannot commit uninitialized/unreferenced notes tree" msgstr "" "Неинициализирано или нереферирано дърво за бележки не може да бъде подадено" -#: notes-utils.c:81 +#: notes-utils.c:83 #, c-format msgid "Bad notes.rewriteMode value: '%s'" -msgstr "Лоша стойност за „notes.rewriteMode“: „%s“" +msgstr "Неправилна стойност за „notes.rewriteMode“: „%s“" -#: notes-utils.c:91 +#: notes-utils.c:93 #, c-format msgid "Refusing to rewrite notes in %s (outside of refs/notes/)" msgstr "" @@ -950,106 +1003,110 @@ msgstr "" #. TRANSLATORS: The first %s is the name of the #. environment variable, the second %s is its value -#: notes-utils.c:118 +#: notes-utils.c:120 #, c-format msgid "Bad %s value: '%s'" msgstr "Зададена е лоша стойност на променливата „%s“: „%s“" -#: object.c:229 +#: object.c:234 #, c-format msgid "unable to parse object: %s" msgstr "обектът „%s“ не може да бъде анализиран" -#: parse-options.c:532 +#: parse-options.c:534 msgid "..." msgstr "…" -#: parse-options.c:550 +#: parse-options.c:552 #, c-format msgid "usage: %s" msgstr "употреба: %s" #. TRANSLATORS: the colon here should align with the #. one in "usage: %s" translation -#: parse-options.c:554 +#: parse-options.c:556 #, c-format msgid " or: %s" msgstr " или: %s" -#: parse-options.c:557 +#: parse-options.c:559 #, c-format msgid " %s" msgstr " %s" -#: parse-options.c:591 +#: parse-options.c:593 msgid "-NUM" msgstr "-ЧИСЛО" #: pathspec.c:133 msgid "global 'glob' and 'noglob' pathspec settings are incompatible" -msgstr "" +msgstr "глобалните настройки за пътища „glob“ и „noglob“ са несъвместими" #: pathspec.c:143 msgid "" "global 'literal' pathspec setting is incompatible with all other global " "pathspec settings" msgstr "" +"глобалната настройка за дословни пътища „literal“ е несъвместима с всички " +"други глобални настройки за пътища" #: pathspec.c:177 msgid "invalid parameter for pathspec magic 'prefix'" -msgstr "" +msgstr "неправилен параметър за опцията за магически пътища „prefix“" #: pathspec.c:183 #, c-format msgid "Invalid pathspec magic '%.*s' in '%s'" -msgstr "" +msgstr "Неправилна стойност за опцията за магически пътища „%.*s“ в „%s“" #: pathspec.c:187 #, c-format msgid "Missing ')' at the end of pathspec magic in '%s'" -msgstr "" +msgstr "Знакът „)“ липсва в опцията за магически пътища в „%s“" #: pathspec.c:205 #, c-format msgid "Unimplemented pathspec magic '%c' in '%s'" -msgstr "" +msgstr "Магическите пътища „%c“ са без реализация за „%s“" #: pathspec.c:230 #, c-format msgid "%s: 'literal' and 'glob' are incompatible" -msgstr "" +msgstr "%s: опциите „literal“ и „glob“ са несъвместими" #: pathspec.c:241 #, c-format msgid "%s: '%s' is outside repository" -msgstr "" +msgstr "%s: „%s“ е извън хранилището" #: pathspec.c:291 #, c-format msgid "Pathspec '%s' is in submodule '%.*s'" -msgstr "" +msgstr "Пътят „%s“ е в подмодула „%.*s“" #: pathspec.c:353 #, c-format msgid "%s: pathspec magic not supported by this command: %s" -msgstr "" +msgstr "%s: магическите пътища не се поддържат от командата „%s“" -#: pathspec.c:433 +#: pathspec.c:432 #, c-format msgid "pathspec '%s' is beyond a symbolic link" -msgstr "" +msgstr "пътят „%s“ е след символна връзка" -#: pathspec.c:442 +#: pathspec.c:441 msgid "" "There is nothing to exclude from by :(exclude) patterns.\n" "Perhaps you forgot to add either ':/' or '.' ?" msgstr "" +"Нищо не се изключва от шаблоните за изключване.\n" +"Това често се случва, ако сте забравили да добавите „:/“ или „.“." -#: progress.c:224 +#: progress.c:225 msgid "done" msgstr "действието завърши" -#: read-cache.c:1238 +#: read-cache.c:1260 #, c-format msgid "" "index.version set, but the value is invalid.\n" @@ -1058,7 +1115,7 @@ msgstr "" "Зададена е неправилна стойност на настройката „index.version“.\n" "Ще се ползва версия %i" -#: read-cache.c:1248 +#: read-cache.c:1270 #, c-format msgid "" "GIT_INDEX_VERSION set, but the value is invalid.\n" @@ -1068,51 +1125,51 @@ msgstr "" "„GIT_INDEX_VERSION“.\n" "Ще се ползва версия %i" -#: remote.c:758 +#: remote.c:753 #, c-format msgid "Cannot fetch both %s and %s to %s" msgstr "Невъзможно е да се доставят едновременно и „%s“, и „%s“ към „%s“" -#: remote.c:762 +#: remote.c:757 #, c-format msgid "%s usually tracks %s, not %s" msgstr "„%s“ обикновено следи „%s“, а не „%s“" -#: remote.c:766 +#: remote.c:761 #, c-format msgid "%s tracks both %s and %s" msgstr "„%s“ следи както „%s“, така и „%s“" -#: remote.c:774 +#: remote.c:769 msgid "Internal error" msgstr "Вътрешна грешка" -#: remote.c:1948 +#: remote.c:1943 #, c-format msgid "Your branch is based on '%s', but the upstream is gone.\n" msgstr "Този клон следи „%s“, но следеният клон е изтрит.\n" -#: remote.c:1952 +#: remote.c:1947 msgid " (use \"git branch --unset-upstream\" to fixup)\n" msgstr " (за да коригирате това, използвайте „git branch --unset-upstream“)\n" -#: remote.c:1955 +#: remote.c:1950 #, c-format msgid "Your branch is up-to-date with '%s'.\n" -msgstr "Клонът е актуализиран както „%s“.\n" +msgstr "Клонът е актуализиран към „%s“.\n" -#: remote.c:1959 +#: remote.c:1954 #, c-format msgid "Your branch is ahead of '%s' by %d commit.\n" msgid_plural "Your branch is ahead of '%s' by %d commits.\n" msgstr[0] "Клонът ви е с %2$d подаване пред „%1$s“.\n" msgstr[1] "Клонът ви е с %2$d подавания пред „%1$s“.\n" -#: remote.c:1965 +#: remote.c:1960 msgid " (use \"git push\" to publish your local commits)\n" msgstr " (публикувайте локалните си промени чрез „git push“)\n" -#: remote.c:1968 +#: remote.c:1963 #, c-format msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n" msgid_plural "" @@ -1122,11 +1179,11 @@ msgstr[0] "" msgstr[1] "" "Клонът ви е с %2$d подавания след „%1$s“ и може да бъде тривиално слят.\n" -#: remote.c:1976 +#: remote.c:1971 msgid " (use \"git pull\" to update your local branch)\n" msgstr " (обновете локалния си клон чрез „git pull“)\n" -#: remote.c:1979 +#: remote.c:1974 #, c-format msgid "" "Your branch and '%s' have diverged,\n" @@ -1141,7 +1198,7 @@ msgstr[1] "" "Текущият клон се е отделил от „%s“,\n" "двата имат съответно по %d и %d несъвпадащи подавания.\n" -#: remote.c:1989 +#: remote.c:1984 msgid " (use \"git pull\" to merge the remote branch into yours)\n" msgstr " (слейте отдалечения клон в локалния чрез „git pull“)\n" @@ -1154,247 +1211,266 @@ msgstr "неуспешно отваряне на „/dev/null“" msgid "dup2(%d,%d) failed" msgstr "неуспешно изпълнение на dup2(%d,%d)" -#: sequencer.c:206 builtin/merge.c:786 builtin/merge.c:899 -#: builtin/merge.c:1009 builtin/merge.c:1019 +#: sequencer.c:171 builtin/merge.c:782 builtin/merge.c:893 +#: builtin/merge.c:1003 builtin/merge.c:1013 #, c-format msgid "Could not open '%s' for writing" -msgstr "" +msgstr "„%s“ не може да бъде отворен за запис" -#: sequencer.c:208 builtin/merge.c:343 builtin/merge.c:789 -#: builtin/merge.c:1011 builtin/merge.c:1024 +#: sequencer.c:173 builtin/merge.c:343 builtin/merge.c:785 +#: builtin/merge.c:1005 builtin/merge.c:1018 #, c-format msgid "Could not write to '%s'" -msgstr "" +msgstr "„%s“ не може да бъде записан" -#: sequencer.c:229 +# FIXME git add for consistence +#: sequencer.c:194 msgid "" "after resolving the conflicts, mark the corrected paths\n" "with 'git add ' or 'git rm '" msgstr "" +"след коригирането на конфликтите, отбележете съответните\n" +"пътища с „git add ПЪТ…“ или „git rm ПЪТ…“." -#: sequencer.c:232 +#: sequencer.c:197 msgid "" "after resolving the conflicts, mark the corrected paths\n" "with 'git add ' or 'git rm '\n" "and commit the result with 'git commit'" msgstr "" +"след коригирането на конфликтите, отбележете съответните\n" +"пътища с „git add ПЪТ…“ или „git rm ПЪТ…“, след което\n" +"подайте резултата с командата „git commit'“." -#: sequencer.c:245 sequencer.c:879 sequencer.c:962 +# FIXME - must be the same as Could not write to '%s' above +#: sequencer.c:210 sequencer.c:841 sequencer.c:924 #, c-format msgid "Could not write to %s" -msgstr "" +msgstr "„%s“ не може да бъде записан" -#: sequencer.c:248 +# FIXME wrap up as ffinishing the work on, in fact, full stop at end for consistency with below +#: sequencer.c:213 #, c-format msgid "Error wrapping up %s" -msgstr "" +msgstr "Обработката на „%s“ не завърши успешно." -#: sequencer.c:263 +#: sequencer.c:228 msgid "Your local changes would be overwritten by cherry-pick." -msgstr "" +msgstr "Локалните ви промени ще бъдат презаписани при отбирането на подавания." -#: sequencer.c:265 +#: sequencer.c:230 msgid "Your local changes would be overwritten by revert." -msgstr "" +msgstr "Локалните ви промени ще бъдат презаписани при отмяната на подавания." -#: sequencer.c:268 +#: sequencer.c:233 msgid "Commit your changes or stash them to proceed." -msgstr "" +msgstr "Подайте или скатайте промените, за да продължите" + +#: sequencer.c:250 +msgid "Failed to lock HEAD during fast_forward_to" +msgstr "Указателят „HEAD“ не може да бъде заключен при тривиално сливане" #. TRANSLATORS: %s will be "revert" or "cherry-pick" -#: sequencer.c:325 +#: sequencer.c:293 #, c-format msgid "%s: Unable to write new index file" msgstr "%s: новият индекс не може да бъде запазен" -#: sequencer.c:356 +#: sequencer.c:324 msgid "Could not resolve HEAD commit\n" -msgstr "" +msgstr "Подаването сочено от указателя „HEAD“ не може да бъде открито\n" -#: sequencer.c:378 +#: sequencer.c:344 msgid "Unable to update cache tree\n" -msgstr "" +msgstr "Дървото на кеша не може да бъде обновено\n" -#: sequencer.c:430 +#: sequencer.c:391 #, c-format msgid "Could not parse commit %s\n" -msgstr "" +msgstr "Подаването „%s“ не може да бъде анализирано\n" -#: sequencer.c:435 +#: sequencer.c:396 #, c-format msgid "Could not parse parent commit %s\n" -msgstr "" +msgstr "Родителското подаване „%s“ не може да бъде анализирано\n" -#: sequencer.c:501 +#: sequencer.c:462 msgid "Your index file is unmerged." msgstr "Индексът не е слят." -#: sequencer.c:520 +#: sequencer.c:481 #, c-format msgid "Commit %s is a merge but no -m option was given." -msgstr "" +msgstr "Подаването „%s“ е сливане, но не е дадена опцията „-m“" -#: sequencer.c:528 +#: sequencer.c:489 #, c-format msgid "Commit %s does not have parent %d" -msgstr "" +msgstr "Подаването „%s“ няма родител %d" -#: sequencer.c:532 +#: sequencer.c:493 #, c-format msgid "Mainline was specified but commit %s is not a merge." -msgstr "" +msgstr "Указано е базово подаване, но подаването „%s“ не е сливане." #. TRANSLATORS: The first %s will be "revert" or #. "cherry-pick", the second %s a SHA1 -#: sequencer.c:545 +#: sequencer.c:506 #, c-format msgid "%s: cannot parse parent commit %s" -msgstr "" +msgstr "%s: неразпозната стойност за родителското подаване „%s“" -#: sequencer.c:549 +#: sequencer.c:510 #, c-format msgid "Cannot get commit message for %s" -msgstr "" +msgstr "Неуспешно извличане на съобщението за подаване на „%s“" -#: sequencer.c:635 +#: sequencer.c:596 #, c-format msgid "could not revert %s... %s" -msgstr "" +msgstr "подаването „%s“… не може да бъде отменено: „%s“" -#: sequencer.c:636 +#: sequencer.c:597 #, c-format msgid "could not apply %s... %s" -msgstr "" +msgstr "подаването „%s“… не може да бъде приложено: „%s“" -#: sequencer.c:672 +#: sequencer.c:633 msgid "empty commit set passed" -msgstr "" +msgstr "зададено е празно множество от подавания" -#: sequencer.c:680 +#: sequencer.c:641 #, c-format msgid "git %s: failed to read the index" -msgstr "" +msgstr "git %s: неуспешно изчитане на индекса" -#: sequencer.c:685 +#: sequencer.c:645 #, c-format msgid "git %s: failed to refresh the index" -msgstr "" +msgstr "git %s: неуспешно обновяване на индекса" -#: sequencer.c:743 +#: sequencer.c:705 #, c-format msgid "Cannot %s during a %s" -msgstr "" +msgstr "По време на „%1$s“ не може да се извърши „%2$s“" -#: sequencer.c:765 +#: sequencer.c:727 #, c-format msgid "Could not parse line %d." -msgstr "" +msgstr "%d-ят ред не може да се анализира." -#: sequencer.c:770 +#: sequencer.c:732 msgid "No commits parsed." -msgstr "" +msgstr "Никое от подаванията не може да се разпознае." -#: sequencer.c:783 +# FIXME Could not open %s. - full stop for consistence with next message +#: sequencer.c:745 #, c-format msgid "Could not open %s" -msgstr "" +msgstr "„%s“ не може да се прочете." -#: sequencer.c:787 +#: sequencer.c:749 #, c-format msgid "Could not read %s." -msgstr "" +msgstr "„%s“ не може да се отвори." -#: sequencer.c:794 +#: sequencer.c:756 #, c-format msgid "Unusable instruction sheet: %s" -msgstr "" +msgstr "Файлът с описание на предстоящите действия — „%s“ не може да се ползва" -#: sequencer.c:824 +#: sequencer.c:786 #, c-format msgid "Invalid key: %s" -msgstr "" +msgstr "Неправилен ключ: „%s“" -#: sequencer.c:827 +#: sequencer.c:789 #, c-format msgid "Invalid value for %s: %s" -msgstr "" +msgstr "Неправилна стойност за „%s“: „%s“" -#: sequencer.c:839 +#: sequencer.c:801 #, c-format msgid "Malformed options sheet: %s" -msgstr "" +msgstr "Неправилно съдържание на файла с опции: „%s“" -#: sequencer.c:860 +#: sequencer.c:822 msgid "a cherry-pick or revert is already in progress" msgstr "" +"в момента вече се извършва отбиране на подавания или пребазиране на клона" -#: sequencer.c:861 +#: sequencer.c:823 msgid "try \"git cherry-pick (--continue | --quit | --abort)\"" -msgstr "" +msgstr "използвайте „git cherry-pick (--continue | --quit | --abort)“" -#: sequencer.c:865 +#: sequencer.c:827 #, c-format msgid "Could not create sequencer directory %s" -msgstr "" +msgstr "Директорията за секвенсора „%s“ не може да бъде създадена" -#: sequencer.c:881 sequencer.c:966 +#: sequencer.c:843 sequencer.c:928 #, c-format msgid "Error wrapping up %s." -msgstr "" +msgstr "Обработката на „%s“ не завърши успешно." -#: sequencer.c:900 sequencer.c:1036 +#: sequencer.c:862 sequencer.c:998 msgid "no cherry-pick or revert in progress" msgstr "" +"в момента не се извършва отбиране на подавания или пребазиране на клона" -#: sequencer.c:902 +#: sequencer.c:864 msgid "cannot resolve HEAD" -msgstr "" +msgstr "Подаването сочено от указателя „HEAD“ не може да бъде открито" -#: sequencer.c:904 +#: sequencer.c:866 msgid "cannot abort from a branch yet to be born" msgstr "" +"действието не може да бъде преустановено, когато сте на клон, който тепърва " +"предстои да бъде създаден" -#: sequencer.c:926 builtin/apply.c:4061 +#: sequencer.c:888 builtin/apply.c:4062 #, c-format msgid "cannot open %s: %s" -msgstr "" +msgstr "файлът „%s“ не може да бъде отворен: %s" -#: sequencer.c:929 +#: sequencer.c:891 #, c-format msgid "cannot read %s: %s" -msgstr "" +msgstr "файлът „%s“ не може да бъде прочетен: %s" -#: sequencer.c:930 +#: sequencer.c:892 msgid "unexpected end of file" -msgstr "" +msgstr "неочакван край на файл" -#: sequencer.c:936 +#: sequencer.c:898 #, c-format msgid "stored pre-cherry-pick HEAD file '%s' is corrupt" msgstr "" +"запазеният преди започването на отбирането файл за указателя „HEAD“ — „%s“ е " +"повреден" -#: sequencer.c:959 +#: sequencer.c:921 #, c-format msgid "Could not format %s." -msgstr "" +msgstr "Файлът „%s“ не може да се форматира по подходящия начин." -#: sequencer.c:1104 +#: sequencer.c:1066 #, c-format msgid "%s: can't cherry-pick a %s" -msgstr "" +msgstr "%s: не може да се отбере „%s“" -#: sequencer.c:1107 +#: sequencer.c:1069 #, c-format msgid "%s: bad revision" -msgstr "" +msgstr "%s: неправилна версия" -#: sequencer.c:1141 +#: sequencer.c:1103 msgid "Can't revert as initial commit" -msgstr "" +msgstr "Първоначалното подаване не може да бъде отменено" -#: sequencer.c:1142 +#: sequencer.c:1104 msgid "Can't cherry-pick into empty head" -msgstr "" +msgstr "При празен връх не могат да се отбират подавания" #: sha1_name.c:439 msgid "" @@ -1408,34 +1484,33 @@ msgid "" "examine these refs and maybe delete them. Turn this message off by\n" "running \"git config advice.objectNameWarning false\"" msgstr "" -"При нормална работа git никога не създава указатели, които завършват с 40\n" -"шестнасетични знаци, защото те ще бъдат прескачани, когато указвате \n" -"шестнайсетични знаци. Една възможност е такива указатели да са създадени\n" -"по погрешка. Например:\n" +"При нормална работа Git никога не създава указатели, които завършват с 40\n" +"шестнадесетични знака, защото стандартно те ще бъдат прескачани.\n" +"Възможно е такива указатели да са създадени случайно. Например:\n" "\n" " git checkout -b $BRANCH $(git rev-parse…)\n" "\n" "където стойността на променливата на средата BRANCH е празна, при което се\n" "създава подобен указател. Прегледайте тези указатели и ги изтрийте. Можете " "да\n" -"спрете това съобщение като изпълнете „git config advice.objectNameWarning " -"false“" +"спрете това съобщение като изпълните командата:\n" +"„git config advice.objectNameWarning false“" -#: sha1_name.c:1072 +#: sha1_name.c:1060 msgid "HEAD does not point to a branch" msgstr "Указателят „HEAD“ не сочи към клон" -#: sha1_name.c:1075 +#: sha1_name.c:1063 #, c-format msgid "No such branch: '%s'" msgstr "Не съществува клон на име „%s“" -#: sha1_name.c:1077 +#: sha1_name.c:1065 #, c-format msgid "No upstream configured for branch '%s'" msgstr "Не е зададен клон-източник за клона „%s“" -#: sha1_name.c:1081 +#: sha1_name.c:1069 #, c-format msgid "Upstream branch '%s' not stored as a remote-tracking branch" msgstr "Клонът-източник „%s“ не е съхранен като следящ клон" @@ -1463,67 +1538,67 @@ msgstr "Записът „%s“ във файла „.gitmodules“ не мож #: submodule.c:120 msgid "staging updated .gitmodules failed" -msgstr "неуспешно добавяне в индекса на променения файл „.gitmodules“" +msgstr "неуспешно добавяне на променения файл „.gitmodules“ в индекса" -#: submodule.c:1121 builtin/init-db.c:363 +#: submodule.c:1118 builtin/init-db.c:363 #, c-format msgid "Could not create git link %s" msgstr "Връзката в Git „%s“ не може да бъде създадена" -#: submodule.c:1132 +#: submodule.c:1129 #, c-format msgid "Could not set core.worktree in %s" -msgstr "В „%s“ не може да се зададе настройката „core.worktree“" +msgstr "Настройката „core.worktree“ не може да се зададе в „%s“" -#: unpack-trees.c:206 +#: unpack-trees.c:202 msgid "Checking out files" msgstr "Изтегляне на файлове" #: urlmatch.c:120 msgid "invalid URL scheme name or missing '://' suffix" -msgstr "" +msgstr "неправилна схема за адрес или суфиксът „://“ липсва" #: urlmatch.c:144 urlmatch.c:297 urlmatch.c:356 #, c-format msgid "invalid %XX escape sequence" -msgstr "" +msgstr "неправилна екранираща последователност „%XX“" #: urlmatch.c:172 msgid "missing host and scheme is not 'file:'" -msgstr "" +msgstr "не е указана машина, а схемата не е „file:“" #: urlmatch.c:189 msgid "a 'file:' URL may not have a port number" -msgstr "" +msgstr "при схема „file:“ не можете да указвате номер на порт" #: urlmatch.c:199 msgid "invalid characters in host name" -msgstr "" +msgstr "неправилни знаци в името на машина" #: urlmatch.c:244 urlmatch.c:255 msgid "invalid port number" -msgstr "" +msgstr "неправилен номер на порт" #: urlmatch.c:322 msgid "invalid '..' path segment" -msgstr "" +msgstr "неправилна част от пътя „..“" -#: wrapper.c:422 +#: wrapper.c:460 #, c-format msgid "unable to access '%s': %s" msgstr "няма достъп до „%s“: %s" -#: wrapper.c:443 +#: wrapper.c:481 #, c-format msgid "unable to access '%s'" msgstr "няма достъп до „%s“" -#: wrapper.c:454 +#: wrapper.c:492 #, c-format msgid "unable to look up current user in the passwd file: %s" msgstr "текущият потребител не може да бъде открит във файла „/etc/passwd“: %s" -#: wrapper.c:455 +#: wrapper.c:493 msgid "no such user" msgstr "такъв потребител не съществува" @@ -1612,7 +1687,7 @@ msgstr "добавени от тях:" #: wt-status.c:260 msgid "deleted by us:" -msgstr "изтрити от нас:" +msgstr "изтрити от вас:" #: wt-status.c:262 msgid "both added:" @@ -1676,15 +1751,15 @@ msgstr "неследено съдържание, " msgid "bug: unhandled diff status %c" msgstr "грешка: състоянието на промяната „%c“ не може да бъде обработено" -#: wt-status.c:765 +#: wt-status.c:764 msgid "Submodules changed but not updated:" msgstr "Подмодулите са променени, но не са обновени:" -#: wt-status.c:767 +#: wt-status.c:766 msgid "Submodule changes to be committed:" msgstr "Промени в подмодулите за подаване:" -#: wt-status.c:846 +#: wt-status.c:845 msgid "" "Do not touch the line above.\n" "Everything below will be removed." @@ -1692,193 +1767,193 @@ msgstr "" "Не променяйте горния ред.\n" "Всичко отдолу ще бъде изтрито." -#: wt-status.c:937 +#: wt-status.c:936 msgid "You have unmerged paths." msgstr "Някои пътища не са слети." -#: wt-status.c:940 +#: wt-status.c:939 msgid " (fix conflicts and run \"git commit\")" msgstr " (коригирайте конфликтите и изпълнете „git commit“)" -#: wt-status.c:943 +#: wt-status.c:942 msgid "All conflicts fixed but you are still merging." msgstr "Всички конфликти са решени, но продължавате сливането." -#: wt-status.c:946 +#: wt-status.c:945 msgid " (use \"git commit\" to conclude merge)" msgstr " (използвайте „git commit“, за да завършите сливането)" -#: wt-status.c:956 +#: wt-status.c:955 msgid "You are in the middle of an am session." msgstr "В момента прилагате поредица от кръпки чрез „git am“." -#: wt-status.c:959 +#: wt-status.c:958 msgid "The current patch is empty." msgstr "Текущата кръпка е празна." -#: wt-status.c:963 +#: wt-status.c:962 msgid " (fix conflicts and then run \"git am --continue\")" msgstr " (коригирайте конфликтите и изпълнете „git am --continue“)" -#: wt-status.c:965 +#: wt-status.c:964 msgid " (use \"git am --skip\" to skip this patch)" msgstr " (използвайте „git am --skip“, за да пропуснете тази кръпка)" -#: wt-status.c:967 +#: wt-status.c:966 msgid " (use \"git am --abort\" to restore the original branch)" msgstr "" " (използвайте „git am --abort“, за да възстановите първоначалния клон)" -#: wt-status.c:1027 wt-status.c:1044 +#: wt-status.c:1026 wt-status.c:1043 #, c-format msgid "You are currently rebasing branch '%s' on '%s'." msgstr "В момента пребазирате клона „%s“ върху „%s“." -#: wt-status.c:1032 wt-status.c:1049 +#: wt-status.c:1031 wt-status.c:1048 msgid "You are currently rebasing." msgstr "В момента пребазирате." -#: wt-status.c:1035 +#: wt-status.c:1034 msgid " (fix conflicts and then run \"git rebase --continue\")" msgstr " (коригирайте конфликтите и използвайте „git rebase --continue“)" -#: wt-status.c:1037 +#: wt-status.c:1036 msgid " (use \"git rebase --skip\" to skip this patch)" msgstr " (използвайте „git rebase --skip“, за да пропуснете тази кръпка)" -#: wt-status.c:1039 +#: wt-status.c:1038 msgid " (use \"git rebase --abort\" to check out the original branch)" msgstr "" " (използвайте „git rebase --abort“, за да възстановите първоначалния клон)" -#: wt-status.c:1052 +#: wt-status.c:1051 msgid " (all conflicts fixed: run \"git rebase --continue\")" msgstr " (всички конфликти са коригирани: изпълнете „git rebase --continue“)" -#: wt-status.c:1056 +#: wt-status.c:1055 #, c-format msgid "" "You are currently splitting a commit while rebasing branch '%s' on '%s'." msgstr "В момента разделяте подаване докато пребазирате клона „%s“ върху „%s“." -#: wt-status.c:1061 +#: wt-status.c:1060 msgid "You are currently splitting a commit during a rebase." msgstr "В момента разделяте подаване докато пребазирате." -#: wt-status.c:1064 +#: wt-status.c:1063 msgid " (Once your working directory is clean, run \"git rebase --continue\")" msgstr "" " (След като работното ви дърво стане чисто, използвайте „git rebase --" "continue“)" -#: wt-status.c:1068 +#: wt-status.c:1067 #, c-format msgid "You are currently editing a commit while rebasing branch '%s' on '%s'." msgstr "" "В момента редактирате подаване докато пребазирате клона „%s“ върху „%s“." -#: wt-status.c:1073 +#: wt-status.c:1072 msgid "You are currently editing a commit during a rebase." msgstr "В момента редактирате подаване докато пребазирате." -#: wt-status.c:1076 +#: wt-status.c:1075 msgid " (use \"git commit --amend\" to amend the current commit)" msgstr "" " (използвайте „git commit --amend“, за да редактирате текущото подаване)" -#: wt-status.c:1078 +#: wt-status.c:1077 msgid "" " (use \"git rebase --continue\" once you are satisfied with your changes)" msgstr "" " (използвайте „git rebase --continue“, след като завършите промените си)" -#: wt-status.c:1088 +#: wt-status.c:1087 #, c-format msgid "You are currently cherry-picking commit %s." msgstr "В момента отбирате подаването „%s“." -#: wt-status.c:1093 +#: wt-status.c:1092 msgid " (fix conflicts and run \"git cherry-pick --continue\")" msgstr " (коригирайте конфликтите и изпълнете „git cherry-pick --continue“)" -#: wt-status.c:1096 +#: wt-status.c:1095 msgid " (all conflicts fixed: run \"git cherry-pick --continue\")" msgstr "" " (всички конфликти са коригирани, изпълнете „git cherry-pick --continue“)" -#: wt-status.c:1098 +#: wt-status.c:1097 msgid " (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)" msgstr "" " (използвайте „git cherry-pick --abort“, за да отмените всички действия с " "отбиране)" -#: wt-status.c:1107 +#: wt-status.c:1106 #, c-format msgid "You are currently reverting commit %s." msgstr "В момента отменяте подаване „%s“." -#: wt-status.c:1112 +#: wt-status.c:1111 msgid " (fix conflicts and run \"git revert --continue\")" msgstr " (коригирайте конфликтите и изпълнете „git revert --continue“)" -#: wt-status.c:1115 +#: wt-status.c:1114 msgid " (all conflicts fixed: run \"git revert --continue\")" msgstr " (всички конфликти са коригирани, изпълнете „git revert --continue“)" -#: wt-status.c:1117 +#: wt-status.c:1116 msgid " (use \"git revert --abort\" to cancel the revert operation)" msgstr "" " (използвайте „git revert --abort“, за да преустановите отмяната на " "подаване)" -#: wt-status.c:1128 +#: wt-status.c:1127 #, c-format msgid "You are currently bisecting, started from branch '%s'." msgstr "В момента търсите двоично, като сте стартирали от клон „%s“." -#: wt-status.c:1132 +#: wt-status.c:1131 msgid "You are currently bisecting." msgstr "В момента търсите двоично." -#: wt-status.c:1135 +#: wt-status.c:1134 msgid " (use \"git bisect reset\" to get back to the original branch)" msgstr "" " (използвайте „git bisect reset“, за да се върнете към първоначалното " "състояние и клон)" -#: wt-status.c:1310 +#: wt-status.c:1309 msgid "On branch " msgstr "На клон " -#: wt-status.c:1317 +#: wt-status.c:1316 msgid "rebase in progress; onto " msgstr "извършвате пребазиране върху " -#: wt-status.c:1324 +#: wt-status.c:1323 msgid "HEAD detached at " -msgstr "Указателят „HEAD“ не е свързан и е на подаване " +msgstr "Указателят „HEAD“ не е свързан и е при подаване " -#: wt-status.c:1326 +#: wt-status.c:1325 msgid "HEAD detached from " msgstr "Указателят „HEAD“ не е свързан и е отделѐн от " -#: wt-status.c:1329 +#: wt-status.c:1328 msgid "Not currently on any branch." -msgstr "Извън всички клони" +msgstr "Извън всички клони." -#: wt-status.c:1346 +#: wt-status.c:1345 msgid "Initial commit" msgstr "Първоначално подаване" -#: wt-status.c:1360 +#: wt-status.c:1359 msgid "Untracked files" msgstr "Неследени файлове" -#: wt-status.c:1362 +#: wt-status.c:1361 msgid "Ignored files" msgstr "Игнорирани файлове" -#: wt-status.c:1366 +#: wt-status.c:1365 #, c-format msgid "" "It took %.2f seconds to enumerate untracked files. 'status -uno'\n" @@ -1887,35 +1962,35 @@ msgid "" msgstr "" "Бяха необходими %.2f секунди за изброяването на неследените файлове.\n" "Добавянето на опцията „-uno“ към командата „git status“, ще ускори\n" -"нещата, но не трябва да забравяте ръчно да добавяте новите файлове.\n" +"изпълнението, но не трябва да забравяте ръчно да добавяте новите файлове.\n" "За повече подробности погледнете „git status help“." -#: wt-status.c:1372 +#: wt-status.c:1371 #, c-format msgid "Untracked files not listed%s" msgstr "Неследените файлове не са изведени%s" -#: wt-status.c:1374 +#: wt-status.c:1373 msgid " (use -u option to show untracked files)" msgstr " (използвайте опцията „-u“, за да изведете неследените файлове)" -#: wt-status.c:1380 +#: wt-status.c:1379 msgid "No changes" msgstr "Няма промени" -#: wt-status.c:1385 +#: wt-status.c:1384 #, c-format msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n" msgstr "" "към индекса за подаване не са добавени промени (използвайте „git add“ и/или " "„git commit -a“)\n" -#: wt-status.c:1388 +#: wt-status.c:1387 #, c-format msgid "no changes added to commit\n" msgstr "към индекса за подаване не са добавени промени\n" -#: wt-status.c:1391 +#: wt-status.c:1390 #, c-format msgid "" "nothing added to commit but untracked files present (use \"git add\" to " @@ -1924,48 +1999,48 @@ msgstr "" "към индекса за подаване не са добавени промени, но има нови файлове " "(използвайте „git add“, за да започне тяхното следене)\n" -#: wt-status.c:1394 +#: wt-status.c:1393 #, c-format msgid "nothing added to commit but untracked files present\n" msgstr "към индекса за подаване не са добавени промени, но има нови файлове\n" -#: wt-status.c:1397 +#: wt-status.c:1396 #, c-format msgid "nothing to commit (create/copy files and use \"git add\" to track)\n" msgstr "" "липсват каквито и да е промени (създайте или копирайте файлове и използвайте " "„git add“, за да започне тяхното следене)\n" -#: wt-status.c:1400 wt-status.c:1405 +#: wt-status.c:1399 wt-status.c:1404 #, c-format msgid "nothing to commit\n" msgstr "липсват каквито и да е промени\n" -#: wt-status.c:1403 +#: wt-status.c:1402 #, c-format msgid "nothing to commit (use -u to show untracked files)\n" msgstr "" "липсват каквито и да е промени (използвайте опцията „-u“, за да се изведат и " "неследените файлове)\n" -#: wt-status.c:1407 +#: wt-status.c:1406 #, c-format msgid "nothing to commit, working directory clean\n" msgstr "липсват каквито и да е промени, работното дърво е чисто\n" -#: wt-status.c:1516 +#: wt-status.c:1515 msgid "HEAD (no branch)" msgstr "HEAD (извън клон)" -#: wt-status.c:1522 +#: wt-status.c:1521 msgid "Initial commit on " -msgstr "Първоначално подаване на " +msgstr "Първоначално подаване на клон" -#: wt-status.c:1554 +#: wt-status.c:1553 msgid "gone" msgstr "изтрит" -#: wt-status.c:1556 wt-status.c:1564 +#: wt-status.c:1555 wt-status.c:1563 msgid "behind " msgstr "назад с " @@ -1976,7 +2051,7 @@ msgstr "неуспешно изтриване на „%s“" #: builtin/add.c:21 msgid "git add [options] [--] ..." -msgstr "git add [ОПЦИИ] [--] ПЪТ…" +msgstr "git add [ОПЦИЯ…] [--] ПЪТ…" #: builtin/add.c:64 #, c-format @@ -1996,7 +2071,7 @@ msgstr "изтриване на „%s“\n" msgid "Unstaged changes after refreshing the index:" msgstr "Промени, които и след обновяването на индекса не са добавени към него:" -#: builtin/add.c:193 +#: builtin/add.c:193 builtin/rev-parse.c:781 msgid "Could not read the index" msgstr "Индексът не може да бъде прочетен" @@ -2028,15 +2103,15 @@ msgid "The following paths are ignored by one of your .gitignore files:\n" msgstr "" "Следните пътища ще бъдат игнорирани според някой от файловете „.gitignore“:\n" -#: builtin/add.c:248 builtin/clean.c:876 builtin/fetch.c:93 builtin/mv.c:70 -#: builtin/prune-packed.c:77 builtin/push.c:489 builtin/remote.c:1344 +#: builtin/add.c:248 builtin/clean.c:875 builtin/fetch.c:108 builtin/mv.c:70 +#: builtin/prune-packed.c:77 builtin/push.c:488 builtin/remote.c:1367 #: builtin/rm.c:269 msgid "dry run" msgstr "пробно изпълнeние" -#: builtin/add.c:249 builtin/apply.c:4410 builtin/check-ignore.c:19 -#: builtin/commit.c:1256 builtin/count-objects.c:95 builtin/fsck.c:612 -#: builtin/log.c:1592 builtin/mv.c:69 builtin/read-tree.c:113 +#: builtin/add.c:249 builtin/apply.c:4411 builtin/check-ignore.c:19 +#: builtin/commit.c:1328 builtin/count-objects.c:95 builtin/fsck.c:606 +#: builtin/log.c:1613 builtin/mv.c:69 builtin/read-tree.c:113 msgid "be verbose" msgstr "повече подробности" @@ -2044,7 +2119,7 @@ msgstr "повече подробности" msgid "interactive picking" msgstr "интерактивно отбиране на промени" -#: builtin/add.c:252 builtin/checkout.c:1108 builtin/reset.c:283 +#: builtin/add.c:252 builtin/checkout.c:1102 builtin/reset.c:285 msgid "select hunks interactively" msgstr "интерактивен избор на парчета код" @@ -2092,7 +2167,7 @@ msgstr "" #: builtin/add.c:286 #, c-format msgid "Use -f if you really want to add them.\n" -msgstr "Използвайте опцията „-f“, ако наистина искате да ги добавите.\n" +msgstr "Използвайте опцията „-f“, за да ги добавите наистина.\n" #: builtin/add.c:287 msgid "no files added" @@ -2102,91 +2177,99 @@ msgstr "не са добавени файлове" msgid "adding files failed" msgstr "неуспешно добавяне на файлове" -#: builtin/add.c:330 +#: builtin/add.c:329 msgid "-A and -u are mutually incompatible" msgstr "опциите „-A“ и „-u“ са несъвместими" -#: builtin/add.c:337 +#: builtin/add.c:336 msgid "Option --ignore-missing can only be used together with --dry-run" msgstr "Опцията „--ignore-missing“ е съвместима само с „--dry-run“" -#: builtin/add.c:358 +#: builtin/add.c:357 #, c-format msgid "Nothing specified, nothing added.\n" msgstr "Нищо не е зададено и нищо не е добавено.\n" -#: builtin/add.c:359 +#: builtin/add.c:358 #, c-format msgid "Maybe you wanted to say 'git add .'?\n" msgstr "Вероятно искахте да използвате „git add .“?\n" -#: builtin/add.c:364 builtin/check-ignore.c:172 builtin/clean.c:920 -#: builtin/commit.c:320 builtin/mv.c:90 builtin/reset.c:234 builtin/rm.c:299 +#: builtin/add.c:363 builtin/check-ignore.c:172 builtin/clean.c:919 +#: builtin/commit.c:319 builtin/mv.c:90 builtin/reset.c:234 builtin/rm.c:299 msgid "index file corrupt" msgstr "файлът с индекса е повреден" -#: builtin/add.c:448 builtin/apply.c:4506 builtin/mv.c:280 builtin/rm.c:432 +#: builtin/add.c:446 builtin/apply.c:4506 builtin/mv.c:280 builtin/rm.c:431 msgid "Unable to write new index file" msgstr "Новият индекс не може да бъде записан" #: builtin/apply.c:57 msgid "git apply [options] [...]" -msgstr "" +msgstr "git apply [ОПЦИЯ…] [КРЪПКА…]" #: builtin/apply.c:110 #, c-format msgid "unrecognized whitespace option '%s'" -msgstr "" +msgstr "непозната опция за знаците за интервали „%s“" #: builtin/apply.c:125 #, c-format msgid "unrecognized whitespace ignore option '%s'" -msgstr "" +msgstr "непозната опция за игнориране на знаците за интервали „%s“" -#: builtin/apply.c:823 +#: builtin/apply.c:825 #, c-format msgid "Cannot prepare timestamp regexp %s" -msgstr "" +msgstr "Регулярният израз за времето „%s“ не може за бъде компилиран" -#: builtin/apply.c:832 +#: builtin/apply.c:834 #, c-format msgid "regexec returned %d for input: %s" -msgstr "" +msgstr "Регулярният израз върна %d при подадена последователност „%s“ на входа" -#: builtin/apply.c:913 +#: builtin/apply.c:915 #, c-format msgid "unable to find filename in patch at line %d" -msgstr "" +msgstr "Липсва име на файл на ред %d от кръпката" -#: builtin/apply.c:945 +#: builtin/apply.c:947 #, c-format msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d" msgstr "" +"git apply: лош изход от командата „git-diff“ — на ред %2$d се очакваше „/dev/" +"null“, а бе получен „%1$s“" -#: builtin/apply.c:949 +#: builtin/apply.c:951 #, c-format msgid "git apply: bad git-diff - inconsistent new filename on line %d" msgstr "" +"git apply: лош изход от командата „git-diff“ — на ред %d бе получено " +"неправилно име на нов файл" -#: builtin/apply.c:950 +#: builtin/apply.c:952 #, c-format msgid "git apply: bad git-diff - inconsistent old filename on line %d" msgstr "" +"git apply: лош изход от командата „git-diff“ — на ред %d бе получено " +"неправилно име на стар файл" -#: builtin/apply.c:957 +#: builtin/apply.c:959 #, c-format msgid "git apply: bad git-diff - expected /dev/null on line %d" msgstr "" +"git apply: лош изход от командата „git-diff“ — на ред %d се очакваше „/dev/" +"null“" #: builtin/apply.c:1422 #, c-format msgid "recount: unexpected line: %.*s" -msgstr "" +msgstr "при повторното преброяване бе получен неочакван ред: „%.*s“" #: builtin/apply.c:1479 #, c-format msgid "patch fragment without header at line %d: %.*s" -msgstr "" +msgstr "част от кръпка без заглавна част на ред %d: %.*s" #: builtin/apply.c:1496 #, c-format @@ -2197,30 +2280,34 @@ msgid_plural "" "git diff header lacks filename information when removing %d leading pathname " "components (line %d)" msgstr[0] "" +"След съкращаването на %d-та част от компонентите на пътя, в заглавната част " +"на „git diff“ липсва информация за име на файл (ред: %d)" msgstr[1] "" +"След съкращаването на първите %d части от компонентите на пътя, в заглавната " +"част на „git diff“ липсва информация за име на файл (ред: %d)" #: builtin/apply.c:1656 msgid "new file depends on old contents" -msgstr "" +msgstr "новият файл зависи от старото съдържание на файла" #: builtin/apply.c:1658 msgid "deleted file still has contents" -msgstr "" +msgstr "изтритият файл не е празен" #: builtin/apply.c:1684 #, c-format msgid "corrupt patch at line %d" -msgstr "" +msgstr "грешка в кръпката на ред %d" #: builtin/apply.c:1720 #, c-format msgid "new file %s depends on old contents" -msgstr "" +msgstr "новият файл „%s“ зависи от старото съдържание на файла" #: builtin/apply.c:1722 #, c-format msgid "deleted file %s still has contents" -msgstr "" +msgstr "изтритият файл „%s“ не е празен" # FIXME - double **?? #: builtin/apply.c:1725 @@ -2231,44 +2318,47 @@ msgstr "●● предупреждение: файлът „%s“ вече е #: builtin/apply.c:1871 #, c-format msgid "corrupt binary patch at line %d: %.*s" -msgstr "" +msgstr "грешка в двоичната кръпка на ред %d: %.*s" #: builtin/apply.c:1900 #, c-format msgid "unrecognized binary patch at line %d" -msgstr "" +msgstr "неразпозната двоичната кръпка на ред %d" #: builtin/apply.c:1986 #, c-format msgid "patch with only garbage at line %d" -msgstr "" +msgstr "кръпката е с изцяло повредени данни на ред %d" #: builtin/apply.c:2076 #, c-format msgid "unable to read symlink %s" -msgstr "" +msgstr "символната връзка „%s“ не може да бъде прочетена" #: builtin/apply.c:2080 #, c-format msgid "unable to open or read %s" -msgstr "" +msgstr "файлът „%s“ не може да бъде отворен или прочетен" #: builtin/apply.c:2688 #, c-format msgid "invalid start of line: '%c'" -msgstr "" +msgstr "неправилно начало на ред: „%c“" #: builtin/apply.c:2806 #, c-format msgid "Hunk #%d succeeded at %d (offset %d line)." msgid_plural "Hunk #%d succeeded at %d (offset %d lines)." msgstr[0] "" +"%d-то парче код бе успешно приложено на ред %d (отместване от %d ред)." msgstr[1] "" +"%d-то парче код бе успешно приложено на ред %d (отместване от %d реда)." #: builtin/apply.c:2818 #, c-format msgid "Context reduced to (%ld/%ld) to apply fragment at %d" msgstr "" +"Контекстът е намален на (%ld/%ld) за прилагането на парчето код на ред %d" #: builtin/apply.c:2824 #, c-format @@ -2276,100 +2366,105 @@ msgid "" "while searching for:\n" "%.*s" msgstr "" +"при търсене за:\n" +"%.*s" #: builtin/apply.c:2843 #, c-format msgid "missing binary patch data for '%s'" -msgstr "" +msgstr "липсват данните за двоичната кръпка за „%s“" -#: builtin/apply.c:2946 +#: builtin/apply.c:2944 #, c-format msgid "binary patch does not apply to '%s'" -msgstr "" +msgstr "двоичната кръпка не може да бъде приложена върху „%s“" -#: builtin/apply.c:2952 +#: builtin/apply.c:2950 #, c-format msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)" msgstr "" +"двоичната кръпка за „%s“ води до неправилни резултати (очакваше се SHA1: " +"„%s“, а бе получено: „%s“)" -#: builtin/apply.c:2973 +#: builtin/apply.c:2971 #, c-format msgid "patch failed: %s:%ld" -msgstr "" +msgstr "неуспешно прилагане на кръпка: „%s:%ld“" #: builtin/apply.c:3095 #, c-format msgid "cannot checkout %s" -msgstr "" +msgstr "„%s“ не може да се изтегли" #: builtin/apply.c:3140 builtin/apply.c:3149 builtin/apply.c:3194 #, c-format msgid "read of %s failed" -msgstr "" +msgstr "неуспешно прочитане на „%s“" #: builtin/apply.c:3174 builtin/apply.c:3396 #, c-format msgid "path %s has been renamed/deleted" -msgstr "" +msgstr "обектът с път „%s“ е преименуван или изтрит" #: builtin/apply.c:3255 builtin/apply.c:3410 #, c-format msgid "%s: does not exist in index" -msgstr "" +msgstr "„%s“ не съществува в индекса" #: builtin/apply.c:3259 builtin/apply.c:3402 builtin/apply.c:3424 #, c-format msgid "%s: %s" -msgstr "" +msgstr "„%s“: %s" #: builtin/apply.c:3264 builtin/apply.c:3418 #, c-format msgid "%s: does not match index" -msgstr "" +msgstr "„%s“ не съответства на индекса" #: builtin/apply.c:3366 msgid "removal patch leaves file contents" -msgstr "" +msgstr "изтриващата кръпка оставя файла непразен" #: builtin/apply.c:3435 #, c-format msgid "%s: wrong type" -msgstr "" +msgstr "„%s“: неправилен вид" #: builtin/apply.c:3437 #, c-format msgid "%s has type %o, expected %o" -msgstr "" +msgstr "„%s“ е от вид „%o“, а се очакваше „%o“" #: builtin/apply.c:3538 #, c-format msgid "%s: already exists in index" -msgstr "" +msgstr "„%s“: вече съществува в индекса" #: builtin/apply.c:3541 #, c-format msgid "%s: already exists in working directory" -msgstr "" +msgstr "„%s“: вече съществува в работната директория" #: builtin/apply.c:3561 #, c-format msgid "new mode (%o) of %s does not match old mode (%o)" -msgstr "" +msgstr "новите права за достъп (%o) на „%s“ не съвпадат със старите (%o)" #: builtin/apply.c:3566 #, c-format msgid "new mode (%o) of %s does not match old mode (%o) of %s" msgstr "" +"новите права за достъп (%o) на „%s“ не съвпадат със старите (%o) на „%s“" #: builtin/apply.c:3574 #, c-format msgid "%s: patch does not apply" -msgstr "" +msgstr "Кръпката „%s“ не може да бъде приложена" #: builtin/apply.c:3587 #, c-format msgid "Checking patch %s..." -msgstr "" +msgstr "Проверяване на кръпката „%s“…" #: builtin/apply.c:3680 builtin/checkout.c:213 builtin/reset.c:134 #, c-format @@ -2379,255 +2474,261 @@ msgstr "неуспешно създаване на запис в кеша чре #: builtin/apply.c:3823 #, c-format msgid "unable to remove %s from index" -msgstr "" +msgstr "„%s“ не може да се извади от индекса" -#: builtin/apply.c:3851 +#: builtin/apply.c:3852 #, c-format msgid "corrupt patch for submodule %s" -msgstr "" +msgstr "повредена кръпка за модула „%s“" -#: builtin/apply.c:3855 +#: builtin/apply.c:3856 #, c-format msgid "unable to stat newly created file '%s'" msgstr "" +"не може да се получи информация чрез „stat“ за новосъздадения файл „%s“" -#: builtin/apply.c:3860 +#: builtin/apply.c:3861 #, c-format msgid "unable to create backing store for newly created file %s" msgstr "" +"не може да се за създаде мястото за съхранение на новосъздадения файл „%s“" -#: builtin/apply.c:3863 builtin/apply.c:3971 +#: builtin/apply.c:3864 builtin/apply.c:3972 #, c-format msgid "unable to add cache entry for %s" -msgstr "" +msgstr "не може да се добави запис в кеша за „%s“" -#: builtin/apply.c:3896 +#: builtin/apply.c:3897 #, c-format msgid "closing file '%s'" -msgstr "" +msgstr "затваряне на файла „%s“" -#: builtin/apply.c:3945 +#: builtin/apply.c:3946 #, c-format msgid "unable to write file '%s' mode %o" -msgstr "" +msgstr "файлът „%s“ не може да се запише с режим на достъп „%o“" -#: builtin/apply.c:4032 +#: builtin/apply.c:4033 #, c-format msgid "Applied patch %s cleanly." -msgstr "" +msgstr "Кръпката „%s“ бе приложена чисто." -#: builtin/apply.c:4040 +#: builtin/apply.c:4041 msgid "internal error" -msgstr "" +msgstr "вътрешна грешка" -#: builtin/apply.c:4043 +#: builtin/apply.c:4044 #, c-format msgid "Applying patch %%s with %d reject..." msgid_plural "Applying patch %%s with %d rejects..." -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Прилагане на кръпката „%%s“ с %d отхвърлено парче…" +msgstr[1] "Прилагане на кръпката „%%s“ с %d отхвърлени парчета…" -#: builtin/apply.c:4053 +#: builtin/apply.c:4054 #, c-format msgid "truncating .rej filename to %.*s.rej" -msgstr "" +msgstr "съкращаване на името на файла с отхвърлените парчета на „ %.*s.rej“" -#: builtin/apply.c:4074 +#: builtin/apply.c:4075 #, c-format msgid "Hunk #%d applied cleanly." -msgstr "" +msgstr "%d-то парче бе успешно приложено." -#: builtin/apply.c:4077 +#: builtin/apply.c:4078 #, c-format msgid "Rejected hunk #%d." -msgstr "" +msgstr "%d-то парче бе отхвърлено." -#: builtin/apply.c:4227 +#: builtin/apply.c:4228 msgid "unrecognized input" -msgstr "" +msgstr "непознат вход" -#: builtin/apply.c:4238 +#: builtin/apply.c:4239 msgid "unable to read index file" msgstr "индексът не може да бъде записан" -#: builtin/apply.c:4357 builtin/apply.c:4360 builtin/clone.c:90 -#: builtin/fetch.c:78 +#: builtin/apply.c:4358 builtin/apply.c:4361 builtin/clone.c:90 +#: builtin/fetch.c:93 msgid "path" msgstr "път" -#: builtin/apply.c:4358 +#: builtin/apply.c:4359 msgid "don't apply changes matching the given path" -msgstr "" +msgstr "без прилагане на промените напасващи на дадения път" -#: builtin/apply.c:4361 +#: builtin/apply.c:4362 msgid "apply changes matching the given path" -msgstr "" +msgstr "прилагане на промените напасващи на дадения път" -#: builtin/apply.c:4363 +#: builtin/apply.c:4364 msgid "num" -msgstr "" +msgstr "БРОЙ" -#: builtin/apply.c:4364 +#: builtin/apply.c:4365 msgid "remove leading slashes from traditional diff paths" -msgstr "" +msgstr "премахване на този БРОЙ водещи елементи от пътищата в разликата" -#: builtin/apply.c:4367 +#: builtin/apply.c:4368 msgid "ignore additions made by the patch" -msgstr "" +msgstr "игнориране на редовете добавени от тази кръпка" -#: builtin/apply.c:4369 +#: builtin/apply.c:4370 msgid "instead of applying the patch, output diffstat for the input" -msgstr "" +msgstr "извеждане на статистика на промените без прилагане на кръпката" -#: builtin/apply.c:4373 +#: builtin/apply.c:4374 msgid "show number of added and deleted lines in decimal notation" -msgstr "" +msgstr "извеждане на броя на добавените и изтритите редове" -#: builtin/apply.c:4375 +#: builtin/apply.c:4376 msgid "instead of applying the patch, output a summary for the input" -msgstr "" +msgstr "извеждане на статистика на входните данни без прилагане на кръпката" -#: builtin/apply.c:4377 +#: builtin/apply.c:4378 msgid "instead of applying the patch, see if the patch is applicable" -msgstr "" +msgstr "проверка дали кръпката може да се приложи, без действително прилагане" -#: builtin/apply.c:4379 +#: builtin/apply.c:4380 msgid "make sure the patch is applicable to the current index" -msgstr "" +msgstr "проверка дали кръпката може да бъде приложена към текущия индекс" -#: builtin/apply.c:4381 +#: builtin/apply.c:4382 msgid "apply a patch without touching the working tree" -msgstr "" +msgstr "прилагане на кръпката без промяна на работното дърво" -#: builtin/apply.c:4383 +#: builtin/apply.c:4384 msgid "also apply the patch (use with --stat/--summary/--check)" msgstr "" +"кръпката да бъде приложена. Опцията се комбинира с „--check“/„--stat“/„--" +"summary“" -#: builtin/apply.c:4385 +#: builtin/apply.c:4386 msgid "attempt three-way merge if a patch does not apply" -msgstr "" +msgstr "пробване с тройно сливане, ако кръпката не може да се приложи директно" -#: builtin/apply.c:4387 +#: builtin/apply.c:4388 msgid "build a temporary index based on embedded index information" msgstr "" +"създаване на временен индекс на база на включената информация за индекса" -#: builtin/apply.c:4389 builtin/checkout-index.c:197 builtin/ls-files.c:455 +#: builtin/apply.c:4390 builtin/checkout-index.c:198 builtin/ls-files.c:455 msgid "paths are separated with NUL character" msgstr "разделяне на пътищата с нулевия знак „NUL“" -#: builtin/apply.c:4392 +#: builtin/apply.c:4393 msgid "ensure at least lines of context match" msgstr "да се осигури контекст от поне такъв БРОЙ съвпадащи редове" -#: builtin/apply.c:4393 +#: builtin/apply.c:4394 msgid "action" -msgstr "" +msgstr "действие" -#: builtin/apply.c:4394 +#: builtin/apply.c:4395 msgid "detect new or modified lines that have whitespace errors" -msgstr "" +msgstr "засичане на нови или променени редове с грешки в знаците за интервали" -#: builtin/apply.c:4397 builtin/apply.c:4400 +#: builtin/apply.c:4398 builtin/apply.c:4401 msgid "ignore changes in whitespace when finding context" msgstr "" +"игнориране на промените в знаците за интервали при откриване на контекста" -#: builtin/apply.c:4403 +#: builtin/apply.c:4404 msgid "apply the patch in reverse" -msgstr "" +msgstr "прилагане на кръпката в обратна посока" -#: builtin/apply.c:4405 +#: builtin/apply.c:4406 msgid "don't expect at least one line of context" -msgstr "" +msgstr "без изискване на дори и един ред контекст" -#: builtin/apply.c:4407 +#: builtin/apply.c:4408 msgid "leave the rejected hunks in corresponding *.rej files" -msgstr "" +msgstr "оставяне на отхвърлените парчета във файлове с разширение „.rej“" -#: builtin/apply.c:4409 +#: builtin/apply.c:4410 msgid "allow overlapping hunks" -msgstr "" +msgstr "позволяване на застъпващи се парчета" -#: builtin/apply.c:4412 +#: builtin/apply.c:4413 msgid "tolerate incorrectly detected missing new-line at the end of file" -msgstr "" +msgstr "пренебрегване на неправилно липсващ знак за нов ред в края на файл" -#: builtin/apply.c:4415 +#: builtin/apply.c:4416 msgid "do not trust the line counts in the hunk headers" -msgstr "" +msgstr "без доверяване на номерата на редовете в заглавните части на парчетата" -#: builtin/apply.c:4417 +#: builtin/apply.c:4418 msgid "root" -msgstr "" +msgstr "НАЧАЛНА_ДИРЕКТОРИЯ" -#: builtin/apply.c:4418 +#: builtin/apply.c:4419 msgid "prepend to all filenames" -msgstr "" +msgstr "добавяне на тази НАЧАЛНА_ДИРЕКТОРИЯ към имената на всички файлове" -#: builtin/apply.c:4440 +#: builtin/apply.c:4441 msgid "--3way outside a repository" -msgstr "" +msgstr "като „--3way“, но извън хранилище" -#: builtin/apply.c:4448 +#: builtin/apply.c:4449 msgid "--index outside a repository" -msgstr "" +msgstr "като „--index“, но извън хранилище" -#: builtin/apply.c:4451 +#: builtin/apply.c:4452 msgid "--cached outside a repository" -msgstr "" +msgstr "като „--cached“, но извън хранилище" -#: builtin/apply.c:4467 +#: builtin/apply.c:4468 #, c-format msgid "can't open patch '%s'" -msgstr "" +msgstr "кръпката „%s“ не може да бъде отворена" -#: builtin/apply.c:4481 +#: builtin/apply.c:4482 #, c-format msgid "squelched %d whitespace error" msgid_plural "squelched %d whitespace errors" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "пренебрегната е %d грешка в знаците за интервали" +msgstr[1] "пренебрегнати са %d грешки в знаците за интервали" -#: builtin/apply.c:4487 builtin/apply.c:4497 +#: builtin/apply.c:4488 builtin/apply.c:4498 #, c-format msgid "%d line adds whitespace errors." msgid_plural "%d lines add whitespace errors." -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d ред добавя грешки в знаците за интервали." +msgstr[1] "%d реда добавят грешки в знаците за интервали." #: builtin/archive.c:17 #, c-format msgid "could not create archive file '%s'" -msgstr "" +msgstr "архивният файл „%s“ не може да бъде създаден" #: builtin/archive.c:20 msgid "could not redirect output" -msgstr "" +msgstr "изходът не може да бъде пренасочен" #: builtin/archive.c:37 msgid "git archive: Remote with no URL" -msgstr "" +msgstr "git archive: Липсва адрес за отдалеченото хранилище" #: builtin/archive.c:58 msgid "git archive: expected ACK/NAK, got EOF" -msgstr "" +msgstr "git archive: очакваше се „ACK“/„NAK“, а бе получен „EOF“" #: builtin/archive.c:61 #, c-format msgid "git archive: NACK %s" -msgstr "" +msgstr "git archive: получен е „NACK“ — %s" #: builtin/archive.c:63 #, c-format msgid "remote error: %s" -msgstr "" +msgstr "отдалечена грешка: %s" #: builtin/archive.c:64 msgid "git archive: protocol error" -msgstr "" +msgstr "git archive: протоколна грешка" #: builtin/archive.c:68 msgid "git archive: expected a flush" -msgstr "" +msgstr "git archive: очакваше се изчистване на буферите чрез „flush“" #: builtin/bisect--helper.c:7 msgid "git bisect--helper --next-all [--no-checkout]" @@ -2642,139 +2743,150 @@ msgid "update BISECT_HEAD instead of checking out the current commit" msgstr "" "обновяване на указателя „BISECT_HEAD“ вместо да се използва текущото подаване" -#: builtin/blame.c:27 +#: builtin/blame.c:30 msgid "git blame [options] [rev-opts] [rev] [--] file" -msgstr "git blame [ОПЦИИ] [ОПЦИИ_ЗА_ВЕРСИЯТА] [ВЕРСИЯ] [--] ФАЙЛ" +msgstr "git blame [ОПЦИЯ…] [ОПЦИИ_ЗА_ВЕРСИЯТА] [ВЕРСИЯ] [--] ФАЙЛ" -#: builtin/blame.c:32 +#: builtin/blame.c:35 msgid "[rev-opts] are documented in git-rev-list(1)" msgstr "ОПЦИИте_ЗА_ВЕРСИЯТА са документирани в ръководството git-rev-list(1)" -#: builtin/blame.c:2242 +#: builtin/blame.c:2501 msgid "Show blame entries as we find them, incrementally" msgstr "Извеждане на анотациите с намирането им, последователно" # FIXME SHA-1 -> SHA1 -#: builtin/blame.c:2243 +#: builtin/blame.c:2502 msgid "Show blank SHA-1 for boundary commits (Default: off)" msgstr "" "Извеждане на празни суми по SHA1 за граничните подавания (стандартно опцията " "е изключена)" -#: builtin/blame.c:2244 +#: builtin/blame.c:2503 msgid "Do not treat root commits as boundaries (Default: off)" msgstr "" "Началните подавания да не се считат за гранични (стандартно опцията е " "изключена)" -#: builtin/blame.c:2245 +#: builtin/blame.c:2504 msgid "Show work cost statistics" msgstr "Извеждане на статистика за извършените действия" -#: builtin/blame.c:2246 +#: builtin/blame.c:2505 msgid "Show output score for blame entries" msgstr "Извеждане на допълнителна информация за определянето на анотациите" -#: builtin/blame.c:2247 +#: builtin/blame.c:2506 msgid "Show original filename (Default: auto)" msgstr "" "Извеждане на първоначалното име на файл (стандартно това е автоматично)" -#: builtin/blame.c:2248 +#: builtin/blame.c:2507 msgid "Show original linenumber (Default: off)" msgstr "" "Извеждане на първоначалният номер на ред (стандартно опцията е изключена)" -#: builtin/blame.c:2249 +#: builtin/blame.c:2508 msgid "Show in a format designed for machine consumption" msgstr "Извеждане във формат за по-нататъшна обработка" -#: builtin/blame.c:2250 +#: builtin/blame.c:2509 msgid "Show porcelain format with per-line commit information" msgstr "" -"Извеждане във формат за по-нататъшна обработка с информация на всеки ред" +"Извеждане във формат за команди от потребителско ниво с информация на всеки " +"ред" -#: builtin/blame.c:2251 +#: builtin/blame.c:2510 msgid "Use the same output mode as git-annotate (Default: off)" msgstr "" "Използване на същия формат като „git-annotate“ (стандартно опцията е " "изключена)" -#: builtin/blame.c:2252 +#: builtin/blame.c:2511 msgid "Show raw timestamp (Default: off)" msgstr "Извеждане на неформатирани времена (стандартно опцията е изключена)" -#: builtin/blame.c:2253 +#: builtin/blame.c:2512 msgid "Show long commit SHA1 (Default: off)" msgstr "Извеждане на пълните суми по SHA1 (стандартно опцията е изключена)" -#: builtin/blame.c:2254 +#: builtin/blame.c:2513 msgid "Suppress author name and timestamp (Default: off)" -msgstr "Без име на автор и време на промяна(стандартно опцията е изключена)" +msgstr "Без име на автор и време на промяна (стандартно опцията е изключена)" -#: builtin/blame.c:2255 +#: builtin/blame.c:2514 msgid "Show author email instead of name (Default: off)" msgstr "" "Извеждане на е-пощата на автора, а не името му (стандартно опцията е " "изключена)" -#: builtin/blame.c:2256 +#: builtin/blame.c:2515 msgid "Ignore whitespace differences" msgstr "Без разлики в знаците за интервали" -#: builtin/blame.c:2257 +#: builtin/blame.c:2516 msgid "Spend extra cycles to find better match" msgstr "Допълнителни изчисления за по-добри резултати" -#: builtin/blame.c:2258 +#: builtin/blame.c:2517 msgid "Use revisions from instead of calling git-rev-list" msgstr "Изчитане на версиите от ФАЙЛ, а не чрез изпълнение на „git-rev-list“" -#: builtin/blame.c:2259 +#: builtin/blame.c:2518 msgid "Use 's contents as the final image" msgstr "Използване на съдържанието на ФАЙЛа като крайно положение" -#: builtin/blame.c:2260 builtin/blame.c:2261 +#: builtin/blame.c:2519 builtin/blame.c:2520 msgid "score" msgstr "напасване на редовете" -#: builtin/blame.c:2260 +#: builtin/blame.c:2519 msgid "Find line copies within and across files" msgstr "" "Търсене на копирани редове както в рамките на един файл, така и от един файл " "към друг" -#: builtin/blame.c:2261 +#: builtin/blame.c:2520 msgid "Find line movements within and across files" msgstr "" "Търсене на преместени редове както в рамките на един файл, така и от един " "файл към друг" -#: builtin/blame.c:2262 +#: builtin/blame.c:2521 msgid "n,m" msgstr "n,m" -#: builtin/blame.c:2262 +#: builtin/blame.c:2521 msgid "Process only line range n,m, counting from 1" msgstr "" "Информация само за редовете в интервала от n до m включително. Броенето " "започва от 1" +#. TRANSLATORS: This string is used to tell us the maximum +#. display width for a relative timestamp in "git blame" +#. output. For C locale, "4 years, 11 months ago", which +#. takes 22 places, is the longest among various forms of +#. relative timestamps, but your language may need more or +#. fewer display columns. +#: builtin/blame.c:2599 +msgid "4 years, 11 months ago" +msgstr "преди 4 години и 11 месеца" + #: builtin/branch.c:24 msgid "git branch [options] [-r | -a] [--merged | --no-merged]" -msgstr "git branch [ОПЦИИ] [-r | -a] [--merged | --no-merged]" +msgstr "git branch [ОПЦИЯ…] [-r | -a] [--merged | --no-merged]" #: builtin/branch.c:25 msgid "git branch [options] [-l] [-f] []" -msgstr "git branch [ОПЦИИ] [-l] [-f] ИМЕ_НА_КЛОН [НАЧАЛО]" +msgstr "git branch [ОПЦИЯ…] [-l] [-f] ИМЕ_НА_КЛОН [НАЧАЛО]" #: builtin/branch.c:26 msgid "git branch [options] [-r] (-d | -D) ..." -msgstr "git branch [ОПЦИИ] [-r] (-d | -D) ИМЕ_НА_КЛОН…" +msgstr "git branch [ОПЦИЯ…] [-r] (-d | -D) ИМЕ_НА_КЛОН…" #: builtin/branch.c:27 msgid "git branch [options] (-m | -M) [] " -msgstr "git branch [ОПЦИИ] (-m | -M) [СТАР_КЛОН] НОВ_КЛОН" +msgstr "git branch [ОПЦИЯ…] (-m | -M) [СТАР_КЛОН] НОВ_КЛОН" #: builtin/branch.c:150 #, c-format @@ -2955,11 +3067,11 @@ msgstr "На клона с неправилно име „%s“ е дадено #: builtin/branch.c:727 #, c-format msgid "Branch renamed to %s, but HEAD is not updated!" -msgstr "Клонът е преименуван на „%s“, но указателят „HEAD“ не е преименуван" +msgstr "Клонът е преименуван на „%s“, но указателят „HEAD“ не е обновен" #: builtin/branch.c:734 msgid "Branch is renamed, but update of config-file failed" -msgstr "Клонът е преименуван, но конфигурационният файл не бе обновен" +msgstr "Клонът е преименуван, но конфигурационният файл не е обновен" #: builtin/branch.c:749 #, c-format @@ -3001,9 +3113,9 @@ msgid "act on remote-tracking branches" msgstr "действие върху следящите клони" #: builtin/branch.c:817 builtin/branch.c:823 builtin/branch.c:844 -#: builtin/branch.c:850 builtin/commit.c:1494 builtin/commit.c:1495 -#: builtin/commit.c:1496 builtin/commit.c:1497 builtin/tag.c:527 -#: builtin/tag.c:533 +#: builtin/branch.c:850 builtin/commit.c:1573 builtin/commit.c:1574 +#: builtin/commit.c:1575 builtin/commit.c:1576 builtin/tag.c:615 +#: builtin/tag.c:621 msgid "commit" msgstr "подаване" @@ -3068,7 +3180,7 @@ msgstr "извеждане по колони" msgid "Failed to resolve HEAD as a valid ref." msgstr "Не може да се открие към какво сочи указателят „HEAD“" -#: builtin/branch.c:872 builtin/clone.c:635 +#: builtin/branch.c:872 builtin/clone.c:636 msgid "HEAD not found below refs/heads!" msgstr "В директорията „refs/heads“ липсва файл „HEAD“" @@ -3179,55 +3291,60 @@ msgstr " git branch --set-upstream-to %s\n" #: builtin/bundle.c:47 #, c-format msgid "%s is okay\n" -msgstr "" +msgstr "Пратката „%s“ е наред\n" #: builtin/bundle.c:56 msgid "Need a repository to create a bundle." -msgstr "" +msgstr "За създаването на пратка е необходимо хранилище." #: builtin/bundle.c:60 msgid "Need a repository to unbundle." -msgstr "" +msgstr "За приемането на пратка е необходимо хранилище." #: builtin/cat-file.c:331 msgid "git cat-file (-t|-s|-e|-p||--textconv) " -msgstr "" +msgstr "git cat-file (-t|-s|-e|-p|ВИД|--textconv) ОБЕКТ" #: builtin/cat-file.c:332 msgid "git cat-file (--batch|--batch-check) < " -msgstr "" +msgstr "git cat-file (--batch|--batch-check) < СПИСЪК_С_ОБЕКТИ" #: builtin/cat-file.c:369 msgid " can be one of: blob, tree, commit, tag" msgstr "" +"ВИДът може да е: „blob“ (обект BLOB), „tree“ (дърво), „commit“ (подаване), " +"„tag“ (етикет)" #: builtin/cat-file.c:370 msgid "show object type" -msgstr "" +msgstr "извеждане на вида на обект" #: builtin/cat-file.c:371 msgid "show object size" -msgstr "" +msgstr "извеждане на размера на обект" #: builtin/cat-file.c:373 msgid "exit with zero when there's no error" -msgstr "" +msgstr "изход с 0, когато няма грешка" #: builtin/cat-file.c:374 msgid "pretty-print object's content" -msgstr "" +msgstr "форматирано извеждане на съдържанието на обекта" #: builtin/cat-file.c:376 msgid "for blob objects, run textconv on object's content" msgstr "" +"да се стартира програмата зададена в настройката „textconv“ за преобразуване " +"на съдържанието на обекта" #: builtin/cat-file.c:378 msgid "show info and content of objects fed from the standard input" msgstr "" +"извеждане на информация и съдържание на обектите подадени на стандартния вход" #: builtin/cat-file.c:381 msgid "show info about objects fed from the standard input" -msgstr "" +msgstr "извеждане на информация за обектите подадени на стандартния вход" #: builtin/check-attr.c:11 msgid "git check-attr [-a | --all | attr...] [--] pathname..." @@ -3253,45 +3370,48 @@ msgstr "изчитане на имената на файловете от ста msgid "terminate input and output records by a NUL character" msgstr "разделяне на входните и изходните записи с нулевия знак „NUL“" -#: builtin/check-ignore.c:18 builtin/checkout.c:1089 builtin/gc.c:271 +#: builtin/check-ignore.c:18 builtin/checkout.c:1083 builtin/gc.c:285 msgid "suppress progress reporting" msgstr "без показване на напредъка" #: builtin/check-ignore.c:26 msgid "show non-matching input paths" -msgstr "" +msgstr "извеждане на несъвпадащите пътища" #: builtin/check-ignore.c:28 msgid "ignore index when checking" -msgstr "" +msgstr "прескачане на индекса при проверката" #: builtin/check-ignore.c:154 msgid "cannot specify pathnames with --stdin" -msgstr "" +msgstr "опцията „--stdin“ е несъвместима с имена на пътища" +# FIXME options #: builtin/check-ignore.c:157 msgid "-z only makes sense with --stdin" -msgstr "" +msgstr "опцията „-z“ изисква „--stdin“" #: builtin/check-ignore.c:159 msgid "no path specified" -msgstr "" +msgstr "не е зададен път" #: builtin/check-ignore.c:163 msgid "--quiet is only valid with a single pathname" -msgstr "" +msgstr "опцията „--quiet“ изисква да е подаден точно един път" +# FIXME options #: builtin/check-ignore.c:165 msgid "cannot have both --quiet and --verbose" -msgstr "" +msgstr "опциите „--quiet“ и „--verbose“ са несъвместими" +# FIXME options #: builtin/check-ignore.c:168 msgid "--non-matching is only valid with --verbose" -msgstr "" +msgstr "опцията „--non-matching“ изисква „--verbose“" #: builtin/check-mailmap.c:8 msgid "git check-mailmap [options] ..." -msgstr "git check-mailmap [ОПЦИИ] КОНТАКТ…" +msgstr "git check-mailmap [ОПЦИЯ…] КОНТАКТ…" #: builtin/check-mailmap.c:13 msgid "also read contacts from stdin" @@ -3308,55 +3428,55 @@ msgstr "не са указани контакти" #: builtin/checkout-index.c:126 msgid "git checkout-index [options] [--] [...]" -msgstr "" +msgstr "git checkout-index [ОПЦИЯ…] [--] [ФАЙЛ…]" -#: builtin/checkout-index.c:187 +#: builtin/checkout-index.c:188 msgid "check out all files in the index" -msgstr "" +msgstr "изтегляне на всички файлове в индекса" -#: builtin/checkout-index.c:188 +#: builtin/checkout-index.c:189 msgid "force overwrite of existing files" -msgstr "" +msgstr "презаписване на файловете, дори и да съществуват" -#: builtin/checkout-index.c:190 +#: builtin/checkout-index.c:191 msgid "no warning for existing files and files not in index" -msgstr "" +msgstr "без предупреждения при липсващи файлове и файлове не в индекса" -#: builtin/checkout-index.c:192 +#: builtin/checkout-index.c:193 msgid "don't checkout new files" -msgstr "" +msgstr "без изтегляне на нови файлове" -#: builtin/checkout-index.c:194 +#: builtin/checkout-index.c:195 msgid "update stat information in the index file" msgstr "обновяване на информацията получена чрез „stat“ за файловете в индекса" -#: builtin/checkout-index.c:200 +#: builtin/checkout-index.c:201 msgid "read list of paths from the standard input" -msgstr "" +msgstr "изчитане на пътищата от стандартния вход" -#: builtin/checkout-index.c:202 +#: builtin/checkout-index.c:203 msgid "write the content to temporary files" -msgstr "" +msgstr "записване на съдържанието във временни файлове" -#: builtin/checkout-index.c:203 builtin/column.c:30 +#: builtin/checkout-index.c:204 builtin/column.c:30 msgid "string" -msgstr "" +msgstr "НИЗ" -#: builtin/checkout-index.c:204 +#: builtin/checkout-index.c:205 msgid "when creating files, prepend " -msgstr "" +msgstr "при създаването на нови файлове да се добавя префикса НИЗ" -#: builtin/checkout-index.c:207 +#: builtin/checkout-index.c:208 msgid "copy out the files from named stage" -msgstr "" +msgstr "копиране на файловете от това състояние на сливане" #: builtin/checkout.c:25 msgid "git checkout [options] " -msgstr "git checkout [ОПЦИИ] КЛОН" +msgstr "git checkout [ОПЦИЯ…] КЛОН" #: builtin/checkout.c:26 msgid "git checkout [options] [] -- ..." -msgstr "git checkout [ОПЦИИ] [КЛОН] -- ФАЙЛ…" +msgstr "git checkout [ОПЦИЯ…] [КЛОН] -- ФАЙЛ…" #: builtin/checkout.c:114 builtin/checkout.c:147 #, c-format @@ -3390,77 +3510,77 @@ msgstr "пътят „%s“ не може да бъде слян" msgid "Unable to add merge result for '%s'" msgstr "Резултатът за „%s“ не може да бъде слян" -#: builtin/checkout.c:232 builtin/checkout.c:235 builtin/checkout.c:238 -#: builtin/checkout.c:241 +#: builtin/checkout.c:231 builtin/checkout.c:234 builtin/checkout.c:237 +#: builtin/checkout.c:240 #, c-format msgid "'%s' cannot be used with updating paths" msgstr "Опцията „%s“ е несъвместима с обновяването на пътища" -#: builtin/checkout.c:244 builtin/checkout.c:247 +#: builtin/checkout.c:243 builtin/checkout.c:246 #, c-format msgid "'%s' cannot be used with %s" msgstr "Опцията „%s“ е несъвместима с „%s“" -#: builtin/checkout.c:250 +#: builtin/checkout.c:249 #, c-format msgid "Cannot update paths and switch to branch '%s' at the same time." msgstr "" "Невъзможно е едновременно да обновявате пътища и да се прехвърлите към клона " "„%s“." -#: builtin/checkout.c:261 builtin/checkout.c:450 +#: builtin/checkout.c:260 builtin/checkout.c:449 msgid "corrupt index file" msgstr "повреден файл на индекса" -#: builtin/checkout.c:321 builtin/checkout.c:328 +#: builtin/checkout.c:320 builtin/checkout.c:327 #, c-format msgid "path '%s' is unmerged" msgstr "пътят „%s“ не е слят" -#: builtin/checkout.c:472 +#: builtin/checkout.c:471 msgid "you need to resolve your current index first" msgstr "първо трябва да коригирате индекса си" -#: builtin/checkout.c:593 +#: builtin/checkout.c:591 #, c-format msgid "Can not do reflog for '%s'\n" msgstr "Журналът на указателите за „%s“ не може да бъде създаден\n" -#: builtin/checkout.c:631 +#: builtin/checkout.c:629 msgid "HEAD is now at" msgstr "Указателят „HEAD“ в момента сочи към" -#: builtin/checkout.c:638 +#: builtin/checkout.c:636 #, c-format msgid "Reset branch '%s'\n" msgstr "Зануляване на клона „%s“\n" -#: builtin/checkout.c:641 +#: builtin/checkout.c:639 #, c-format msgid "Already on '%s'\n" msgstr "Вече сте на „%s“\n" -#: builtin/checkout.c:645 +#: builtin/checkout.c:643 #, c-format msgid "Switched to and reset branch '%s'\n" msgstr "Преминаване към клона „%s“ и зануляване на промените\n" -#: builtin/checkout.c:647 builtin/checkout.c:1032 +#: builtin/checkout.c:645 builtin/checkout.c:1026 #, c-format msgid "Switched to a new branch '%s'\n" msgstr "Преминахте към новия клон „%s“\n" -#: builtin/checkout.c:649 +#: builtin/checkout.c:647 #, c-format msgid "Switched to branch '%s'\n" msgstr "Преминахте към клона „%s“\n" -#: builtin/checkout.c:705 +#: builtin/checkout.c:699 #, c-format msgid " ... and %d more.\n" msgstr "… и още %d.\n" -#: builtin/checkout.c:711 +#: builtin/checkout.c:705 #, c-format msgid "" "Warning: you are leaving %d commit behind, not connected to\n" @@ -3482,7 +3602,7 @@ msgstr[1] "" "\n" "%s\n" -#: builtin/checkout.c:729 +#: builtin/checkout.c:723 #, c-format msgid "" "If you want to keep them by creating a new branch, this may be a good time\n" @@ -3491,150 +3611,149 @@ msgid "" " git branch new_branch_name %s\n" "\n" msgstr "" -"Ако все пак искате да ги запазите, сега вероятно е най-подходящият момент " -"да\n" -"създадете нов клон с тях чрез командата:\n" +"Ако все пак искате да запазите тези промени, сега е най-подходящият\n" +"момент да създадете нов клон за тях чрез командата:\n" "\n" " git branch ИМЕ_НА_НОВИЯ_КЛОН %s\n" "\n" -#: builtin/checkout.c:759 +#: builtin/checkout.c:753 msgid "internal error in revision walk" msgstr "вътрешна грешка при обхождането на версиите" -#: builtin/checkout.c:763 +#: builtin/checkout.c:757 msgid "Previous HEAD position was" msgstr "Преди това „HEAD“ сочеше към" -#: builtin/checkout.c:790 builtin/checkout.c:1027 +#: builtin/checkout.c:784 builtin/checkout.c:1021 msgid "You are on a branch yet to be born" msgstr "В момента сте на клон, който предстои да бъде създаден" -#: builtin/checkout.c:934 +#: builtin/checkout.c:928 #, c-format msgid "only one reference expected, %d given." msgstr "очакваше се един указател, а сте подали %d." -#: builtin/checkout.c:973 +#: builtin/checkout.c:967 #, c-format msgid "invalid reference: %s" msgstr "неправилен указател: %s" -#: builtin/checkout.c:1002 +#: builtin/checkout.c:996 #, c-format msgid "reference is not a tree: %s" msgstr "указателят не сочи към обект-дърво: %s" -#: builtin/checkout.c:1041 +#: builtin/checkout.c:1035 msgid "paths cannot be used with switching branches" msgstr "задаването на път е несъвместимо с преминаването от един клон към друг" -#: builtin/checkout.c:1044 builtin/checkout.c:1048 +#: builtin/checkout.c:1038 builtin/checkout.c:1042 #, c-format msgid "'%s' cannot be used with switching branches" msgstr "опцията „%s“ е несъвместима с преминаването от един клон към друг" -#: builtin/checkout.c:1052 builtin/checkout.c:1055 builtin/checkout.c:1060 -#: builtin/checkout.c:1063 +#: builtin/checkout.c:1046 builtin/checkout.c:1049 builtin/checkout.c:1054 +#: builtin/checkout.c:1057 #, c-format msgid "'%s' cannot be used with '%s'" msgstr "опцията „%s“ е несъвместима с „%s“" -#: builtin/checkout.c:1068 +#: builtin/checkout.c:1062 #, c-format msgid "Cannot switch branch to a non-commit '%s'" msgstr "" "За да преминете към клон, подайте указател, който сочи към подаване. „%s“ не " "е такъв" -#: builtin/checkout.c:1090 builtin/checkout.c:1092 builtin/clone.c:88 +#: builtin/checkout.c:1084 builtin/checkout.c:1086 builtin/clone.c:88 #: builtin/remote.c:159 builtin/remote.c:161 msgid "branch" msgstr "клон" -#: builtin/checkout.c:1091 +#: builtin/checkout.c:1085 msgid "create and checkout a new branch" msgstr "създаване и преминаване към нов клон" -#: builtin/checkout.c:1093 +#: builtin/checkout.c:1087 msgid "create/reset and checkout a branch" msgstr "създаване/зануляване на клон и преминаване към него" -#: builtin/checkout.c:1094 +#: builtin/checkout.c:1088 msgid "create reflog for new branch" msgstr "създаване на журнал на указателите за нов клон" -#: builtin/checkout.c:1095 +#: builtin/checkout.c:1089 msgid "detach the HEAD at named commit" msgstr "отделяне на указателя „HEAD“ към указаното подаване" -#: builtin/checkout.c:1096 +#: builtin/checkout.c:1090 msgid "set upstream info for new branch" msgstr "задаване на кой клон бива следен при създаването на новия клон" -#: builtin/checkout.c:1098 +#: builtin/checkout.c:1092 msgid "new-branch" msgstr "НОВ_КЛОН" -#: builtin/checkout.c:1098 +#: builtin/checkout.c:1092 msgid "new unparented branch" msgstr "нов клон без родител" -#: builtin/checkout.c:1099 +#: builtin/checkout.c:1093 msgid "checkout our version for unmerged files" msgstr "изтегляне на вашата версия на неслетите файлове" -#: builtin/checkout.c:1101 +#: builtin/checkout.c:1095 msgid "checkout their version for unmerged files" msgstr "изтегляне на чуждата версия на неслетите файлове" -#: builtin/checkout.c:1103 +#: builtin/checkout.c:1097 msgid "force checkout (throw away local modifications)" msgstr "принудително изтегляне (вашите промени ще бъдат занулени)" -#: builtin/checkout.c:1104 +#: builtin/checkout.c:1098 msgid "perform a 3-way merge with the new branch" msgstr "извършване на тройно сливане с новия клон" -#: builtin/checkout.c:1105 builtin/merge.c:225 +#: builtin/checkout.c:1099 builtin/merge.c:225 msgid "update ignored files (default)" msgstr "обновяване на игнорираните файлове (стандартно)" -#: builtin/checkout.c:1106 builtin/log.c:1228 parse-options.h:245 +#: builtin/checkout.c:1100 builtin/log.c:1236 parse-options.h:245 msgid "style" msgstr "стил" -#: builtin/checkout.c:1107 +#: builtin/checkout.c:1101 msgid "conflict style (merge or diff3)" msgstr "действие при конфликт (сливане или тройна разлика)" -#: builtin/checkout.c:1110 +#: builtin/checkout.c:1104 msgid "do not limit pathspecs to sparse entries only" msgstr "без ограничаване на изброените пътища само до частично изтеглените" -#: builtin/checkout.c:1112 +#: builtin/checkout.c:1106 msgid "second guess 'git checkout no-such-branch'" msgstr "" "последващ опит за отгатване след неуспешен опит с „git checkout no-such-" "branch“" -#: builtin/checkout.c:1135 +#: builtin/checkout.c:1129 msgid "-b, -B and --orphan are mutually exclusive" msgstr "Опциите „-b“, „-B“ и „--orphan“ са несъвместими една с друга" -#: builtin/checkout.c:1152 +#: builtin/checkout.c:1146 msgid "--track needs a branch name" msgstr "опцията „--track“ изисква име на клон" -#: builtin/checkout.c:1159 +#: builtin/checkout.c:1153 msgid "Missing branch name; try -b" msgstr "Липсва име на клон, използвайте опцията „-b“" -#: builtin/checkout.c:1196 +#: builtin/checkout.c:1190 msgid "invalid path specification" msgstr "указан е неправилен път" -#: builtin/checkout.c:1203 +#: builtin/checkout.c:1197 #, c-format msgid "" "Cannot update paths and switch to branch '%s' at the same time.\n" @@ -3643,49 +3762,48 @@ msgstr "" "Не можете едновременно да обновявате пътища и да преминете към клона „%s“.\n" "Дали не искате да изтеглите „%s“, който не сочи към подаване?" -#: builtin/checkout.c:1208 +#: builtin/checkout.c:1202 #, c-format msgid "git checkout: --detach does not take a path argument '%s'" msgstr "git checkout: опцията „--detach“ не приема аргумент-път „%s“" -#: builtin/checkout.c:1212 +#: builtin/checkout.c:1206 msgid "" "git checkout: --ours/--theirs, --force and --merge are incompatible when\n" "checking out of the index." msgstr "" -"git checkout: опциите „--ours“/„--theirs“, „--force“ и „--merge“ са " -"несъвместими\n" -"с изтегляне от индекса." +"git checkout: опциите „--ours“/„--theirs“, „--force“ и „--merge“\n" +"са несъвместими с изтегляне от индекса." #: builtin/clean.c:26 msgid "" "git clean [-d] [-f] [-i] [-n] [-q] [-e ] [-x | -X] [--] ..." -msgstr "" +msgstr "git clean [-d] [-f] [-i] [-n] [-q] [-e ШАБЛОН] [-x | -X] [--] ПЪТ…" #: builtin/clean.c:30 #, c-format msgid "Removing %s\n" -msgstr "" +msgstr "Изтриване на „%s“\n" #: builtin/clean.c:31 #, c-format msgid "Would remove %s\n" -msgstr "" +msgstr "Файлът „%s“ ще бъде изтрит\n" #: builtin/clean.c:32 #, c-format msgid "Skipping repository %s\n" -msgstr "" +msgstr "Прескачане на хранилището „%s“\n" #: builtin/clean.c:33 #, c-format msgid "Would skip repository %s\n" -msgstr "" +msgstr "Хранилището „%s“ ще бъде прескочено\n" #: builtin/clean.c:34 #, c-format msgid "failed to remove %s" -msgstr "" +msgstr "файлът „%s“ не може да бъде изтрит" #: builtin/clean.c:295 msgid "" @@ -3694,6 +3812,10 @@ msgid "" "foo - select item based on unique prefix\n" " - (empty) select nothing" msgstr "" +"Подсказка:\n" +"1 — избор на обект според реда\n" +"ПРЕФИКС — избор на единствен обект по този уникален префикс\n" +" — (празно) нищо да не се избира" #: builtin/clean.c:299 msgid "" @@ -3706,36 +3828,47 @@ msgid "" "* - choose all items\n" " - (empty) finish selecting" msgstr "" +"Подсказка:\n" +"1 — избор на един обект\n" +"3-5 — интервал за избор на обекти\n" +"2-3,6-9 — множество интервали за избор на обекти\n" +"ПРЕФИКС — избор на единствен обект по този уникален префикс\n" +"-… — отмяна на избора на обекти\n" +"* — избиране на всички обекти\n" +" — (празно) завършване на избирането" +# FIXME WTF does this mean #: builtin/clean.c:517 #, c-format msgid "Huh (%s)?" -msgstr "" +msgstr "Неправилен избор (%s)" -#: builtin/clean.c:660 +# FIXME - should we use >> or sth else +#: builtin/clean.c:659 #, c-format msgid "Input ignore patterns>> " -msgstr "" +msgstr "Шаблони за игнорирани елементи≫ " -#: builtin/clean.c:697 +#: builtin/clean.c:696 #, c-format msgid "WARNING: Cannot find items matched by: %s" -msgstr "" +msgstr "ПРЕДУПРЕЖДЕНИЕ: Никой обект не напасва на „%s“" -#: builtin/clean.c:718 +#: builtin/clean.c:717 msgid "Select items to delete" -msgstr "" +msgstr "Избиране на обекти за изтриване" -#: builtin/clean.c:758 +#: builtin/clean.c:757 #, c-format msgid "remove %s? " -msgstr "" +msgstr "Да се изтрие ли „%s“? " -#: builtin/clean.c:783 +# FIXME improve message +#: builtin/clean.c:782 msgid "Bye." -msgstr "" +msgstr "Изход." -#: builtin/clean.c:791 +#: builtin/clean.c:790 msgid "" "clean - start cleaning\n" "filter by pattern - exclude items from deletion\n" @@ -3745,81 +3878,94 @@ msgid "" "help - this screen\n" "? - help for prompt selection" msgstr "" +"clean — начало на изчистването\n" +"filter by pattern — шаблон за обекти, които да не се трият\n" +"select by numbers — номера на обекти, които да се трият\n" +"ask each — потвърждаване на всяко изтриване (подобно на „rm -i“)\n" +"quit — край на изчистването\n" +"help — този край\n" +"? — подсказка за шаблоните" # FIXME how many *** -#: builtin/clean.c:818 +#: builtin/clean.c:817 msgid "*** Commands ***" msgstr "●●● Команди ●●●" -#: builtin/clean.c:819 +# FIXME improve message +#: builtin/clean.c:818 msgid "What now" -msgstr "" +msgstr "Избор на следващо действие" -#: builtin/clean.c:827 +#: builtin/clean.c:826 msgid "Would remove the following item:" msgid_plural "Would remove the following items:" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Следният обект ще бъде изтрит:" +msgstr[1] "Следните обекти ще бъдат изтрити:" -#: builtin/clean.c:844 +#: builtin/clean.c:843 msgid "No more files to clean, exiting." -msgstr "" +msgstr "Файловете за изчистване свършиха. Изход от програмата." -#: builtin/clean.c:875 +#: builtin/clean.c:874 msgid "do not print names of files removed" -msgstr "" +msgstr "без извеждане на имената на файловете, които ще бъдат изтрити" -#: builtin/clean.c:877 +#: builtin/clean.c:876 msgid "force" -msgstr "" +msgstr "принудително изтриване" -#: builtin/clean.c:878 +#: builtin/clean.c:877 msgid "interactive cleaning" -msgstr "" +msgstr "интерактивно изтриване" -#: builtin/clean.c:880 +#: builtin/clean.c:879 msgid "remove whole directories" -msgstr "" +msgstr "изтриване на цели директории" -#: builtin/clean.c:881 builtin/describe.c:415 builtin/grep.c:716 -#: builtin/ls-files.c:486 builtin/name-rev.c:314 builtin/show-ref.c:185 +#: builtin/clean.c:880 builtin/describe.c:406 builtin/grep.c:714 +#: builtin/ls-files.c:486 builtin/name-rev.c:311 builtin/show-ref.c:185 msgid "pattern" msgstr "шаблон" -#: builtin/clean.c:882 +#: builtin/clean.c:881 msgid "add to ignore rules" -msgstr "" +msgstr "добавяне на ШАБЛОН от файлове, които да не се трият" -#: builtin/clean.c:883 +#: builtin/clean.c:882 msgid "remove ignored files, too" -msgstr "" +msgstr "изтриване и на игнорираните файлове" -#: builtin/clean.c:885 +#: builtin/clean.c:884 msgid "remove only ignored files" -msgstr "" +msgstr "изтриване само на игнорирани файлове" -#: builtin/clean.c:903 +#: builtin/clean.c:902 msgid "-x and -X cannot be used together" -msgstr "" +msgstr "опциите „-x“ и „-X“ са несъвместими" -#: builtin/clean.c:907 +#: builtin/clean.c:906 msgid "" "clean.requireForce set to true and neither -i, -n, nor -f given; refusing to " "clean" msgstr "" +"Настройката „clean.requireForce“ е зададена като истина, което изисква някоя " +"от опциите „-i“, „-n“ или „-f“. Няма да се извърши изчистване" -#: builtin/clean.c:910 +#: builtin/clean.c:909 msgid "" "clean.requireForce defaults to true and neither -i, -n, nor -f given; " "refusing to clean" msgstr "" +"Настройката „clean.requireForce“ не е зададена, но стандартно е истина, " +"което изисква някоя от опциите „-i“, „-n“ или „-f“. Няма да се извърши " +"изчистване" #: builtin/clone.c:36 msgid "git clone [options] [--] []" -msgstr "git clone [ОПЦИИ] [--] ХРАНИЛИЩЕ [ДИРЕКТОРИЯ]" +msgstr "git clone [ОПЦИЯ…] [--] ХРАНИЛИЩЕ [ДИРЕКТОРИЯ]" -#: builtin/clone.c:64 builtin/fetch.c:97 builtin/merge.c:222 -#: builtin/push.c:504 +#: builtin/clone.c:64 builtin/fetch.c:112 builtin/merge.c:222 +#: builtin/push.c:503 msgid "force progress reporting" msgstr "извеждане на напредъка" @@ -3833,7 +3979,8 @@ msgstr "създаване на голо хранилище" #: builtin/clone.c:71 msgid "create a mirror repository (implies bare)" -msgstr "създаване на хранилище-огледало (това включва хранилището да е голо)" +msgstr "" +"създаване на хранилище-огледало (включва опцията „--bare“ за голо хранилище)" #: builtin/clone.c:73 msgid "to clone from a local repository" @@ -3879,7 +4026,7 @@ msgstr "изтегляне на този КЛОН, а не соченият от msgid "path to git-upload-pack on the remote" msgstr "път към командата „git-upload-pack“ на отдалеченото хранилище" -#: builtin/clone.c:92 builtin/fetch.c:98 builtin/grep.c:661 +#: builtin/clone.c:92 builtin/fetch.c:113 builtin/grep.c:659 msgid "depth" msgstr "ДЪЛБОЧИНА" @@ -3952,7 +4099,7 @@ msgstr "връзката „%s“ не може да бъде създадена #: builtin/clone.c:365 #, c-format msgid "failed to copy file to '%s'" -msgstr "файлът не можа да бъде копиран като „%s“" +msgstr "файлът не може да бъде копиран като „%s“" #: builtin/clone.c:388 builtin/clone.c:565 #, c-format @@ -3974,152 +4121,153 @@ msgstr "" #, c-format msgid "Could not find remote branch %s to clone." msgstr "" -"Клонът „%s“ от отдалеченото хранилище което клонирате,\n" -"който следва да бъде изтеглен, не съществува." +"Клонът „%s“ от отдалеченото хранилище, което клонирате,\n" +"и който следва да бъде изтеглен, не съществува." +# FIXME translator note that the space at end is necesssary #: builtin/clone.c:560 #, c-format msgid "Checking connectivity... " -msgstr "Проверка на връзката…" +msgstr "Проверка на връзката… " #: builtin/clone.c:563 msgid "remote did not send all necessary objects" msgstr "отдалеченото хранилище не изпрати всички необходими обекти." -#: builtin/clone.c:626 +#: builtin/clone.c:627 msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n" msgstr "" "указателят „HEAD“ от отдалеченото хранилище сочи към нещо,\n" "което не съществува. Не може да се изтегли определен клон.\n" -#: builtin/clone.c:657 +#: builtin/clone.c:658 msgid "unable to checkout working tree" msgstr "работното дърво не може да бъде подготвено" -#: builtin/clone.c:765 +#: builtin/clone.c:768 msgid "Too many arguments." msgstr "Прекалено много аргументи." -#: builtin/clone.c:769 +#: builtin/clone.c:772 msgid "You must specify a repository to clone." msgstr "Трябва да укажете кое хранилище искате да клонирате." -#: builtin/clone.c:780 +#: builtin/clone.c:783 #, c-format msgid "--bare and --origin %s options are incompatible." msgstr "опциите „--bare“ и „--origin %s“ са несъвместими." -#: builtin/clone.c:783 +#: builtin/clone.c:786 msgid "--bare and --separate-git-dir are incompatible." msgstr "опциите „--bare“ и „--separate-git-dir“ са несъвместими." -#: builtin/clone.c:796 +#: builtin/clone.c:799 #, c-format msgid "repository '%s' does not exist" msgstr "не съществува хранилище „%s“" -#: builtin/clone.c:802 -msgid "--depth is ignored in local clones; use file:// instead." -msgstr "" -"При локално клониране опцията „--depth“ се игнорира. Ползвайте схемата " -"„file://“." - -#: builtin/clone.c:805 -msgid "source repository is shallow, ignoring --local" -msgstr "клонираното хранилище е плитко, затова опцията „--local“ се игнорира" - -#: builtin/clone.c:810 -msgid "--local is ignored" -msgstr "опцията „--local“ се игнорира" - -#: builtin/clone.c:814 builtin/fetch.c:1119 +#: builtin/clone.c:805 builtin/fetch.c:1143 #, c-format msgid "depth %s is not a positive number" msgstr "дълбочината трябва да е положително цяло число, а не „%s“" -#: builtin/clone.c:824 +#: builtin/clone.c:815 #, c-format msgid "destination path '%s' already exists and is not an empty directory." msgstr "целевият път „%s“ съществува и не е празна директория." -#: builtin/clone.c:834 +#: builtin/clone.c:825 #, c-format msgid "working tree '%s' already exists." msgstr "в „%s“ вече съществува работно дърво." -#: builtin/clone.c:847 builtin/clone.c:859 +#: builtin/clone.c:838 builtin/clone.c:850 #, c-format msgid "could not create leading directories of '%s'" msgstr "родителските директории на „%s“ не могат да бъдат създадени" -#: builtin/clone.c:850 +#: builtin/clone.c:841 #, c-format msgid "could not create work tree dir '%s'." msgstr "работното дърво в „%s“ не може да бъде създадено." -#: builtin/clone.c:869 +#: builtin/clone.c:860 #, c-format msgid "Cloning into bare repository '%s'...\n" msgstr "Клониране и създаване на голо хранилище в „%s“…\n" -#: builtin/clone.c:871 +#: builtin/clone.c:862 #, c-format msgid "Cloning into '%s'...\n" msgstr "Клониране и създаване на хранилище в „%s“…\n" +#: builtin/clone.c:898 +msgid "--depth is ignored in local clones; use file:// instead." +msgstr "" +"При локално клониране опцията „--depth“ се игнорира. Ползвайте схемата " +"„file://“." + +#: builtin/clone.c:901 +msgid "source repository is shallow, ignoring --local" +msgstr "клонираното хранилище е плитко, затова опцията „--local“ се игнорира" + #: builtin/clone.c:906 +msgid "--local is ignored" +msgstr "опцията „--local“ се игнорира" + +#: builtin/clone.c:910 #, c-format msgid "Don't know how to clone %s" msgstr "Не се поддържа клониране на връзки от вида „%s“ " -#: builtin/clone.c:957 builtin/clone.c:965 +#: builtin/clone.c:961 builtin/clone.c:969 #, c-format msgid "Remote branch %s not found in upstream %s" msgstr "Отдалеченият клон „%s“ липсва в клонираното хранилище „%s“" -#: builtin/clone.c:968 +#: builtin/clone.c:972 msgid "You appear to have cloned an empty repository." msgstr "Изглежда клонирахте празно хранилище." #: builtin/column.c:9 msgid "git column [options]" -msgstr "" +msgstr "git column [ОПЦИЯ…]" #: builtin/column.c:26 msgid "lookup config vars" -msgstr "" +msgstr "извеждане на настройките" #: builtin/column.c:27 builtin/column.c:28 msgid "layout to use" -msgstr "" +msgstr "как да се подреди резултата" #: builtin/column.c:29 msgid "Maximum width" -msgstr "" +msgstr "Максимална широчина" #: builtin/column.c:30 msgid "Padding space on left border" -msgstr "" +msgstr "Поле в знаци отляво" #: builtin/column.c:31 msgid "Padding space on right border" -msgstr "" +msgstr "Поле в знаци отдясно" #: builtin/column.c:32 msgid "Padding space between columns" -msgstr "" +msgstr "Поле в знаци между колоните" #: builtin/column.c:51 msgid "--command must be the first argument" -msgstr "" +msgstr "опцията „--command“ трябва да е първият аргумент" #: builtin/commit.c:36 msgid "git commit [options] [--] ..." -msgstr "git commit [ОПЦИИ] [--] ПЪТ…" +msgstr "git commit [ОПЦИЯ…] [--] ПЪТ…" #: builtin/commit.c:41 msgid "git status [options] [--] ..." -msgstr "git status [ОПЦИИ] [--] ПЪТ…" +msgstr "git status [ОПЦИЯ…] [--] ПЪТ…" #: builtin/commit.c:46 msgid "" @@ -4197,90 +4345,99 @@ msgstr "" msgid "failed to unpack HEAD tree object" msgstr "неуспешно изваждана на върховото дърво (HEAD tree object) от пакет" -#: builtin/commit.c:330 +#: builtin/commit.c:328 msgid "unable to create temporary index" msgstr "неуспешно създаване на временен индекс" -#: builtin/commit.c:336 +#: builtin/commit.c:334 msgid "interactive add failed" msgstr "неуспешно интерактивно добавяне" -#: builtin/commit.c:369 builtin/commit.c:390 builtin/commit.c:440 +#: builtin/commit.c:366 builtin/commit.c:387 builtin/commit.c:435 msgid "unable to write new_index file" msgstr "неуспешен запис на новия индекс" -#: builtin/commit.c:421 +#: builtin/commit.c:418 msgid "cannot do a partial commit during a merge." msgstr "по време на сливане не може да се извърши частично подаване." -#: builtin/commit.c:423 +#: builtin/commit.c:420 msgid "cannot do a partial commit during a cherry-pick." msgstr "по време на отбиране не може да се извърши частично подаване." -#: builtin/commit.c:433 +#: builtin/commit.c:429 msgid "cannot read the index" msgstr "индексът не може да бъде прочетен" -#: builtin/commit.c:453 +#: builtin/commit.c:447 msgid "unable to write temporary index file" msgstr "временният индекс не може да бъде записан" -#: builtin/commit.c:544 builtin/commit.c:550 +#: builtin/commit.c:557 builtin/commit.c:563 #, c-format msgid "invalid commit: %s" msgstr "неправилно подаване: %s" -#: builtin/commit.c:572 +#: builtin/commit.c:585 msgid "malformed --author parameter" msgstr "неправилен параметър към опцията „--author“" #: builtin/commit.c:592 #, c-format +msgid "invalid date format: %s" +msgstr "неправилен формат на дата: %s" + +#: builtin/commit.c:609 +#, c-format msgid "Malformed ident string: '%s'" msgstr "Неправилен низ за идентичност: „%s“" -#: builtin/commit.c:629 builtin/commit.c:663 builtin/commit.c:1014 +#: builtin/commit.c:642 +msgid "" +"unable to select a comment character that is not used\n" +"in the current commit message" +msgstr "" +"не може да се избере знак за коментар — в текущото съобщение за подаване са " +"използвани всички подобни знаци" + +#: builtin/commit.c:679 builtin/commit.c:712 builtin/commit.c:1086 #, c-format msgid "could not lookup commit %s" msgstr "следното подаване не може да бъде открито: %s" -#: builtin/commit.c:641 builtin/shortlog.c:273 +#: builtin/commit.c:691 builtin/shortlog.c:273 #, c-format msgid "(reading log message from standard input)\n" msgstr "(изчитане на съобщението за подаване от стандартния вход)\n" -#: builtin/commit.c:643 +#: builtin/commit.c:693 msgid "could not read log from standard input" msgstr "съобщението за подаване не бе прочетено стандартния вход" -#: builtin/commit.c:647 +#: builtin/commit.c:697 #, c-format msgid "could not read log file '%s'" msgstr "файлът със съобщението за подаване „%s“ не може да бъде прочетен" -#: builtin/commit.c:654 -msgid "commit has empty message" -msgstr "подаване с празно съобщение" - -#: builtin/commit.c:670 +#: builtin/commit.c:719 msgid "could not read MERGE_MSG" msgstr "съобщението за сливане MERGE_MSG не може да бъде прочетено" -#: builtin/commit.c:674 +#: builtin/commit.c:723 msgid "could not read SQUASH_MSG" msgstr "съобщението за смачкване SQUASH_MSG не може да бъде прочетено" -#: builtin/commit.c:678 +#: builtin/commit.c:727 #, c-format msgid "could not read '%s'" msgstr "файлът „%s“ не може да бъде прочетен" -#: builtin/commit.c:749 +#: builtin/commit.c:798 msgid "could not write commit template" msgstr "шаблонът за подаване не може да бъде запазен" # FIXME -#: builtin/commit.c:764 +#: builtin/commit.c:816 #, c-format msgid "" "\n" @@ -4296,7 +4453,7 @@ msgstr "" "и опитайте отново.\n" # FIXME -#: builtin/commit.c:769 +#: builtin/commit.c:821 #, c-format msgid "" "\n" @@ -4312,16 +4469,16 @@ msgstr "" " %s\n" "и опитайте отново.\n" -#: builtin/commit.c:782 +#: builtin/commit.c:834 #, c-format msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '%c' will be ignored, and an empty message aborts the commit.\n" msgstr "" "Въведете съобщението за подаване на промените. Редовете, които започват\n" -"с „%c“ ще бъдат филтрирани, а празно съобщение отменя подаването.\n" +"с „%c“, ще бъдат пропуснати, а празно съобщение преустановява подаването.\n" -#: builtin/commit.c:789 +#: builtin/commit.c:841 #, c-format msgid "" "Please enter the commit message for your changes. Lines starting\n" @@ -4329,154 +4486,158 @@ msgid "" "An empty message aborts the commit.\n" msgstr "" "Въведете съобщението за подаване на промените. Редовете, които започват\n" -"с „%c“ НЯМА да бъдат филтрирани, може да ги изтриете вие. Празно \n" -"съобщение отменя подаването.\n" +"с „%c“, също ще бъдат включени — може да ги изтриете вие. Празно \n" +"съобщение преустановява подаването.\n" + +#: builtin/commit.c:855 +#, c-format +msgid "%sAuthor: %.*s <%.*s>" +msgstr "%sАвтор: %.*s <%.*s>" -#: builtin/commit.c:802 +#: builtin/commit.c:863 #, c-format -msgid "%sAuthor: %s" -msgstr "%sАвтор: %s" +msgid "%sDate: %s" +msgstr "%sДата: %s" -#: builtin/commit.c:809 +#: builtin/commit.c:870 #, c-format -msgid "%sCommitter: %s" -msgstr "%sПодаващ: %s" +msgid "%sCommitter: %.*s <%.*s>" +msgstr "%sПодаващ: %.*s <%.*s>" -#: builtin/commit.c:829 +#: builtin/commit.c:888 msgid "Cannot read index" msgstr "Индексът не може да бъде прочетен" -#: builtin/commit.c:872 +#: builtin/commit.c:945 msgid "Error building trees" msgstr "Грешка при изграждане на дърветата" -#: builtin/commit.c:887 builtin/tag.c:391 +#: builtin/commit.c:960 builtin/tag.c:495 #, c-format msgid "Please supply the message using either -m or -F option.\n" msgstr "Подайте съобщението с някоя от опциите „-m“ или „-F“.\n" -#: builtin/commit.c:989 +#: builtin/commit.c:1061 #, c-format msgid "No existing author found with '%s'" msgstr "Не е открит автор с име „%s“." -#: builtin/commit.c:1004 builtin/commit.c:1244 +#: builtin/commit.c:1076 builtin/commit.c:1316 #, c-format msgid "Invalid untracked files mode '%s'" msgstr "Неправилна стойност за неследените файлове: „%s“" -#: builtin/commit.c:1041 +#: builtin/commit.c:1113 msgid "--long and -z are incompatible" msgstr "Опциите „--long“ и „-z“ са несъвместими." -#: builtin/commit.c:1071 +#: builtin/commit.c:1143 msgid "Using both --reset-author and --author does not make sense" msgstr "Опциите „--reset-author“ и „--author“ са несъвместими." -#: builtin/commit.c:1080 +#: builtin/commit.c:1152 msgid "You have nothing to amend." msgstr "Няма какво да бъде поправено." -#: builtin/commit.c:1083 +#: builtin/commit.c:1155 msgid "You are in the middle of a merge -- cannot amend." msgstr "В момента се извършва сливане, не можете да поправяте." -#: builtin/commit.c:1085 +#: builtin/commit.c:1157 msgid "You are in the middle of a cherry-pick -- cannot amend." msgstr "В момента се извършва отбиране на подаване, не можете да поправяте." -#: builtin/commit.c:1088 +#: builtin/commit.c:1160 msgid "Options --squash and --fixup cannot be used together" msgstr "Опциите „--squash“ и „--fixup“ са несъвместими." -#: builtin/commit.c:1098 +#: builtin/commit.c:1170 msgid "Only one of -c/-C/-F/--fixup can be used." -msgstr "" -"Можете да използвате само една от опциите „-c“, „-C“, „-F“ и „--fixup“." +msgstr "Опциите „-c“, „-C“, „-F“ и „--fixup““ са несъвместими." -#: builtin/commit.c:1100 +#: builtin/commit.c:1172 msgid "Option -m cannot be combined with -c/-C/-F/--fixup." msgstr "Опцията „-m“ е несъвместима с „-c“, „-C“, „-F“ и „--fixup“." -#: builtin/commit.c:1108 +#: builtin/commit.c:1180 msgid "--reset-author can be used only with -C, -c or --amend." msgstr "" "Опцията „--reset-author“ може да се използва само заедно с „-C“, „-c“ или\n" "„--amend“." -#: builtin/commit.c:1125 +#: builtin/commit.c:1197 msgid "Only one of --include/--only/--all/--interactive/--patch can be used." msgstr "" "Опциите „--include“, „--only“, „--all“, „--interactive“ и „--patch“ са\n" "несъвместими." -#: builtin/commit.c:1127 +#: builtin/commit.c:1199 msgid "No paths with --include/--only does not make sense." msgstr "Опциите „--include“ и „--only“ изискват аргументи." # FIXME bad message -#: builtin/commit.c:1129 +#: builtin/commit.c:1201 msgid "Clever... amending the last one with dirty index." msgstr "" -"Поправяте последното подаване докато индекса има проблеми. Това е лоша идея." +"Поправяте последното подаване докато индексът има проблеми. Това е лоша идея." -#: builtin/commit.c:1131 +#: builtin/commit.c:1203 msgid "Explicit paths specified without -i or -o; assuming --only paths..." msgstr "" "Зададени са изрични пътища без опциите „-i“ или „-o“. Приема се, че все едно " "сте\n" "ползвали опцията „--only“ с ПЪТища…" -#: builtin/commit.c:1143 builtin/tag.c:639 +#: builtin/commit.c:1215 builtin/tag.c:727 #, c-format msgid "Invalid cleanup mode %s" msgstr "Несъществуващ режим на изчистване „%s“" -#: builtin/commit.c:1148 +#: builtin/commit.c:1220 msgid "Paths with -a does not make sense." -msgstr "Използването на пътища е несъвместимо със задаването на опцията „-a“." +msgstr "Опцията „-a“ е несъвместима със задаването на пътища." -#: builtin/commit.c:1258 builtin/commit.c:1516 +#: builtin/commit.c:1330 builtin/commit.c:1595 msgid "show status concisely" msgstr "кратка информация за състоянието" -#: builtin/commit.c:1260 builtin/commit.c:1518 +#: builtin/commit.c:1332 builtin/commit.c:1597 msgid "show branch information" msgstr "информация за клоните" -#: builtin/commit.c:1262 builtin/commit.c:1520 builtin/push.c:490 +#: builtin/commit.c:1334 builtin/commit.c:1599 builtin/push.c:489 msgid "machine-readable output" msgstr "формат на изхода за четене от програма" -#: builtin/commit.c:1265 builtin/commit.c:1522 +#: builtin/commit.c:1337 builtin/commit.c:1601 msgid "show status in long format (default)" msgstr "подробна информация за състоянието (стандартно)" -#: builtin/commit.c:1268 builtin/commit.c:1525 +#: builtin/commit.c:1340 builtin/commit.c:1604 msgid "terminate entries with NUL" msgstr "разделяне на елементите с нулевия знак „NUL“" -#: builtin/commit.c:1270 builtin/commit.c:1528 builtin/fast-export.c:674 -#: builtin/fast-export.c:677 builtin/tag.c:514 +#: builtin/commit.c:1342 builtin/commit.c:1607 builtin/fast-export.c:703 +#: builtin/fast-export.c:706 builtin/tag.c:602 msgid "mode" msgstr "режим" -#: builtin/commit.c:1271 builtin/commit.c:1528 +#: builtin/commit.c:1343 builtin/commit.c:1607 msgid "show untracked files, optional modes: all, normal, no. (Default: all)" msgstr "" "извеждане на неследените файлове. Възможните режими са „all“ (подробна\n" "информация), „normal“ (кратка информация), „no“ (без неследените файлове).\n" "Стандартният режим е: „all“." -#: builtin/commit.c:1274 +#: builtin/commit.c:1346 msgid "show ignored files" msgstr "извеждане на игнорираните файлове" -#: builtin/commit.c:1275 parse-options.h:153 +#: builtin/commit.c:1347 parse-options.h:153 msgid "when" msgstr "кога" -#: builtin/commit.c:1276 +#: builtin/commit.c:1348 msgid "" "ignore changes to submodules, optional when: all, dirty, untracked. " "(Default: all)" @@ -4485,233 +4646,233 @@ msgstr "" "една от\n" "„all“ (всички), „dirty“ (тези с неподадени промени), „untracked“ (неследени)" -#: builtin/commit.c:1278 +#: builtin/commit.c:1350 msgid "list untracked files in columns" msgstr "извеждане на неследените файлове в колони" -#: builtin/commit.c:1347 +#: builtin/commit.c:1419 msgid "couldn't look up newly created commit" msgstr "току що създаденото подаване не може да бъде открито" -#: builtin/commit.c:1349 +#: builtin/commit.c:1421 msgid "could not parse newly created commit" msgstr "току що създаденото подаване не може да бъде анализирано" -#: builtin/commit.c:1390 +#: builtin/commit.c:1469 msgid "detached HEAD" -msgstr "несвързан връх HEAD" +msgstr "несвързан връх „HEAD“" -#: builtin/commit.c:1392 +#: builtin/commit.c:1471 msgid " (root-commit)" msgstr " (начално подаване)" -#: builtin/commit.c:1486 +#: builtin/commit.c:1565 msgid "suppress summary after successful commit" msgstr "без информация след успешно подаване" -#: builtin/commit.c:1487 +#: builtin/commit.c:1566 msgid "show diff in commit message template" msgstr "добавяне на разликата към шаблона за съобщението при подаване" -#: builtin/commit.c:1489 +#: builtin/commit.c:1568 msgid "Commit message options" msgstr "Опции за съобщението при подаване" -#: builtin/commit.c:1490 builtin/tag.c:512 +#: builtin/commit.c:1569 builtin/tag.c:600 msgid "read message from file" -msgstr "взимане та съобщението от файл" +msgstr "взимане на съобщението от файл" -#: builtin/commit.c:1491 +#: builtin/commit.c:1570 msgid "author" msgstr "автор" -#: builtin/commit.c:1491 +#: builtin/commit.c:1570 msgid "override author for commit" msgstr "задаване на автор за подаването" -#: builtin/commit.c:1492 builtin/gc.c:272 +#: builtin/commit.c:1571 builtin/gc.c:286 msgid "date" msgstr "дата" -#: builtin/commit.c:1492 +#: builtin/commit.c:1571 msgid "override date for commit" msgstr "задаване на дата за подаването" -#: builtin/commit.c:1493 builtin/merge.c:216 builtin/notes.c:409 -#: builtin/notes.c:566 builtin/tag.c:510 +#: builtin/commit.c:1572 builtin/merge.c:216 builtin/notes.c:409 +#: builtin/notes.c:566 builtin/tag.c:598 msgid "message" msgstr "съобщение" -#: builtin/commit.c:1493 +#: builtin/commit.c:1572 msgid "commit message" msgstr "съобщение при подаване" -#: builtin/commit.c:1494 +#: builtin/commit.c:1573 msgid "reuse and edit message from specified commit" msgstr "преизползване и редактиране на съобщението от указаното подаване" -#: builtin/commit.c:1495 +#: builtin/commit.c:1574 msgid "reuse message from specified commit" msgstr "преизползване на съобщението от указаното подаване" -#: builtin/commit.c:1496 +#: builtin/commit.c:1575 msgid "use autosquash formatted message to fixup specified commit" msgstr "" "използване на автоматичното съобщение при смачкване за вкарване на " "указаното\n" "подаване в предното без следа" -#: builtin/commit.c:1497 +#: builtin/commit.c:1576 msgid "use autosquash formatted message to squash specified commit" msgstr "" "използване на автоматичното съобщение при смачкване за смачкване на " "указаното\n" "подаване в предното" -#: builtin/commit.c:1498 +#: builtin/commit.c:1577 msgid "the commit is authored by me now (used with -C/-c/--amend)" msgstr "" "смяна на автора да съвпада с подаващия (използва се с „-C“/„-c“/„--amend“)" -#: builtin/commit.c:1499 builtin/log.c:1180 builtin/revert.c:86 +#: builtin/commit.c:1578 builtin/log.c:1188 builtin/revert.c:86 msgid "add Signed-off-by:" msgstr "добавяне на поле за подпис — „Signed-off-by:“" -#: builtin/commit.c:1500 +#: builtin/commit.c:1579 msgid "use specified template file" msgstr "използване на указания шаблонен файл" -#: builtin/commit.c:1501 +#: builtin/commit.c:1580 msgid "force edit of commit" msgstr "редактиране на подаване" -#: builtin/commit.c:1502 +#: builtin/commit.c:1581 msgid "default" msgstr "стандартно" -#: builtin/commit.c:1502 builtin/tag.c:515 +#: builtin/commit.c:1581 builtin/tag.c:603 msgid "how to strip spaces and #comments from message" msgstr "кои празни знаци и #коментари да се махат от съобщенията" -#: builtin/commit.c:1503 +#: builtin/commit.c:1582 msgid "include status in commit message template" msgstr "вмъкване на състоянието в шаблона за съобщението при подаване" -#: builtin/commit.c:1504 builtin/merge.c:223 builtin/revert.c:92 -#: builtin/tag.c:516 +#: builtin/commit.c:1583 builtin/merge.c:223 builtin/revert.c:92 +#: builtin/tag.c:604 msgid "key-id" msgstr "ИДЕНТИФИКАТОР_НА_КЛЮЧ" -#: builtin/commit.c:1505 builtin/merge.c:224 builtin/revert.c:93 +#: builtin/commit.c:1584 builtin/merge.c:224 builtin/revert.c:93 msgid "GPG sign commit" msgstr "подписване на подаването с GPG" -#: builtin/commit.c:1508 +#: builtin/commit.c:1587 msgid "Commit contents options" msgstr "Опции за избор на файлове при подаване" -#: builtin/commit.c:1509 +#: builtin/commit.c:1588 msgid "commit all changed files" msgstr "подаване на всички променени файлове" -#: builtin/commit.c:1510 +#: builtin/commit.c:1589 msgid "add specified files to index for commit" msgstr "добавяне на указаните файлове към индекса за подаване" -#: builtin/commit.c:1511 +#: builtin/commit.c:1590 msgid "interactively add files" msgstr "интерактивно добавяне на файлове" -#: builtin/commit.c:1512 +#: builtin/commit.c:1591 msgid "interactively add changes" msgstr "интерактивно добавяне на промени" -#: builtin/commit.c:1513 +#: builtin/commit.c:1592 msgid "commit only specified files" msgstr "подаване само на указаните файлове" -#: builtin/commit.c:1514 +#: builtin/commit.c:1593 msgid "bypass pre-commit hook" msgstr "без изпълнение на куката преди подаване (pre-commit)" -#: builtin/commit.c:1515 +#: builtin/commit.c:1594 msgid "show what would be committed" msgstr "отпечатване на това, което би било подадено" -#: builtin/commit.c:1526 +#: builtin/commit.c:1605 msgid "amend previous commit" msgstr "поправяне на предишното подаване" -#: builtin/commit.c:1527 +#: builtin/commit.c:1606 msgid "bypass post-rewrite hook" msgstr "без изпълнение на куката след презаписване (post-rewrite)" -#: builtin/commit.c:1532 +#: builtin/commit.c:1611 msgid "ok to record an empty change" msgstr "позволяване на празни подавания" -#: builtin/commit.c:1534 +#: builtin/commit.c:1613 msgid "ok to record a change with an empty message" msgstr "позволяване на подавания с празни съобщения" -#: builtin/commit.c:1562 +#: builtin/commit.c:1641 msgid "could not parse HEAD commit" msgstr "върховото подаване „HEAD“ не може да бъде прочетено" -#: builtin/commit.c:1601 builtin/merge.c:518 +#: builtin/commit.c:1680 builtin/merge.c:518 #, c-format msgid "could not open '%s' for reading" msgstr "файлът не може да бъде прочетен: „%s“" -#: builtin/commit.c:1608 +#: builtin/commit.c:1687 #, c-format msgid "Corrupt MERGE_HEAD file (%s)" msgstr "Повреден файл за върха за сливането „MERGE_HEAD“ (%s)" -#: builtin/commit.c:1615 +#: builtin/commit.c:1694 msgid "could not read MERGE_MODE" msgstr "режимът на сливане „MERGE_MODE“ не може да бъде прочетен" -#: builtin/commit.c:1634 +#: builtin/commit.c:1713 #, c-format msgid "could not read commit message: %s" msgstr "съобщението за подаване не може да бъде прочетено: %s" -#: builtin/commit.c:1645 +#: builtin/commit.c:1724 #, c-format msgid "Aborting commit; you did not edit the message.\n" msgstr "Неизвършване на подаване поради нередактирано съобщение.\n" -#: builtin/commit.c:1650 +#: builtin/commit.c:1729 #, c-format msgid "Aborting commit due to empty commit message.\n" msgstr "Неизвършване на подаване поради празно съобщение.\n" -#: builtin/commit.c:1665 builtin/merge.c:857 builtin/merge.c:882 +#: builtin/commit.c:1744 builtin/merge.c:851 builtin/merge.c:876 msgid "failed to write commit object" msgstr "обектът за подаването не може да бъде записан" -#: builtin/commit.c:1686 +#: builtin/commit.c:1756 msgid "cannot lock HEAD ref" msgstr "указателят към върха „HEAD“ не може да бъде заключен" -#: builtin/commit.c:1690 +#: builtin/commit.c:1769 msgid "cannot update HEAD ref" msgstr "указателят към върха „HEAD“ не може да бъде обновен" -#: builtin/commit.c:1701 +#: builtin/commit.c:1780 msgid "" "Repository has been updated, but unable to write\n" "new_index file. Check that disk is not full or quota is\n" "not exceeded, and then \"git reset HEAD\" to recover." msgstr "" "Хранилището е обновено, но новият файл за индекс „new_index“\n" -"не е записан. Проверете дали не е препълнен диска или не сте\n" +"не е записан. Проверете дали дискът не е препълнен или не сте\n" "превишили дисковата си квота. След това изпълнете „git reset HEAD“." #: builtin/config.c:8 msgid "git config [options]" -msgstr "git config [ОПЦИИ]" +msgstr "git config [ОПЦИЯ…]" #: builtin/config.c:53 msgid "Config file location" @@ -4804,12 +4965,11 @@ msgstr "настройка" #: builtin/config.c:72 msgid "find the color configured: [default]" -msgstr "извеждане на зададения цвят на настройката: [стандартно]" +msgstr "извеждане на зададения цвят: [стандартно]" #: builtin/config.c:73 msgid "find the color setting: [stdout-is-tty]" -msgstr "" -"извеждане на зададения цвят на настройката: [стандартният изход е терминал]" +msgstr "извеждане на зададения цвят: [стандартният изход е терминал]" #: builtin/config.c:74 msgid "Type" @@ -4855,135 +5015,144 @@ msgstr "извеждане на размерите на обектите във # FIXME ... instead of *??? #: builtin/describe.c:16 msgid "git describe [options] *" -msgstr "git describe [ОПЦИИ] указател към подаване…" +msgstr "git describe [ОПЦИЯ…] УКАЗАТЕЛ_КЪМ_ПОДАВАНЕ…" #: builtin/describe.c:17 msgid "git describe [options] --dirty" -msgstr "" +msgstr "git describe [ОПЦИЯ…] --dirty" -#: builtin/describe.c:225 +#: builtin/describe.c:216 #, c-format msgid "annotated tag %s not available" -msgstr "" +msgstr "не съществува анотиран етикет „%s“" -#: builtin/describe.c:229 +#: builtin/describe.c:220 #, c-format msgid "annotated tag %s has no embedded name" -msgstr "" +msgstr "в анотирания етикет „%s“ липсва вградено име" -#: builtin/describe.c:231 +#: builtin/describe.c:222 #, c-format msgid "tag '%s' is really '%s' here" -msgstr "" +msgstr "етикетът „%s“ тук е всъщност „%s“" -#: builtin/describe.c:258 +#: builtin/describe.c:249 #, c-format msgid "Not a valid object name %s" -msgstr "" +msgstr "Неправилно име на обект „%s“" -#: builtin/describe.c:261 +#: builtin/describe.c:252 #, c-format msgid "%s is not a valid '%s' object" -msgstr "" +msgstr "„%s“ е неправилен обект „%s“" -#: builtin/describe.c:278 +#: builtin/describe.c:269 #, c-format msgid "no tag exactly matches '%s'" -msgstr "" +msgstr "никой етикет не напасва точно „%s“" -#: builtin/describe.c:280 +#: builtin/describe.c:271 #, c-format msgid "searching to describe %s\n" -msgstr "" +msgstr "търсене за описание на „%s“\n" -#: builtin/describe.c:327 +#: builtin/describe.c:318 #, c-format msgid "finished search at %s\n" -msgstr "" +msgstr "търсенето приключи при „%s“\n" -#: builtin/describe.c:354 +#: builtin/describe.c:345 #, c-format msgid "" "No annotated tags can describe '%s'.\n" "However, there were unannotated tags: try --tags." msgstr "" +"Никой анотиран етикет не описва „%s“.\n" +"Съществуват и неанотирани етикети. Пробвайте с опцията „--tags“." -#: builtin/describe.c:358 +#: builtin/describe.c:349 #, c-format msgid "" "No tags can describe '%s'.\n" "Try --always, or create some tags." msgstr "" +"Никой етикет не описва „%s“.\n" +"Пробвайте с опцията „--always“ или създайте етикети." -#: builtin/describe.c:379 +# FIXME - plural +#: builtin/describe.c:370 #, c-format msgid "traversed %lu commits\n" -msgstr "" +msgstr "претърсени са %lu подавания\n" -#: builtin/describe.c:382 +#: builtin/describe.c:373 #, c-format msgid "" "more than %i tags found; listed %i most recent\n" "gave up search at %s\n" msgstr "" +"открити са над %i етикета, изведени са последните %i,\n" +"търсенето бе прекратено при „%s“.\n" -#: builtin/describe.c:404 +#: builtin/describe.c:395 msgid "find the tag that comes after the commit" -msgstr "" +msgstr "откриване на етикета, който следва подаване" -#: builtin/describe.c:405 +#: builtin/describe.c:396 msgid "debug search strategy on stderr" msgstr "" +"извеждане на информация за трасиране на стратегията за търсене на " +"стандартната грешка" -#: builtin/describe.c:406 +#: builtin/describe.c:397 msgid "use any ref" -msgstr "" +msgstr "използване на произволен указател" -#: builtin/describe.c:407 +#: builtin/describe.c:398 msgid "use any tag, even unannotated" -msgstr "" +msgstr "използване на всеки етикет — включително и неанотираните" -#: builtin/describe.c:408 +#: builtin/describe.c:399 msgid "always use long format" -msgstr "" +msgstr "винаги да се ползва дългият формат" -#: builtin/describe.c:409 +#: builtin/describe.c:400 msgid "only follow first parent" -msgstr "" +msgstr "проследяване само на първия родител" -#: builtin/describe.c:412 +#: builtin/describe.c:403 msgid "only output exact matches" -msgstr "" +msgstr "извеждане само на точните съвпадения" -#: builtin/describe.c:414 +#: builtin/describe.c:405 msgid "consider most recent tags (default: 10)" msgstr "да се търси само в този БРОЙ последни етикети (стандартно: 10)" -#: builtin/describe.c:416 +#: builtin/describe.c:407 msgid "only consider tags matching " -msgstr "" +msgstr "да се търси само измежду етикетите напасващи този ШАБЛОН" -#: builtin/describe.c:418 builtin/name-rev.c:321 +#: builtin/describe.c:409 builtin/name-rev.c:318 msgid "show abbreviated commit object as fallback" -msgstr "" +msgstr "извеждане на съкратено име на обект като резервен вариант" -#: builtin/describe.c:419 +#: builtin/describe.c:410 msgid "mark" -msgstr "" +msgstr "МАРКЕР" -#: builtin/describe.c:420 +#: builtin/describe.c:411 msgid "append on dirty working tree (default: \"-dirty\")" -msgstr "" +msgstr "добавяне на такъв МАРКЕР на работното дърво (стандартно е „-dirty“)" -#: builtin/describe.c:438 +#: builtin/describe.c:429 msgid "--long is incompatible with --abbrev=0" -msgstr "" +msgstr "Опциите „--long“ и „--abbrev=0“ са несъвместими" -#: builtin/describe.c:464 +#: builtin/describe.c:455 msgid "No names found, cannot describe anything." -msgstr "" +msgstr "Не са открити имена — нищо не може да бъде описано." -#: builtin/describe.c:484 +#: builtin/describe.c:475 msgid "--dirty is incompatible with commit-ishes" msgstr "опцията „--dirty“ е несъвместима с указател към подаване" @@ -5016,305 +5185,320 @@ msgstr "зададени са повече от 2 обекта: „%s“" msgid "unhandled object '%s' given." msgstr "зададен е неподдържан обект „%s“." -#: builtin/fast-export.c:22 +#: builtin/fast-export.c:23 msgid "git fast-export [rev-list-opts]" -msgstr "" +msgstr "git fast-export [ОПЦИИ_ЗА_СПИСЪКА_С_ВЕРСИИ]" -#: builtin/fast-export.c:673 +#: builtin/fast-export.c:702 msgid "show progress after objects" -msgstr "съобщение за напредъка на всеки такъв БРОЙ обекта" +msgstr "Съобщение за напредъка на всеки такъв БРОЙ обекта" -#: builtin/fast-export.c:675 +#: builtin/fast-export.c:704 msgid "select handling of signed tags" -msgstr "" +msgstr "Как да се обработват подписаните етикети" -#: builtin/fast-export.c:678 +#: builtin/fast-export.c:707 msgid "select handling of tags that tag filtered objects" -msgstr "" +msgstr "Как да се обработват етикетите на филтрираните обекти" -#: builtin/fast-export.c:681 +#: builtin/fast-export.c:710 msgid "Dump marks to this file" -msgstr "" +msgstr "Запазване на маркерите в този файл" -#: builtin/fast-export.c:683 +#: builtin/fast-export.c:712 msgid "Import marks from this file" -msgstr "" +msgstr "Внасяне на маркерите от този файл" -#: builtin/fast-export.c:685 +#: builtin/fast-export.c:714 msgid "Fake a tagger when tags lack one" -msgstr "" +msgstr "Да се използва изкуствено име на човек при липса на задаващ етикета" -#: builtin/fast-export.c:687 +#: builtin/fast-export.c:716 msgid "Output full tree for each commit" -msgstr "" +msgstr "Извеждане на цялото дърво за всяко подаване" -#: builtin/fast-export.c:689 +#: builtin/fast-export.c:718 msgid "Use the done feature to terminate the stream" -msgstr "" +msgstr "Използване на маркер за завършване на потока" -#: builtin/fast-export.c:690 +#: builtin/fast-export.c:719 msgid "Skip output of blob data" -msgstr "" +msgstr "Без извеждане на съдържанието на обектите BLOB" + +#: builtin/fast-export.c:720 +msgid "refspec" +msgstr "указател на версия" + +#: builtin/fast-export.c:721 +msgid "Apply refspec to exported refs" +msgstr "Прилагане на указателя на версия към изнесените указатели" #: builtin/fetch.c:20 msgid "git fetch [] [ [...]]" -msgstr "git fetch [ОПЦИИ] [ХРАНИЛИЩЕ [УКАЗАТЕЛ…]]" +msgstr "git fetch [ОПЦИЯ…] [ХРАНИЛИЩЕ [УКАЗАТЕЛ…]]" #: builtin/fetch.c:21 msgid "git fetch [] " -msgstr "git fetch [ОПЦИИ] ГРУПА" +msgstr "git fetch [ОПЦИЯ…] ГРУПА" #: builtin/fetch.c:22 msgid "git fetch --multiple [] [( | )...]" -msgstr "git fetch --multiple [ОПЦИИ] [(ХРАНИЛИЩЕ | ГРУПА)…]" +msgstr "git fetch --multiple [ОПЦИЯ…] [(ХРАНИЛИЩЕ | ГРУПА)…]" #: builtin/fetch.c:23 msgid "git fetch --all []" -msgstr "git fetch --all [ОПЦИИ]" +msgstr "git fetch --all [ОПЦИЯ…]" -#: builtin/fetch.c:75 +#: builtin/fetch.c:90 msgid "fetch from all remotes" msgstr "доставяне от всички отдалечени хранилища" -#: builtin/fetch.c:77 +#: builtin/fetch.c:92 msgid "append to .git/FETCH_HEAD instead of overwriting" -msgstr "добавяне към вместо замяна на „.git/FETCH_HEAD“" +msgstr "добавяне към „.git/FETCH_HEAD“ вместо замяна" -#: builtin/fetch.c:79 +#: builtin/fetch.c:94 msgid "path to upload pack on remote end" msgstr "отдалечен път, където да се качи пакетът" -#: builtin/fetch.c:80 +#: builtin/fetch.c:95 msgid "force overwrite of local branch" msgstr "принудително презаписване на локалния клон" -#: builtin/fetch.c:82 +#: builtin/fetch.c:97 msgid "fetch from multiple remotes" msgstr "доставяне от множество отдалечени хранилища" -#: builtin/fetch.c:84 +#: builtin/fetch.c:99 msgid "fetch all tags and associated objects" msgstr "доставяне на всички етикети и принадлежащи обекти" -#: builtin/fetch.c:86 +#: builtin/fetch.c:101 msgid "do not fetch all tags (--no-tags)" msgstr "без доставянето на всички етикети „--no-tags“" -#: builtin/fetch.c:88 +#: builtin/fetch.c:103 msgid "prune remote-tracking branches no longer on remote" -msgstr "окастряне на клоните следящи вече не съществуващи отдалечени клони" +msgstr "окастряне на клоните следящи вече несъществуващи отдалечени клони" -#: builtin/fetch.c:89 +#: builtin/fetch.c:104 msgid "on-demand" msgstr "при нужда" -#: builtin/fetch.c:90 +#: builtin/fetch.c:105 msgid "control recursive fetching of submodules" msgstr "управление на рекурсивното доставяне на подмодулите" -#: builtin/fetch.c:94 +#: builtin/fetch.c:109 msgid "keep downloaded pack" msgstr "запазване на изтеглените пакети с обекти" -#: builtin/fetch.c:96 +#: builtin/fetch.c:111 msgid "allow updating of HEAD ref" msgstr "позволяване на обновяването на указателя „HEAD“" -#: builtin/fetch.c:99 +#: builtin/fetch.c:114 msgid "deepen history of shallow clone" msgstr "задълбочаване на историята на плитко хранилище" -#: builtin/fetch.c:101 +#: builtin/fetch.c:116 msgid "convert to a complete repository" msgstr "превръщане в пълно хранилище" -#: builtin/fetch.c:103 builtin/log.c:1197 +#: builtin/fetch.c:118 builtin/log.c:1205 msgid "dir" msgstr "директория" -#: builtin/fetch.c:104 +#: builtin/fetch.c:119 msgid "prepend this to submodule path output" msgstr "добавяне на това пред пътя на подмодула" -#: builtin/fetch.c:107 +#: builtin/fetch.c:122 msgid "default mode for recursion" msgstr "стандартен режим на рекурсия" -#: builtin/fetch.c:109 +#: builtin/fetch.c:124 msgid "accept refs that update .git/shallow" msgstr "приемане на указатели, които обновяват „.git/shallow“" -#: builtin/fetch.c:347 +#: builtin/fetch.c:125 +msgid "refmap" +msgstr "карта с указатели" + +#: builtin/fetch.c:126 +msgid "specify fetch refmap" +msgstr "указване на картата с указатели за доставяне" + +#: builtin/fetch.c:376 msgid "Couldn't find remote ref HEAD" msgstr "Указателят „HEAD“ в отдалеченото хранилище не може да бъде открит" -#: builtin/fetch.c:411 +#: builtin/fetch.c:440 #, c-format msgid "object %s not found" msgstr "обектът „%s“ липсва" -#: builtin/fetch.c:416 +#: builtin/fetch.c:445 msgid "[up to date]" msgstr "[актуализиран]" -# FIXME - the signs -#: builtin/fetch.c:430 +#: builtin/fetch.c:459 #, c-format msgid "! %-*s %-*s -> %s (can't fetch in current branch)" -msgstr "! %-*s %-*s -> %s (в текущия клон не може да се доставя)" +msgstr "! %-*s %-*s → %s (в текущия клон не може да се доставя)" -#: builtin/fetch.c:431 builtin/fetch.c:517 +#: builtin/fetch.c:460 builtin/fetch.c:546 msgid "[rejected]" msgstr "[отхвърлен]" -#: builtin/fetch.c:442 +#: builtin/fetch.c:471 msgid "[tag update]" msgstr "[обновяване на етикетите]" -#: builtin/fetch.c:444 builtin/fetch.c:479 builtin/fetch.c:497 +#: builtin/fetch.c:473 builtin/fetch.c:508 builtin/fetch.c:526 msgid " (unable to update local ref)" msgstr " (локалните указатели не могат да бъдат обновени)" -#: builtin/fetch.c:462 +#: builtin/fetch.c:491 msgid "[new tag]" msgstr "[нов етикет]" -#: builtin/fetch.c:465 +#: builtin/fetch.c:494 msgid "[new branch]" msgstr "[нов клон]" -#: builtin/fetch.c:468 +#: builtin/fetch.c:497 msgid "[new ref]" msgstr "[нов указател]" -#: builtin/fetch.c:513 +#: builtin/fetch.c:542 msgid "unable to update local ref" msgstr "локален указател не може да бъде обновен" -#: builtin/fetch.c:513 +#: builtin/fetch.c:542 msgid "forced update" msgstr "принудително обновяване" -#: builtin/fetch.c:519 +#: builtin/fetch.c:548 msgid "(non-fast-forward)" msgstr "(сливането не е тривиално)" -#: builtin/fetch.c:552 builtin/fetch.c:785 +#: builtin/fetch.c:581 builtin/fetch.c:814 #, c-format msgid "cannot open %s: %s\n" msgstr "файлът „%s“ не може да бъде отворен: %s\n" -#: builtin/fetch.c:561 +#: builtin/fetch.c:590 #, c-format msgid "%s did not send all necessary objects\n" msgstr "хранилището „%s“ не изпрати всички необходими обекти\n" -#: builtin/fetch.c:579 +#: builtin/fetch.c:608 #, c-format msgid "reject %s because shallow roots are not allowed to be updated" msgstr "" "отхвърляне на върха „%s“, защото плитките хранилища не могат да бъдат " "обновявани" -#: builtin/fetch.c:667 builtin/fetch.c:750 +#: builtin/fetch.c:696 builtin/fetch.c:779 #, c-format msgid "From %.*s\n" msgstr "От %.*s\n" -#: builtin/fetch.c:678 +# FIXME - is the space necessary +#: builtin/fetch.c:707 #, c-format msgid "" "some local refs could not be updated; try running\n" " 'git remote prune %s' to remove any old, conflicting branches" msgstr "" "някои локални указатели не могат да бъдат обновени. Изпълнете командата\n" -" „git remote prune %s“, за да премахнете остарелите клони, които " +"„git remote prune %s“, за да премахнете остарелите клони, които\n" "предизвикват конфликта" -#: builtin/fetch.c:730 +#: builtin/fetch.c:759 #, c-format msgid " (%s will become dangling)" msgstr " (обектът „%s“ ще се окаже извън клон)" -#: builtin/fetch.c:731 +#: builtin/fetch.c:760 #, c-format msgid " (%s has become dangling)" msgstr " (обектът „%s“ вече е извън клон)" -#: builtin/fetch.c:755 +#: builtin/fetch.c:784 msgid "[deleted]" msgstr "[изтрит]" -#: builtin/fetch.c:756 builtin/remote.c:1050 +#: builtin/fetch.c:785 builtin/remote.c:1059 msgid "(none)" msgstr "(нищо)" -#: builtin/fetch.c:775 +#: builtin/fetch.c:804 #, c-format msgid "Refusing to fetch into current branch %s of non-bare repository" -msgstr "" -"Не може да изтегляте в текущия клон „%s“, на хранилище, което не е голо" +msgstr "Не може да изтегляте в текущия клон „%s“ на хранилище, което не е голо" -#: builtin/fetch.c:794 +#: builtin/fetch.c:823 #, c-format msgid "Option \"%s\" value \"%s\" is not valid for %s" msgstr "Стойността „%2$s“ за опцията „%1$s“ не е съвместима с „%3$s“" -#: builtin/fetch.c:797 +#: builtin/fetch.c:826 #, c-format msgid "Option \"%s\" is ignored for %s\n" msgstr "Опцията „%s“ се игнорира при „%s“\n" -#: builtin/fetch.c:853 +#: builtin/fetch.c:882 #, c-format msgid "Don't know how to fetch from %s" msgstr "Не се поддържа доставяне от „%s“" -#: builtin/fetch.c:1015 +#: builtin/fetch.c:1044 #, c-format msgid "Fetching %s\n" msgstr "Доставяне на „%s“\n" -#: builtin/fetch.c:1017 builtin/remote.c:90 +#: builtin/fetch.c:1046 builtin/remote.c:90 #, c-format msgid "Could not fetch %s" msgstr "„%s“ не може да се достави" -#: builtin/fetch.c:1035 +#: builtin/fetch.c:1064 msgid "" "No remote repository specified. Please, specify either a URL or a\n" "remote name from which new revisions should be fetched." msgstr "" "Не сте указали отдалечено хранилище. Задайте или адрес, или име\n" -"на отдалечено хранилище, от където да се доставят новите версии." +"на отдалечено хранилище, откъдето да се доставят новите версии." -#: builtin/fetch.c:1059 +#: builtin/fetch.c:1087 msgid "You need to specify a tag name." msgstr "Трябва да укажете име на етикет." -#: builtin/fetch.c:1107 +#: builtin/fetch.c:1131 msgid "--depth and --unshallow cannot be used together" msgstr "опциите „--depth“ и „--unshallow“ са несъвместими" -#: builtin/fetch.c:1109 +#: builtin/fetch.c:1133 msgid "--unshallow on a complete repository does not make sense" msgstr "не можете да използвате опцията „--unshallow“ върху пълно хранилище" -#: builtin/fetch.c:1132 +#: builtin/fetch.c:1156 msgid "fetch --all does not take a repository argument" -msgstr "към „git fetch --all“ не можете да добавите хранилище аргумент" +msgstr "към „git fetch --all“ не можете да добавите аргумент — хранилище" -#: builtin/fetch.c:1134 +#: builtin/fetch.c:1158 msgid "fetch --all does not make sense with refspecs" msgstr "" -"към „git fetch --all“ не можете да добавите указател на версия за аргумент" +"към „git fetch --all“ не можете да добавите аргумент — указател на версия" -#: builtin/fetch.c:1145 +#: builtin/fetch.c:1169 #, c-format msgid "No such remote or remote group: %s" msgstr "Няма нито отдалечено хранилище, нито група от хранилища на име „%s“" -#: builtin/fetch.c:1153 +#: builtin/fetch.c:1177 msgid "Fetching a group and specifying refspecs does not make sense" msgstr "Указването на група и указването на версия са несъвместими" @@ -5322,9 +5506,9 @@ msgstr "Указването на група и указването на вер msgid "git fmt-merge-msg [-m ] [--log[=]|--no-log] [--file ]" msgstr "git fmt-merge-msg [-m СЪОБЩЕНИЕ] [--log[=БРОЙ]|--no-log] [--file ФАЙЛ]" -#: builtin/fmt-merge-msg.c:663 builtin/fmt-merge-msg.c:666 builtin/grep.c:700 -#: builtin/merge.c:196 builtin/repack.c:175 builtin/repack.c:179 -#: builtin/show-branch.c:654 builtin/show-ref.c:178 builtin/tag.c:501 +#: builtin/fmt-merge-msg.c:663 builtin/fmt-merge-msg.c:666 builtin/grep.c:698 +#: builtin/merge.c:196 builtin/repack.c:179 builtin/repack.c:183 +#: builtin/show-branch.c:654 builtin/show-ref.c:178 builtin/tag.c:589 #: parse-options.h:132 parse-options.h:239 msgid "n" msgstr "БРОЙ" @@ -5351,154 +5535,155 @@ msgstr "за начало на съобщението да се ползва Т msgid "file to read from" msgstr "файл, от който да се чете" -#: builtin/for-each-ref.c:1063 +#: builtin/for-each-ref.c:1051 msgid "git for-each-ref [options] []" -msgstr "" +msgstr "git for-each-ref [ОПЦИЯ…] [ШАБЛОН]" -#: builtin/for-each-ref.c:1078 +#: builtin/for-each-ref.c:1066 msgid "quote placeholders suitably for shells" -msgstr "" +msgstr "цитиране подходящо за командни интерпретатори на обвивката" -#: builtin/for-each-ref.c:1080 +#: builtin/for-each-ref.c:1068 msgid "quote placeholders suitably for perl" -msgstr "" +msgstr "цитиране подходящо за perl" -#: builtin/for-each-ref.c:1082 +#: builtin/for-each-ref.c:1070 msgid "quote placeholders suitably for python" -msgstr "" +msgstr "цитиране подходящо за python" -#: builtin/for-each-ref.c:1084 +#: builtin/for-each-ref.c:1072 msgid "quote placeholders suitably for tcl" -msgstr "" +msgstr "цитиране подходящо за tcl" -#: builtin/for-each-ref.c:1087 +#: builtin/for-each-ref.c:1075 msgid "show only matched refs" msgstr "извеждане само на този БРОЙ напаснати указатели" -#: builtin/for-each-ref.c:1088 builtin/replace.c:177 +#: builtin/for-each-ref.c:1076 builtin/replace.c:435 msgid "format" msgstr "ФОРМАТ" -#: builtin/for-each-ref.c:1088 +#: builtin/for-each-ref.c:1076 msgid "format to use for the output" msgstr "ФОРМАТ за изхода" -#: builtin/for-each-ref.c:1089 +#: builtin/for-each-ref.c:1077 msgid "key" -msgstr "" +msgstr "ключ" -#: builtin/for-each-ref.c:1090 +#: builtin/for-each-ref.c:1078 msgid "field name to sort on" -msgstr "" +msgstr "име на полето, по което да е подредбата" #: builtin/fsck.c:147 builtin/prune.c:172 msgid "Checking connectivity" msgstr "Проверка на връзката" -#: builtin/fsck.c:544 +#: builtin/fsck.c:538 msgid "Checking object directories" msgstr "Проверка на директориите с обекти" -#: builtin/fsck.c:607 +#: builtin/fsck.c:601 msgid "git fsck [options] [...]" -msgstr "git fsck [ОПЦИИ] [ОБЕКТ…]" +msgstr "git fsck [ОПЦИЯ…] [ОБЕКТ…]" -#: builtin/fsck.c:613 +#: builtin/fsck.c:607 msgid "show unreachable objects" msgstr "показване на недостижимите обекти" -#: builtin/fsck.c:614 +#: builtin/fsck.c:608 msgid "show dangling objects" msgstr "показване на обектите извън клоните" -#: builtin/fsck.c:615 +#: builtin/fsck.c:609 msgid "report tags" msgstr "показване на етикетите" -#: builtin/fsck.c:616 +#: builtin/fsck.c:610 msgid "report root nodes" msgstr "показване на кореновите възли" -#: builtin/fsck.c:617 +#: builtin/fsck.c:611 msgid "make index objects head nodes" msgstr "задаване на обекти от индекса да са коренови" # FIXME bad message -#: builtin/fsck.c:618 +#: builtin/fsck.c:612 msgid "make reflogs head nodes (default)" msgstr "проследяване на указателите от журнала като глави (стандартно)" -#: builtin/fsck.c:619 +#: builtin/fsck.c:613 msgid "also consider packs and alternate objects" msgstr "допълнително да се проверяват пакетите и алтернативните обекти" -#: builtin/fsck.c:620 +#: builtin/fsck.c:614 msgid "enable more strict checking" msgstr "по-строги проверки" -#: builtin/fsck.c:622 +#: builtin/fsck.c:616 msgid "write dangling objects in .git/lost-found" msgstr "запазване на обектите извън клоните в директорията „.git/lost-found“" -#: builtin/fsck.c:623 builtin/prune.c:144 +#: builtin/fsck.c:617 builtin/prune.c:144 msgid "show progress" msgstr "показване на напредъка" -#: builtin/fsck.c:673 +#: builtin/fsck.c:667 msgid "Checking objects" msgstr "Проверка на обектите" +# FIXME plural with ... #: builtin/gc.c:24 msgid "git gc [options]" -msgstr "git gc [ОПЦИИ]" +msgstr "git gc [ОПЦИЯ…]" -#: builtin/gc.c:90 +#: builtin/gc.c:91 #, c-format msgid "Invalid %s: '%s'" msgstr "Неправилна стойност за „%s“: „%s“" -#: builtin/gc.c:117 +#: builtin/gc.c:118 #, c-format msgid "insanely long object directory %.*s" msgstr "прекалено дълга директория с обекти „%.*s“" -#: builtin/gc.c:273 +#: builtin/gc.c:287 msgid "prune unreferenced objects" msgstr "окастряне на обектите, към които нищо не сочи" -#: builtin/gc.c:275 +#: builtin/gc.c:289 msgid "be more thorough (increased runtime)" msgstr "изчерпателно търсене на боклука (за сметка на повече време работа)" -#: builtin/gc.c:276 +#: builtin/gc.c:290 msgid "enable auto-gc mode" msgstr "включване на автоматичното събиране на боклука (auto-gc)" -#: builtin/gc.c:277 +#: builtin/gc.c:291 msgid "force running gc even if there may be another gc running" msgstr "" "изрично стартиране на събирането на боклука, дори и ако вече работи друго " "събиране" -#: builtin/gc.c:318 +#: builtin/gc.c:332 #, c-format msgid "Auto packing the repository in background for optimum performance.\n" msgstr "" "Автоматично пакетиране на заден фон на хранилището за по-добра " "производителност.\n" -#: builtin/gc.c:320 +#: builtin/gc.c:334 #, c-format msgid "Auto packing the repository for optimum performance.\n" msgstr "Автоматично пакетиране на хранилището за по-добра производителност.\n" -#: builtin/gc.c:321 +#: builtin/gc.c:335 #, c-format msgid "See \"git help gc\" for manual housekeeping.\n" msgstr "" "Вижте ръководството за повече информация как да изпълните „git help gc“.\n" -#: builtin/gc.c:336 +#: builtin/gc.c:353 #, c-format msgid "" "gc is already running on machine '%s' pid % (use --force if not)" @@ -5507,256 +5692,251 @@ msgstr "" "процеса: % (ако сте сигурни, че това не е вярно, това използвайте\n" "опцията „--force“)" -#: builtin/gc.c:361 +#: builtin/gc.c:375 msgid "" "There are too many unreachable loose objects; run 'git prune' to remove them." msgstr "" -"Има прекалено много недостижими, непакетирани обекти. Използвайте „git " -"prune“, за да\n" -"ги окастрите." +"Има прекалено много недостижими, непакетирани обекти.\n" +"Използвайте „git prune“, за да ги окастрите." +# FIXME plural ... options #: builtin/grep.c:23 msgid "git grep [options] [-e] [...] [[--] ...]" -msgstr "git grep [ОПЦИИ] [-e] ШАБЛОН [ВЕРСИЯ…] [[--] ПЪТ…]" +msgstr "git grep [ОПЦИЯ…] [-e] ШАБЛОН [ВЕРСИЯ…] [[--] ПЪТ…]" #: builtin/grep.c:218 #, c-format msgid "grep: failed to create thread: %s" msgstr "grep: неуспешно създаване на нишка: %s" -#: builtin/grep.c:365 -#, c-format -msgid "Failed to chdir: %s" -msgstr "Неуспешна смяна на директория: %s" - -#: builtin/grep.c:443 builtin/grep.c:478 +#: builtin/grep.c:441 builtin/grep.c:476 #, c-format msgid "unable to read tree (%s)" msgstr "дървото не може да бъде прочетено (%s)" -#: builtin/grep.c:493 +#: builtin/grep.c:491 #, c-format msgid "unable to grep from object of type %s" msgstr "не може да се изпълни „grep“ от обект от вида %s" -#: builtin/grep.c:549 +#: builtin/grep.c:547 #, c-format msgid "switch `%c' expects a numerical value" msgstr "опцията „%c“ очаква число за аргумент" -#: builtin/grep.c:566 +#: builtin/grep.c:564 #, c-format msgid "cannot open '%s'" msgstr "„%s“ не може да бъде отворен" -#: builtin/grep.c:640 +#: builtin/grep.c:638 msgid "search in index instead of in the work tree" msgstr "търсене в индекса, а не в работното дърво" -#: builtin/grep.c:642 +#: builtin/grep.c:640 msgid "find in contents not managed by git" msgstr "търсене и във файловете, които не са под управлението на git" -#: builtin/grep.c:644 +#: builtin/grep.c:642 msgid "search in both tracked and untracked files" msgstr "търсене и в следените, и в неследените файлове" -#: builtin/grep.c:646 +#: builtin/grep.c:644 msgid "search also in ignored files" msgstr "търсене и в игнорираните файлове" -#: builtin/grep.c:649 +#: builtin/grep.c:647 msgid "show non-matching lines" msgstr "извеждане на редовете, които не съвпадат" -#: builtin/grep.c:651 +#: builtin/grep.c:649 msgid "case insensitive matching" msgstr "без значение на регистъра на буквите (главни/малки)" -#: builtin/grep.c:653 +#: builtin/grep.c:651 msgid "match patterns only at word boundaries" msgstr "напасване на шаблоните само по границите на думите" -#: builtin/grep.c:655 +#: builtin/grep.c:653 msgid "process binary files as text" msgstr "обработване на двоичните файлове като текстови" -#: builtin/grep.c:657 +#: builtin/grep.c:655 msgid "don't match patterns in binary files" msgstr "прескачане на двоичните файлове" -#: builtin/grep.c:660 +#: builtin/grep.c:658 msgid "process binary files with textconv filters" msgstr "" "обработване на двоичните файлове чрез филтри за преобразуване към текст" -#: builtin/grep.c:662 +#: builtin/grep.c:660 msgid "descend at most levels" msgstr "навлизане максимално на тази ДЪЛБОЧИНА в дървото" -#: builtin/grep.c:666 +#: builtin/grep.c:664 msgid "use extended POSIX regular expressions" msgstr "разширени регулярни изрази по POSIX" -#: builtin/grep.c:669 +#: builtin/grep.c:667 msgid "use basic POSIX regular expressions (default)" msgstr "основни регулярни изрази по POSIX (стандартно)" -#: builtin/grep.c:672 +#: builtin/grep.c:670 msgid "interpret patterns as fixed strings" msgstr "шаблоните са дословни низове" -#: builtin/grep.c:675 +#: builtin/grep.c:673 msgid "use Perl-compatible regular expressions" msgstr "регулярни изрази на Perl" -#: builtin/grep.c:678 +#: builtin/grep.c:676 msgid "show line numbers" msgstr "извеждане на номерата на редовете" -#: builtin/grep.c:679 +#: builtin/grep.c:677 msgid "don't show filenames" msgstr "без извеждане на имената на файловете" -#: builtin/grep.c:680 +#: builtin/grep.c:678 msgid "show filenames" msgstr "извеждане на имената на файловете" -#: builtin/grep.c:682 +#: builtin/grep.c:680 msgid "show filenames relative to top directory" msgstr "" "извеждане на относителните имена на файловете спрямо основната директория на " "хранилището" -#: builtin/grep.c:684 +#: builtin/grep.c:682 msgid "show only filenames instead of matching lines" msgstr "извеждане само на имената на файловете без напасващите редове" -#: builtin/grep.c:686 +#: builtin/grep.c:684 msgid "synonym for --files-with-matches" msgstr "синоним на „--files-with-matches“" -#: builtin/grep.c:689 +#: builtin/grep.c:687 msgid "show only the names of files without match" msgstr "" "извеждане само на имената на файловете, които не съдържат ред, напасващ на " "шаблона" -#: builtin/grep.c:691 +#: builtin/grep.c:689 msgid "print NUL after filenames" msgstr "извеждане на нулевия знак „NUL“ след всяко име на файл" -#: builtin/grep.c:693 +#: builtin/grep.c:691 msgid "show the number of matches instead of matching lines" msgstr "извеждане на броя на съвпаденията вместо напасващите редове" -#: builtin/grep.c:694 +#: builtin/grep.c:692 msgid "highlight matches" msgstr "оцветяване на напасванията" -#: builtin/grep.c:696 +#: builtin/grep.c:694 msgid "print empty line between matches from different files" msgstr "извеждане на празен ред между напасванията от различни файлове" -#: builtin/grep.c:698 +#: builtin/grep.c:696 msgid "show filename only once above matches from same file" msgstr "" "извеждане на името на файла само веднъж за всички напасвания от този файл" -#: builtin/grep.c:701 +#: builtin/grep.c:699 msgid "show context lines before and after matches" msgstr "извеждане на такъв БРОЙ редове преди и след напасванията" -#: builtin/grep.c:704 +#: builtin/grep.c:702 msgid "show context lines before matches" msgstr "извеждане на такъв БРОЙ редове преди напасванията" -#: builtin/grep.c:706 +#: builtin/grep.c:704 msgid "show context lines after matches" msgstr "извеждане на такъв БРОЙ редове след напасванията" -#: builtin/grep.c:707 +#: builtin/grep.c:705 msgid "shortcut for -C NUM" msgstr "синоним на „-C БРОЙ“" -#: builtin/grep.c:710 +#: builtin/grep.c:708 msgid "show a line with the function name before matches" msgstr "извеждане на ред с името на функцията, в която е напаснат шаблона" -#: builtin/grep.c:712 +#: builtin/grep.c:710 msgid "show the surrounding function" msgstr "извеждане на обхващащата функция" -#: builtin/grep.c:715 +#: builtin/grep.c:713 msgid "read patterns from file" msgstr "изчитане на шаблоните от файл" -#: builtin/grep.c:717 +#: builtin/grep.c:715 msgid "match " msgstr "напасване на ШАБЛОН" -#: builtin/grep.c:719 +#: builtin/grep.c:717 msgid "combine patterns specified with -e" msgstr "комбиниране на шаблоните указани с опцията „-e“" -#: builtin/grep.c:731 +#: builtin/grep.c:729 msgid "indicate hit with exit status without output" msgstr "" "без извеждане на стандартния изход. Изходният код указва наличието на " "напасване" -#: builtin/grep.c:733 +#: builtin/grep.c:731 msgid "show only matches from files that match all patterns" msgstr "" "извеждане на редове само от файловете, които напасват на всички шаблони" -#: builtin/grep.c:735 +#: builtin/grep.c:733 msgid "show parse tree for grep expression" msgstr "извеждане на дървото за анализ на регулярния израз" -#: builtin/grep.c:739 +#: builtin/grep.c:737 msgid "pager" -msgstr "програма за обхождане" +msgstr "програма за преглед по страници" -#: builtin/grep.c:739 +#: builtin/grep.c:737 msgid "show matching files in the pager" -msgstr "извеждане на съвпадащите файлове в програма за обхождане" +msgstr "извеждане на съвпадащите файлове в програма за преглед по страници" -#: builtin/grep.c:742 +#: builtin/grep.c:740 msgid "allow calling of grep(1) (ignored by this build)" msgstr "" "позволяване на стартирането на grep(1) (текущият компилат пренебрегва тази " "опция)" -#: builtin/grep.c:743 builtin/show-ref.c:187 +#: builtin/grep.c:741 builtin/show-ref.c:187 msgid "show usage" msgstr "извеждане на начина на употреба на командата" -#: builtin/grep.c:810 +#: builtin/grep.c:808 msgid "no pattern given." msgstr "липсва шаблон." -#: builtin/grep.c:868 +#: builtin/grep.c:866 msgid "--open-files-in-pager only works on the worktree" msgstr "" "опцията „--open-files-in-pager“ е съвместима само с търсене в работното дърво" -#: builtin/grep.c:891 +#: builtin/grep.c:892 msgid "--cached or --untracked cannot be used with --no-index." msgstr "опциите „--cached“ и „--untracked“ са несъвместими с „--no-index“." -#: builtin/grep.c:896 +#: builtin/grep.c:897 msgid "--no-index or --untracked cannot be used with revs." msgstr "" "опциите „--cached“ и „--untracked“ са несъвместими с търсене във версии." -#: builtin/grep.c:899 +#: builtin/grep.c:900 msgid "--[no-]exclude-standard cannot be used for tracked contents." msgstr "" "опциите „--(no-)exclude-standard“ са несъвместими с търсене по следени " "файлове." -#: builtin/grep.c:907 +#: builtin/grep.c:908 msgid "both --cached and trees are given." msgstr "опцията „--cached“ е несъвместима със задаване на дърво." @@ -5765,34 +5945,36 @@ msgid "" "git hash-object [-t ] [-w] [--path=|--no-filters] [--stdin] [--] " "..." msgstr "" +"git hash-object [-t ВИД] [-w] [--path=ФАЙЛ|--no-filters] [--stdin] [--] ФАЙЛ…" +# FIXME - list of paths or path... #: builtin/hash-object.c:61 msgid "git hash-object --stdin-paths < " -msgstr "" +msgstr "git hash-object --stdin-paths < ПЪТ…" -#: builtin/hash-object.c:72 builtin/tag.c:521 +#: builtin/hash-object.c:72 builtin/tag.c:609 msgid "type" -msgstr "" +msgstr "ВИД" #: builtin/hash-object.c:72 msgid "object type" -msgstr "" +msgstr "вид на обекта" #: builtin/hash-object.c:73 msgid "write the object into the object database" -msgstr "" +msgstr "записване на обекта в базата от данни за обектите" #: builtin/hash-object.c:74 msgid "read the object from stdin" -msgstr "" +msgstr "изчитане на обекта от стандартния вход" #: builtin/hash-object.c:76 msgid "store file as is without filters" -msgstr "" +msgstr "запазване на файла както е — без филтри" #: builtin/hash-object.c:77 msgid "process file as it were from this path" -msgstr "" +msgstr "обработване на файла все едно е с този път" #: builtin/help.c:41 msgid "print all available commands" @@ -5847,7 +6029,7 @@ msgid "" "'%s': path for unsupported man viewer.\n" "Please consider using 'man..cmd' instead." msgstr "" -"„%s“: път към неподдържана програма за разглеждане на\n" +"„%s“: път към неподдържана програма за преглед на\n" " ръководството. Вместо нея пробвайте „man..cmd“." #: builtin/help.c:228 @@ -5856,7 +6038,7 @@ msgid "" "'%s': cmd for supported man viewer.\n" "Please consider using 'man..path' instead." msgstr "" -"„%s“: команда за поддържана програма за разглеждане на\n" +"„%s“: команда за поддържана програма за преглед на\n" " ръководството. Вместо нея пробвайте „man..path“." #: builtin/help.c:353 @@ -5866,11 +6048,13 @@ msgstr "„%s“: непозната програма за преглед на #: builtin/help.c:370 msgid "no man viewer handled the request" -msgstr "никоя програма за ръководство не успя да обработи заявката" +msgstr "никоя програма за преглед на ръководство не успя да обработи заявката" #: builtin/help.c:378 msgid "no info viewer handled the request" -msgstr "никоя програма за информационни страници не успя да обработи заявката" +msgstr "" +"никоя програма за преглед на информационните страници не успя да обработи " +"заявката" #: builtin/help.c:424 msgid "Defining attributes per path" @@ -5914,367 +6098,394 @@ msgstr "употреба: %s%s" msgid "`git %s' is aliased to `%s'" msgstr "„git %s“ е синоним на „%s“" -#: builtin/index-pack.c:184 +# FIXME merge with next? +#: builtin/index-pack.c:145 #, c-format -msgid "object type mismatch at %s" -msgstr "" +msgid "unable to open %s" +msgstr "обектът „%s“ не може да бъде отворен" -#: builtin/index-pack.c:204 -msgid "object of unexpected type" -msgstr "" +#: builtin/index-pack.c:191 +#, c-format +msgid "object type mismatch at %s" +msgstr "неправилен вид на обекта „%s“" + +#: builtin/index-pack.c:211 +#, c-format +msgid "did not receive expected object %s" +msgstr "очакваният обект „%s“ не бе получен" + +#: builtin/index-pack.c:214 +#, c-format +msgid "object %s: expected type %s, found %s" +msgstr "неправилен вид на обекта „%s“: очакваше се „%s“, а бе получен „%s“" -#: builtin/index-pack.c:244 +#: builtin/index-pack.c:256 #, c-format msgid "cannot fill %d byte" msgid_plural "cannot fill %d bytes" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "не може да се запълни %d байт" +msgstr[1] "не може да се запълнят %d байта" -#: builtin/index-pack.c:254 +#: builtin/index-pack.c:266 msgid "early EOF" -msgstr "" +msgstr "неочакван край на файл" -#: builtin/index-pack.c:255 +#: builtin/index-pack.c:267 msgid "read error on input" -msgstr "" +msgstr "грешка при четене на входните данни" -#: builtin/index-pack.c:267 +#: builtin/index-pack.c:279 msgid "used more bytes than were available" -msgstr "" +msgstr "използвани са повече от наличните байтове" -#: builtin/index-pack.c:274 +#: builtin/index-pack.c:286 msgid "pack too large for current definition of off_t" -msgstr "" +msgstr "пакетният файл е прекалено голям за текущата стойност на типа „off_t“" -#: builtin/index-pack.c:290 +#: builtin/index-pack.c:302 #, c-format msgid "unable to create '%s'" -msgstr "" +msgstr "пакетният файл „%s“ не може да бъде създаден" -#: builtin/index-pack.c:295 +#: builtin/index-pack.c:307 #, c-format msgid "cannot open packfile '%s'" -msgstr "" +msgstr "пакетният файл „%s“ не може да бъде отворен" -#: builtin/index-pack.c:309 +#: builtin/index-pack.c:321 msgid "pack signature mismatch" -msgstr "" +msgstr "несъответствие в подписа към пакетния файл" -#: builtin/index-pack.c:311 +#: builtin/index-pack.c:323 #, c-format msgid "pack version % unsupported" -msgstr "" +msgstr "не се поддържа пакетиране вeрсия „%“" -#: builtin/index-pack.c:329 +#: builtin/index-pack.c:341 #, c-format msgid "pack has bad object at offset %lu: %s" -msgstr "" +msgstr "повреден обект в пакетния файл при отместване %lu: %s" -#: builtin/index-pack.c:451 +#: builtin/index-pack.c:462 #, c-format msgid "inflate returned %d" -msgstr "" +msgstr "декомпресирането с „inflate“ върна %d" -#: builtin/index-pack.c:500 +#: builtin/index-pack.c:511 msgid "offset value overflow for delta base object" -msgstr "" +msgstr "стойността на отместването за обекта-разлика води до препълване" -#: builtin/index-pack.c:508 +#: builtin/index-pack.c:519 msgid "delta base offset is out of bound" -msgstr "" +msgstr "стойността на отместването за обекта-разлика е извън диапазона" -#: builtin/index-pack.c:516 +#: builtin/index-pack.c:527 #, c-format msgid "unknown object type %d" -msgstr "" +msgstr "непознат вид обект %d" -#: builtin/index-pack.c:547 +#: builtin/index-pack.c:558 msgid "cannot pread pack file" -msgstr "" +msgstr "пакетният файл не може да бъде прочетен" -#: builtin/index-pack.c:549 +#: builtin/index-pack.c:560 #, c-format msgid "premature end of pack file, %lu byte missing" msgid_plural "premature end of pack file, %lu bytes missing" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "неочакван край на файл, липсва %lu байт" +msgstr[1] "неочакван край на файл, липсват %lu байта" -#: builtin/index-pack.c:575 +#: builtin/index-pack.c:586 msgid "serious inflate inconsistency" -msgstr "" +msgstr "сериозна грешка при декомпресиране с „inflate“" -#: builtin/index-pack.c:666 builtin/index-pack.c:672 builtin/index-pack.c:695 -#: builtin/index-pack.c:729 builtin/index-pack.c:738 +#: builtin/index-pack.c:677 builtin/index-pack.c:683 builtin/index-pack.c:706 +#: builtin/index-pack.c:740 builtin/index-pack.c:749 #, c-format msgid "SHA1 COLLISION FOUND WITH %s !" msgstr "" +"СЪВПАДЕНИЕ НА СТОЙНОСТИТЕ ЗА СУМИТЕ ЗА SHA1: „%s“ НА ДВА РАЗЛИЧНИ ОБЕКТА!" -#: builtin/index-pack.c:669 builtin/pack-objects.c:162 +# FIXME merge with next? +#: builtin/index-pack.c:680 builtin/pack-objects.c:162 #: builtin/pack-objects.c:254 #, c-format msgid "unable to read %s" -msgstr "" +msgstr "обектът „%s“ не може да бъде прочетен" -#: builtin/index-pack.c:735 +#: builtin/index-pack.c:746 #, c-format msgid "cannot read existing object %s" -msgstr "" +msgstr "съществуващият обект „%s“ не може да бъде прочетен" -#: builtin/index-pack.c:749 +#: builtin/index-pack.c:760 #, c-format msgid "invalid blob object %s" -msgstr "" +msgstr "неправилен обект BLOB „%s“" -#: builtin/index-pack.c:763 +# FIXME perhaps invalid object +#: builtin/index-pack.c:774 #, c-format msgid "invalid %s" -msgstr "" +msgstr "неправилен обект „%s“" -#: builtin/index-pack.c:766 +#: builtin/index-pack.c:777 msgid "Error in object" -msgstr "" +msgstr "Грешка в обекта" -#: builtin/index-pack.c:768 +#: builtin/index-pack.c:779 #, c-format msgid "Not all child objects of %s are reachable" -msgstr "" +msgstr "Някои обекти, наследници на „%s“, не могат да бъдат достигнати" -#: builtin/index-pack.c:839 builtin/index-pack.c:869 +#: builtin/index-pack.c:851 builtin/index-pack.c:881 msgid "failed to apply delta" -msgstr "" +msgstr "разликата не може да бъде приложена" -#: builtin/index-pack.c:1010 +#: builtin/index-pack.c:1022 msgid "Receiving objects" -msgstr "" +msgstr "Получаване на обекти" -#: builtin/index-pack.c:1010 +#: builtin/index-pack.c:1022 msgid "Indexing objects" -msgstr "" +msgstr "Индексиране на обекти" -#: builtin/index-pack.c:1036 +#: builtin/index-pack.c:1048 msgid "pack is corrupted (SHA1 mismatch)" -msgstr "" +msgstr "пакетният файл е повреден (нееднакви суми по SHA1)" -#: builtin/index-pack.c:1041 +#: builtin/index-pack.c:1053 msgid "cannot fstat packfile" -msgstr "" +msgstr "не може да се получи информация за пакетния файл с „fstat“" -#: builtin/index-pack.c:1044 +#: builtin/index-pack.c:1056 msgid "pack has junk at the end" -msgstr "" +msgstr "в края на пакетния файл има повредени данни" -#: builtin/index-pack.c:1055 +# FIXME WTF message +#: builtin/index-pack.c:1067 msgid "confusion beyond insanity in parse_pack_objects()" -msgstr "" +msgstr "катастрофална грешка във функцията „parse_pack_objects“" -#: builtin/index-pack.c:1078 +#: builtin/index-pack.c:1090 msgid "Resolving deltas" -msgstr "" +msgstr "Откриване на съответните разлики" -#: builtin/index-pack.c:1088 +#: builtin/index-pack.c:1100 #, c-format msgid "unable to create thread: %s" -msgstr "" +msgstr "не може да се създаде нишка: %s" -#: builtin/index-pack.c:1130 +# FIXME WTF message +#: builtin/index-pack.c:1142 msgid "confusion beyond insanity" -msgstr "" +msgstr "катастрофална грешка" -#: builtin/index-pack.c:1138 +#: builtin/index-pack.c:1150 #, c-format msgid "completed with %d local objects" -msgstr "" +msgstr "действието завърши с %d локални обекта" -#: builtin/index-pack.c:1148 +#: builtin/index-pack.c:1160 #, c-format msgid "Unexpected tail checksum for %s (disk corruption?)" msgstr "" +"Неочаквана последваща сума за грешки за „%s“ (причината може да е грешка в " +"диска)" -#: builtin/index-pack.c:1152 +#: builtin/index-pack.c:1164 #, c-format msgid "pack has %d unresolved delta" msgid_plural "pack has %d unresolved deltas" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "в пакета има %d ненапасваща разлика" +msgstr[1] "в пакета има %d ненапасващи разлики" -#: builtin/index-pack.c:1177 +#: builtin/index-pack.c:1189 #, c-format msgid "unable to deflate appended object (%d)" -msgstr "" +msgstr "добавеният обект не може да се компресира с „deflate“: %d" -#: builtin/index-pack.c:1256 +#: builtin/index-pack.c:1268 #, c-format msgid "local object %s is corrupt" -msgstr "" +msgstr "локалният обект „%s“ е повреден" -#: builtin/index-pack.c:1280 +#: builtin/index-pack.c:1292 msgid "error while closing pack file" -msgstr "" +msgstr "грешка при затварянето на пакетния файл" -#: builtin/index-pack.c:1293 +#: builtin/index-pack.c:1305 #, c-format msgid "cannot write keep file '%s'" msgstr "" +"грешка при записването на файла „%s“, осигуряващ запазване на директория" -#: builtin/index-pack.c:1301 +#: builtin/index-pack.c:1313 #, c-format msgid "cannot close written keep file '%s'" msgstr "" +"грешка при затварянето на записания файл „%s“, осигуряващ запазване на " +"директория" -#: builtin/index-pack.c:1314 +#: builtin/index-pack.c:1326 msgid "cannot store pack file" -msgstr "" +msgstr "пакетният файл не може да бъде запазен" -#: builtin/index-pack.c:1325 +#: builtin/index-pack.c:1337 msgid "cannot store index file" msgstr "файлът за индекса не може да бъде съхранен" -#: builtin/index-pack.c:1358 +#: builtin/index-pack.c:1370 #, c-format msgid "bad pack.indexversion=%" -msgstr "" +msgstr "зададена е неправилна версия пакетиране: „pack.indexversion=%“" -#: builtin/index-pack.c:1364 +#: builtin/index-pack.c:1376 #, c-format msgid "invalid number of threads specified (%d)" -msgstr "" +msgstr "зададен е неправилен брой нишки: %d" -#: builtin/index-pack.c:1368 builtin/index-pack.c:1546 +#: builtin/index-pack.c:1380 builtin/index-pack.c:1559 #, c-format msgid "no threads support, ignoring %s" -msgstr "" +msgstr "липсва поддръжка за нишки. „%s“ ще се пренебрегне" -#: builtin/index-pack.c:1426 +#: builtin/index-pack.c:1438 #, c-format msgid "Cannot open existing pack file '%s'" -msgstr "" +msgstr "Съществуващият пакетен файл „%s“ не може да бъде отворен" -#: builtin/index-pack.c:1428 +#: builtin/index-pack.c:1440 #, c-format msgid "Cannot open existing pack idx file for '%s'" -msgstr "" +msgstr "Съществуващият индекс за пакетния файл „%s“ не може да бъде отворен" -#: builtin/index-pack.c:1475 +#: builtin/index-pack.c:1487 #, c-format msgid "non delta: %d object" msgid_plural "non delta: %d objects" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d обект не е разлика" +msgstr[1] "%d обекта не са разлика" -#: builtin/index-pack.c:1482 +#: builtin/index-pack.c:1494 #, c-format msgid "chain length = %d: %lu object" msgid_plural "chain length = %d: %lu objects" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "дължината на веригата е %d: %lu обект" +msgstr[1] "дължината на веригата е %d: %lu обекта" -#: builtin/index-pack.c:1510 +# FIXME it is not the cwd it is the previous cwd +#: builtin/index-pack.c:1523 msgid "Cannot come back to cwd" -msgstr "" +msgstr "Процесът не може да се върне към предишната работна директория" -#: builtin/index-pack.c:1558 builtin/index-pack.c:1561 -#: builtin/index-pack.c:1573 builtin/index-pack.c:1577 +#: builtin/index-pack.c:1571 builtin/index-pack.c:1574 +#: builtin/index-pack.c:1586 builtin/index-pack.c:1590 #, c-format msgid "bad %s" -msgstr "" +msgstr "неправилна стойност „%s“" -#: builtin/index-pack.c:1591 +#: builtin/index-pack.c:1604 msgid "--fix-thin cannot be used without --stdin" -msgstr "" +msgstr "опцията „--fix-thin“ изисква „--stdin“" -#: builtin/index-pack.c:1595 builtin/index-pack.c:1605 +#: builtin/index-pack.c:1608 builtin/index-pack.c:1617 #, c-format msgid "packfile name '%s' does not end with '.pack'" -msgstr "" +msgstr "името на пакетния файл „%s“ не завършва на „.pack“" -#: builtin/index-pack.c:1614 +#: builtin/index-pack.c:1625 msgid "--verify with no packfile name given" -msgstr "" +msgstr "опцията „--verify“ изисква име на пакетен файл" #: builtin/init-db.c:35 #, c-format msgid "Could not make %s writable by group" -msgstr "" +msgstr "Не могат да се дадат права за запис в директорията „%s“ на групата" +# FIXME - bad wording insanely #: builtin/init-db.c:62 #, c-format msgid "insanely long template name %s" -msgstr "" +msgstr "твърде дълго име на шаблон: „%s“" #: builtin/init-db.c:67 #, c-format msgid "cannot stat '%s'" -msgstr "" +msgstr "не може да се получи информация чрез „stat“ за директорията „%s“" #: builtin/init-db.c:73 #, c-format msgid "cannot stat template '%s'" -msgstr "" +msgstr "не може да се получи информация чрез „stat“ за шаблона „%s“" #: builtin/init-db.c:80 #, c-format msgid "cannot opendir '%s'" -msgstr "" +msgstr "директорията „%s“ не може да бъде отворена" #: builtin/init-db.c:97 #, c-format msgid "cannot readlink '%s'" -msgstr "" +msgstr "връзката „%s“ не може да бъде прочетена" +# FIXME - bad wording insanely #: builtin/init-db.c:99 #, c-format msgid "insanely long symlink %s" -msgstr "" +msgstr "твърде дълго име на символна връзка: „%s“" #: builtin/init-db.c:102 #, c-format msgid "cannot symlink '%s' '%s'" -msgstr "" +msgstr "не може да се създаде символна връзка „%s“ в „%s“" #: builtin/init-db.c:106 #, c-format msgid "cannot copy '%s' to '%s'" -msgstr "" +msgstr "„%s“ не може да се копира в „%s“" #: builtin/init-db.c:110 #, c-format msgid "ignoring template %s" -msgstr "" +msgstr "игнориране на шаблона „%s“" +# FIXME bad word insanely #: builtin/init-db.c:133 #, c-format msgid "insanely long template path %s" -msgstr "" +msgstr "твърде дълъг път към шаблон: „%s“" #: builtin/init-db.c:141 #, c-format msgid "templates not found %s" -msgstr "" +msgstr "директорията с шаблоните не е открита: „%s“" #: builtin/init-db.c:154 #, c-format msgid "not copying templates of a wrong format version %d from '%s'" msgstr "" +"шаблоните с неправилен номер на формата %d няма да бъдат копирани от „%s“" #: builtin/init-db.c:192 #, c-format msgid "insane git directory %s" -msgstr "" +msgstr "твърде дълго име на директория на Git: „%s“" #: builtin/init-db.c:323 builtin/init-db.c:326 #, c-format msgid "%s already exists" -msgstr "" +msgstr "Директорията „%s“ вече съществува" #: builtin/init-db.c:355 #, c-format msgid "unable to handle file type %d" -msgstr "" +msgstr "файлове от вид %d не се поддържат" #: builtin/init-db.c:358 #, c-format msgid "unable to move %s to %s" -msgstr "" +msgstr "„%s“ не може да се премести в „%s“" #. TRANSLATORS: The first '%s' is either "Reinitialized #. existing" or "Initialized empty", the second " shared" or @@ -6282,51 +6493,55 @@ msgstr "" #: builtin/init-db.c:418 #, c-format msgid "%s%s Git repository in %s%s\n" -msgstr "" +msgstr "%s%s хранилище на Git в „%s%s“\n" #: builtin/init-db.c:419 msgid "Reinitialized existing" -msgstr "" +msgstr "Наново инициализирано, съществуващо" #: builtin/init-db.c:419 msgid "Initialized empty" -msgstr "" +msgstr "Инициализирано празно" #: builtin/init-db.c:420 msgid " shared" -msgstr "" +msgstr ", споделено" #: builtin/init-db.c:439 msgid "cannot tell cwd" -msgstr "" +msgstr "текущата директория не може да бъде определена" #: builtin/init-db.c:465 msgid "" "git init [-q | --quiet] [--bare] [--template=] [--" "shared[=]] [directory]" msgstr "" +"git init [-q | --quiet] [--bare] [--template=ДИРЕКТОРИЯ_С_ШАБЛОНИ] [--" +"shared[=ПРАВА]] [ДИРЕКТОРИЯ]" #: builtin/init-db.c:488 msgid "permissions" -msgstr "" +msgstr "права" #: builtin/init-db.c:489 msgid "specify that the git repository is to be shared amongst several users" msgstr "" +"указване, че хранилището на Git ще бъде споделено от повече от един " +"потребител" -#: builtin/init-db.c:491 builtin/prune-packed.c:79 builtin/repack.c:168 +#: builtin/init-db.c:491 builtin/prune-packed.c:79 builtin/repack.c:172 msgid "be quiet" msgstr "без извеждане на информация" #: builtin/init-db.c:523 builtin/init-db.c:528 #, c-format msgid "cannot mkdir %s" -msgstr "" +msgstr "директорията „%s“ не може да бъде създадена" #: builtin/init-db.c:532 #, c-format msgid "cannot chdir to %s" -msgstr "" +msgstr "не може да се влезе в директорията „%s“" #: builtin/init-db.c:554 #, c-format @@ -6334,58 +6549,60 @@ msgid "" "%s (or --work-tree=) not allowed without specifying %s (or --git-" "dir=)" msgstr "" +"%s (или --work-tree=ДИРЕКТОРИЯ) изисква указването на %s (или --git-" +"dir=ДИРЕКТОРИЯ)" #: builtin/init-db.c:578 msgid "Cannot access current working directory" -msgstr "" +msgstr "Текущата работна директория е недостъпна" #: builtin/init-db.c:585 #, c-format msgid "Cannot access work tree '%s'" -msgstr "" +msgstr "Работното дърво в „%s“ е недостъпно" #: builtin/log.c:41 msgid "git log [] [] [[--] ...]\n" -msgstr "git log [ОПЦИИ] [ДИАПАЗОН_НА_ВЕРСИИТЕ] [[--] ПЪТ…]\n" +msgstr "git log [ОПЦИЯ…] [ДИАПАЗОН_НА_ВЕРСИИТЕ] [[--] ПЪТ…]\n" #: builtin/log.c:42 msgid " or: git show [options] ..." -msgstr " или: git show [ОПЦИИ] ОБЕКТ…" +msgstr " или: git show [ОПЦИЯ…] ОБЕКТ…" -#: builtin/log.c:125 +#: builtin/log.c:127 msgid "suppress diff output" msgstr "без извеждане на разликите" -#: builtin/log.c:126 +#: builtin/log.c:128 msgid "show source" msgstr "извеждане на изходния код" -#: builtin/log.c:127 +#: builtin/log.c:129 msgid "Use mail map file" msgstr "" "Използване на файл за съответствията на имената и адресите на е-поща („." "mailmap“)" -#: builtin/log.c:128 +#: builtin/log.c:130 msgid "decorate options" msgstr "настройки на форма̀та на извежданата информация" -#: builtin/log.c:231 +#: builtin/log.c:229 #, c-format msgid "Final output: %d %s\n" msgstr "Резултат: %d %s\n" -#: builtin/log.c:473 builtin/log.c:565 +#: builtin/log.c:470 builtin/log.c:562 #, c-format msgid "Could not read object %s" msgstr "Обектът не може да бъде прочетен: %s" -#: builtin/log.c:589 +#: builtin/log.c:586 #, c-format msgid "Unknown type: %d" msgstr "Неизвестен вид: %d" -#: builtin/log.c:689 +#: builtin/log.c:687 msgid "format.headers without value" msgstr "не е зададена стойност на „format.headers“" @@ -6406,204 +6623,214 @@ msgstr "Трябва да зададете точно един диапазон. msgid "Not a range." msgstr "Не е диапазон." -#: builtin/log.c:911 +#: builtin/log.c:916 msgid "Cover letter needs email format" msgstr "Придружаващото писмо трябва да е форматирано като е-писмо" -#: builtin/log.c:987 +# FIXME bad wording insanely +#: builtin/log.c:995 #, c-format msgid "insane in-reply-to: %s" msgstr "неправилен формат на заглавната част за отговор „in-reply-to“: %s" -#: builtin/log.c:1015 +#: builtin/log.c:1023 msgid "git format-patch [options] [ | ]" -msgstr "git format-patch [ОПЦИИ] [ОТ | ДИАПАЗОН_НА_ВЕРСИИТЕ]" +msgstr "git format-patch [ОПЦИЯ…] [ОТ | ДИАПАЗОН_НА_ВЕРСИИТЕ]" -# FIXME message -#: builtin/log.c:1060 +# FIXME message WTF why ask it +#: builtin/log.c:1068 msgid "Two output directories?" msgstr "" "Можете да укажете максимум една директория за изход, а сте задали поне две." -#: builtin/log.c:1175 +#: builtin/log.c:1183 msgid "use [PATCH n/m] even with a single patch" msgstr "номерация „[PATCH n/m]“ дори и при единствена кръпка" -#: builtin/log.c:1178 +#: builtin/log.c:1186 msgid "use [PATCH] even with multiple patches" msgstr "номерация „[PATCH]“ дори и при множество кръпки" -#: builtin/log.c:1182 +#: builtin/log.c:1190 msgid "print patches to standard out" msgstr "извеждане на кръпките на стандартния изход" -#: builtin/log.c:1184 +#: builtin/log.c:1192 msgid "generate a cover letter" msgstr "създаване на придружаващо писмо" -#: builtin/log.c:1186 +#: builtin/log.c:1194 msgid "use simple number sequence for output file names" msgstr "проста числова последователност за имената на файловете-кръпки" -#: builtin/log.c:1187 +#: builtin/log.c:1195 msgid "sfx" msgstr "ЗНАЦИ" -#: builtin/log.c:1188 +#: builtin/log.c:1196 msgid "use instead of '.patch'" msgstr "използване на тези ЗНАЦИ за суфикс вместо „.patch“" -#: builtin/log.c:1190 +#: builtin/log.c:1198 msgid "start numbering patches at instead of 1" msgstr "номерирането на кръпките да започва от този БРОЙ, а не с 1" -#: builtin/log.c:1192 +#: builtin/log.c:1200 msgid "mark the series as Nth re-roll" msgstr "отбелязване, че това е N-тата поредна редакция на поредицата от кръпки" -#: builtin/log.c:1194 +#: builtin/log.c:1202 msgid "Use [] instead of [PATCH]" msgstr "Използване на този „[ПРЕФИКС]“ вместо „[PATCH]“" -#: builtin/log.c:1197 +#: builtin/log.c:1205 msgid "store resulting files in " msgstr "запазване на изходните файлове в тази ДИРЕКТОРИЯ" -#: builtin/log.c:1200 +#: builtin/log.c:1208 msgid "don't strip/add [PATCH]" msgstr "без добавяне/махане на префикса „[PATCH]“" -#: builtin/log.c:1203 +#: builtin/log.c:1211 msgid "don't output binary diffs" msgstr "без извеждане на разлики между двоични файлове" -#: builtin/log.c:1205 +#: builtin/log.c:1213 msgid "don't include a patch matching a commit upstream" msgstr "да не се включват кръпки, които присъстват в следения клон" -#: builtin/log.c:1207 +#: builtin/log.c:1215 msgid "show patch format instead of default (patch + stat)" msgstr "" "извеждане във формат за кръпки, а на в стандартния (кръпка и статистика)" -#: builtin/log.c:1209 +#: builtin/log.c:1217 msgid "Messaging" msgstr "Опции при изпращане" -#: builtin/log.c:1210 +#: builtin/log.c:1218 msgid "header" msgstr "ЗАГЛАВНА_ЧАСТ" -#: builtin/log.c:1211 +#: builtin/log.c:1219 msgid "add email header" msgstr "добавяне на тази ЗАГЛАВНА_ЧАСТ" -#: builtin/log.c:1212 builtin/log.c:1214 +#: builtin/log.c:1220 builtin/log.c:1222 msgid "email" msgstr "Е-ПОЩА" -#: builtin/log.c:1212 +#: builtin/log.c:1220 msgid "add To: header" msgstr "добавяне на заглавна част „To:“ (до)" -#: builtin/log.c:1214 +#: builtin/log.c:1222 msgid "add Cc: header" msgstr "добавяне на заглавна част „Cc:“ (и до)" -#: builtin/log.c:1216 +#: builtin/log.c:1224 msgid "ident" msgstr "ИДЕНТИЧНОСТ" -#: builtin/log.c:1217 +#: builtin/log.c:1225 msgid "set From address to (or committer ident if absent)" msgstr "" "задаване на адреса в заглавната част „From“ да е тази ИДЕНТИЧНОСТ. Ако не е " "зададена такава, се взима адреса на подаващия" -#: builtin/log.c:1219 +#: builtin/log.c:1227 msgid "message-id" msgstr "ИДЕНТИФИКАТОР_НА_СЪОБЩЕНИЕ" -#: builtin/log.c:1220 +#: builtin/log.c:1228 msgid "make first mail a reply to " msgstr "" "първото съобщение да е в отговор на е-писмото с този " "ИДЕНТИФИКАТОР_НА_СЪОБЩЕНИЕ" -#: builtin/log.c:1221 builtin/log.c:1224 +#: builtin/log.c:1229 builtin/log.c:1232 msgid "boundary" msgstr "граница" -#: builtin/log.c:1222 +#: builtin/log.c:1230 msgid "attach the patch" msgstr "прикрепяне на кръпката" -#: builtin/log.c:1225 +#: builtin/log.c:1233 msgid "inline the patch" msgstr "включване на кръпката в текста на писмата" -#: builtin/log.c:1229 +#: builtin/log.c:1237 msgid "enable message threading, styles: shallow, deep" msgstr "" "използване на нишки за съобщенията. Стилът е „shallow“ (плитък) или " "„deep“ (дълбок)" -#: builtin/log.c:1231 +#: builtin/log.c:1239 msgid "signature" msgstr "подпис" -#: builtin/log.c:1232 +#: builtin/log.c:1240 msgid "add a signature" msgstr "добавяне на поле за подпис" -#: builtin/log.c:1233 +#: builtin/log.c:1242 +msgid "add a signature from a file" +msgstr "добавяне на подпис от файл" + +#: builtin/log.c:1243 msgid "don't print the patch filenames" msgstr "без извеждане на имената на кръпките" -#: builtin/log.c:1307 +#: builtin/log.c:1317 #, c-format msgid "invalid ident line: %s" msgstr "грешна идентичност: %s" -#: builtin/log.c:1322 +#: builtin/log.c:1332 msgid "-n and -k are mutually exclusive." msgstr "опциите „-n“ и „-k“ са несъвместими." -#: builtin/log.c:1324 +#: builtin/log.c:1334 msgid "--subject-prefix and -k are mutually exclusive." msgstr "опциите „--subject-prefix“ и „-k“ са несъвместими." -#: builtin/log.c:1332 +#: builtin/log.c:1342 msgid "--name-only does not make sense" msgstr "опцията „--name-only“ е несъвместима с генерирането на кръпки" -#: builtin/log.c:1334 +#: builtin/log.c:1344 msgid "--name-status does not make sense" msgstr "опцията „--name-status“ е несъвместима с генерирането на кръпки" -#: builtin/log.c:1336 +#: builtin/log.c:1346 msgid "--check does not make sense" msgstr "опцията „--check“ е несъвместима с генерирането на кръпки" -#: builtin/log.c:1359 +#: builtin/log.c:1369 msgid "standard output, or directory, which one?" msgstr "" "изходът може да или стандартният, или да е в директория, но не и двете." -#: builtin/log.c:1361 +#: builtin/log.c:1371 #, c-format msgid "Could not create directory '%s'" -msgstr "Папката „%s“ не може да бъде създадена" +msgstr "Директорията „%s“ не може да бъде създадена" -#: builtin/log.c:1509 +#: builtin/log.c:1468 +#, c-format +msgid "unable to read signature file '%s'" +msgstr "файлът „%s“ с подпис не може да бъде прочетен" + +#: builtin/log.c:1531 msgid "Failed to create output files" msgstr "Изходните файлове не могат да бъдат създадени" -#: builtin/log.c:1558 +#: builtin/log.c:1579 msgid "git cherry [-v] [ [ []]]" msgstr "git cherry [-v] [ОТДАЛЕЧЕН_КЛОН [ВРЪХ [ПРЕДЕЛ]]]" -#: builtin/log.c:1613 +#: builtin/log.c:1634 #, c-format msgid "" "Could not find a tracked remote branch, please specify manually.\n" @@ -6611,118 +6838,121 @@ msgstr "" "Следеният отдалечен клон не бе открит, затова изрично задайте " "ОТДАЛЕЧЕН_КЛОН.\n" -#: builtin/log.c:1626 builtin/log.c:1628 builtin/log.c:1640 +#: builtin/log.c:1647 builtin/log.c:1649 builtin/log.c:1661 #, c-format msgid "Unknown commit %s" msgstr "Непознато подаване „%s“" #: builtin/ls-files.c:401 msgid "git ls-files [options] [...]" -msgstr "" +msgstr "git ls-files [ОПЦИЯ…] [ФАЙЛ…]" #: builtin/ls-files.c:458 msgid "identify the file status with tags" -msgstr "" +msgstr "извеждане на състоянието на файловете с еднобуквени флагове" #: builtin/ls-files.c:460 msgid "use lowercase letters for 'assume unchanged' files" -msgstr "" +msgstr "малки букви за файловете, които да се счетат за непроменени" #: builtin/ls-files.c:462 msgid "show cached files in the output (default)" -msgstr "" +msgstr "извеждане на кешираните файлове (стандартно)" #: builtin/ls-files.c:464 msgid "show deleted files in the output" -msgstr "" +msgstr "извеждане на изтритите файлове" #: builtin/ls-files.c:466 msgid "show modified files in the output" -msgstr "" +msgstr "извеждане на променените файлове" #: builtin/ls-files.c:468 msgid "show other files in the output" -msgstr "" +msgstr "извеждане на другите файлове" #: builtin/ls-files.c:470 msgid "show ignored files in the output" -msgstr "" +msgstr "извеждане на игнорираните файлове" #: builtin/ls-files.c:473 msgid "show staged contents' object name in the output" -msgstr "" +msgstr "извеждане на името на обекта за съдържанието на индекса" #: builtin/ls-files.c:475 msgid "show files on the filesystem that need to be removed" -msgstr "" +msgstr "извеждане на файловете, които трябва да бъдат изтрити" #: builtin/ls-files.c:477 msgid "show 'other' directories' name only" -msgstr "" +msgstr "извеждане само на името на другите директории" #: builtin/ls-files.c:480 msgid "don't show empty directories" -msgstr "" +msgstr "без извеждане на празните директории" #: builtin/ls-files.c:483 msgid "show unmerged files in the output" -msgstr "" +msgstr "извеждане на неслетите файлове" +# FIXME not clear about what this option does #: builtin/ls-files.c:485 msgid "show resolve-undo information" -msgstr "" +msgstr "извеждане на информацията за отмяна на разрешените подавания" #: builtin/ls-files.c:487 msgid "skip files matching pattern" -msgstr "" +msgstr "прескачане на файловете напасващи ШАБЛОНа" #: builtin/ls-files.c:490 msgid "exclude patterns are read from " -msgstr "" +msgstr "шаблоните за игнориране да се прочетат от този ФАЙЛ" #: builtin/ls-files.c:493 msgid "read additional per-directory exclude patterns in " msgstr "" +"изчитане на допълнителните шаблони за игнориране по директория от този ФАЙЛ" #: builtin/ls-files.c:495 msgid "add the standard git exclusions" -msgstr "" +msgstr "добавяне на стандартно игнорираните от Git файлове" #: builtin/ls-files.c:498 msgid "make the output relative to the project top directory" -msgstr "" +msgstr "пътищата да са относителни спрямо основната директория на проекта" #: builtin/ls-files.c:501 msgid "if any is not in the index, treat this as an error" -msgstr "" +msgstr "грешка, ако някой от тези ФАЙЛове не е в индекса" #: builtin/ls-files.c:502 msgid "tree-ish" -msgstr "" +msgstr "УКАЗАТЕЛ_КЪМ_ДЪРВО" #: builtin/ls-files.c:503 msgid "pretend that paths removed since are still present" msgstr "" +"считане, че пътищата изтрити след УКАЗАТЕЛя_КЪМ_ДЪРВО все още съществуват" #: builtin/ls-files.c:505 msgid "show debugging data" -msgstr "" +msgstr "извеждане на информацията за изчистване на грешки" #: builtin/ls-tree.c:28 msgid "git ls-tree [] [...]" -msgstr "" +msgstr "git ls-tree [ОПЦИЯ…] УКАЗАТЕЛ_КЪМ_ДЪРВО [ПЪТ…]" #: builtin/ls-tree.c:126 msgid "only show trees" -msgstr "" +msgstr "извеждане само на дървета" #: builtin/ls-tree.c:128 msgid "recurse into subtrees" -msgstr "" +msgstr "рекурсивно обхождане поддърветата" #: builtin/ls-tree.c:130 msgid "show trees when recursing" -msgstr "" +msgstr "извеждане на дърветата при рекурсивното обхождане" #: builtin/ls-tree.c:133 msgid "terminate entries with NUL byte" @@ -6730,62 +6960,65 @@ msgstr "разделяне на обектите с нулевия знак „N #: builtin/ls-tree.c:134 msgid "include object size" -msgstr "" +msgstr "извеждане на размера на обекта" #: builtin/ls-tree.c:136 builtin/ls-tree.c:138 msgid "list only filenames" -msgstr "" +msgstr "извеждане само имената на файловете" #: builtin/ls-tree.c:141 msgid "use full path names" -msgstr "" +msgstr "използване на пълните имена на пътищата" #: builtin/ls-tree.c:143 msgid "list entire tree; not just current directory (implies --full-name)" msgstr "" +"извеждане на цялото дърво, не само на текущата директория (включва опцията " +"„--full-name“)" #: builtin/merge.c:43 msgid "git merge [options] [...]" -msgstr "" +msgstr "git merge [ОПЦИЯ…] [ПОДАВАНЕ…]" #: builtin/merge.c:44 msgid "git merge [options] HEAD " -msgstr "" +msgstr "git merge [ОПЦИЯ…] СЪОБЩЕНИЕ HEAD ПОДАВАНЕ" #: builtin/merge.c:45 msgid "git merge --abort" -msgstr "" +msgstr "git merge --abort" +# FIXME -m rather than just m #: builtin/merge.c:98 msgid "switch `m' requires a value" -msgstr "" +msgstr "опцията „-m“ изисква стойност" #: builtin/merge.c:135 #, c-format msgid "Could not find merge strategy '%s'.\n" -msgstr "" +msgstr "Няма такава стратегия за сливане: „%s“.\n" #: builtin/merge.c:136 #, c-format msgid "Available strategies are:" -msgstr "" +msgstr "Наличните стратегии са:" #: builtin/merge.c:141 #, c-format msgid "Available custom strategies are:" -msgstr "" +msgstr "Допълнителните стратегии са:" #: builtin/merge.c:191 msgid "do not show a diffstat at the end of the merge" -msgstr "" +msgstr "без извеждане на статистиката след завършване на сливане" #: builtin/merge.c:194 msgid "show a diffstat at the end of the merge" -msgstr "" +msgstr "извеждане на статистиката след завършване на сливане" #: builtin/merge.c:195 msgid "(synonym to --stat)" -msgstr "" +msgstr "(синоним на „--stat“)" #: builtin/merge.c:197 msgid "add (at most ) entries from shortlog to merge commit message" @@ -6795,27 +7028,27 @@ msgstr "" #: builtin/merge.c:200 msgid "create a single commit instead of doing a merge" -msgstr "" +msgstr "създаване на едно подаване вместо извършване на сливане" #: builtin/merge.c:202 msgid "perform a commit if the merge succeeds (default)" -msgstr "" +msgstr "извършване на подаване при успешно сливане (стандартно действие)" #: builtin/merge.c:204 msgid "edit message before committing" -msgstr "" +msgstr "редактиране на съобщението преди подаване" #: builtin/merge.c:205 msgid "allow fast-forward (default)" -msgstr "" +msgstr "позволяване на тривиално сливане (стандартно действие)" #: builtin/merge.c:207 msgid "abort if fast-forward is not possible" -msgstr "" +msgstr "преустановяване, ако сливането не е тривиално" #: builtin/merge.c:211 msgid "Verify that the named commit has a valid GPG signature" -msgstr "" +msgstr "Проверка, че именуваното подаване е с правилен подпис на GPG" #: builtin/merge.c:212 builtin/notes.c:742 builtin/revert.c:89 msgid "strategy" @@ -6823,102 +7056,105 @@ msgstr "стратегия" #: builtin/merge.c:213 msgid "merge strategy to use" -msgstr "" +msgstr "стратегия за сливане, която да се ползва" #: builtin/merge.c:214 msgid "option=value" -msgstr "" +msgstr "опция=стойност" #: builtin/merge.c:215 msgid "option for selected merge strategy" -msgstr "" +msgstr "опция за избраната стратегия за сливане" #: builtin/merge.c:217 msgid "merge commit message (for a non-fast-forward merge)" -msgstr "" +msgstr "съобщение при подаването със сливане (при нетривиални сливания)" #: builtin/merge.c:221 msgid "abort the current in-progress merge" -msgstr "" +msgstr "преустановяване на текущото сливане" #: builtin/merge.c:250 msgid "could not run stash." -msgstr "" +msgstr "не може да се извърши скатаване" #: builtin/merge.c:255 msgid "stash failed" -msgstr "" +msgstr "неуспешно скатаване" #: builtin/merge.c:260 #, c-format msgid "not a valid object: %s" -msgstr "" +msgstr "неправилен обект: „%s“" #: builtin/merge.c:279 builtin/merge.c:296 msgid "read-tree failed" -msgstr "" +msgstr "неуспешно прочитане на обект-дърво" #: builtin/merge.c:326 msgid " (nothing to squash)" -msgstr "" +msgstr " (няма какво да се смачка)" #: builtin/merge.c:339 #, c-format msgid "Squash commit -- not updating HEAD\n" -msgstr "" +msgstr "Подаване със смачкване — указателят „HEAD“ няма да бъде обновен\n" #: builtin/merge.c:371 msgid "Writing SQUASH_MSG" -msgstr "" +msgstr "Записване на съобщението за смачкване SQUASH_MSG" #: builtin/merge.c:373 msgid "Finishing SQUASH_MSG" -msgstr "" +msgstr "Завършване на съобщението за смачкване SQUASH_MSG" #: builtin/merge.c:396 #, c-format msgid "No merge message -- not updating HEAD\n" msgstr "" +"Липсва съобщение при подаване — указателят „HEAD“ няма да бъде обновен\n" #: builtin/merge.c:446 #, c-format msgid "'%s' does not point to a commit" -msgstr "" +msgstr "„%s“ не сочи към подаване" #: builtin/merge.c:558 #, c-format msgid "Bad branch.%s.mergeoptions string: %s" -msgstr "" +msgstr "Неправилен низ за настройката „branch.%s.mergeoptions“: „%s“" #: builtin/merge.c:653 msgid "git write-tree failed to write a tree" msgstr "Командата „git write-tree“ не успя да запише обект-дърво" -#: builtin/merge.c:681 +#: builtin/merge.c:678 msgid "Not handling anything other than two heads merge." -msgstr "" +msgstr "Поддържа се само сливане на точно две истории." -#: builtin/merge.c:695 +#: builtin/merge.c:692 #, c-format msgid "Unknown option for merge-recursive: -X%s" -msgstr "" +msgstr "Непозната опция за рекурсивното сливане „merge-recursive“: „-X%s“" -#: builtin/merge.c:709 +#: builtin/merge.c:705 #, c-format msgid "unable to write %s" -msgstr "" +msgstr "„%s“ не може да бъде записан" -#: builtin/merge.c:798 +#: builtin/merge.c:794 #, c-format msgid "Could not read from '%s'" -msgstr "" +msgstr "От „%s“ не може да се чете" -#: builtin/merge.c:807 +#: builtin/merge.c:803 #, c-format msgid "Not committing merge; use 'git commit' to complete the merge.\n" msgstr "" +"Сливането няма да бъде подадено. За завършването му и подаването му " +"използвайте командата „git commit“.\n" -#: builtin/merge.c:813 +#: builtin/merge.c:809 #, c-format msgid "" "Please enter a commit message to explain why this merge is necessary,\n" @@ -6927,48 +7163,56 @@ msgid "" "Lines starting with '%c' will be ignored, and an empty message aborts\n" "the commit.\n" msgstr "" +"В съобщението при подаване добавете информация за причината за\n" +"сливането, особено ако сливате обновен отдалечен клон в тематичен клон.\n" +"\n" +"Редовете, които започват с „%c“ ще бъдат пропуснати, а празно съобщение\n" +"преустановява подаването.\n" -#: builtin/merge.c:837 +#: builtin/merge.c:833 msgid "Empty commit message." -msgstr "" +msgstr "Празно съобщение при подаване." -#: builtin/merge.c:849 +# FIXME - WTF is wonderful. +#: builtin/merge.c:845 #, c-format msgid "Wonderful.\n" -msgstr "" +msgstr "Чудесно.\n" -#: builtin/merge.c:914 +#: builtin/merge.c:908 #, c-format msgid "Automatic merge failed; fix conflicts and then commit the result.\n" -msgstr "" +msgstr "Неуспешно сливане — коригирайте конфликтите и подайте резултата.\n" -#: builtin/merge.c:930 +#: builtin/merge.c:924 #, c-format msgid "'%s' is not a commit" -msgstr "" +msgstr "„%s“ не е подаване" -#: builtin/merge.c:971 +#: builtin/merge.c:965 msgid "No current branch." -msgstr "" +msgstr "Няма текущ клон." -#: builtin/merge.c:973 +#: builtin/merge.c:967 msgid "No remote for the current branch." -msgstr "" +msgstr "Текущият клон не следи никой." -#: builtin/merge.c:975 +#: builtin/merge.c:969 msgid "No default upstream defined for the current branch." -msgstr "" +msgstr "Текущият клон не следи никой клон." -#: builtin/merge.c:980 +#: builtin/merge.c:974 #, c-format msgid "No remote-tracking branch for %s from %s" -msgstr "" +msgstr "Никой клон не следи клона „%s“ от хранилището „%s“" -#: builtin/merge.c:1136 +#: builtin/merge.c:1130 msgid "There is no merge to abort (MERGE_HEAD missing)." msgstr "" +"Не може да преустановите сливане, защото в момента не се извършва такова " +"(липсва указател „MERGE_HEAD“)." -#: builtin/merge.c:1152 git-pull.sh:31 +#: builtin/merge.c:1146 git-pull.sh:31 msgid "" "You have not concluded your merge (MERGE_HEAD exists).\n" "Please, commit your changes before you can merge." @@ -6976,11 +7220,11 @@ msgstr "" "Не сте завършили сливане. (Указателят „MERGE_HEAD“ съществува).\n" "Подайте промените си, преди да започнете ново сливане." -#: builtin/merge.c:1155 git-pull.sh:34 +#: builtin/merge.c:1149 git-pull.sh:34 msgid "You have not concluded your merge (MERGE_HEAD exists)." msgstr "Не сте завършили сливане. (Указателят „MERGE_HEAD“ съществува)." -#: builtin/merge.c:1159 +#: builtin/merge.c:1153 msgid "" "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n" "Please, commit your changes before you can merge." @@ -6988,183 +7232,197 @@ msgstr "" "Не сте завършили отбиране на подаване (указателят „CHERRY_PICK_HEAD“\n" "съществува). Подайте промените си, преди да започнете ново сливане." -#: builtin/merge.c:1162 +#: builtin/merge.c:1156 msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)." msgstr "" "Не сте завършили отбиране на подаване (указателят „CHERRY_PICK_HEAD“\n" "съществува)." -#: builtin/merge.c:1171 +#: builtin/merge.c:1165 msgid "You cannot combine --squash with --no-ff." -msgstr "" +msgstr "Опцията „--squash“ е несъвместима с „--no-ff“." -#: builtin/merge.c:1180 +#: builtin/merge.c:1174 msgid "No commit specified and merge.defaultToUpstream not set." msgstr "" +"Не е указано подаване и настройката „merge.defaultToUpstream“ не е зададена." -#: builtin/merge.c:1212 +#: builtin/merge.c:1206 msgid "Can merge only exactly one commit into empty head" -msgstr "" +msgstr "Можете да слеете точно едно подаване във връх без история" -#: builtin/merge.c:1215 +#: builtin/merge.c:1209 msgid "Squash commit into empty head not supported yet" -msgstr "" +msgstr "Подаване със смачкване във връх без история все още не се поддържа" -#: builtin/merge.c:1217 +#: builtin/merge.c:1211 msgid "Non-fast-forward commit does not make sense into an empty head" msgstr "" +"Понеже върхът е без история, всички сливания са тривиални, не може да се " +"извърши нетривиално сливане изисквано от опцията „--no-ff“" -#: builtin/merge.c:1222 +#: builtin/merge.c:1216 #, c-format msgid "%s - not something we can merge" -msgstr "" +msgstr "„%s“ — не е нещо, което може да се слее" -#: builtin/merge.c:1273 +#: builtin/merge.c:1267 #, c-format msgid "Commit %s has an untrusted GPG signature, allegedly by %s." msgstr "" +"Подаването „%s“ е с недоверен подпис от GPG, който твърди, че е на „%s“." -#: builtin/merge.c:1276 +#: builtin/merge.c:1270 #, c-format msgid "Commit %s has a bad GPG signature allegedly by %s." msgstr "" +"Подаването „%s“ е с неправилен подпис от GPG, който твърди, че е на „%s“." -#: builtin/merge.c:1279 +#: builtin/merge.c:1273 #, c-format msgid "Commit %s does not have a GPG signature." -msgstr "" +msgstr "Подаването „%s“ е без подпис от GPG." -#: builtin/merge.c:1282 +#: builtin/merge.c:1276 #, c-format msgid "Commit %s has a good GPG signature by %s\n" -msgstr "" +msgstr "Подаването „%s“ е с коректен подпис от GPG на „%s“.\n" -#: builtin/merge.c:1366 +#: builtin/merge.c:1357 #, c-format msgid "Updating %s..%s\n" -msgstr "" +msgstr "Обновяване „%s..%s“\n" -#: builtin/merge.c:1405 +#: builtin/merge.c:1396 #, c-format msgid "Trying really trivial in-index merge...\n" -msgstr "" +msgstr "Проба с най-тривиалното сливане в рамките на индекса…\n" -#: builtin/merge.c:1412 +# FIXME WTF message +#: builtin/merge.c:1403 #, c-format msgid "Nope.\n" -msgstr "" +msgstr "Неуспех.\n" -#: builtin/merge.c:1444 +#: builtin/merge.c:1435 msgid "Not possible to fast-forward, aborting." msgstr "" +"Не може да се извърши тривиално сливане, преустановяване на действието." -#: builtin/merge.c:1467 builtin/merge.c:1546 +#: builtin/merge.c:1458 builtin/merge.c:1537 #, c-format msgid "Rewinding the tree to pristine...\n" -msgstr "" +msgstr "Привеждане на дървото към първоначалното…\n" -#: builtin/merge.c:1471 +#: builtin/merge.c:1462 #, c-format msgid "Trying merge strategy %s...\n" -msgstr "" +msgstr "Пробване със стратегията за сливане „%s“…\n" -#: builtin/merge.c:1537 +#: builtin/merge.c:1528 #, c-format msgid "No merge strategy handled the merge.\n" -msgstr "" +msgstr "Никоя стратегия за сливане не може да извърши сливането.\n" -#: builtin/merge.c:1539 +#: builtin/merge.c:1530 #, c-format msgid "Merge with strategy %s failed.\n" -msgstr "" +msgstr "Неуспешно сливане със стратегия „%s“.\n" -#: builtin/merge.c:1548 +#: builtin/merge.c:1539 #, c-format msgid "Using the %s to prepare resolving by hand.\n" msgstr "" +"Ползва се стратегията „%s“, която ще подготви дървото за коригиране на " +"ръка.\n" -#: builtin/merge.c:1560 +#: builtin/merge.c:1551 #, c-format msgid "Automatic merge went well; stopped before committing as requested\n" msgstr "" +"Автоматичното сливане завърши успешно. Самото подаване не е извършено, " +"защото бе зададена опцията „--no-commit“.\n" #: builtin/merge-base.c:29 msgid "git merge-base [-a|--all] ..." -msgstr "" +msgstr "git merge-base [-a|--all] ПОДАВАНЕ ПОДАВАНЕ…" #: builtin/merge-base.c:30 msgid "git merge-base [-a|--all] --octopus ..." -msgstr "" +msgstr "git merge-base [-a|--all] --octopus ПОДАВАНЕ…" #: builtin/merge-base.c:31 msgid "git merge-base --independent ..." -msgstr "" +msgstr "git merge-base --independent ПОДАВАНЕ…" #: builtin/merge-base.c:32 msgid "git merge-base --is-ancestor " -msgstr "" +msgstr "git merge-base --is-ancestor ПОДАВАНЕ_1 ПОДАВАНЕ_2" #: builtin/merge-base.c:33 msgid "git merge-base --fork-point []" -msgstr "" +msgstr "git merge-base --fork-point УКАЗАТЕЛ [ПОДАВАНЕ]" #: builtin/merge-base.c:214 msgid "output all common ancestors" -msgstr "" +msgstr "извеждане на всички общи предшественици" #: builtin/merge-base.c:216 msgid "find ancestors for a single n-way merge" msgstr "" +"откриване на предшествениците за еднократно сливане на множество истории" #: builtin/merge-base.c:218 msgid "list revs not reachable from others" -msgstr "" +msgstr "извеждане на недостижимите от другите указатели" #: builtin/merge-base.c:220 msgid "is the first one ancestor of the other?" -msgstr "" +msgstr "ПОДАВАНЕ_1 предшественик ли е на ПОДАВАНЕ_2?" #: builtin/merge-base.c:222 msgid "find where forked from reflog of " -msgstr "" +msgstr "откриване къде ПОДАВАНЕто се е отклонило от историята на УКАЗАТЕЛя" #: builtin/merge-file.c:8 msgid "" "git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file " "file2" msgstr "" +"git merge-file [ОПЦИЯ…] [-L ИМЕ_1 [-L ОРИГИНАЛ [-L ИМЕ_2]]] ФАЙЛ_1 ОРИГ_ФАЙЛ " +"ФАЙЛ_2" #: builtin/merge-file.c:33 msgid "send results to standard output" -msgstr "" +msgstr "извеждане на резултатите на стандартния изход" #: builtin/merge-file.c:34 msgid "use a diff3 based merge" -msgstr "" +msgstr "сливане на базата на „diff3“" #: builtin/merge-file.c:35 msgid "for conflicts, use our version" -msgstr "" +msgstr "при конфликти да се ползва локалната версия" #: builtin/merge-file.c:37 msgid "for conflicts, use their version" -msgstr "" +msgstr "при конфликти да се ползва чуждата версия" #: builtin/merge-file.c:39 msgid "for conflicts, use a union version" -msgstr "" +msgstr "при конфликти да се ползва обединена версия" #: builtin/merge-file.c:42 msgid "for conflicts, use this marker size" -msgstr "" +msgstr "при конфликти да се ползва маркер с такъв БРОЙ знаци" #: builtin/merge-file.c:43 msgid "do not warn about conflicts" -msgstr "" +msgstr "без предупреждения при конфликти" #: builtin/merge-file.c:45 msgid "set labels for file1/orig_file/file2" -msgstr "" +msgstr "задаване на етикети за ФАЙЛ_1/ОРИГИНАЛ/ФАЙЛ_2" #: builtin/mktree.c:64 msgid "git mktree [-z] [--missing] [--batch]" @@ -7172,7 +7430,7 @@ msgstr "git mktree [-z] [--missing] [--batch]" #: builtin/mktree.c:150 msgid "input is NUL terminated" -msgstr "входните записа са разделени с нулевия знак „NUL“" +msgstr "входните записи са разделени с нулевия знак „NUL“" #: builtin/mktree.c:151 builtin/write-tree.c:24 msgid "allow missing objects" @@ -7184,7 +7442,7 @@ msgstr "разрешаване на създаването на повече о #: builtin/mv.c:15 msgid "git mv [options] ... " -msgstr "git mv [ОПЦИИ] ОБЕКТ… ЦЕЛ" +msgstr "git mv [ОПЦИЯ…] ОБЕКТ… ЦЕЛ" #: builtin/mv.c:71 msgid "force move/rename even if target exists" @@ -7220,7 +7478,7 @@ msgstr "Директорията „%s“ е в индекса, но не е п #: builtin/mv.c:140 builtin/rm.c:318 msgid "Please, stage your changes to .gitmodules or stash them to proceed" msgstr "" -"За да продължите или вкарайте промените по файла „.gitmodules“ в индекса,\n" +"За да продължите, или вкарайте промените по файла „.gitmodules“ в индекса,\n" "или ги скатайте" # FIXME message @@ -7237,298 +7495,308 @@ msgstr "първоначалната директория е празна" msgid "not under version control" msgstr "не е под контрола на Git" -#: builtin/mv.c:207 +#: builtin/mv.c:208 msgid "destination exists" msgstr "целта съществува" -#: builtin/mv.c:215 +#: builtin/mv.c:216 #, c-format msgid "overwriting '%s'" msgstr "презаписване на „%s“" -#: builtin/mv.c:218 +#: builtin/mv.c:219 msgid "Cannot overwrite" msgstr "Презаписването е невъзможно" -#: builtin/mv.c:221 +#: builtin/mv.c:222 msgid "multiple sources for the same target" msgstr "множество източници за една цел" -#: builtin/mv.c:223 +#: builtin/mv.c:224 msgid "destination directory does not exist" msgstr "целевата директория не съществува" -#: builtin/mv.c:243 +#: builtin/mv.c:244 #, c-format msgid "%s, source=%s, destination=%s" msgstr "%s, обект: „%s“, цел: „%s“" -#: builtin/mv.c:253 +#: builtin/mv.c:254 #, c-format msgid "Renaming %s to %s\n" msgstr "Преименуване на „%s“ на „%s“\n" -#: builtin/mv.c:256 builtin/remote.c:726 builtin/repack.c:355 +#: builtin/mv.c:257 builtin/remote.c:725 builtin/repack.c:358 #, c-format msgid "renaming '%s' failed" msgstr "неуспешно преименуване на „%s“" -#: builtin/name-rev.c:258 +#: builtin/name-rev.c:255 msgid "git name-rev [options] ..." -msgstr "" +msgstr "git name-rev [ОПЦИЯ…] ПОДАВАНЕ…" -#: builtin/name-rev.c:259 +#: builtin/name-rev.c:256 msgid "git name-rev [options] --all" -msgstr "" +msgstr "git name-rev [ОПЦИЯ…] --all" -#: builtin/name-rev.c:260 +#: builtin/name-rev.c:257 msgid "git name-rev [options] --stdin" -msgstr "" +msgstr "git name-rev [ОПЦИЯ…] --stdin" -# FIXME -#: builtin/name-rev.c:312 +# FIXME sha +#: builtin/name-rev.c:309 msgid "print only names (no SHA-1)" -msgstr "" +msgstr "извеждане само на имената (без сумите по SHA1)" -#: builtin/name-rev.c:313 +#: builtin/name-rev.c:310 msgid "only use tags to name the commits" -msgstr "" +msgstr "използване само на етикетите за именуване на подаванията" -#: builtin/name-rev.c:315 +#: builtin/name-rev.c:312 msgid "only use refs matching " -msgstr "" +msgstr "използване само на шаблоните напасващи на ШАБЛОНа" -#: builtin/name-rev.c:317 +#: builtin/name-rev.c:314 msgid "list all commits reachable from all refs" msgstr "" +"извеждане на всички подавания, които могат да бъдат достигнати от всички " +"указатели" -#: builtin/name-rev.c:318 +#: builtin/name-rev.c:315 msgid "read from stdin" -msgstr "" +msgstr "четене от стандартния вход" -#: builtin/name-rev.c:319 +#: builtin/name-rev.c:316 msgid "allow to print `undefined` names (default)" -msgstr "" +msgstr "да се извеждат и недефинираните имена (стандартна стойност на опцията)" -#: builtin/name-rev.c:325 +#: builtin/name-rev.c:322 msgid "dereference tags in the input (internal use)" -msgstr "" +msgstr "извеждане на идентификаторите на обекти-етикети (за вътрешни нужди)" #: builtin/notes.c:24 msgid "git notes [--ref ] [list []]" -msgstr "" +msgstr "git notes [--ref УКАЗАТЕЛ_ЗА_БЕЛЕЖКА] [list [ОБЕКТ]]" #: builtin/notes.c:25 msgid "" "git notes [--ref ] add [-f] [-m | -F | (-c | -C) " "] []" msgstr "" +"git notes [--ref УКАЗАТЕЛ_ЗА_БЕЛЕЖКА] add [-f] [-m СЪОБЩЕНИЕ | -F ФАЙЛ | (-c " +"| -C) ОБЕКТ] [ОБЕКТ]" #: builtin/notes.c:26 msgid "git notes [--ref ] copy [-f] " msgstr "" +"git notes [--ref УКАЗАТЕЛ_ЗА_БЕЛЕЖКА] copy [-f] ОБЕКТ_ИЗТОЧНИК ОБЕКТ_ЦЕЛ" #: builtin/notes.c:27 msgid "" "git notes [--ref ] append [-m | -F | (-c | -C) " "] []" msgstr "" +"git notes [--ref УКАЗАТЕЛ_ЗА_БЕЛЕЖКА] append [-m СЪОБЩЕНИЕ | -F ФАЙЛ | (-c | " +"-C) ОБЕКТ] [ОБЕКТ]" #: builtin/notes.c:28 msgid "git notes [--ref ] edit []" -msgstr "" +msgstr "git notes [--ref УКАЗАТЕЛ_ЗА_БЕЛЕЖКА] edit [ОБЕКТ]" #: builtin/notes.c:29 msgid "git notes [--ref ] show []" -msgstr "" +msgstr "git notes [--ref УКАЗАТЕЛ_ЗА_БЕЛЕЖКА] show [ОБЕКТ]" #: builtin/notes.c:30 msgid "" "git notes [--ref ] merge [-v | -q] [-s ] " msgstr "" +"git notes [--ref УКАЗАТЕЛ_ЗА_БЕЛЕЖКА] merge [-v | -q] [-s СТРАТЕГИЯ] " +"УКАЗАТЕЛ_ЗА_БЕЛЕЖКА" #: builtin/notes.c:31 msgid "git notes merge --commit [-v | -q]" -msgstr "" +msgstr "git notes merge --commit [-v | -q]" #: builtin/notes.c:32 msgid "git notes merge --abort [-v | -q]" -msgstr "" +msgstr "git notes merge --abort [-v | -q]" #: builtin/notes.c:33 msgid "git notes [--ref ] remove [...]" -msgstr "" +msgstr "git notes [--ref УКАЗАТЕЛ_ЗА_БЕЛЕЖКА] remove [ОБЕКТ…]" #: builtin/notes.c:34 msgid "git notes [--ref ] prune [-n | -v]" -msgstr "" +msgstr "git notes [--ref УКАЗАТЕЛ_ЗА_БЕЛЕЖКА] prune [-n | -v]" #: builtin/notes.c:35 msgid "git notes [--ref ] get-ref" -msgstr "" +msgstr "git notes [--ref УКАЗАТЕЛ_ЗА_БЕЛЕЖКА] get-ref" #: builtin/notes.c:40 msgid "git notes [list []]" -msgstr "" +msgstr "git notes [list [ОБЕКТ]]" #: builtin/notes.c:45 msgid "git notes add [] []" -msgstr "" +msgstr "git notes add [ОПЦИЯ…] [ОБЕКТ]" #: builtin/notes.c:50 msgid "git notes copy [] " -msgstr "" +msgstr "git notes copy [ОПЦИЯ…] ОБЕКТ_ИЗТОЧНИК ОБЕКТ_ЦЕЛ" #: builtin/notes.c:51 msgid "git notes copy --stdin [ ]..." -msgstr "" +msgstr "git notes copy --stdin [ОБЕКТ_ИЗТОЧНИК ОБЕКТ_ЦЕЛ]…" #: builtin/notes.c:56 msgid "git notes append [] []" -msgstr "" +msgstr "git notes append [ОПЦИЯ…] [ОБЕКТ]" #: builtin/notes.c:61 msgid "git notes edit []" -msgstr "" +msgstr "git notes edit [ОБЕКТ]" #: builtin/notes.c:66 msgid "git notes show []" -msgstr "" +msgstr "git notes show [ОБЕКТ]" #: builtin/notes.c:71 msgid "git notes merge [] " -msgstr "" +msgstr "git notes merge [ОПЦИЯ…] УКАЗАТЕЛ_ЗА_БЕЛЕЖКА" #: builtin/notes.c:72 msgid "git notes merge --commit []" -msgstr "" +msgstr "git notes merge --commit [ОПЦИЯ…]" #: builtin/notes.c:73 msgid "git notes merge --abort []" -msgstr "" +msgstr "git notes merge --abort [ОПЦИЯ…]" #: builtin/notes.c:78 msgid "git notes remove []" -msgstr "" +msgstr "git notes remove [ОБЕКТ]" #: builtin/notes.c:83 msgid "git notes prune []" -msgstr "" +msgstr "git notes prune [ОПЦИЯ…]" #: builtin/notes.c:88 msgid "git notes get-ref" -msgstr "" +msgstr "git notes get-ref" #: builtin/notes.c:137 #, c-format msgid "unable to start 'show' for object '%s'" -msgstr "" +msgstr "действието „show“ не може да се изпълни за обект „%s“" #: builtin/notes.c:141 msgid "could not read 'show' output" -msgstr "" +msgstr "изведената информация от действието „show“ не може да се прочете" #: builtin/notes.c:149 #, c-format msgid "failed to finish 'show' for object '%s'" -msgstr "" +msgstr "действието „show“ не може да се завърши за обект „%s“" -#: builtin/notes.c:167 builtin/tag.c:373 +#: builtin/notes.c:167 builtin/tag.c:477 #, c-format msgid "could not create file '%s'" -msgstr "" +msgstr "файлът „%s“ не може да бъде създаден" #: builtin/notes.c:186 msgid "Please supply the note contents using either -m or -F option" -msgstr "" +msgstr "Задайте съдържанието на бележката с някоя от опциите „-m“ или „-F“" #: builtin/notes.c:207 builtin/notes.c:848 #, c-format msgid "Removing note for object %s\n" -msgstr "" +msgstr "Изтриване на бележката за обекта „%s“\n" #: builtin/notes.c:212 msgid "unable to write note object" -msgstr "" +msgstr "обектът-бележка не може да бъде записан" #: builtin/notes.c:214 #, c-format msgid "The note contents has been left in %s" -msgstr "" +msgstr "Съдържанието на бележката е във файла „%s“" -#: builtin/notes.c:248 builtin/tag.c:604 +#: builtin/notes.c:248 builtin/tag.c:692 #, c-format msgid "cannot read '%s'" -msgstr "" +msgstr "файлът „%s“ не може да бъде прочетен" -#: builtin/notes.c:250 builtin/tag.c:607 +#: builtin/notes.c:250 builtin/tag.c:695 #, c-format msgid "could not open or read '%s'" -msgstr "" +msgstr "файлът „%s“ не може да бъде отворен или прочетен" #: builtin/notes.c:269 builtin/notes.c:320 builtin/notes.c:322 #: builtin/notes.c:382 builtin/notes.c:436 builtin/notes.c:519 #: builtin/notes.c:524 builtin/notes.c:599 builtin/notes.c:641 -#: builtin/notes.c:843 builtin/tag.c:620 +#: builtin/notes.c:843 builtin/tag.c:708 #, c-format msgid "Failed to resolve '%s' as a valid ref." -msgstr "" +msgstr "Не може да се открие към какво сочи „%s“." #: builtin/notes.c:272 #, c-format msgid "Failed to read object '%s'." -msgstr "" +msgstr "Обектът „%s“ не може да бъде прочетен." #: builtin/notes.c:276 #, c-format msgid "Cannot read note data from non-blob object '%s'." msgstr "" +"Съдържанието на бележка не може да се вземе от обект, който не е BLOB: „%s“." #: builtin/notes.c:316 #, c-format msgid "Malformed input line: '%s'." -msgstr "" +msgstr "Даденият входен ред е с неправилен формат: „%s“." #: builtin/notes.c:331 #, c-format msgid "Failed to copy notes from '%s' to '%s'" -msgstr "" +msgstr "Бележката не може да се копира от „%s“ към „%s“" #: builtin/notes.c:375 builtin/notes.c:429 builtin/notes.c:502 #: builtin/notes.c:514 builtin/notes.c:587 builtin/notes.c:634 #: builtin/notes.c:908 msgid "too many parameters" -msgstr "" +msgstr "прекалено много параметри" #: builtin/notes.c:388 builtin/notes.c:647 #, c-format msgid "No note found for object %s." -msgstr "" +msgstr "Няма бележки за обекта „%s“." #: builtin/notes.c:410 builtin/notes.c:567 msgid "note contents as a string" -msgstr "" +msgstr "низ, който е съдържанието на бележката" #: builtin/notes.c:413 builtin/notes.c:570 msgid "note contents in a file" -msgstr "" +msgstr "файл със съдържанието на бележката" #: builtin/notes.c:415 builtin/notes.c:418 builtin/notes.c:572 -#: builtin/notes.c:575 builtin/tag.c:539 +#: builtin/notes.c:575 builtin/tag.c:627 msgid "object" -msgstr "" +msgstr "обект" #: builtin/notes.c:416 builtin/notes.c:573 msgid "reuse and edit specified note object" -msgstr "" +msgstr "преизползване и редактиране на указания обект-бележка" #: builtin/notes.c:419 builtin/notes.c:576 msgid "reuse specified note object" -msgstr "" +msgstr "преизползване на указания обект-бележка" #: builtin/notes.c:421 builtin/notes.c:489 msgid "replace existing notes" -msgstr "" +msgstr "замяна на съществуващите бележки" #: builtin/notes.c:455 #, c-format @@ -7536,23 +7804,28 @@ msgid "" "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite " "existing notes" msgstr "" +"Не може да се добави бележка, защото такава вече съществува за обекта „%s“. " +"Използвайте опцията „-f“, за да презапишете съществуващи бележки." #: builtin/notes.c:460 builtin/notes.c:537 #, c-format msgid "Overwriting existing notes for object %s\n" -msgstr "" +msgstr "Презаписване на съществуващите бележки за обекта „%s“\n" #: builtin/notes.c:490 msgid "read objects from stdin" -msgstr "" +msgstr "изчитане на обектите от стандартния вход" +# FIXME imporve message #: builtin/notes.c:492 msgid "load rewriting config for (implies --stdin)" msgstr "" +"зареждане на настройките за КОМАНДАта, която презаписва подавания (включва " +"опцията „--stdin“)" #: builtin/notes.c:510 msgid "too few parameters" -msgstr "" +msgstr "прекалено малко параметри" #: builtin/notes.c:531 #, c-format @@ -7560,11 +7833,15 @@ msgid "" "Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite " "existing notes" msgstr "" +"Не може да се копира бележка, защото такава вече съществува за обекта „%s“. " +"Използвайте опцията „-f“, за да презапишете съществуващи бележки." #: builtin/notes.c:543 #, c-format msgid "Missing notes on source object %s. Cannot copy." msgstr "" +"Не може да се копира бележка, която не съществува — няма бележки за обекта-" +"източник „%s“." #: builtin/notes.c:592 #, c-format @@ -7572,59 +7849,67 @@ msgid "" "The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n" "Please use 'git notes add -f -m/-F/-c/-C' instead.\n" msgstr "" +"Задаването на опциите „-m“/„-F“/„-c“/„-C“ с командата „edit“ вече е " +"остаряло.\n" +"Вместо това ги използвайте с командата „add“: „git notes add -f -m/-F/-c/-" +"C“.\n" #: builtin/notes.c:739 msgid "General options" -msgstr "" +msgstr "Общи опции" #: builtin/notes.c:741 msgid "Merge options" -msgstr "" +msgstr "Опции при сливане" #: builtin/notes.c:743 msgid "" "resolve notes conflicts using the given strategy (manual/ours/theirs/union/" "cat_sort_uniq)" msgstr "" +"коригиране на конфликтите при сливане на бележките чрез тази стратегия — " +"„manual“ (ръчно), „ours“ (вашата версия), „theirs“ (чуждата версия), " +"„union“ (обединяване), „cat_sort_uniq“ (обединяване, подреждане, уникални " +"резултати)" #: builtin/notes.c:745 msgid "Committing unmerged notes" -msgstr "" +msgstr "Подаване на неслети бележки" #: builtin/notes.c:747 msgid "finalize notes merge by committing unmerged notes" -msgstr "" +msgstr "завършване на сливането чрез подаване на неслети бележки" #: builtin/notes.c:749 msgid "Aborting notes merge resolution" -msgstr "" +msgstr "Преустановяване на корекцията при сливането на бележки" #: builtin/notes.c:751 msgid "abort notes merge" -msgstr "" +msgstr "преустановяване на сливането на бележки" #: builtin/notes.c:846 #, c-format msgid "Object %s has no note\n" -msgstr "" +msgstr "Няма бележки за обекта „%s“\n" #: builtin/notes.c:858 msgid "attempt to remove non-existent note is not an error" -msgstr "" +msgstr "опитът за изтриването на несъществуваща бележка не се счита за грешка" #: builtin/notes.c:861 msgid "read object names from the standard input" -msgstr "" +msgstr "изчитане на имената на обектите от стандартния вход" #: builtin/notes.c:942 msgid "notes-ref" -msgstr "" +msgstr "УКАЗАТЕЛ_ЗА_БЕЛЕЖКА" #: builtin/notes.c:943 msgid "use notes from " -msgstr "" +msgstr "да се използва бележката сочена от този УКАЗАТЕЛ_ЗА_БЕЛЕЖКА" -#: builtin/notes.c:978 builtin/remote.c:1593 +#: builtin/notes.c:978 builtin/remote.c:1616 #, c-format msgid "Unknown subcommand: %s" msgstr "Непозната подкоманда: %s" @@ -7632,15 +7917,19 @@ msgstr "Непозната подкоманда: %s" #: builtin/pack-objects.c:25 msgid "git pack-objects --stdout [options...] [< ref-list | < object-list]" msgstr "" +"git pack-objects --stdout [ОПЦИЯ…] [< СПИСЪК_С_ВЕРСИИ | < СПИСЪК_С_ОБЕКТИ]" +# FIXME [options] vs [options...] #: builtin/pack-objects.c:26 msgid "git pack-objects [options...] base-name [< ref-list | < object-list]" msgstr "" +"git pack-objects [ОПЦИЯ…] ПРЕФИКС_НА_ИМЕТО [< СПИСЪК_С_ВЕРСИИ | < " +"СПИСЪК_С_ОБЕКТИ]" #: builtin/pack-objects.c:175 builtin/pack-objects.c:178 #, c-format msgid "deflate error (%d)" -msgstr "" +msgstr "грешка при декомпресиране с „deflate“ (%d)" #: builtin/pack-objects.c:771 msgid "Writing objects" @@ -7649,166 +7938,182 @@ msgstr "Записване на обектите" #: builtin/pack-objects.c:1012 msgid "disabling bitmap writing, as some objects are not being packed" msgstr "" +"изключване на записването на битовата маска, защото някои обекти няма да се " +"пакетират" #: builtin/pack-objects.c:2174 msgid "Compressing objects" msgstr "Компресиране на обектите" -#: builtin/pack-objects.c:2530 +#: builtin/pack-objects.c:2526 #, c-format msgid "unsupported index version %s" -msgstr "" +msgstr "неподдържана версия на индекса „%s“" -#: builtin/pack-objects.c:2534 +#: builtin/pack-objects.c:2530 #, c-format msgid "bad index version '%s'" -msgstr "" +msgstr "неправилна версия на индекса „%s“" -#: builtin/pack-objects.c:2557 +#: builtin/pack-objects.c:2553 #, c-format msgid "option %s does not accept negative form" -msgstr "" +msgstr "опцията „%s“ не притежава отрицателна версия" -#: builtin/pack-objects.c:2561 +#: builtin/pack-objects.c:2557 #, c-format msgid "unable to parse value '%s' for option %s" -msgstr "" +msgstr "неразпозната стойност „%s“ за опцията „%s“" -#: builtin/pack-objects.c:2580 +#: builtin/pack-objects.c:2576 msgid "do not show progress meter" -msgstr "" +msgstr "без извеждане на напредъка" -#: builtin/pack-objects.c:2582 +#: builtin/pack-objects.c:2578 msgid "show progress meter" -msgstr "" +msgstr "извеждане на напредъка" -#: builtin/pack-objects.c:2584 +#: builtin/pack-objects.c:2580 msgid "show progress meter during object writing phase" -msgstr "" +msgstr "извеждане на напредъка във фазата на запазване на обектите" -#: builtin/pack-objects.c:2587 +#: builtin/pack-objects.c:2583 msgid "similar to --all-progress when progress meter is shown" msgstr "" +"същото действие като опцията „--all-progress“ при извеждането на напредъка" -#: builtin/pack-objects.c:2588 +#: builtin/pack-objects.c:2584 msgid "version[,offset]" -msgstr "" +msgstr "ВЕРСИЯ[,ОТМЕСТВАНЕ]" -#: builtin/pack-objects.c:2589 +#: builtin/pack-objects.c:2585 msgid "write the pack index file in the specified idx format version" msgstr "" +"запазване на индекса на пакетните файлове във форма̀та с указаната версия" -#: builtin/pack-objects.c:2592 +#: builtin/pack-objects.c:2588 msgid "maximum size of each output pack file" -msgstr "" +msgstr "максимален размер на всеки пакетен файл" -#: builtin/pack-objects.c:2594 +#: builtin/pack-objects.c:2590 msgid "ignore borrowed objects from alternate object store" -msgstr "" +msgstr "игнориране на обектите заети от други хранилища на обекти" -#: builtin/pack-objects.c:2596 +#: builtin/pack-objects.c:2592 msgid "ignore packed objects" -msgstr "" +msgstr "игнориране на пакетираните обекти" -#: builtin/pack-objects.c:2598 +#: builtin/pack-objects.c:2594 msgid "limit pack window by objects" -msgstr "" +msgstr "ограничаване на прозореца за пакетиране по брой обекти" -#: builtin/pack-objects.c:2600 +#: builtin/pack-objects.c:2596 msgid "limit pack window by memory in addition to object limit" msgstr "" +"ограничаване на прозореца за пакетиране и по памет освен по брой обекти" -#: builtin/pack-objects.c:2602 +#: builtin/pack-objects.c:2598 msgid "maximum length of delta chain allowed in the resulting pack" msgstr "" +"максимална дължина на веригата от разлики, която е позволена в пакетния файл" -#: builtin/pack-objects.c:2604 +#: builtin/pack-objects.c:2600 msgid "reuse existing deltas" -msgstr "" +msgstr "преизползване на съществуващите разлики" -#: builtin/pack-objects.c:2606 +#: builtin/pack-objects.c:2602 msgid "reuse existing objects" -msgstr "" +msgstr "преизползване на съществуващите обекти" -#: builtin/pack-objects.c:2608 +#: builtin/pack-objects.c:2604 msgid "use OFS_DELTA objects" -msgstr "" +msgstr "използване на обекти „OFS_DELTA“" -#: builtin/pack-objects.c:2610 +#: builtin/pack-objects.c:2606 msgid "use threads when searching for best delta matches" msgstr "" +"стартиране на нишки за претърсване на най-добрите съвпадения на разликите" -#: builtin/pack-objects.c:2612 +#: builtin/pack-objects.c:2608 msgid "do not create an empty pack output" -msgstr "" +msgstr "без създаване на празен пакетен файл" -#: builtin/pack-objects.c:2614 +#: builtin/pack-objects.c:2610 msgid "read revision arguments from standard input" -msgstr "" +msgstr "изчитане на версиите от стандартния вход" -#: builtin/pack-objects.c:2616 +#: builtin/pack-objects.c:2612 msgid "limit the objects to those that are not yet packed" -msgstr "" +msgstr "ограничаване до все още непакетираните обекти" -#: builtin/pack-objects.c:2619 +#: builtin/pack-objects.c:2615 msgid "include objects reachable from any reference" msgstr "" +"включване на всички обекти, които могат да се достигнат от произволен " +"указател" -#: builtin/pack-objects.c:2622 +#: builtin/pack-objects.c:2618 msgid "include objects referred by reflog entries" -msgstr "" +msgstr "включване и на обектите сочени от записите в журнала на указателите" -#: builtin/pack-objects.c:2625 +#: builtin/pack-objects.c:2621 msgid "output pack to stdout" -msgstr "" +msgstr "извеждане на пакета на стандартния изход" -#: builtin/pack-objects.c:2627 +#: builtin/pack-objects.c:2623 msgid "include tag objects that refer to objects to be packed" msgstr "" +"включване и на обектите-етикети, които сочат към обектите, които ще бъдат " +"пакетирани" -#: builtin/pack-objects.c:2629 +#: builtin/pack-objects.c:2625 msgid "keep unreachable objects" -msgstr "" +msgstr "запазване на недостижимите обекти" -#: builtin/pack-objects.c:2630 parse-options.h:140 +#: builtin/pack-objects.c:2626 parse-options.h:140 msgid "time" -msgstr "време" +msgstr "ВРЕМЕ" -#: builtin/pack-objects.c:2631 +#: builtin/pack-objects.c:2627 msgid "unpack unreachable objects newer than